From 4921f3e806854a0be302ae3f3fd0627094760536 Mon Sep 17 00:00:00 2001 From: PJBot Date: Mon, 1 Jul 2024 03:07:34 +0000 Subject: [PATCH 001/765] Automatic changelog update --- Resources/Changelog/Changelog.yml | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 8a849d31a6e..102a6b7eb03 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,13 +1,4 @@ Entries: -- author: Flareguy - changes: - - message: Colored jumpsuits, shoes, and (most) colored gloves are now colorized - off of one set of greyscale sprites. They should now be more consistent & significantly - less ugly. - type: Tweak - id: 6350 - time: '2024-04-14T08:41:39.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/26943 - author: BramvanZijp changes: - message: Nanotrasen's Small Arms Division has slightly improved the firerate and @@ -3824,3 +3815,11 @@ id: 6849 time: '2024-06-30T17:56:31.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/29516 +- author: EmoGarbage404 + changes: + - message: Blurry vision no longer causes names to momentarily appear as "???" when + examining. + type: Remove + id: 6850 + time: '2024-07-01T03:06:28.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/29633 From 6c7dc6e831c89480542f0fe6d97a2ef3dec9c70f Mon Sep 17 00:00:00 2001 From: Cojoke <83733158+Cojoke-dot@users.noreply.github.com> Date: Mon, 1 Jul 2024 00:33:08 -0500 Subject: [PATCH 002/765] Add Slowdown to Dragging Items that Slow when Held (#29364) * Add slowdown to dragging Items that slow when held * Heh, fancy * Heh, fancy * rename SetMovementSpeedModifiers to GetHeldMovementSpeedModifiers because it was not setting anything --- Content.Shared/Item/HeldSpeedModifierSystem.cs | 8 +++++++- .../Movement/Pulling/Systems/PullingSystem.cs | 11 +++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/Content.Shared/Item/HeldSpeedModifierSystem.cs b/Content.Shared/Item/HeldSpeedModifierSystem.cs index d7afa8f40fa..c3286191b98 100644 --- a/Content.Shared/Item/HeldSpeedModifierSystem.cs +++ b/Content.Shared/Item/HeldSpeedModifierSystem.cs @@ -29,7 +29,7 @@ private void OnGotUnequippedHand(Entity ent, ref Got _movementSpeedModifier.RefreshMovementSpeedModifiers(args.User); } - private void OnRefreshMovementSpeedModifiers(EntityUid uid, HeldSpeedModifierComponent component, HeldRelayedEvent args) + public (float,float) GetHeldMovementSpeedModifiers(EntityUid uid, HeldSpeedModifierComponent component) { var walkMod = component.WalkModifier; var sprintMod = component.SprintModifier; @@ -39,6 +39,12 @@ private void OnRefreshMovementSpeedModifiers(EntityUid uid, HeldSpeedModifierCom sprintMod = clothingSpeedModifier.SprintModifier; } + return (walkMod, sprintMod); + } + + private void OnRefreshMovementSpeedModifiers(EntityUid uid, HeldSpeedModifierComponent component, HeldRelayedEvent args) + { + var (walkMod, sprintMod) = GetHeldMovementSpeedModifiers(uid, component); args.Args.ModifySpeed(walkMod, sprintMod); } } diff --git a/Content.Shared/Movement/Pulling/Systems/PullingSystem.cs b/Content.Shared/Movement/Pulling/Systems/PullingSystem.cs index eb2872df9c1..edc8ad51617 100644 --- a/Content.Shared/Movement/Pulling/Systems/PullingSystem.cs +++ b/Content.Shared/Movement/Pulling/Systems/PullingSystem.cs @@ -8,6 +8,7 @@ using Content.Shared.Hands.EntitySystems; using Content.Shared.Input; using Content.Shared.Interaction; +using Content.Shared.Item; using Content.Shared.Movement.Events; using Content.Shared.Movement.Pulling.Components; using Content.Shared.Movement.Pulling.Events; @@ -43,6 +44,7 @@ public sealed class PullingSystem : EntitySystem [Dependency] private readonly SharedInteractionSystem _interaction = default!; [Dependency] private readonly SharedPhysicsSystem _physics = default!; [Dependency] private readonly SharedPopupSystem _popup = default!; + [Dependency] private readonly HeldSpeedModifierSystem _clothingMoveSpeed = default!; public override void Initialize() { @@ -192,6 +194,14 @@ private void AddPullVerbs(EntityUid uid, PullableComponent component, GetVerbsEv private void OnRefreshMovespeed(EntityUid uid, PullerComponent component, RefreshMovementSpeedModifiersEvent args) { + if (TryComp(component.Pulling, out var heldMoveSpeed) && component.Pulling.HasValue) + { + var (walkMod, sprintMod) = + _clothingMoveSpeed.GetHeldMovementSpeedModifiers(component.Pulling.Value, heldMoveSpeed); + args.ModifySpeed(walkMod, sprintMod); + return; + } + args.ModifySpeed(component.WalkSpeedModifier, component.SprintSpeedModifier); } @@ -459,6 +469,7 @@ public bool TryStartPull(EntityUid pullerUid, EntityUid pullableUid, // Messaging var message = new PullStartedMessage(pullerUid, pullableUid); + _modifierSystem.RefreshMovementSpeedModifiers(pullerUid); _alertsSystem.ShowAlert(pullerUid, pullerComp.PullingAlert); _alertsSystem.ShowAlert(pullableUid, pullableComp.PulledAlert); From cd5fb3bed1ab9e1a23f172cd68d2aeadcd80c3ae Mon Sep 17 00:00:00 2001 From: PJBot Date: Mon, 1 Jul 2024 05:34:15 +0000 Subject: [PATCH 003/765] Automatic changelog update --- Resources/Changelog/Changelog.yml | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 102a6b7eb03..adb76650290 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,15 +1,4 @@ Entries: -- author: BramvanZijp - changes: - - message: Nanotrasen's Small Arms Division has slightly improved the firerate and - drastically improved the accuracy on its WT550 SMGs. - type: Tweak - - message: The WT550 and C-20R SMGs can now fire in a 5 round burst-fire mode, making - it easier for their users to control the recoil on these weapons. - type: Add - id: 6351 - time: '2024-04-14T08:51:07.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/26886 - author: Dutch-VanDerLinde changes: - message: Holoparasites and holoclowns will now phase through projectiles such @@ -3823,3 +3812,10 @@ id: 6850 time: '2024-07-01T03:06:28.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/29633 +- author: Cojoke-dot + changes: + - message: Items that slow down a person when held now slow down when dragged too. + type: Tweak + id: 6851 + time: '2024-07-01T05:33:08.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/29364 From 971686db874b33896f3ace603a501dd5e2c25b41 Mon Sep 17 00:00:00 2001 From: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com> Date: Mon, 1 Jul 2024 16:09:41 +1000 Subject: [PATCH 004/765] Update submodule to 227.0.0 (#29634) --- RobustToolbox | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RobustToolbox b/RobustToolbox index 860c9af2bfb..a9aea7027f1 160000 --- a/RobustToolbox +++ b/RobustToolbox @@ -1 +1 @@ -Subproject commit 860c9af2bfbf1477b96519067ef5e62b2525d987 +Subproject commit a9aea7027f1840c83bcaf1c973caf099745f9eed From 221b8ae4753d3b7446f23e2faa584de7f340cbe5 Mon Sep 17 00:00:00 2001 From: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com> Date: Mon, 1 Jul 2024 16:11:30 +1000 Subject: [PATCH 005/765] Add FTL arrival visuals (#29402) * Add FTL arrival visuals * weh * Update Content.Shared/Shuttles/Components/FTLComponent.cs Co-authored-by: Tayrtahn --------- Co-authored-by: Tayrtahn --- Content.Client/Shuttles/FtlArrivalOverlay.cs | 82 ++++++++++++++++++ .../Systems/ShuttleSystem.EmergencyConsole.cs | 3 +- .../Shuttles/Systems/ShuttleSystem.cs | 21 +++++ .../Systems/ShuttleSystem.FasterThanLight.cs | 20 ++++- .../Shuttles/Systems/ShuttleSystem.cs | 2 + .../Shuttles/Components/FTLComponent.cs | 16 ++-- .../Components/FtlVisualizerComponent.cs | 23 +++++ .../Prototypes/Entities/Effects/shuttle.yml | 12 +++ .../Effects/medi_holo.rsi/medi_holo.png | Bin 0 -> 1286 bytes .../Textures/Effects/medi_holo.rsi/meta.json | 26 ++++++ 10 files changed, 196 insertions(+), 9 deletions(-) create mode 100644 Content.Client/Shuttles/FtlArrivalOverlay.cs create mode 100644 Content.Client/Shuttles/Systems/ShuttleSystem.cs rename {Content.Server => Content.Shared}/Shuttles/Components/FTLComponent.cs (81%) create mode 100644 Content.Shared/Shuttles/Components/FtlVisualizerComponent.cs create mode 100644 Resources/Prototypes/Entities/Effects/shuttle.yml create mode 100644 Resources/Textures/Effects/medi_holo.rsi/medi_holo.png create mode 100644 Resources/Textures/Effects/medi_holo.rsi/meta.json diff --git a/Content.Client/Shuttles/FtlArrivalOverlay.cs b/Content.Client/Shuttles/FtlArrivalOverlay.cs new file mode 100644 index 00000000000..f24a1e96488 --- /dev/null +++ b/Content.Client/Shuttles/FtlArrivalOverlay.cs @@ -0,0 +1,82 @@ +using System.Numerics; +using Content.Shared.Shuttles.Components; +using Robust.Client.GameObjects; +using Robust.Client.Graphics; +using Robust.Shared.Enums; +using Robust.Shared.Map.Components; +using Robust.Shared.Prototypes; +using Robust.Shared.Timing; + +namespace Content.Client.Shuttles; + +/// +/// Plays a visualization whenever a shuttle is arriving from FTL. +/// +public sealed class FtlArrivalOverlay : Overlay +{ + public override OverlaySpace Space => OverlaySpace.WorldSpaceBelowEntities; + + private EntityLookupSystem _lookups; + private SharedMapSystem _maps; + private SharedTransformSystem _transforms; + private SpriteSystem _sprites; + [Dependency] private readonly IEntityManager _entManager = default!; + [Dependency] private readonly IGameTiming _timing = default!; + [Dependency] private readonly IPrototypeManager _protos = default!; + + private readonly HashSet> _visualizers = new(); + + private ShaderInstance _shader; + + public FtlArrivalOverlay() + { + IoCManager.InjectDependencies(this); + _lookups = _entManager.System(); + _transforms = _entManager.System(); + _maps = _entManager.System(); + _sprites = _entManager.System(); + + _shader = _protos.Index("unshaded").Instance(); + } + + protected override bool BeforeDraw(in OverlayDrawArgs args) + { + _visualizers.Clear(); + _lookups.GetEntitiesOnMap(args.MapId, _visualizers); + + return _visualizers.Count > 0; + } + + protected override void Draw(in OverlayDrawArgs args) + { + args.WorldHandle.UseShader(_shader); + + foreach (var (uid, comp) in _visualizers) + { + var grid = comp.Grid; + + if (!_entManager.TryGetComponent(grid, out MapGridComponent? mapGrid)) + continue; + + var texture = _sprites.GetFrame(comp.Sprite, TimeSpan.FromSeconds(comp.Elapsed), loop: false); + comp.Elapsed += (float) _timing.FrameTime.TotalSeconds; + + // Need to manually transform the viewport in terms of the visualizer entity as the grid isn't in position. + var (_, _, worldMatrix, invMatrix) = _transforms.GetWorldPositionRotationMatrixWithInv(uid); + args.WorldHandle.SetTransform(worldMatrix); + var localAABB = invMatrix.TransformBox(args.WorldBounds); + + var tilesEnumerator = _maps.GetLocalTilesEnumerator(grid, mapGrid, localAABB); + + while (tilesEnumerator.MoveNext(out var tile)) + { + var bounds = _lookups.GetLocalBounds(tile, mapGrid.TileSize); + + args.WorldHandle.DrawTextureRect(texture, bounds); + } + } + + args.WorldHandle.UseShader(null); + args.WorldHandle.SetTransform(Matrix3x2.Identity); + } +} diff --git a/Content.Client/Shuttles/Systems/ShuttleSystem.EmergencyConsole.cs b/Content.Client/Shuttles/Systems/ShuttleSystem.EmergencyConsole.cs index d5154a87bef..73c11de2795 100644 --- a/Content.Client/Shuttles/Systems/ShuttleSystem.EmergencyConsole.cs +++ b/Content.Client/Shuttles/Systems/ShuttleSystem.EmergencyConsole.cs @@ -38,9 +38,8 @@ public bool EnableShuttlePosition private bool _enableShuttlePosition; private EmergencyShuttleOverlay? _overlay; - public override void Initialize() + private void InitializeEmergency() { - base.Initialize(); SubscribeNetworkEvent(OnShuttlePosMessage); } diff --git a/Content.Client/Shuttles/Systems/ShuttleSystem.cs b/Content.Client/Shuttles/Systems/ShuttleSystem.cs new file mode 100644 index 00000000000..a2c048ff90e --- /dev/null +++ b/Content.Client/Shuttles/Systems/ShuttleSystem.cs @@ -0,0 +1,21 @@ +using Robust.Client.Graphics; + +namespace Content.Client.Shuttles.Systems; + +public sealed partial class ShuttleSystem +{ + [Dependency] private readonly IOverlayManager _overlays = default!; + + public override void Initialize() + { + base.Initialize(); + InitializeEmergency(); + _overlays.AddOverlay(new FtlArrivalOverlay()); + } + + public override void Shutdown() + { + base.Shutdown(); + _overlays.RemoveOverlay(); + } +} diff --git a/Content.Server/Shuttles/Systems/ShuttleSystem.FasterThanLight.cs b/Content.Server/Shuttles/Systems/ShuttleSystem.FasterThanLight.cs index 28f784f1dda..518867b5558 100644 --- a/Content.Server/Shuttles/Systems/ShuttleSystem.FasterThanLight.cs +++ b/Content.Server/Shuttles/Systems/ShuttleSystem.FasterThanLight.cs @@ -82,6 +82,8 @@ public sealed partial class ShuttleSystem private void InitializeFTL() { SubscribeLocalEvent(OnStationPostInit); + SubscribeLocalEvent(OnFtlShutdown); + _bodyQuery = GetEntityQuery(); _buckleQuery = GetEntityQuery(); _beaconQuery = GetEntityQuery(); @@ -98,6 +100,12 @@ private void InitializeFTL() _cfg.OnValueChanged(CCVars.HyperspaceKnockdownTime, time => _hyperspaceKnockdownTime = TimeSpan.FromSeconds(time), true); } + private void OnFtlShutdown(Entity ent, ref ComponentShutdown args) + { + Del(ent.Comp.VisualizerEntity); + ent.Comp.VisualizerEntity = null; + } + private void OnStationPostInit(ref StationPostInitEvent ev) { // Add all grid maps as ftl destinations that anyone can FTL to. @@ -422,8 +430,16 @@ private void UpdateFTLTravelling(Entity entity) var comp = entity.Comp1; comp.StateTime = StartEndTime.FromCurTime(_gameTiming, DefaultArrivalTime); comp.State = FTLState.Arriving; - // TODO: Arrival effects - // For now we'll just use the ss13 bubbles but we can do fancier. + + if (entity.Comp1.VisualizerProto != null) + { + comp.VisualizerEntity = SpawnAtPosition(entity.Comp1.VisualizerProto, entity.Comp1.TargetCoordinates); + var visuals = Comp(comp.VisualizerEntity.Value); + visuals.Grid = entity.Owner; + Dirty(comp.VisualizerEntity.Value, visuals); + _transform.SetLocalRotation(comp.VisualizerEntity.Value, entity.Comp1.TargetAngle); + _pvs.AddGlobalOverride(comp.VisualizerEntity.Value); + } _thruster.DisableLinearThrusters(shuttle); _thruster.EnableLinearThrustDirection(shuttle, DirectionFlag.South); diff --git a/Content.Server/Shuttles/Systems/ShuttleSystem.cs b/Content.Server/Shuttles/Systems/ShuttleSystem.cs index bbafef022c8..b8f216db737 100644 --- a/Content.Server/Shuttles/Systems/ShuttleSystem.cs +++ b/Content.Server/Shuttles/Systems/ShuttleSystem.cs @@ -11,6 +11,7 @@ using Content.Shared.Throwing; using JetBrains.Annotations; using Robust.Server.GameObjects; +using Robust.Server.GameStates; using Robust.Shared.Audio; using Robust.Shared.Audio.Systems; using Robust.Shared.Configuration; @@ -40,6 +41,7 @@ public sealed partial class ShuttleSystem : SharedShuttleSystem [Dependency] private readonly FixtureSystem _fixtures = default!; [Dependency] private readonly MapLoaderSystem _loader = default!; [Dependency] private readonly MetaDataSystem _metadata = default!; + [Dependency] private readonly PvsOverrideSystem _pvs = default!; [Dependency] private readonly SharedAudioSystem _audio = default!; [Dependency] private readonly SharedMapSystem _maps = default!; [Dependency] private readonly SharedPhysicsSystem _physics = default!; diff --git a/Content.Server/Shuttles/Components/FTLComponent.cs b/Content.Shared/Shuttles/Components/FTLComponent.cs similarity index 81% rename from Content.Server/Shuttles/Components/FTLComponent.cs rename to Content.Shared/Shuttles/Components/FTLComponent.cs index 691e9231370..6b236d3dcf0 100644 --- a/Content.Server/Shuttles/Components/FTLComponent.cs +++ b/Content.Shared/Shuttles/Components/FTLComponent.cs @@ -2,16 +2,16 @@ using Content.Shared.Tag; using Content.Shared.Timing; using Robust.Shared.Audio; +using Robust.Shared.GameStates; using Robust.Shared.Map; using Robust.Shared.Prototypes; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; -namespace Content.Server.Shuttles.Components; +namespace Content.Shared.Shuttles.Components; /// /// Added to a component when it is queued or is travelling via FTL. /// -[RegisterComponent] +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] public sealed partial class FTLComponent : Component { // TODO Full game save / add datafields @@ -29,13 +29,19 @@ public sealed partial class FTLComponent : Component [ViewVariables(VVAccess.ReadWrite)] public float TravelTime = 0f; + [DataField] + public EntProtoId? VisualizerProto = "FtlVisualizerEntity"; + + [DataField, AutoNetworkedField] + public EntityUid? VisualizerEntity; + /// /// Coordinates to arrive it: May be relative to another grid (for docking) or map coordinates. /// - [ViewVariables(VVAccess.ReadWrite), DataField] + [DataField, AutoNetworkedField] public EntityCoordinates TargetCoordinates; - [DataField] + [DataField, AutoNetworkedField] public Angle TargetAngle; /// diff --git a/Content.Shared/Shuttles/Components/FtlVisualizerComponent.cs b/Content.Shared/Shuttles/Components/FtlVisualizerComponent.cs new file mode 100644 index 00000000000..628a4f828b2 --- /dev/null +++ b/Content.Shared/Shuttles/Components/FtlVisualizerComponent.cs @@ -0,0 +1,23 @@ +using Robust.Shared.GameStates; +using Robust.Shared.Utility; + +namespace Content.Shared.Shuttles.Components; + +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +public sealed partial class FtlVisualizerComponent : Component +{ + /// + /// Clientside time tracker for the animation. + /// + [ViewVariables(VVAccess.ReadWrite)] + public float Elapsed; + + [DataField(required: true)] + public SpriteSpecifier.Rsi Sprite; + + /// + /// Target grid to pull FTL visualization from. + /// + [DataField, AutoNetworkedField] + public EntityUid Grid; +} diff --git a/Resources/Prototypes/Entities/Effects/shuttle.yml b/Resources/Prototypes/Entities/Effects/shuttle.yml new file mode 100644 index 00000000000..d4538116ac9 --- /dev/null +++ b/Resources/Prototypes/Entities/Effects/shuttle.yml @@ -0,0 +1,12 @@ +- type: entity + id: FtlVisualizerEntity + noSpawn: true + description: Visualizer for shuttles arriving. You shouldn't see this! + components: + - type: FtlVisualizer + sprite: + sprite: /Textures/Effects/medi_holo.rsi + state: medi_holo + - type: Tag + tags: + - HideContextMenu diff --git a/Resources/Textures/Effects/medi_holo.rsi/medi_holo.png b/Resources/Textures/Effects/medi_holo.rsi/medi_holo.png new file mode 100644 index 0000000000000000000000000000000000000000..9b024faa2d799b09ede0769fb89521a2c66e6b29 GIT binary patch literal 1286 zcmV+h1^N1kP)5Ot-`|VJ$T9$<&?@>gayZ*Tuo?pzy z+r{3C$N+d#F!?wE@4xWf|`9J;Z?ayYjDYg=5pyA&PlRxNhpP!wb?ViK? zKvLe1?*Yb$48TZ-$cM*oA6{4810b>>?OgwVowEt1>LI8_QxL3#i!XPgv9ne{?ahy- zI7owZxtB_RQ{zI;$Fu{JZ}Ok8_1U}U(+}c%Kn8RLO6k^sb*KONhIDJdbHNSBKw}Sb z1B7U$KsUe`H^3M-z!*2c7&pKeH^3M-z!*2cnC=W%tZrW&`u+AFq~C@0uOj+O&UjrI zKqoym!JM`X{bAB$6U=D~G;aV*C}$#RTW;S8{VPsX)3zynn>7FV}i=HydwH6-jIYLg%6FUQ7i&VXY>Y(R&I3BC;CAjN>hN;s)(^wkhKD^EJLF%N0NFZwV_icluA7#`g#=z)9 z=9hK#A>uVO#Rg#X(O+g`8E066pkwmgq<+QZ!Keb=f0Gh+-Q4?}L zy+sH1gjoSlKQ#s9oQ@9Zm+I#!$e1P!NWD@?!P5@HiTqG&>PlrPR4zsA^89)JjmpPP z)(W5-Z*5?cv%FDTay4{}ECVznUy_C-6F;R1SgjU~UA!+~|HKjMB<@7xkJOvpOH9%S)pWF9X zVBH_U#q)n0PeI1)45)oB4z;ZHE%6m#j2mFgU;sA_NN-S>(x{b&7OO@tM+2Nm5Z1>Z z9J{m$iYxOyOt@Ue>bSc8JG|*bV wG)bFqSnikFRtszWlCV!f)_>r-vk8vz7wA2u47-?TCIA2c07*qoM6N<$f_7g|Z2$lO literal 0 HcmV?d00001 diff --git a/Resources/Textures/Effects/medi_holo.rsi/meta.json b/Resources/Textures/Effects/medi_holo.rsi/meta.json new file mode 100644 index 00000000000..1be502223e5 --- /dev/null +++ b/Resources/Textures/Effects/medi_holo.rsi/meta.json @@ -0,0 +1,26 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "https://github.com/tgstation/tgstation/tree/217b39cc85e45302d407d5c1ab60809bd9e18987", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "medi_holo", + "delays": [ + [ + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1 + ] + ] + } + ] +} \ No newline at end of file From d774b3f2d9d666fb04b3614d2c236863aae80bd9 Mon Sep 17 00:00:00 2001 From: PJBot Date: Mon, 1 Jul 2024 06:12:36 +0000 Subject: [PATCH 006/765] Automatic changelog update --- Resources/Changelog/Changelog.yml | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index adb76650290..cd238052770 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,12 +1,4 @@ Entries: -- author: Dutch-VanDerLinde - changes: - - message: Holoparasites and holoclowns will now phase through projectiles such - as bullets, like a holocarp. - type: Tweak - id: 6352 - time: '2024-04-14T08:52:57.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/26862 - author: Tyzemol changes: - message: Board game crate now comes with character sheets @@ -3819,3 +3811,10 @@ id: 6851 time: '2024-07-01T05:33:08.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/29364 +- author: metalgearsloth + changes: + - message: Add effects for when shuttles are arriving. + type: Add + id: 6852 + time: '2024-07-01T06:11:30.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/29402 From 8cda9cc1b15b99358528fd0989233ec42fe48a3d Mon Sep 17 00:00:00 2001 From: Plykiya <58439124+Plykiya@users.noreply.github.com> Date: Mon, 1 Jul 2024 08:39:05 -0700 Subject: [PATCH 007/765] Fixes gravity wells (#29617) * Fixes gravity wells * thank you slarticodefast * Minor nitpicks addressed * NITPICKS UNDONE * REDO THE NITPICK, WE LOVE MATRIX MULTIPLCATION * Revert "REDO THE NITPICK, WE LOVE MATRIX MULTIPLCATION" This reverts commit c782eee1a1c7bda90c7ca686928019cc5f25c8cf. * NITPICK REDO --------- Co-authored-by: plykiya --- .../Singularity/EntitySystems/GravityWellSystem.cs | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/Content.Server/Singularity/EntitySystems/GravityWellSystem.cs b/Content.Server/Singularity/EntitySystems/GravityWellSystem.cs index f53d658ebd7..8c884d023c4 100644 --- a/Content.Server/Singularity/EntitySystems/GravityWellSystem.cs +++ b/Content.Server/Singularity/EntitySystems/GravityWellSystem.cs @@ -156,7 +156,7 @@ public void GravPulse(EntityUid uid, float maxRange, float minRange, float baseR /// The minimum distance at which entities can be affected by the gravity pulse. /// The base velocity added to any entities within affected by the gravity pulse scaled by the displacement of those entities from the epicenter. public void GravPulse(EntityCoordinates entityPos, float maxRange, float minRange, in Matrix3x2 baseMatrixDeltaV) - => GravPulse(entityPos.ToMap(EntityManager, _transform), maxRange, minRange, in baseMatrixDeltaV); + => GravPulse(_transform.ToMapCoordinates(entityPos), maxRange, minRange, in baseMatrixDeltaV); /// /// Greates a gravitational pulse, shoving around all entities within some distance of an epicenter. @@ -167,7 +167,7 @@ public void GravPulse(EntityCoordinates entityPos, float maxRange, float minRang /// The base radial velocity that will be added to entities within range towards the center of the gravitational pulse. /// The base tangential velocity that will be added to entities within countrclockwise around the center of the gravitational pulse. public void GravPulse(EntityCoordinates entityPos, float maxRange, float minRange, float baseRadialDeltaV = 0.0f, float baseTangentialDeltaV = 0.0f) - => GravPulse(entityPos.ToMap(EntityManager, _transform), maxRange, minRange, baseRadialDeltaV, baseTangentialDeltaV); + => GravPulse(_transform.ToMapCoordinates(entityPos), maxRange, minRange, baseRadialDeltaV, baseTangentialDeltaV); /// /// Causes a gravitational pulse, shoving around all entities within some distance of an epicenter. @@ -206,7 +206,7 @@ public void GravPulse(MapCoordinates mapPos, float maxRange, float minRange, in continue; var scaling = (1f / distance2) * physics.Mass; // TODO: Variable falloff gradiants. - _physics.ApplyLinearImpulse(entity, Vector2.Transform(displacement, baseMatrixDeltaV) * scaling, body: physics); + _physics.ApplyLinearImpulse(entity, Vector2.TransformNormal(displacement, baseMatrixDeltaV) * scaling, body: physics); } } @@ -219,10 +219,7 @@ public void GravPulse(MapCoordinates mapPos, float maxRange, float minRange, in /// The base amount of velocity that will be added to entities in range towards the epicenter of the pulse. /// The base amount of velocity that will be added to entities in range counterclockwise relative to the epicenter of the pulse. public void GravPulse(MapCoordinates mapPos, float maxRange, float minRange = 0.0f, float baseRadialDeltaV = 0.0f, float baseTangentialDeltaV = 0.0f) - => GravPulse(mapPos, maxRange, minRange, new Matrix3x2( - baseRadialDeltaV, -baseTangentialDeltaV, 0.0f, - +baseTangentialDeltaV, baseRadialDeltaV, 0.0f - )); + => GravPulse(mapPos, maxRange, minRange, new Matrix3x2(baseRadialDeltaV, -baseTangentialDeltaV, baseTangentialDeltaV, baseRadialDeltaV, 0.0f, 0.0f)); #endregion GravPulse From abb3126cffa5826e4d115660ed58534ed98fbe10 Mon Sep 17 00:00:00 2001 From: PJBot Date: Mon, 1 Jul 2024 15:40:11 +0000 Subject: [PATCH 008/765] Automatic changelog update --- Resources/Changelog/Changelog.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index cd238052770..87fff0538ad 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,11 +1,4 @@ Entries: -- author: Tyzemol - changes: - - message: Board game crate now comes with character sheets - type: Add - id: 6353 - time: '2024-04-14T08:54:40.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/26926 - author: FairlySadPanda changes: - message: Clown shoes make you waddle, as God intended. @@ -3818,3 +3811,10 @@ id: 6852 time: '2024-07-01T06:11:30.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/29402 +- author: Plykiya + changes: + - message: Gravity wells, like the supermatter grenade, now function properly again. + type: Fix + id: 6853 + time: '2024-07-01T15:39:05.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/29617 From 527f8bc709abc6e5af5e081f57372b150a462633 Mon Sep 17 00:00:00 2001 From: jmcb Date: Mon, 1 Jul 2024 17:27:49 +0100 Subject: [PATCH 009/765] Fix showing tips on the login screen from the localized tip dataset (#29640) Regression introduced in #28285 --- Content.Client/Launcher/LauncherConnectingGui.xaml.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Content.Client/Launcher/LauncherConnectingGui.xaml.cs b/Content.Client/Launcher/LauncherConnectingGui.xaml.cs index ac74ad7b60d..5015b710eb4 100644 --- a/Content.Client/Launcher/LauncherConnectingGui.xaml.cs +++ b/Content.Client/Launcher/LauncherConnectingGui.xaml.cs @@ -116,7 +116,7 @@ private void HandleDisconnectReason(INetStructuredReason? reason) private void ChangeLoginTip() { var tipsDataset = _cfg.GetCVar(CCVars.LoginTipsDataset); - var loginTipsEnabled = _prototype.TryIndex(tipsDataset, out var tips); + var loginTipsEnabled = _prototype.TryIndex(tipsDataset, out var tips); LoginTips.Visible = loginTipsEnabled; if (!loginTipsEnabled) @@ -131,7 +131,7 @@ private void ChangeLoginTip() var randomIndex = _random.Next(tipList.Count); var tip = tipList[randomIndex]; - LoginTip.SetMessage(tip); + LoginTip.SetMessage(Loc.GetString(tip)); LoginTipTitle.Text = Loc.GetString("connecting-window-tip", ("numberTip", randomIndex)); } From ebda1de4fa7d4459afc57d6e87b5b4db4335d10a Mon Sep 17 00:00:00 2001 From: PJBot Date: Mon, 1 Jul 2024 16:28:55 +0000 Subject: [PATCH 010/765] Automatic changelog update --- Resources/Changelog/Changelog.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 87fff0538ad..67c5cd23d9c 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,11 +1,4 @@ Entries: -- author: FairlySadPanda - changes: - - message: Clown shoes make you waddle, as God intended. - type: Add - id: 6354 - time: '2024-04-14T12:12:54.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/26338 - author: beck-thompson changes: - message: Cybersun pen now makes a slashing noise when doing damage. @@ -3818,3 +3811,10 @@ id: 6853 time: '2024-07-01T15:39:05.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/29617 +- author: joelsgp + changes: + - message: Fixed login tips + type: Fix + id: 6854 + time: '2024-07-01T16:27:49.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/29640 From c1b97b0e64ad1b228b0a0e02d88f96119fa3e777 Mon Sep 17 00:00:00 2001 From: jmcb Date: Mon, 1 Jul 2024 18:10:49 +0100 Subject: [PATCH 011/765] Remove outdated NotNullWhen annotation (#29641) A previous version of this function returned a bool. Since this no longer does that, remove the annotation. --- .../Atmos/Piping/Other/EntitySystems/GasMinerSystem.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Content.Server/Atmos/Piping/Other/EntitySystems/GasMinerSystem.cs b/Content.Server/Atmos/Piping/Other/EntitySystems/GasMinerSystem.cs index 251ee797647..1aa5973c968 100644 --- a/Content.Server/Atmos/Piping/Other/EntitySystems/GasMinerSystem.cs +++ b/Content.Server/Atmos/Piping/Other/EntitySystems/GasMinerSystem.cs @@ -39,7 +39,7 @@ private void OnMinerUpdated(Entity ent, ref AtmosDeviceUpdate _atmosphereSystem.Merge(environment, merger); } - private float CapSpawnAmount(Entity ent, float toSpawnTarget, [NotNullWhen(true)] out GasMixture? environment) + private float CapSpawnAmount(Entity ent, float toSpawnTarget, out GasMixture? environment) { var (uid, miner) = ent; var transform = Transform(uid); From 50b01f39aa6f183e7652ebdf05e2425ff63f7440 Mon Sep 17 00:00:00 2001 From: Cojoke <83733158+Cojoke-dot@users.noreply.github.com> Date: Mon, 1 Jul 2024 16:14:38 -0500 Subject: [PATCH 012/765] Allow Flares to light cigarettes (#29476) * Allow Flares to light cigarettes * !IsHot check * nicer looking(and I think the right way to do that...) * heh, whoops * Adds IgnitionEvent, IgnitionSource now functions as IsHot when Ignited * Fixes + remove redundancy * Hows this? * press enter Co-authored-by: ShadowCommander <10494922+ShadowCommander@users.noreply.github.com> * Flare is not forever hot anymore * Formatting fixes * Make IgnitionEvent readonly --------- Co-authored-by: ShadowCommander <10494922+ShadowCommander@users.noreply.github.com> --- Content.Server/IgnitionSource/IgnitionEvent.cs | 7 +++++++ Content.Server/IgnitionSource/IgnitionSourceSystem.cs | 9 ++++++++- .../Light/EntitySystems/ExpendableLightSystem.cs | 9 +++++---- Resources/Prototypes/Entities/Objects/Tools/flare.yml | 1 - 4 files changed, 20 insertions(+), 6 deletions(-) create mode 100644 Content.Server/IgnitionSource/IgnitionEvent.cs diff --git a/Content.Server/IgnitionSource/IgnitionEvent.cs b/Content.Server/IgnitionSource/IgnitionEvent.cs new file mode 100644 index 00000000000..b86bf52b2d4 --- /dev/null +++ b/Content.Server/IgnitionSource/IgnitionEvent.cs @@ -0,0 +1,7 @@ +namespace Content.Server.IgnitionSource; + +/// +/// Raised in order to toggle the ignitionSourceComponent on an entity on or off +/// +[ByRefEvent] +public readonly record struct IgnitionEvent(bool Ignite = false); diff --git a/Content.Server/IgnitionSource/IgnitionSourceSystem.cs b/Content.Server/IgnitionSource/IgnitionSourceSystem.cs index c20e5207a41..3925cc86b5a 100644 --- a/Content.Server/IgnitionSource/IgnitionSourceSystem.cs +++ b/Content.Server/IgnitionSource/IgnitionSourceSystem.cs @@ -19,18 +19,25 @@ public override void Initialize() SubscribeLocalEvent(OnIsHot); SubscribeLocalEvent(OnItemToggle); + SubscribeLocalEvent(OnIgnitionEvent); } private void OnIsHot(Entity ent, ref IsHotEvent args) { - SetIgnited((ent.Owner, ent.Comp), args.IsHot); + args.IsHot = ent.Comp.Ignited; } + private void OnItemToggle(Entity ent, ref ItemToggledEvent args) { if (TryComp(ent, out var comp)) SetIgnited((ent.Owner, comp), args.Activated); } + private void OnIgnitionEvent(Entity ent, ref IgnitionEvent args) + { + SetIgnited((ent.Owner, ent.Comp), args.Ignite); + } + /// /// Simply sets the ignited field to the ignited param. /// diff --git a/Content.Server/Light/EntitySystems/ExpendableLightSystem.cs b/Content.Server/Light/EntitySystems/ExpendableLightSystem.cs index 571c23c5dbd..ba44b42ead1 100644 --- a/Content.Server/Light/EntitySystems/ExpendableLightSystem.cs +++ b/Content.Server/Light/EntitySystems/ExpendableLightSystem.cs @@ -1,3 +1,4 @@ +using Content.Server.IgnitionSource; using Content.Server.Light.Components; using Content.Shared.Clothing.Components; using Content.Shared.Clothing.EntitySystems; @@ -99,8 +100,8 @@ public bool TryActivate(Entity ent) _item.SetHeldPrefix(ent, "lit", component: item); } - var isHotEvent = new IsHotEvent() {IsHot = true}; - RaiseLocalEvent(ent, isHotEvent); + var ignite = new IgnitionEvent(true); + RaiseLocalEvent(ent, ref ignite); component.CurrentState = ExpendableLightState.Lit; component.StateExpiryTime = component.GlowDuration; @@ -134,8 +135,8 @@ private void UpdateVisualizer(Entity ent, AppearanceCo case ExpendableLightState.Dead: _appearance.SetData(ent, ExpendableLightVisuals.Behavior, string.Empty, appearance); - var isHotEvent = new IsHotEvent() {IsHot = true}; - RaiseLocalEvent(ent, isHotEvent); + var ignite = new IgnitionEvent(false); + RaiseLocalEvent(ent, ref ignite); break; } } diff --git a/Resources/Prototypes/Entities/Objects/Tools/flare.yml b/Resources/Prototypes/Entities/Objects/Tools/flare.yml index fdf53148631..d36f67d00d4 100644 --- a/Resources/Prototypes/Entities/Objects/Tools/flare.yml +++ b/Resources/Prototypes/Entities/Objects/Tools/flare.yml @@ -26,7 +26,6 @@ loop: true volume: -10 maxDistance: 5 - - type: Sprite sprite: Objects/Misc/flare.rsi layers: From 554661a77a6d7d227ad018153904433da9abd941 Mon Sep 17 00:00:00 2001 From: PJBot Date: Mon, 1 Jul 2024 21:15:44 +0000 Subject: [PATCH 013/765] Automatic changelog update --- Resources/Changelog/Changelog.yml | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 67c5cd23d9c..22285bf3936 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,11 +1,4 @@ Entries: -- author: beck-thompson - changes: - - message: Cybersun pen now makes a slashing noise when doing damage. - type: Fix - id: 6355 - time: '2024-04-14T20:04:06.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/26951 - author: TokenStyle changes: - message: Lockers cannot be deconstructed with a screwdriver when locked now. @@ -3818,3 +3811,12 @@ id: 6854 time: '2024-07-01T16:27:49.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/29640 +- author: Cojoke-dot + changes: + - message: Flares can now light Cigarettes and other similar things + type: Tweak + - message: Flares now are no longer hot after burning out + type: Tweak + id: 6855 + time: '2024-07-01T21:14:38.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/29476 From c2fbcff98767bb18e362f133fe4a31c30d4a4e26 Mon Sep 17 00:00:00 2001 From: Tayrtahn Date: Mon, 1 Jul 2024 18:23:36 -0400 Subject: [PATCH 014/765] Fix nukeops ending early if an operative dies at base (#29642) Fix nukeops ending early if an operative died at base --- .../Tests/GameRules/NukeOpsTest.cs | 46 ++++++++++++++----- .../GameTicking/Rules/NukeopsRuleSystem.cs | 24 +++++----- 2 files changed, 46 insertions(+), 24 deletions(-) diff --git a/Content.IntegrationTests/Tests/GameRules/NukeOpsTest.cs b/Content.IntegrationTests/Tests/GameRules/NukeOpsTest.cs index 48fe46a8c85..feb96894255 100644 --- a/Content.IntegrationTests/Tests/GameRules/NukeOpsTest.cs +++ b/Content.IntegrationTests/Tests/GameRules/NukeOpsTest.cs @@ -7,6 +7,7 @@ using Content.Server.Mind; using Content.Server.Pinpointer; using Content.Server.Roles; +using Content.Server.RoundEnd; using Content.Server.Shuttles.Components; using Content.Server.Station.Components; using Content.Shared.CCVar; @@ -49,6 +50,7 @@ public async Task TryStopNukeOpsFromConstantlyFailing() var roleSys = server.System(); var invSys = server.System(); var factionSys = server.System(); + var roundEndSys = server.System(); server.CfgMan.SetCVar(CCVars.GridFill, true); @@ -63,11 +65,11 @@ public async Task TryStopNukeOpsFromConstantlyFailing() // Opt into the nukies role. await pair.SetAntagPreference("NukeopsCommander", true); - await pair.SetAntagPreference( "NukeopsMedic", true, dummies[1].UserId); + await pair.SetAntagPreference("NukeopsMedic", true, dummies[1].UserId); // Initially, the players have no attached entities Assert.That(pair.Player?.AttachedEntity, Is.Null); - Assert.That(dummies.All(x => x.AttachedEntity == null)); + Assert.That(dummies.All(x => x.AttachedEntity == null)); // There are no grids or maps Assert.That(entMan.Count(), Is.Zero); @@ -150,7 +152,8 @@ void CheckDummy(int i) } // The game rule exists, and all the stations/shuttles/maps are properly initialized - var rule = entMan.AllComponents().Single().Component; + var rule = entMan.AllComponents().Single(); + var ruleComp = rule.Component; var gridsRule = entMan.AllComponents().Single().Component; foreach (var grid in gridsRule.MapGrids) { @@ -158,12 +161,14 @@ void CheckDummy(int i) Assert.That(entMan.HasComponent(grid)); Assert.That(entMan.HasComponent(grid)); } - Assert.That(entMan.EntityExists(rule.TargetStation)); + Assert.That(entMan.EntityExists(ruleComp.TargetStation)); - Assert.That(entMan.HasComponent(rule.TargetStation)); + Assert.That(entMan.HasComponent(ruleComp.TargetStation)); - var nukieShuttlEnt = entMan.AllComponents().FirstOrDefault().Uid; + var nukieShuttle = entMan.AllComponents().Single(); + var nukieShuttlEnt = nukieShuttle.Uid; Assert.That(entMan.EntityExists(nukieShuttlEnt)); + Assert.That(nukieShuttle.Component.AssociatedRule, Is.EqualTo(rule.Uid)); EntityUid? nukieStationEnt = null; foreach (var grid in gridsRule.MapGrids) @@ -179,12 +184,12 @@ void CheckDummy(int i) var nukieStation = entMan.GetComponent(nukieStationEnt!.Value); Assert.That(entMan.EntityExists(nukieStation.Station)); - Assert.That(nukieStation.Station, Is.Not.EqualTo(rule.TargetStation)); + Assert.That(nukieStation.Station, Is.Not.EqualTo(ruleComp.TargetStation)); Assert.That(server.MapMan.MapExists(gridsRule.Map)); var nukieMap = mapSys.GetMap(gridsRule.Map!.Value); - var targetStation = entMan.GetComponent(rule.TargetStation!.Value); + var targetStation = entMan.GetComponent(ruleComp.TargetStation!.Value); var targetGrid = targetStation.Grids.First(); var targetMap = entMan.GetComponent(targetGrid).MapUid!.Value; Assert.That(targetMap, Is.Not.EqualTo(nukieMap)); @@ -206,7 +211,7 @@ void CheckDummy(int i) Assert.That(LifeStage(targetMap), Is.GreaterThan(EntityLifeStage.Initialized)); Assert.That(LifeStage(nukieStationEnt.Value), Is.GreaterThan(EntityLifeStage.Initialized)); Assert.That(LifeStage(nukieShuttlEnt), Is.GreaterThan(EntityLifeStage.Initialized)); - Assert.That(LifeStage(rule.TargetStation), Is.GreaterThan(EntityLifeStage.Initialized)); + Assert.That(LifeStage(ruleComp.TargetStation), Is.GreaterThan(EntityLifeStage.Initialized)); // Make sure the player has hands. We've had fucking disarmed nukies before. Assert.That(entMan.HasComponent(player)); @@ -222,10 +227,10 @@ void CheckDummy(int i) } Assert.That(total, Is.GreaterThan(3)); - // Finally lets check the nukie commander passed basic training and figured out how to breathe. + // Check the nukie commander passed basic training and figured out how to breathe. var totalSeconds = 30; var totalTicks = (int) Math.Ceiling(totalSeconds / server.Timing.TickPeriod.TotalSeconds); - int increment = 5; + var increment = 5; var resp = entMan.GetComponent(player); var damage = entMan.GetComponent(player); for (var tick = 0; tick < totalTicks; tick += increment) @@ -235,7 +240,24 @@ void CheckDummy(int i) Assert.That(damage.TotalDamage, Is.EqualTo(FixedPoint2.Zero)); } - ticker.SetGamePreset((GamePresetPrototype?)null); + // Check that the round does not end prematurely when agents are deleted in the outpost + var nukies = dummyEnts.Where(entMan.HasComponent).Append(player).ToArray(); + await server.WaitAssertion(() => + { + for (var i = 0; i < nukies.Length - 1; i++) + { + entMan.DeleteEntity(nukies[i]); + Assert.That(roundEndSys.IsRoundEndRequested, Is.False, + $"The round ended, but {nukies.Length - i - 1} nukies are still alive!"); + } + // Delete the last nukie and make sure the round ends. + entMan.DeleteEntity(nukies[^1]); + + Assert.That(roundEndSys.IsRoundEndRequested, + "All nukies were deleted, but the round didn't end!"); + }); + + ticker.SetGamePreset((GamePresetPrototype?) null); await pair.CleanReturnAsync(); } } diff --git a/Content.Server/GameTicking/Rules/NukeopsRuleSystem.cs b/Content.Server/GameTicking/Rules/NukeopsRuleSystem.cs index 6688bfd980c..6cafd38d30e 100644 --- a/Content.Server/GameTicking/Rules/NukeopsRuleSystem.cs +++ b/Content.Server/GameTicking/Rules/NukeopsRuleSystem.cs @@ -57,13 +57,12 @@ public override void Initialize() SubscribeLocalEvent(OnMobStateChanged); SubscribeLocalEvent(OnOperativeZombified); - SubscribeLocalEvent(OnMapInit); - SubscribeLocalEvent(OnShuttleFTLAttempt); SubscribeLocalEvent(OnWarDeclared); SubscribeLocalEvent(OnShuttleCallAttempt); SubscribeLocalEvent(OnAfterAntagEntSelected); + SubscribeLocalEvent(OnRuleLoadedGrids); } protected override void Started(EntityUid uid, NukeopsRuleComponent component, GameRuleComponent gameRule, @@ -256,17 +255,18 @@ private void OnOperativeZombified(EntityUid uid, NukeOperativeComponent componen RemCompDeferred(uid, component); } - private void OnMapInit(Entity ent, ref MapInitEvent args) + private void OnRuleLoadedGrids(Entity ent, ref RuleLoadedGridsEvent args) { - var map = Transform(ent).MapID; - - var rules = EntityQueryEnumerator(); - while (rules.MoveNext(out var uid, out _, out var grids)) + // Check each nukie shuttle + var query = EntityQueryEnumerator(); + while (query.MoveNext(out var uid, out var shuttle)) { - if (map != grids.Map) - continue; - ent.Comp.AssociatedRule = uid; - break; + // Check if the shuttle's mapID is the one that just got loaded for this rule + if (Transform(uid).MapID == args.Map) + { + shuttle.AssociatedRule = ent; + break; + } } } @@ -376,7 +376,7 @@ private void DistributeExtraTc(Entity nukieRule) if (Transform(uid).MapID != Transform(outpost).MapID) // Will receive bonus TC only on their start outpost continue; - _store.TryAddCurrency(new () { { TelecrystalCurrencyPrototype, nukieRule.Comp.WarTcAmountPerNukie } }, uid, component); + _store.TryAddCurrency(new() { { TelecrystalCurrencyPrototype, nukieRule.Comp.WarTcAmountPerNukie } }, uid, component); var msg = Loc.GetString("store-currency-war-boost-given", ("target", uid)); _popupSystem.PopupEntity(msg, uid); From f9d600f84dc74ddd93c4e0598e4148f67f475c74 Mon Sep 17 00:00:00 2001 From: PJBot Date: Mon, 1 Jul 2024 22:24:42 +0000 Subject: [PATCH 015/765] Automatic changelog update --- Resources/Changelog/Changelog.yml | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 22285bf3936..e0d6bbb1945 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,11 +1,4 @@ Entries: -- author: TokenStyle - changes: - - message: Lockers cannot be deconstructed with a screwdriver when locked now. - type: Fix - id: 6356 - time: '2024-04-14T22:26:47.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/26961 - author: pissdemon changes: - message: Catwalks over lava are slightly less likely to catch you on fire again. @@ -3820,3 +3813,11 @@ id: 6855 time: '2024-07-01T21:14:38.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/29476 +- author: Tayrtahn + changes: + - message: Fixed NukeOps ending prematurely in some situations where operatives + were still alive. + type: Fix + id: 6856 + time: '2024-07-01T22:23:36.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/29642 From 2b7305875fc6970da3b0b8cc289b7a1a942389ce Mon Sep 17 00:00:00 2001 From: Tayrtahn Date: Mon, 1 Jul 2024 23:30:53 -0400 Subject: [PATCH 016/765] Fixed buckled players thrashing while speaking in beds (#29653) * Fix characters thrashing when talking while lying down * Remove weird design choice --- Content.Client/Rotation/RotationVisualizerSystem.cs | 4 ++-- Content.Shared/Buckle/SharedBuckleSystem.Buckle.cs | 4 ++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/Content.Client/Rotation/RotationVisualizerSystem.cs b/Content.Client/Rotation/RotationVisualizerSystem.cs index 6105c10c803..6d3be4d1c05 100644 --- a/Content.Client/Rotation/RotationVisualizerSystem.cs +++ b/Content.Client/Rotation/RotationVisualizerSystem.cs @@ -23,8 +23,8 @@ private void OnAppearanceChange(EntityUid uid, RotationVisualsComponent componen if (args.Sprite == null) return; - // If not defined, defaults to standing. - _appearance.TryGetData(uid, RotationVisuals.RotationState, out var state, args.Component); + if (!_appearance.TryGetData(uid, RotationVisuals.RotationState, out var state, args.Component)) + return; switch (state) { diff --git a/Content.Shared/Buckle/SharedBuckleSystem.Buckle.cs b/Content.Shared/Buckle/SharedBuckleSystem.Buckle.cs index fd6ffd30e39..0ce8c992682 100644 --- a/Content.Shared/Buckle/SharedBuckleSystem.Buckle.cs +++ b/Content.Shared/Buckle/SharedBuckleSystem.Buckle.cs @@ -9,6 +9,7 @@ using Content.Shared.Movement.Pulling.Events; using Content.Shared.Popups; using Content.Shared.Pulling.Events; +using Content.Shared.Rotation; using Content.Shared.Standing; using Content.Shared.Storage.Components; using Content.Shared.Stunnable; @@ -195,6 +196,7 @@ protected void SetBuckledTo(Entity buckle, Entity buckle, Entity strap SetBuckledTo(buckle, strap!); Appearance.SetData(strap, StrapVisuals.State, true); Appearance.SetData(buckle, BuckleVisuals.Buckled, true); + Appearance.SetData(buckle, RotationVisuals.RotationState, RotationState.Horizontal); _rotationVisuals.SetHorizontalAngle(buckle.Owner, strap.Comp.Rotation); @@ -455,6 +458,7 @@ private void Unbuckle(Entity buckle, Entity str _rotationVisuals.ResetHorizontalAngle(buckle.Owner); Appearance.SetData(strap, StrapVisuals.State, strap.Comp.BuckledEntities.Count != 0); Appearance.SetData(buckle, BuckleVisuals.Buckled, false); + Appearance.SetData(buckle, RotationVisuals.RotationState, RotationState.Vertical); if (HasComp(buckle) || _mobState.IsIncapacitated(buckle)) _standing.Down(buckle); From 1d52e9419e37837c576ed7a50dcba25a4be21376 Mon Sep 17 00:00:00 2001 From: PJBot Date: Tue, 2 Jul 2024 03:31:59 +0000 Subject: [PATCH 017/765] Automatic changelog update --- Resources/Changelog/Changelog.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index e0d6bbb1945..8da32dc372f 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,11 +1,4 @@ Entries: -- author: pissdemon - changes: - - message: Catwalks over lava are slightly less likely to catch you on fire again. - type: Fix - id: 6357 - time: '2024-04-15T01:27:58.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/26968 - author: Velcroboy changes: - message: Fixed sec/lawyer and vault airlocks @@ -3821,3 +3814,10 @@ id: 6856 time: '2024-07-01T22:23:36.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/29642 +- author: Tayrtahn + changes: + - message: Fixed characters thrashing when speaking in beds. + type: Fix + id: 6857 + time: '2024-07-02T03:30:53.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/29653 From f1c0e2cc7376ca06ea2f7870d0a70edc79c183a0 Mon Sep 17 00:00:00 2001 From: Chief-Engineer <119664036+Chief-Engineer@users.noreply.github.com> Date: Tue, 2 Jul 2024 04:09:24 -0500 Subject: [PATCH 018/765] add more info to entity json in logs (#18672) * add more info to entity json in logs * replace TryGetSessionById * remove unused dependency * get admin status from the entity * group values by component * alphabetize * I've discovered that my original plans may be bad for performance --- .../EntityStringRepresentationConverter.cs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/Content.Server/Administration/Logs/Converters/EntityStringRepresentationConverter.cs b/Content.Server/Administration/Logs/Converters/EntityStringRepresentationConverter.cs index 32551e5a7d6..39d34e5f183 100644 --- a/Content.Server/Administration/Logs/Converters/EntityStringRepresentationConverter.cs +++ b/Content.Server/Administration/Logs/Converters/EntityStringRepresentationConverter.cs @@ -1,10 +1,14 @@ using System.Text.Json; +using Content.Server.Administration.Managers; +using Robust.Server.Player; namespace Content.Server.Administration.Logs.Converters; [AdminLogConverter] public sealed class EntityStringRepresentationConverter : AdminLogConverter { + [Dependency] private readonly IAdminManager _adminManager = default!; + public override void Write(Utf8JsonWriter writer, EntityStringRepresentation value, JsonSerializerOptions options) { writer.WriteStartObject(); @@ -19,6 +23,21 @@ public override void Write(Utf8JsonWriter writer, EntityStringRepresentation val if (value.Session != null) { writer.WriteString("player", value.Session.UserId.UserId); + + if (_adminManager.IsAdmin(value.Uid)) + { + writer.WriteBoolean("admin", true); + } + } + + if (value.Prototype != null) + { + writer.WriteString("prototype", value.Prototype); + } + + if (value.Deleted) + { + writer.WriteBoolean("deleted", true); } writer.WriteEndObject(); From 52dfa736b1aa2f50eeab87bd9e47892e260c9439 Mon Sep 17 00:00:00 2001 From: slarticodefast <161409025+slarticodefast@users.noreply.github.com> Date: Tue, 2 Jul 2024 15:04:15 +0200 Subject: [PATCH 019/765] Fix MouseRotator on rotated grids (#29663) * fix harm mode rotation * cleanup * -pi to pi --- .../MouseRotator/MouseRotatorSystem.cs | 15 ++++++++++----- .../MouseRotator/MouseRotatorComponent.cs | 13 +------------ .../MouseRotator/SharedMouseRotatorSystem.cs | 17 +---------------- 3 files changed, 12 insertions(+), 33 deletions(-) diff --git a/Content.Client/MouseRotator/MouseRotatorSystem.cs b/Content.Client/MouseRotator/MouseRotatorSystem.cs index ce174c6144c..18d60d9a7b9 100644 --- a/Content.Client/MouseRotator/MouseRotatorSystem.cs +++ b/Content.Client/MouseRotator/MouseRotatorSystem.cs @@ -2,7 +2,6 @@ using Robust.Client.Graphics; using Robust.Client.Input; using Robust.Client.Player; -using Robust.Client.Replays.Loading; using Robust.Shared.Map; using Robust.Shared.Timing; @@ -46,13 +45,19 @@ public override void Update(float frameTime) // only raise event if the cardinal direction has changed if (rotator.Simple4DirMode) { - var angleDir = angle.GetCardinalDir(); - if (angleDir == curRot.GetCardinalDir()) + var eyeRot = _eye.CurrentEye.Rotation; // camera rotation + var angleDir = (angle + eyeRot).GetCardinalDir(); // apply GetCardinalDir in the camera frame, not in the world frame + if (angleDir == (curRot + eyeRot).GetCardinalDir()) return; - RaisePredictiveEvent(new RequestMouseRotatorRotationSimpleEvent() + var rotation = angleDir.ToAngle() - eyeRot; // convert back to world frame + if (rotation >= Math.PI) // convert to [-PI, +PI) + rotation -= 2 * Math.PI; + else if (rotation < -Math.PI) + rotation += 2 * Math.PI; + RaisePredictiveEvent(new RequestMouseRotatorRotationEvent { - Direction = angleDir, + Rotation = rotation }); return; diff --git a/Content.Shared/MouseRotator/MouseRotatorComponent.cs b/Content.Shared/MouseRotator/MouseRotatorComponent.cs index a35dfe0a288..2844b3cb8b5 100644 --- a/Content.Shared/MouseRotator/MouseRotatorComponent.cs +++ b/Content.Shared/MouseRotator/MouseRotatorComponent.cs @@ -30,8 +30,7 @@ public sealed partial class MouseRotatorComponent : Component public double RotationSpeed = float.MaxValue; /// - /// This one is important. If this is true, does not apply, and the system will - /// use instead. In this mode, the client will only send + /// This one is important. If this is true, does not apply. In this mode, the client will only send /// events when an entity should snap to a different cardinal direction, rather than for every angle change. /// /// This is useful for cases like humans, where what really matters is the visual sprite direction, as opposed to something @@ -50,13 +49,3 @@ public sealed class RequestMouseRotatorRotationEvent : EntityEventArgs { public Angle Rotation; } - -/// -/// Simpler version of for implementations -/// that only require snapping to 4-dir and not full angle rotation. -/// -[Serializable, NetSerializable] -public sealed class RequestMouseRotatorRotationSimpleEvent : EntityEventArgs -{ - public Direction Direction; -} diff --git a/Content.Shared/MouseRotator/SharedMouseRotatorSystem.cs b/Content.Shared/MouseRotator/SharedMouseRotatorSystem.cs index c57d477bd2f..9663b3363d1 100644 --- a/Content.Shared/MouseRotator/SharedMouseRotatorSystem.cs +++ b/Content.Shared/MouseRotator/SharedMouseRotatorSystem.cs @@ -1,5 +1,4 @@ using Content.Shared.Interaction; -using Robust.Shared.Timing; namespace Content.Shared.MouseRotator; @@ -16,7 +15,6 @@ public override void Initialize() base.Initialize(); SubscribeAllEvent(OnRequestRotation); - SubscribeAllEvent(OnRequestSimpleRotation); } public override void Update(float frameTime) @@ -50,7 +48,7 @@ public override void Update(float frameTime) private void OnRequestRotation(RequestMouseRotatorRotationEvent msg, EntitySessionEventArgs args) { if (args.SenderSession.AttachedEntity is not { } ent - || !TryComp(ent, out var rotator) || rotator.Simple4DirMode) + || !TryComp(ent, out var rotator)) { Log.Error($"User {args.SenderSession.Name} ({args.SenderSession.UserId}) tried setting local rotation directly without a valid mouse rotator component attached!"); return; @@ -59,17 +57,4 @@ private void OnRequestRotation(RequestMouseRotatorRotationEvent msg, EntitySessi rotator.GoalRotation = msg.Rotation; Dirty(ent, rotator); } - - private void OnRequestSimpleRotation(RequestMouseRotatorRotationSimpleEvent ev, EntitySessionEventArgs args) - { - if (args.SenderSession.AttachedEntity is not { } ent - || !TryComp(ent, out var rotator) || !rotator.Simple4DirMode) - { - Log.Error($"User {args.SenderSession.Name} ({args.SenderSession.UserId}) tried setting 4-dir rotation directly without a valid mouse rotator component attached!"); - return; - } - - rotator.GoalRotation = ev.Direction.ToAngle(); - Dirty(ent, rotator); - } } From 54e11ab94979576bf98db8bd4e93ce84dbcb1a26 Mon Sep 17 00:00:00 2001 From: PJBot Date: Tue, 2 Jul 2024 13:05:23 +0000 Subject: [PATCH 020/765] Automatic changelog update --- Resources/Changelog/Changelog.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 8da32dc372f..6e97ab1da40 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,11 +1,4 @@ Entries: -- author: Velcroboy - changes: - - message: Fixed sec/lawyer and vault airlocks - type: Fix - id: 6358 - time: '2024-04-15T22:22:16.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/26980 - author: tosatur changes: - message: Made clown snoring quieter @@ -3821,3 +3814,10 @@ id: 6857 time: '2024-07-02T03:30:53.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/29653 +- author: slarticodefast + changes: + - message: Fixed sprite rotation in harm mode on rotated grids. + type: Fix + id: 6858 + time: '2024-07-02T13:04:15.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/29663 From 73f02aaa0b815fbfe86f172b4fad654762f76f29 Mon Sep 17 00:00:00 2001 From: lzk <124214523+lzk228@users.noreply.github.com> Date: Tue, 2 Jul 2024 15:32:21 +0200 Subject: [PATCH 021/765] Add ability to add additional friendly and hostile factions in prototypes (#29636) * Make friendly and hostile factions in NpcFactionMemberComponent datafiels * :trollface: * :trollface: --- .../Nyanotrasen/Psionics/PsionicsSystem.cs | 8 +-- .../Components/NpcFactionMemberComponent.cs | 14 +++-- .../NPC/Systems/NpcFactionSystem.cs | 9 ++++ .../Faction/ClothingAddFactionComponent.cs | 21 -------- .../NPC/Systems/FactionSystem.Core.cs | 40 -------------- .../NPC/Systems/FactionSystem.Items.cs | 52 ------------------- .../Entities/Clothing/Uniforms/jumpsuits.yml | 4 +- RobustToolbox | 2 +- 8 files changed, 25 insertions(+), 125 deletions(-) delete mode 100644 Content.Shared/Nyanotrasen/NPC/Systems/Components/Faction/ClothingAddFactionComponent.cs delete mode 100644 Content.Shared/Nyanotrasen/NPC/Systems/FactionSystem.Core.cs delete mode 100644 Content.Shared/Nyanotrasen/NPC/Systems/FactionSystem.Items.cs diff --git a/Content.Server/Nyanotrasen/Psionics/PsionicsSystem.cs b/Content.Server/Nyanotrasen/Psionics/PsionicsSystem.cs index fbde7271f1c..d81e116b0aa 100644 --- a/Content.Server/Nyanotrasen/Psionics/PsionicsSystem.cs +++ b/Content.Server/Nyanotrasen/Psionics/PsionicsSystem.cs @@ -30,7 +30,7 @@ public sealed class PsionicsSystem : EntitySystem [Dependency] private readonly MindSwapPowerSystem _mindSwapPowerSystem = default!; [Dependency] private readonly GlimmerSystem _glimmerSystem = default!; [Dependency] private readonly ChatSystem _chat = default!; - [Dependency] private readonly NpcFactionSystem _npcFactonSystem = default!; + [Dependency] private readonly NpcFactionSystem _faction = default!; [Dependency] private readonly IConfigurationManager _cfg = default!; [Dependency] private readonly SharedAudioSystem _audio = default!; @@ -98,10 +98,10 @@ private void OnInit(EntityUid uid, PsionicComponent component, ComponentInit arg if (!TryComp(uid, out var factions)) return; - if (_npcFactonSystem.ContainsFaction(uid, "GlimmerMonster", factions)) + if (_faction.IsMember((uid, factions), "GlimmerMonster")) return; - _npcFactonSystem.AddFaction(uid, "PsionicInterloper"); + _faction.AddFaction((uid, factions) "PsionicInterloper"); } private void OnRemove(EntityUid uid, PsionicComponent component, ComponentRemove args) @@ -109,7 +109,7 @@ private void OnRemove(EntityUid uid, PsionicComponent component, ComponentRemove if (!TryComp(uid, out var factions)) return; - _npcFactonSystem.RemoveFaction(uid, "PsionicInterloper"); + _faction.RemoveFaction((uid, factions), "PsionicInterloper"); } private void OnStamHit(EntityUid uid, AntiPsionicWeaponComponent component, StaminaMeleeHitEvent args) diff --git a/Content.Shared/NPC/Components/NpcFactionMemberComponent.cs b/Content.Shared/NPC/Components/NpcFactionMemberComponent.cs index 188ece81ed7..208dfd4681a 100644 --- a/Content.Shared/NPC/Components/NpcFactionMemberComponent.cs +++ b/Content.Shared/NPC/Components/NpcFactionMemberComponent.cs @@ -26,11 +26,15 @@ public sealed partial class NpcFactionMemberComponent : Component [ViewVariables] public readonly HashSet> HostileFactions = new(); - // Nyano - Summary - Begin modified code block: support for specific entities to be friendly. /// - /// Permanently friendly specific entities. Our summoner, etc. - /// Would like to separate. Could I do that by extending this method, maybe? + /// Used to add friendly factions in prototypes. /// - public HashSet ExceptionalFriendlies = new(); - // Nyano - End modified code block. + [DataField, ViewVariables] + public HashSet>? AddFriendlyFactions; + + /// + /// Used to add hostile factions in prototypes. + /// + [DataField, ViewVariables] + public HashSet>? AddHostileFactions; } diff --git a/Content.Shared/NPC/Systems/NpcFactionSystem.cs b/Content.Shared/NPC/Systems/NpcFactionSystem.cs index f0bb1945eb4..ea762ec1130 100644 --- a/Content.Shared/NPC/Systems/NpcFactionSystem.cs +++ b/Content.Shared/NPC/Systems/NpcFactionSystem.cs @@ -60,6 +60,15 @@ private void RefreshFactions(Entity ent) ent.Comp.FriendlyFactions.UnionWith(factionData.Friendly); ent.Comp.HostileFactions.UnionWith(factionData.Hostile); } + // Add additional factions if it is written in prototype + if (ent.Comp.AddFriendlyFactions != null) + { + ent.Comp.FriendlyFactions.UnionWith(ent.Comp.AddFriendlyFactions); + } + if (ent.Comp.AddHostileFactions != null) + { + ent.Comp.HostileFactions.UnionWith(ent.Comp.AddHostileFactions); + } } /// diff --git a/Content.Shared/Nyanotrasen/NPC/Systems/Components/Faction/ClothingAddFactionComponent.cs b/Content.Shared/Nyanotrasen/NPC/Systems/Components/Faction/ClothingAddFactionComponent.cs deleted file mode 100644 index 3d55cd9a8c9..00000000000 --- a/Content.Shared/Nyanotrasen/NPC/Systems/Components/Faction/ClothingAddFactionComponent.cs +++ /dev/null @@ -1,21 +0,0 @@ -using Content.Shared.NPC.Prototypes; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; - -namespace Content.Shared.NPC.Components -{ - /// - /// Allows clothing to add a faction to you when you wear it. - /// - [RegisterComponent] - public sealed partial class ClothingAddFactionComponent : Component - { - public bool IsActive = false; - - /// - /// Faction added - /// - [ViewVariables(VVAccess.ReadWrite), - DataField("faction", required: true, customTypeSerializer:typeof(PrototypeIdSerializer))] - public string Faction = ""; - } -} diff --git a/Content.Shared/Nyanotrasen/NPC/Systems/FactionSystem.Core.cs b/Content.Shared/Nyanotrasen/NPC/Systems/FactionSystem.Core.cs deleted file mode 100644 index 385f3a1099e..00000000000 --- a/Content.Shared/Nyanotrasen/NPC/Systems/FactionSystem.Core.cs +++ /dev/null @@ -1,40 +0,0 @@ -using Content.Shared.NPC.Components; - -namespace Content.Shared.NPC.Systems; - -public partial class NpcFactionSystem : EntitySystem -{ - public void InitializeCore() - { - SubscribeLocalEvent(OnGetNearbyHostiles); - } - - public bool ContainsFaction(EntityUid uid, string faction, NpcFactionMemberComponent? component = null) - { - if (!Resolve(uid, ref component, false)) - return false; - - return component.Factions.Contains(faction); - } - - public void AddFriendlyEntity(EntityUid uid, EntityUid fEntity, NpcFactionMemberComponent? component = null) - { - if (!Resolve(uid, ref component, false)) - return; - - component.ExceptionalFriendlies.Add(fEntity); - } - - private void OnGetNearbyHostiles(EntityUid uid, NpcFactionMemberComponent component, ref GetNearbyHostilesEvent args) - { - args.ExceptionalFriendlies.UnionWith(component.ExceptionalFriendlies); - } -} - -/// -/// Raised on an entity when it's trying to determine which nearby entities are hostile. -/// -/// Entities that will be counted as hostile regardless of faction. Overriden by friendlies. -/// Entities that will be counted as friendly regardless of faction. Overrides hostiles. -[ByRefEvent] -public readonly record struct GetNearbyHostilesEvent(HashSet ExceptionalHostiles, HashSet ExceptionalFriendlies); diff --git a/Content.Shared/Nyanotrasen/NPC/Systems/FactionSystem.Items.cs b/Content.Shared/Nyanotrasen/NPC/Systems/FactionSystem.Items.cs deleted file mode 100644 index 012b59c6cc8..00000000000 --- a/Content.Shared/Nyanotrasen/NPC/Systems/FactionSystem.Items.cs +++ /dev/null @@ -1,52 +0,0 @@ -using Content.Shared.Clothing.Components; -using Content.Shared.Inventory.Events; -using Content.Shared.NPC.Components; - -namespace Content.Shared.NPC.Systems; - -public partial class NpcFactionSystem : EntitySystem -{ - public void InitializeItems() - { - // SubscribeLocalEvent(OnItemPurchased); - - SubscribeLocalEvent(OnClothingEquipped); - SubscribeLocalEvent(OnClothingUnequipped); - } - - /// - /// If we bought something we probably don't want it to start biting us after it's automatically placed in our hands. - /// If you do, consider finding a better solution to grenade penguin CBT. - /// - // private void OnItemPurchased(EntityUid uid, NpcFactionMemberComponent component, ref ItemPurchasedEvent args) - // { - // component.ExceptionalFriendlies.Add(args.Purchaser); - // } - - private void OnClothingEquipped(EntityUid uid, ClothingAddFactionComponent component, GotEquippedEvent args) - { - if (!TryComp(uid, out var clothing)) - return; - - if (!clothing.Slots.HasFlag(args.SlotFlags)) - return; - - if (!TryComp(args.Equipee, out var factionComponent)) - return; - - if (factionComponent.Factions.Contains(component.Faction)) - return; - - component.IsActive = true; - AddFaction(args.Equipee, component.Faction); - } - - private void OnClothingUnequipped(EntityUid uid, ClothingAddFactionComponent component, GotUnequippedEvent args) - { - if (!component.IsActive) - return; - - component.IsActive = false; - RemoveFaction(args.Equipee, component.Faction); - } -} diff --git a/Resources/Prototypes/Nyanotrasen/Entities/Clothing/Uniforms/jumpsuits.yml b/Resources/Prototypes/Nyanotrasen/Entities/Clothing/Uniforms/jumpsuits.yml index 11f6d32b5c3..f45e854c2ac 100644 --- a/Resources/Prototypes/Nyanotrasen/Entities/Clothing/Uniforms/jumpsuits.yml +++ b/Resources/Prototypes/Nyanotrasen/Entities/Clothing/Uniforms/jumpsuits.yml @@ -8,7 +8,7 @@ sprite: Nyanotrasen/Clothing/Uniforms/Jumpsuit/mailman.rsi - type: Clothing sprite: Nyanotrasen/Clothing/Uniforms/Jumpsuit/mailman.rsi -# - type: ClothingAddFaction +# - type: FactionClothing # faction: Mailman - type: entity @@ -21,7 +21,7 @@ sprite: Nyanotrasen/Clothing/Uniforms/Jumpskirt/mailman.rsi - type: Clothing sprite: Nyanotrasen/Clothing/Uniforms/Jumpskirt/mailman.rsi -# - type: ClothingAddFaction +# - type: FactionClothing # faction: Mailman - type: entity diff --git a/RobustToolbox b/RobustToolbox index a9aea7027f1..860c9af2bfb 160000 --- a/RobustToolbox +++ b/RobustToolbox @@ -1 +1 @@ -Subproject commit a9aea7027f1840c83bcaf1c973caf099745f9eed +Subproject commit 860c9af2bfbf1477b96519067ef5e62b2525d987 From 4c7fc456a40313e0ac10571f519e81c6bba8b11c Mon Sep 17 00:00:00 2001 From: lzk <124214523+lzk228@users.noreply.github.com> Date: Tue, 2 Jul 2024 15:33:48 +0200 Subject: [PATCH 022/765] space law book (#29392) * Space Law Book * crate --- .../Catalog/Fills/Books/bookshelf.yml | 2 ++ .../Catalog/Fills/Crates/service.yml | 1 + .../Catalog/Fills/Lockers/heads.yml | 26 ++++++++++------- .../Catalog/Fills/Lockers/security.yml | 24 ++++++++++------ .../VendingMachines/Inventories/lawdrobe.yml | 1 + .../Entities/Objects/Misc/books.yml | 28 +++++++++++++++++++ .../Prototypes/Roles/Jobs/Civilian/lawyer.yml | 5 +++- 7 files changed, 68 insertions(+), 19 deletions(-) diff --git a/Resources/Prototypes/Catalog/Fills/Books/bookshelf.yml b/Resources/Prototypes/Catalog/Fills/Books/bookshelf.yml index 09c7e165bfa..a0b6b57ec17 100644 --- a/Resources/Prototypes/Catalog/Fills/Books/bookshelf.yml +++ b/Resources/Prototypes/Catalog/Fills/Books/bookshelf.yml @@ -35,6 +35,8 @@ orGroup: BookPool - id: BookChemicalCompendium orGroup: BookPool + - id: BookSpaceLaw + orGroup: BookPool - id: BookNarsieLegend prob: 0.1 orGroup: BookAuthor diff --git a/Resources/Prototypes/Catalog/Fills/Crates/service.yml b/Resources/Prototypes/Catalog/Fills/Crates/service.yml index 149cb1acf32..8202cb491ef 100644 --- a/Resources/Prototypes/Catalog/Fills/Crates/service.yml +++ b/Resources/Prototypes/Catalog/Fills/Crates/service.yml @@ -188,6 +188,7 @@ - id: BookMedicalReferenceBook - id: BookHowToSurvive - id: BookChemicalCompendium + - id: BookSpaceLaw - type: entity id: CrateServiceSodaDispenser diff --git a/Resources/Prototypes/Catalog/Fills/Lockers/heads.yml b/Resources/Prototypes/Catalog/Fills/Lockers/heads.yml index c488eb2fae7..e2f3831a380 100644 --- a/Resources/Prototypes/Catalog/Fills/Lockers/heads.yml +++ b/Resources/Prototypes/Catalog/Fills/Lockers/heads.yml @@ -350,12 +350,15 @@ - id: BoxEncryptionKeySecurity - id: HoloprojectorSecurity - id: BookSecretDocuments - - id: BoxPDASecurity # Delta-V - - id: WeaponEnergyGunMultiphase # DeltaV - HoS Energy Gun - - id: HoSIDCard # Delta-V - - id: ClothingShoesBootsWinterHeadOfSecurity #Delta V: Add departmental winter boots - - id: LunchboxCommandFilledRandom # Delta-V Lunchboxes! + - id: BookSpaceLaw + # Begin DeltaV additions + - id: BoxPDASecurity + - id: WeaponEnergyGunMultiphase + - id: HoSIDCard + - id: ClothingShoesBootsWinterHeadOfSecurity + - id: LunchboxCommandFilledRandom prob: 0.3 + # End DeltaV additions - type: entity id: LockerHeadOfSecurityFilled @@ -379,12 +382,15 @@ - id: BoxEncryptionKeySecurity - id: HoloprojectorSecurity - id: BookSecretDocuments - - id: BoxPDASecurity # Delta-V - - id: WeaponEnergyGunMultiphase # DeltaV - HoS Energy Gun - - id: HoSIDCard # Delta-V - - id: ClothingShoesBootsWinterHeadOfSecurity #Delta V: Add departmental winter boots - - id: LunchboxCommandFilledRandom # Delta-V Lunchboxes! + - id: BookSpaceLaw + # Begin DeltaV additions + - id: BoxPDASecurity + - id: WeaponEnergyGunMultiphase + - id: HoSIDCard + - id: ClothingShoesBootsWinterHeadOfSecurity + - id: LunchboxCommandFilledRandom prob: 0.3 + # End DeltaV additions - type: entity id: LockerFreezerVaultFilled diff --git a/Resources/Prototypes/Catalog/Fills/Lockers/security.yml b/Resources/Prototypes/Catalog/Fills/Lockers/security.yml index 582b039c3bf..d7237f90b38 100644 --- a/Resources/Prototypes/Catalog/Fills/Lockers/security.yml +++ b/Resources/Prototypes/Catalog/Fills/Lockers/security.yml @@ -20,11 +20,14 @@ - id: DoorRemoteArmory - id: ClothingOuterHardsuitCombatWarden # DeltaV - ClothingOuterHardsuitWarden replaced in favour of warden's riot combat hardsuit. - id: HoloprojectorSecurity - - id: BoxPDAPrisoner # Delta-V - - id: ClothingShoesBootsWinterWarden #Delta V: Add departmental winter boots - - id: BoxEncryptionKeyPrisoner #Delta-V - - id: LunchboxSecurityFilledRandom # Delta-v Lunchboxes! + - id: BookSpaceLaw + # Begin DeltaV additions + - id: BoxPDAPrisoner + - id: ClothingShoesBootsWinterWarden + - id: BoxEncryptionKeyPrisoner + - id: LunchboxSecurityFilledRandom prob: 0.3 + # End DeltaV additions - type: entity id: LockerWardenFilled @@ -47,11 +50,14 @@ - id: RubberStampWarden - id: DoorRemoteArmory - id: HoloprojectorSecurity - - id: BoxPDAPrisoner # Delta-V - - id: ClothingShoesBootsWinterWarden #Delta V: Add departmental winter boots - - id: BoxEncryptionKeyPrisoner #Delta-V - - id: LunchboxSecurityFilledRandom # Delta-v Lunchboxes! + - id: BookSpaceLaw + # Begin DeltaV additions + - id: BoxPDAPrisoner + - id: ClothingShoesBootsWinterWarden + - id: BoxEncryptionKeyPrisoner + - id: LunchboxSecurityFilledRandom prob: 0.3 + # End DeltaV additions - type: entity id: LockerSecurityFilled @@ -94,6 +100,8 @@ prob: 0.1 - id: HoloprojectorSecurity prob: 0.6 + - id: BookSpaceLaw + prob: 0.5 - id: LunchboxSecurityFilledRandom # Delta-v Lunchboxes! prob: 0.3 diff --git a/Resources/Prototypes/Catalog/VendingMachines/Inventories/lawdrobe.yml b/Resources/Prototypes/Catalog/VendingMachines/Inventories/lawdrobe.yml index 33803ffd842..1638f07dad9 100644 --- a/Resources/Prototypes/Catalog/VendingMachines/Inventories/lawdrobe.yml +++ b/Resources/Prototypes/Catalog/VendingMachines/Inventories/lawdrobe.yml @@ -15,6 +15,7 @@ ClothingHeadsetJustice: 2 # DeltaV - Justice dept ClothingNeckLawyerbadge: 2 BriefcaseBrown: 2 + BookSpaceLaw: 3 LuxuryPen: 2 RubberStampLawyer: 3 # DeltaV - add lawyer stamp to lawdrobe ClothingOuterCoatOvercoat: 2 # DeltaV - add overcoat to LawDrobe diff --git a/Resources/Prototypes/Entities/Objects/Misc/books.yml b/Resources/Prototypes/Entities/Objects/Misc/books.yml index fd4cac781ba..d5cf78c65b9 100644 --- a/Resources/Prototypes/Entities/Objects/Misc/books.yml +++ b/Resources/Prototypes/Entities/Objects/Misc/books.yml @@ -353,6 +353,34 @@ guides: - Chemicals +- type: entity + id: BookSpaceLaw + parent: BaseItem + name: space law + description: A set of Nanotrasen guidelines for keeping law and order on their space stations. + components: + - type: Sprite + sprite: Objects/Misc/books.rsi + layers: + - state: paper + - state: cover_strong + color: "#87011c" + - state: icon_law + color: "#f7d61a" + - type: Tag + tags: + - Book + - type: GuideHelp + openOnActivation: true + guides: + - SpaceLaw + - type: MeleeWeapon # so you can beat stupid cadets + soundHit: + collection: Punch + damage: + types: + Blunt: 1 + - type: entity parent: BookBase id: BookRandom diff --git a/Resources/Prototypes/Roles/Jobs/Civilian/lawyer.yml b/Resources/Prototypes/Roles/Jobs/Civilian/lawyer.yml index c8c19968536..3c3a8c39f33 100644 --- a/Resources/Prototypes/Roles/Jobs/Civilian/lawyer.yml +++ b/Resources/Prototypes/Roles/Jobs/Civilian/lawyer.yml @@ -25,6 +25,9 @@ shoes: ClothingShoesBootsLaceup id: LawyerPDA ears: ClothingHeadsetJustice # DeltaV - Added lawyer to justice department - # TODO add copy of space law inhand: - BriefcaseBrownFilled + storage: + back: + - RubberStampLawyer + - BookSpaceLaw From 5d1430b6e794bc3ee1d611064521b2d27ee3a479 Mon Sep 17 00:00:00 2001 From: PJBot Date: Tue, 2 Jul 2024 13:34:55 +0000 Subject: [PATCH 023/765] Automatic changelog update --- Resources/Changelog/Changelog.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 6e97ab1da40..fe1e352e09d 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,11 +1,4 @@ Entries: -- author: tosatur - changes: - - message: Made clown snoring quieter - type: Tweak - id: 6359 - time: '2024-04-16T18:48:38.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/27012 - author: DEATHB4DEFEAT, Dutch-VanDerLinde, metalgearsloth and musicmanvr changes: - message: Added loadouts @@ -3821,3 +3814,10 @@ id: 6858 time: '2024-07-02T13:04:15.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/29663 +- author: lzk228 + changes: + - message: Space Law book added to the game. + type: Add + id: 6859 + time: '2024-07-02T13:33:49.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/29392 From e3fd46d664a21701f150249abb6e79d4012f193c Mon Sep 17 00:00:00 2001 From: Ko4ergaPunk <62609550+Ko4ergaPunk@users.noreply.github.com> Date: Tue, 2 Jul 2024 18:28:49 +0300 Subject: [PATCH 024/765] pipetka) (#29667) --- Resources/Prototypes/Entities/Clothing/Belt/belts.yml | 2 ++ .../Entities/Objects/Specific/Chemistry/chem_bag.yml | 1 + Resources/Prototypes/Entities/Objects/Specific/chemistry.yml | 4 ++++ Resources/Prototypes/tags.yml | 3 +++ 4 files changed, 10 insertions(+) diff --git a/Resources/Prototypes/Entities/Clothing/Belt/belts.yml b/Resources/Prototypes/Entities/Clothing/Belt/belts.yml index 66a9c60511b..32170331ff3 100644 --- a/Resources/Prototypes/Entities/Clothing/Belt/belts.yml +++ b/Resources/Prototypes/Entities/Clothing/Belt/belts.yml @@ -269,6 +269,7 @@ - Radio - DiscreteHealthAnalyzer - SurgeryTool + - Dropper components: - Hypospray - Injector @@ -343,6 +344,7 @@ - Bottle - Syringe - CigPack + - Dropper components: - Seed - Smokable diff --git a/Resources/Prototypes/Entities/Objects/Specific/Chemistry/chem_bag.yml b/Resources/Prototypes/Entities/Objects/Specific/Chemistry/chem_bag.yml index a4692db9b5f..4af29b6632b 100644 --- a/Resources/Prototypes/Entities/Objects/Specific/Chemistry/chem_bag.yml +++ b/Resources/Prototypes/Entities/Objects/Specific/Chemistry/chem_bag.yml @@ -29,4 +29,5 @@ - PillCanister - Bottle - Syringe + - Dropper - type: Dumpable diff --git a/Resources/Prototypes/Entities/Objects/Specific/chemistry.yml b/Resources/Prototypes/Entities/Objects/Specific/chemistry.yml index beb77c65f81..2bc87a21792 100644 --- a/Resources/Prototypes/Entities/Objects/Specific/chemistry.yml +++ b/Resources/Prototypes/Entities/Objects/Specific/chemistry.yml @@ -303,6 +303,7 @@ solution: injector - type: Item sprite: Objects/Specific/Chemistry/dropper.rsi + size: Tiny - type: Appearance - type: SolutionContainerVisuals maxFillLevels: 1 @@ -311,6 +312,9 @@ inHandsFillBaseName: -fill- - type: StaticPrice price: 40 + - type: Tag + tags: + - Dropper - type: entity name: borgdropper diff --git a/Resources/Prototypes/tags.yml b/Resources/Prototypes/tags.yml index ede344eeaba..f6acfab913e 100644 --- a/Resources/Prototypes/tags.yml +++ b/Resources/Prototypes/tags.yml @@ -545,6 +545,9 @@ - type: Tag id: DrinkSpaceGlue +- type: Tag + id: Dropper + - type: Tag id: Duck From 0b0ce756d23df351f1091249d3b8edecb6a6fea5 Mon Sep 17 00:00:00 2001 From: PJBot Date: Tue, 2 Jul 2024 15:29:55 +0000 Subject: [PATCH 025/765] Automatic changelog update --- Resources/Changelog/Changelog.yml | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index fe1e352e09d..45ebc2d5963 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,11 +1,4 @@ Entries: -- author: DEATHB4DEFEAT, Dutch-VanDerLinde, metalgearsloth and musicmanvr - changes: - - message: Added loadouts - type: Add - id: 6360 - time: '2024-04-16T19:57:41.736477+00:00' - url: null - author: Dutch-VanDerLinde changes: - message: Senior role ID cards now function properly. @@ -3821,3 +3814,12 @@ id: 6859 time: '2024-07-02T13:33:49.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/29392 +- author: Ko4erga + changes: + - message: Dropper can be placed in med belt, plant belt and chemistry bag. + type: Tweak + - message: Dropper size changed. + type: Tweak + id: 6860 + time: '2024-07-02T15:28:49.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/29667 From c0a4865d7545db6ef1b08a7eff0c0de00e4bb5e5 Mon Sep 17 00:00:00 2001 From: Mervill Date: Tue, 2 Jul 2024 13:18:56 -0700 Subject: [PATCH 026/765] Clean up gas miners (#29657) Separate the environment check from CapSpawnAmount into GetValidEnvironment to make the code a little cleaner, and also makes these two checks independent. CapSpawnAmount and GetValidEnvironment now both have zero side-effects Broken renamed Idle to reflect its use. Broken in my mind implies that there's some method for fixing. --------- Co-authored-by: Partmedia --- .../Other/Components/GasMinerComponent.cs | 10 +++++- .../Other/EntitySystems/GasMinerSystem.cs | 36 ++++++++++--------- .../Structures/Piping/Atmospherics/miners.yml | 14 -------- 3 files changed, 29 insertions(+), 31 deletions(-) diff --git a/Content.Server/Atmos/Piping/Other/Components/GasMinerComponent.cs b/Content.Server/Atmos/Piping/Other/Components/GasMinerComponent.cs index 18a0b9b0782..1775ec5dad8 100644 --- a/Content.Server/Atmos/Piping/Other/Components/GasMinerComponent.cs +++ b/Content.Server/Atmos/Piping/Other/Components/GasMinerComponent.cs @@ -5,14 +5,22 @@ namespace Content.Server.Atmos.Piping.Other.Components [RegisterComponent] public sealed partial class GasMinerComponent : Component { + [ViewVariables(VVAccess.ReadWrite)] public bool Enabled { get; set; } = true; - public bool Broken { get; set; } = false; + [ViewVariables(VVAccess.ReadOnly)] + public bool Idle { get; set; } = false; + /// + /// If the number of moles in the external environment exceeds this number, no gas will be mined. + /// [ViewVariables(VVAccess.ReadWrite)] [DataField("maxExternalAmount")] public float MaxExternalAmount { get; set; } = float.PositiveInfinity; + /// + /// If the pressure (in kPA) of the external environment exceeds this number, no gas will be mined. + /// [ViewVariables(VVAccess.ReadWrite)] [DataField("maxExternalPressure")] public float MaxExternalPressure { get; set; } = Atmospherics.GasMinerDefaultMaxExternalPressure; diff --git a/Content.Server/Atmos/Piping/Other/EntitySystems/GasMinerSystem.cs b/Content.Server/Atmos/Piping/Other/EntitySystems/GasMinerSystem.cs index 1aa5973c968..dd46fb6b4c1 100644 --- a/Content.Server/Atmos/Piping/Other/EntitySystems/GasMinerSystem.cs +++ b/Content.Server/Atmos/Piping/Other/EntitySystems/GasMinerSystem.cs @@ -25,10 +25,17 @@ private void OnMinerUpdated(Entity ent, ref AtmosDeviceUpdate { var miner = ent.Comp; + if (!GetValidEnvironment(ent, out var environment)) + { + miner.Idle = true; + return; + } + // SpawnAmount is declared in mol/s so to get the amount of gas we hope to mine, we have to multiply this by // how long we have been waiting to spawn it and further cap the number according to the miner's state. - var toSpawn = CapSpawnAmount(ent, miner.SpawnAmount * args.dt, out var environment); - if (toSpawn <= 0f || environment == null || !miner.Enabled || !miner.SpawnGas.HasValue) + var toSpawn = CapSpawnAmount(ent, miner.SpawnAmount * args.dt, environment); + miner.Idle = toSpawn == 0; + if (miner.Idle || !miner.Enabled || !miner.SpawnGas.HasValue) return; // Time to mine some gas. @@ -39,27 +46,26 @@ private void OnMinerUpdated(Entity ent, ref AtmosDeviceUpdate _atmosphereSystem.Merge(environment, merger); } - private float CapSpawnAmount(Entity ent, float toSpawnTarget, out GasMixture? environment) + private bool GetValidEnvironment(Entity ent, [NotNullWhen(true)] out GasMixture? environment) { var (uid, miner) = ent; var transform = Transform(uid); - environment = _atmosphereSystem.GetContainingMixture((uid, transform), true, true); - var position = _transformSystem.GetGridOrMapTilePosition(uid, transform); - // Space. + // Treat space as an invalid environment if (_atmosphereSystem.IsTileSpace(transform.GridUid, transform.MapUid, position)) { - miner.Broken = true; - return 0f; + environment = null; + return false; } - // Air-blocked location. - if (environment == null) - { - miner.Broken = true; - return 0f; - } + environment = _atmosphereSystem.GetContainingMixture((uid, transform), true, true); + return environment != null; + } + + private float CapSpawnAmount(Entity ent, float toSpawnTarget, GasMixture environment) + { + var (uid, miner) = ent; // How many moles could we theoretically spawn. Cap by pressure and amount. var allowableMoles = Math.Min( @@ -69,11 +75,9 @@ private float CapSpawnAmount(Entity ent, float toSpawnTarget, var toSpawnReal = Math.Clamp(allowableMoles, 0f, toSpawnTarget); if (toSpawnReal < Atmospherics.GasMinMoles) { - miner.Broken = true; return 0f; } - miner.Broken = false; return toSpawnReal; } } diff --git a/Resources/Prototypes/Entities/Structures/Piping/Atmospherics/miners.yml b/Resources/Prototypes/Entities/Structures/Piping/Atmospherics/miners.yml index 6d10b1521e7..64dd38accb4 100644 --- a/Resources/Prototypes/Entities/Structures/Piping/Atmospherics/miners.yml +++ b/Resources/Prototypes/Entities/Structures/Piping/Atmospherics/miners.yml @@ -66,8 +66,6 @@ parent: GasMinerBase id: GasMinerNitrogen suffix: Shuttle, 300kPa - placement: - mode: SnapgridCenter components: - type: GasMiner spawnGas: Nitrogen @@ -94,8 +92,6 @@ name: CO2 gas miner parent: GasMinerBase id: GasMinerCarbonDioxide - placement: - mode: SnapgridCenter components: - type: GasMiner spawnGas: CarbonDioxide @@ -104,8 +100,6 @@ name: plasma gas miner parent: GasMinerBase id: GasMinerPlasma - placement: - mode: SnapgridCenter components: - type: GasMiner spawnGas: Plasma @@ -114,8 +108,6 @@ name: tritium gas miner parent: GasMinerBase id: GasMinerTritium - placement: - mode: SnapgridCenter components: - type: GasMiner spawnGas: Tritium @@ -124,8 +116,6 @@ name: water vapor gas miner parent: GasMinerBase id: GasMinerWaterVapor - placement: - mode: SnapgridCenter components: - type: GasMiner spawnGas: WaterVapor @@ -134,8 +124,6 @@ name: ammonia gas miner parent: GasMinerBase id: GasMinerAmmonia - placement: - mode: SnapgridCenter components: - type: GasMiner spawnGas: Ammonia @@ -144,8 +132,6 @@ name: nitrous oxide gas miner parent: GasMinerBase id: GasMinerNitrousOxide - placement: - mode: SnapgridCenter components: - type: GasMiner spawnGas: NitrousOxide From 8910bf4c0fc80598f4ce50cc8e3418ea395cebc0 Mon Sep 17 00:00:00 2001 From: lzk <124214523+lzk228@users.noreply.github.com> Date: Wed, 3 Jul 2024 02:01:17 +0200 Subject: [PATCH 027/765] Fix GhostCommand naming (#29671) --- Content.Server/Ghost/{Ghost.cs => GhostCommand.cs} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename Content.Server/Ghost/{Ghost.cs => GhostCommand.cs} (96%) diff --git a/Content.Server/Ghost/Ghost.cs b/Content.Server/Ghost/GhostCommand.cs similarity index 96% rename from Content.Server/Ghost/Ghost.cs rename to Content.Server/Ghost/GhostCommand.cs index 69d81d95929..b553d64201a 100644 --- a/Content.Server/Ghost/Ghost.cs +++ b/Content.Server/Ghost/GhostCommand.cs @@ -7,7 +7,7 @@ namespace Content.Server.Ghost { [AnyCommand] - public sealed class Ghost : IConsoleCommand + public sealed class GhostCommand : IConsoleCommand { [Dependency] private readonly IEntityManager _entities = default!; From 169280a80a78684817cf8e44bb48e58ed674a418 Mon Sep 17 00:00:00 2001 From: Tayrtahn Date: Tue, 2 Jul 2024 20:01:37 -0400 Subject: [PATCH 028/765] Code Cleanup: Integration Tests (#29584) * Cleanup PuddleTest * Cleanup GravityGridTest * Cleanup PowerTest * Cleanup SaveLoadMapTest * Cleanup Body tests * Cleanup ContainerOcclusionTest * Cleanup AirlockTest * Cleanup DamageableTest * Cleanup EntityTest * Cleanup FluidSpillTest * Cleanup FollowerSystemTest * Cleanup HandCuffTest * Cleanup InteractionSystemTests * Cleanup InRangeUnobstructed * Cleanup SimplePredictReconcileTest * Cleanup PostMapInitTest * Cleanup SalvageTest * Cleanup SaveLoadSaveTest * Cleanup ShuttleTest * Cleanup MaterialArbitrageTest * Cleanup PrototypeSaveTest * Fix ShuttleTest * Bunch of small ones * Move JobTests to Station directory * More small fixes * Cleanup InteractionTest.Helpers Had to change a method signature, so some callers were modified too. * Missed one --- .../Tests/Actions/ActionsAddedTest.cs | 2 +- .../Tests/Body/GibTest.cs | 2 +- .../Tests/Body/LegTest.cs | 8 +- .../Tests/Body/LungTest.cs | 8 +- .../Tests/Body/SaveLoadReparentTest.cs | 5 +- .../Tests/Buckle/BuckleDragTest.cs | 4 +- Content.IntegrationTests/Tests/CargoTest.cs | 8 +- .../Chemistry/FixedPoint2SerializationTest.cs | 8 +- .../Tests/Chemistry/SolutionRoundingTest.cs | 4 +- .../Tests/Chemistry/SolutionSystemTests.cs | 12 +- .../Tests/Chemistry/TryAllReactionsTest.cs | 4 +- .../Tests/Commands/PardonCommand.cs | 10 +- .../Tests/Commands/RejuvenateTest.cs | 6 +- .../Tests/Commands/RestartRoundTest.cs | 2 +- .../Tests/ContainerOcclusionTest.cs | 14 +- .../Tests/Damageable/DamageSpecifierTest.cs | 44 +-- .../Tests/Damageable/DamageableTest.cs | 5 +- .../Tests/Doors/AirlockTest.cs | 20 +- .../Tests/DummyIconTest.cs | 2 +- Content.IntegrationTests/Tests/EntityTest.cs | 12 +- .../Tests/Fluids/FluidSpillTest.cs | 27 +- .../Tests/Fluids/PuddleTest.cs | 14 +- .../Tests/FollowerSystemTest.cs | 5 +- .../Components/ActionBlocking/HandCuffTest.cs | 7 +- .../Tests/GameRules/AntagPreferenceTest.cs | 2 +- .../Tests/GameRules/FailAndStartPresetTest.cs | 2 +- .../Tests/GravityGridTest.cs | 30 +- .../Click/InteractionSystemTests.cs | 50 +--- .../Tests/Interaction/InRangeUnobstructed.cs | 5 +- .../Interaction/InteractionTest.Helpers.cs | 28 +- .../Tests/Interaction/InteractionTest.cs | 15 +- .../Tests/Linter/StaticFieldValidationTest.cs | 118 ++++---- .../Tests/MachineBoardTest.cs | 11 +- .../Tests/Mapping/MappingTests.cs | 2 +- .../Tests/MaterialArbitrageTest.cs | 17 +- .../Tests/Minds/GhostTests.cs | 28 +- .../Tests/Minds/MindTests.Helpers.cs | 2 +- .../Tests/Movement/BuckleMovementTest.cs | 4 +- .../Tests/Movement/MovementTest.cs | 2 +- .../Tests/Networking/PvsCommandTest.cs | 4 +- .../Networking/SimplePredictReconcileTest.cs | 9 +- .../Tests/PostMapInitTest.cs | 13 +- .../Tests/Power/PowerTest.cs | 272 +++++++++--------- .../Tests/PrototypeSaveTest.cs | 5 +- .../Tests/Puller/PullerTest.cs | 2 +- .../Tests/ResearchTest.cs | 4 +- .../Tests/Round/JobTest.cs | 44 +-- Content.IntegrationTests/Tests/SalvageTest.cs | 4 +- .../Tests/SaveLoadMapTest.cs | 21 +- .../Tests/SaveLoadSaveTest.cs | 20 +- .../Tests/Serialization/SerializationTest.cs | 16 +- Content.IntegrationTests/Tests/ShuttleTest.cs | 19 +- .../Tests/Sprite/ItemSpriteTest.cs | 10 +- .../Tests/{Minds => Station}/JobTests.cs | 0 .../Tests/Toolshed/ToolshedTest.cs | 8 +- .../Tests/VendingMachineRestockTest.cs | 3 +- 56 files changed, 511 insertions(+), 492 deletions(-) rename Content.IntegrationTests/Tests/{Minds => Station}/JobTests.cs (100%) diff --git a/Content.IntegrationTests/Tests/Actions/ActionsAddedTest.cs b/Content.IntegrationTests/Tests/Actions/ActionsAddedTest.cs index 32b15252261..c232e823132 100644 --- a/Content.IntegrationTests/Tests/Actions/ActionsAddedTest.cs +++ b/Content.IntegrationTests/Tests/Actions/ActionsAddedTest.cs @@ -18,7 +18,7 @@ public sealed class ActionsAddedTest [Test] public async Task TestCombatActionsAdded() { - await using var pair = await PoolManager.GetServerClient(new PoolSettings { Connected = true, DummyTicker = false}); + await using var pair = await PoolManager.GetServerClient(new PoolSettings { Connected = true, DummyTicker = false }); var server = pair.Server; var client = pair.Client; var sEntMan = server.ResolveDependency(); diff --git a/Content.IntegrationTests/Tests/Body/GibTest.cs b/Content.IntegrationTests/Tests/Body/GibTest.cs index c0032a85244..4627c79f64d 100644 --- a/Content.IntegrationTests/Tests/Body/GibTest.cs +++ b/Content.IntegrationTests/Tests/Body/GibTest.cs @@ -5,7 +5,7 @@ namespace Content.IntegrationTests.Tests.Body; [TestFixture] -public sealed class GibTest +public sealed class GibTest { [Test] public async Task TestGib() diff --git a/Content.IntegrationTests/Tests/Body/LegTest.cs b/Content.IntegrationTests/Tests/Body/LegTest.cs index e86966f8f54..7b49bbe84a3 100644 --- a/Content.IntegrationTests/Tests/Body/LegTest.cs +++ b/Content.IntegrationTests/Tests/Body/LegTest.cs @@ -5,7 +5,6 @@ using Content.Shared.Rotation; using Robust.Shared.GameObjects; using Robust.Shared.Map; -using Robust.Shared.Maths; namespace Content.IntegrationTests.Tests.Body { @@ -40,13 +39,14 @@ public async Task RemoveLegsFallTest() var appearanceSystem = entityManager.System(); var xformSystem = entityManager.System(); + var map = await pair.CreateTestMap(); + await server.WaitAssertion(() => { - var mapId = mapManager.CreateMap(); BodyComponent body = null; human = entityManager.SpawnEntity("HumanBodyAndAppearanceDummy", - new MapCoordinates(Vector2.Zero, mapId)); + new MapCoordinates(Vector2.Zero, map.MapId)); Assert.Multiple(() => { @@ -61,7 +61,7 @@ await server.WaitAssertion(() => foreach (var leg in legs) { - xformSystem.DetachParentToNull(leg.Id, entityManager.GetComponent(leg.Id)); + xformSystem.DetachEntity(leg.Id, entityManager.GetComponent(leg.Id)); } }); diff --git a/Content.IntegrationTests/Tests/Body/LungTest.cs b/Content.IntegrationTests/Tests/Body/LungTest.cs index dce3741c98d..9b5ee431f1f 100644 --- a/Content.IntegrationTests/Tests/Body/LungTest.cs +++ b/Content.IntegrationTests/Tests/Body/LungTest.cs @@ -60,8 +60,8 @@ public async Task AirConsistencyTest() var mapManager = server.ResolveDependency(); var entityManager = server.ResolveDependency(); var mapLoader = entityManager.System(); + var mapSys = entityManager.System(); - MapId mapId; EntityUid? grid = null; BodyComponent body = default; RespiratorComponent resp = default; @@ -73,7 +73,7 @@ public async Task AirConsistencyTest() await server.WaitPost(() => { - mapId = mapManager.CreateMap(); + mapSys.CreateMap(out var mapId); Assert.That(mapLoader.TryLoad(mapId, testMapName, out var roots)); var query = entityManager.GetEntityQuery(); @@ -142,8 +142,8 @@ public async Task NoSuffocationTest() var entityManager = server.ResolveDependency(); var cfg = server.ResolveDependency(); var mapLoader = entityManager.System(); + var mapSys = entityManager.System(); - MapId mapId; EntityUid? grid = null; RespiratorComponent respirator = null; EntityUid human = default; @@ -152,7 +152,7 @@ public async Task NoSuffocationTest() await server.WaitPost(() => { - mapId = mapManager.CreateMap(); + mapSys.CreateMap(out var mapId); Assert.That(mapLoader.TryLoad(mapId, testMapName, out var ents), Is.True); var query = entityManager.GetEntityQuery(); diff --git a/Content.IntegrationTests/Tests/Body/SaveLoadReparentTest.cs b/Content.IntegrationTests/Tests/Body/SaveLoadReparentTest.cs index 670ce1a474d..01482ba8ee2 100644 --- a/Content.IntegrationTests/Tests/Body/SaveLoadReparentTest.cs +++ b/Content.IntegrationTests/Tests/Body/SaveLoadReparentTest.cs @@ -33,10 +33,11 @@ public async Task Test() var mapLoader = entities.System(); var bodySystem = entities.System(); var containerSystem = entities.System(); + var mapSys = entities.System(); await server.WaitAssertion(() => { - var mapId = maps.CreateMap(); + mapSys.CreateMap(out var mapId); maps.CreateGrid(mapId); var human = entities.SpawnEntity("HumanBodyDummy", new MapCoordinates(0, 0, mapId)); @@ -115,7 +116,7 @@ await server.WaitAssertion(() => mapLoader.SaveMap(mapId, mapPath); maps.DeleteMap(mapId); - mapId = maps.CreateMap(); + mapSys.CreateMap(out mapId); Assert.That(mapLoader.TryLoad(mapId, mapPath, out _), Is.True); var query = EnumerateQueryEnumerator( diff --git a/Content.IntegrationTests/Tests/Buckle/BuckleDragTest.cs b/Content.IntegrationTests/Tests/Buckle/BuckleDragTest.cs index 8df151d5a0e..82d5d3baa04 100644 --- a/Content.IntegrationTests/Tests/Buckle/BuckleDragTest.cs +++ b/Content.IntegrationTests/Tests/Buckle/BuckleDragTest.cs @@ -38,13 +38,13 @@ public async Task BucklePullTest() await RunTicks(5); Assert.That(buckle.Buckled, Is.True); Assert.That(buckle.BuckledTo, Is.EqualTo(STarget)); - Assert.That(strap.BuckledEntities, Is.EquivalentTo(new[]{sUrist})); + Assert.That(strap.BuckledEntities, Is.EquivalentTo(new[] { sUrist })); Assert.That(puller.Pulling, Is.Null); Assert.That(pullable.Puller, Is.Null); Assert.That(pullable.BeingPulled, Is.False); // Start pulling, and thus unbuckle them - await PressKey(ContentKeyFunctions.TryPullObject, cursorEntity:urist); + await PressKey(ContentKeyFunctions.TryPullObject, cursorEntity: urist); await RunTicks(5); Assert.That(buckle.Buckled, Is.False); Assert.That(buckle.BuckledTo, Is.Null); diff --git a/Content.IntegrationTests/Tests/CargoTest.cs b/Content.IntegrationTests/Tests/CargoTest.cs index 2da84f4f9db..3451117aba7 100644 --- a/Content.IntegrationTests/Tests/CargoTest.cs +++ b/Content.IntegrationTests/Tests/CargoTest.cs @@ -19,11 +19,11 @@ namespace Content.IntegrationTests.Tests; [TestFixture] public sealed class CargoTest { - public static HashSet> Ignored = new () - { + private static readonly HashSet> Ignored = + [ // This is ignored because it is explicitly intended to be able to sell for more than it costs. - // new("FunCrateGambling") - }; + // new("FunCrateGambling") // DeltaV - no gambling + ]; [Test] public async Task NoCargoOrderArbitrage() diff --git a/Content.IntegrationTests/Tests/Chemistry/FixedPoint2SerializationTest.cs b/Content.IntegrationTests/Tests/Chemistry/FixedPoint2SerializationTest.cs index 8e3b89bff11..0e3f89c2825 100644 --- a/Content.IntegrationTests/Tests/Chemistry/FixedPoint2SerializationTest.cs +++ b/Content.IntegrationTests/Tests/Chemistry/FixedPoint2SerializationTest.cs @@ -9,10 +9,10 @@ namespace Content.IntegrationTests.Tests.Chemistry { public sealed class FixedPoint2SerializationTest : SerializationTest { - protected override Assembly[] Assemblies => new[] - { + protected override Assembly[] Assemblies => + [ typeof(FixedPoint2SerializationTest).Assembly - }; + ]; [Test] public void DeserializeNullTest() @@ -53,6 +53,6 @@ public void DeserializeNullDefinitionTest() [DataDefinition] public sealed partial class FixedPoint2TestDefinition { - [DataField("unit")] public FixedPoint2? Unit { get; set; } = FixedPoint2.New(5); + [DataField] public FixedPoint2? Unit { get; set; } = FixedPoint2.New(5); } } diff --git a/Content.IntegrationTests/Tests/Chemistry/SolutionRoundingTest.cs b/Content.IntegrationTests/Tests/Chemistry/SolutionRoundingTest.cs index 4d19a96d9e7..89d33186a27 100644 --- a/Content.IntegrationTests/Tests/Chemistry/SolutionRoundingTest.cs +++ b/Content.IntegrationTests/Tests/Chemistry/SolutionRoundingTest.cs @@ -1,5 +1,5 @@ -using Content.Server.Chemistry.Containers.EntitySystems; using Content.Shared.Chemistry.Components; +using Content.Shared.Chemistry.EntitySystems; using Content.Shared.Chemistry.Reaction; using Content.Shared.Chemistry.Reagent; using Content.Shared.FixedPoint; @@ -76,7 +76,7 @@ public async Task Test() await server.WaitPost(() => { - var system = server.System(); + var system = server.System(); var beaker = server.EntMan.SpawnEntity("SolutionRoundingTestContainer", testMap.GridCoords); system.TryGetSolution(beaker, "beaker", out var newSolutionEnt, out var newSolution); diff --git a/Content.IntegrationTests/Tests/Chemistry/SolutionSystemTests.cs b/Content.IntegrationTests/Tests/Chemistry/SolutionSystemTests.cs index d96a035b2dc..6b71dd08be0 100644 --- a/Content.IntegrationTests/Tests/Chemistry/SolutionSystemTests.cs +++ b/Content.IntegrationTests/Tests/Chemistry/SolutionSystemTests.cs @@ -1,5 +1,5 @@ -using Content.Server.Chemistry.Containers.EntitySystems; using Content.Shared.Chemistry.Components; +using Content.Shared.Chemistry.EntitySystems; using Content.Shared.FixedPoint; using Robust.Shared.GameObjects; using Robust.Shared.Prototypes; @@ -11,7 +11,7 @@ namespace Content.IntegrationTests.Tests.Chemistry; // To ensure volume(A) + volume(B) = volume(A+B) // reactions can change this assumption [TestFixture] -[TestOf(typeof(SolutionContainerSystem))] +[TestOf(typeof(SharedSolutionContainerSystem))] public sealed class SolutionSystemTests { [TestPrototypes] @@ -51,7 +51,7 @@ public async Task TryAddTwoNonReactiveReagent() var entityManager = server.ResolveDependency(); var protoMan = server.ResolveDependency(); - var containerSystem = entityManager.System(); + var containerSystem = entityManager.System(); var testMap = await pair.CreateTestMap(); var coordinates = testMap.GridCoords; @@ -97,7 +97,7 @@ public async Task TryAddTooMuchNonReactiveReagent() var entityManager = server.ResolveDependency(); var protoMan = server.ResolveDependency(); - var containerSystem = entityManager.System(); + var containerSystem = entityManager.System(); var coordinates = testMap.GridCoords; EntityUid beaker; @@ -141,7 +141,7 @@ public async Task TryMixAndOverflowTooMuchReagent() var entityManager = server.ResolveDependency(); var protoMan = server.ResolveDependency(); var testMap = await pair.CreateTestMap(); - var containerSystem = entityManager.System(); + var containerSystem = entityManager.System(); var coordinates = testMap.GridCoords; EntityUid beaker; @@ -194,7 +194,7 @@ public async Task TryMixAndOverflowTooBigOverflow() var entityManager = server.ResolveDependency(); var protoMan = server.ResolveDependency(); - var containerSystem = entityManager.System(); + var containerSystem = entityManager.System(); var testMap = await pair.CreateTestMap(); var coordinates = testMap.GridCoords; diff --git a/Content.IntegrationTests/Tests/Chemistry/TryAllReactionsTest.cs b/Content.IntegrationTests/Tests/Chemistry/TryAllReactionsTest.cs index ddfe7b3481e..3664cda922a 100644 --- a/Content.IntegrationTests/Tests/Chemistry/TryAllReactionsTest.cs +++ b/Content.IntegrationTests/Tests/Chemistry/TryAllReactionsTest.cs @@ -1,4 +1,3 @@ -using Content.Server.Chemistry.Containers.EntitySystems; using Content.Shared.Chemistry.Reaction; using Content.Shared.Chemistry.Components; using Robust.Shared.GameObjects; @@ -6,6 +5,7 @@ using Robust.Shared.Prototypes; using Robust.Shared.Utility; using System.Linq; +using Content.Shared.Chemistry.EntitySystems; namespace Content.IntegrationTests.Tests.Chemistry { @@ -34,7 +34,7 @@ public async Task TryAllTest() var prototypeManager = server.ResolveDependency(); var testMap = await pair.CreateTestMap(); var coordinates = testMap.GridCoords; - var solutionContainerSystem = entityManager.System(); + var solutionContainerSystem = entityManager.System(); foreach (var reactionPrototype in prototypeManager.EnumeratePrototypes()) { diff --git a/Content.IntegrationTests/Tests/Commands/PardonCommand.cs b/Content.IntegrationTests/Tests/Commands/PardonCommand.cs index b3a66e3211c..4db9eabf5c6 100644 --- a/Content.IntegrationTests/Tests/Commands/PardonCommand.cs +++ b/Content.IntegrationTests/Tests/Commands/PardonCommand.cs @@ -28,7 +28,7 @@ public async Task PardonTest() Assert.That(netMan.IsConnected); - Assert.That(sPlayerManager.Sessions.Count(), Is.EqualTo(1)); + Assert.That(sPlayerManager.Sessions, Has.Length.EqualTo(1)); // No bans on record Assert.Multiple(async () => { @@ -50,7 +50,7 @@ public async Task PardonTest() var banReason = "test"; - Assert.That(sPlayerManager.Sessions.Count(), Is.EqualTo(1)); + Assert.That(sPlayerManager.Sessions, Has.Length.EqualTo(1)); // Ban the client for 24 hours await server.WaitPost(() => sConsole.ExecuteCommand($"ban {clientSession.Name} {banReason} 1440")); @@ -63,7 +63,7 @@ public async Task PardonTest() }); await pair.RunTicksSync(5); - Assert.That(sPlayerManager.Sessions.Count(), Is.EqualTo(0)); + Assert.That(sPlayerManager.Sessions, Has.Length.EqualTo(0)); Assert.That(!netMan.IsConnected); // Try to pardon a ban that does not exist @@ -143,11 +143,11 @@ public async Task PardonTest() }); // Reconnect client. Slightly faster than dirtying the pair. - Assert.That(sPlayerManager.Sessions.Count(), Is.EqualTo(0)); + Assert.That(sPlayerManager.Sessions, Is.Empty); client.SetConnectTarget(server); await client.WaitPost(() => netMan.ClientConnect(null!, 0, null!)); await pair.RunTicksSync(5); - Assert.That(sPlayerManager.Sessions.Count(), Is.EqualTo(1)); + Assert.That(sPlayerManager.Sessions, Has.Length.EqualTo(1)); await pair.CleanReturnAsync(); } diff --git a/Content.IntegrationTests/Tests/Commands/RejuvenateTest.cs b/Content.IntegrationTests/Tests/Commands/RejuvenateTest.cs index 2fda3ad58e6..cfc80073066 100644 --- a/Content.IntegrationTests/Tests/Commands/RejuvenateTest.cs +++ b/Content.IntegrationTests/Tests/Commands/RejuvenateTest.cs @@ -37,9 +37,9 @@ public async Task RejuvenateDeadTest() var server = pair.Server; var entManager = server.ResolveDependency(); var prototypeManager = server.ResolveDependency(); - var mobStateSystem = entManager.EntitySysManager.GetEntitySystem(); - var damSystem = entManager.EntitySysManager.GetEntitySystem(); - var rejuvenateSystem = entManager.EntitySysManager.GetEntitySystem(); + var mobStateSystem = entManager.System(); + var damSystem = entManager.System(); + var rejuvenateSystem = entManager.System(); await server.WaitAssertion(() => { diff --git a/Content.IntegrationTests/Tests/Commands/RestartRoundTest.cs b/Content.IntegrationTests/Tests/Commands/RestartRoundTest.cs index ff24ec09686..72a05b5246f 100644 --- a/Content.IntegrationTests/Tests/Commands/RestartRoundTest.cs +++ b/Content.IntegrationTests/Tests/Commands/RestartRoundTest.cs @@ -26,7 +26,7 @@ public async Task RestartRoundAfterStart(bool lobbyEnabled) var configManager = server.ResolveDependency(); var entityManager = server.ResolveDependency(); - var gameTicker = entityManager.EntitySysManager.GetEntitySystem(); + var gameTicker = entityManager.System(); await pair.RunTicksSync(5); diff --git a/Content.IntegrationTests/Tests/ContainerOcclusionTest.cs b/Content.IntegrationTests/Tests/ContainerOcclusionTest.cs index c61a70faf0b..37c4b0c9b57 100644 --- a/Content.IntegrationTests/Tests/ContainerOcclusionTest.cs +++ b/Content.IntegrationTests/Tests/ContainerOcclusionTest.cs @@ -43,11 +43,11 @@ public async Task TestA() EntityUid dummy = default; var mapManager = server.ResolveDependency(); - var mapId = mapManager.CreateMap(); + var map = await pair.CreateTestMap(); await server.WaitPost(() => { - var pos = new MapCoordinates(Vector2.Zero, mapId); + var pos = new MapCoordinates(Vector2.Zero, map.MapId); var entStorage = serverEntManager.EntitySysManager.GetEntitySystem(); var container = serverEntManager.SpawnEntity("ContainerOcclusionA", pos); dummy = serverEntManager.SpawnEntity("ContainerOcclusionDummy", pos); @@ -85,11 +85,12 @@ public async Task TestB() EntityUid dummy = default; var mapManager = server.ResolveDependency(); - var mapId = mapManager.CreateMap(); + + var map = await pair.CreateTestMap(); await server.WaitPost(() => { - var pos = new MapCoordinates(Vector2.Zero, mapId); + var pos = new MapCoordinates(Vector2.Zero, map.MapId); var entStorage = serverEntManager.EntitySysManager.GetEntitySystem(); var container = serverEntManager.SpawnEntity("ContainerOcclusionB", pos); dummy = serverEntManager.SpawnEntity("ContainerOcclusionDummy", pos); @@ -127,11 +128,12 @@ public async Task TestAb() EntityUid dummy = default; var mapManager = server.ResolveDependency(); - var mapId = mapManager.CreateMap(); + + var map = await pair.CreateTestMap(); await server.WaitPost(() => { - var pos = new MapCoordinates(Vector2.Zero, mapId); + var pos = new MapCoordinates(Vector2.Zero, map.MapId); var entStorage = serverEntManager.EntitySysManager.GetEntitySystem(); var containerA = serverEntManager.SpawnEntity("ContainerOcclusionA", pos); var containerB = serverEntManager.SpawnEntity("ContainerOcclusionB", pos); diff --git a/Content.IntegrationTests/Tests/Damageable/DamageSpecifierTest.cs b/Content.IntegrationTests/Tests/Damageable/DamageSpecifierTest.cs index 41d17ddedae..bd5cac05dd1 100644 --- a/Content.IntegrationTests/Tests/Damageable/DamageSpecifierTest.cs +++ b/Content.IntegrationTests/Tests/Damageable/DamageSpecifierTest.cs @@ -14,39 +14,39 @@ public void TestDamageSpecifierOperations() // Test basic math operations. // I've already nearly broken these once. When editing the operators. - DamageSpecifier input1 = new() { DamageDict = _input1 }; - DamageSpecifier input2 = new() { DamageDict = _input2 }; - DamageSpecifier output1 = new() { DamageDict = _output1 }; - DamageSpecifier output2 = new() { DamageDict = _output2 }; - DamageSpecifier output3 = new() { DamageDict = _output3 }; - DamageSpecifier output4 = new() { DamageDict = _output4 }; - DamageSpecifier output5 = new() { DamageDict = _output5 }; + DamageSpecifier input1 = new() { DamageDict = Input1 }; + DamageSpecifier input2 = new() { DamageDict = Input2 }; + DamageSpecifier output1 = new() { DamageDict = Output1 }; + DamageSpecifier output2 = new() { DamageDict = Output2 }; + DamageSpecifier output3 = new() { DamageDict = Output3 }; + DamageSpecifier output4 = new() { DamageDict = Output4 }; + DamageSpecifier output5 = new() { DamageDict = Output5 }; Assert.Multiple(() => { - Assert.That((-input1).Equals(output1)); - Assert.That((input1 / 2).Equals(output2)); - Assert.That((input1 * 2).Equals(output3)); + Assert.That(-input1, Is.EqualTo(output1)); + Assert.That(input1 / 2, Is.EqualTo(output2)); + Assert.That(input1 * 2, Is.EqualTo(output3)); }); - var difference = (input1 - input2); - Assert.That(difference.Equals(output4)); + var difference = input1 - input2; + Assert.That(difference, Is.EqualTo(output4)); - var difference2 = (-input2) + input1; - Assert.That(difference.Equals(difference2)); + var difference2 = -input2 + input1; + Assert.That(difference, Is.EqualTo(difference2)); difference.Clamp(-0.25f, 0.25f); - Assert.That(difference.Equals(output5)); + Assert.That(difference, Is.EqualTo(output5)); } - static Dictionary _input1 = new() + private static readonly Dictionary Input1 = new() { { "A", 1.5f }, { "B", 2 }, { "C", 3 } }; - static Dictionary _input2 = new() + private static readonly Dictionary Input2 = new() { { "A", 1 }, { "B", 2 }, @@ -54,28 +54,28 @@ public void TestDamageSpecifierOperations() { "D", 0.05f } }; - static Dictionary _output1 = new() + private static readonly Dictionary Output1 = new() { { "A", -1.5f }, { "B", -2 }, { "C", -3 } }; - static Dictionary _output2 = new() + private static readonly Dictionary Output2 = new() { { "A", 0.75f }, { "B", 1 }, { "C", 1.5 } }; - static Dictionary _output3 = new() + private static readonly Dictionary Output3 = new() { { "A", 3f }, { "B", 4 }, { "C", 6 } }; - static Dictionary _output4 = new() + private static readonly Dictionary Output4 = new() { { "A", 0.5f }, { "B", 0 }, @@ -83,7 +83,7 @@ public void TestDamageSpecifierOperations() { "D", -0.05f } }; - static Dictionary _output5 = new() + private static readonly Dictionary Output5 = new() { { "A", 0.25f }, { "B", 0 }, diff --git a/Content.IntegrationTests/Tests/Damageable/DamageableTest.cs b/Content.IntegrationTests/Tests/Damageable/DamageableTest.cs index c40b8ed286f..69069fc82fe 100644 --- a/Content.IntegrationTests/Tests/Damageable/DamageableTest.cs +++ b/Content.IntegrationTests/Tests/Damageable/DamageableTest.cs @@ -107,10 +107,11 @@ public async Task TestDamageableComponents() FixedPoint2 typeDamage; + var map = await pair.CreateTestMap(); + await server.WaitPost(() => { - var map = sMapManager.CreateMap(); - var coordinates = new MapCoordinates(0, 0, map); + var coordinates = map.MapCoords; sDamageableEntity = sEntityManager.SpawnEntity("TestDamageableEntityId", coordinates); sDamageableComponent = sEntityManager.GetComponent(sDamageableEntity); diff --git a/Content.IntegrationTests/Tests/Doors/AirlockTest.cs b/Content.IntegrationTests/Tests/Doors/AirlockTest.cs index 2fbaa91456f..e47c73611a4 100644 --- a/Content.IntegrationTests/Tests/Doors/AirlockTest.cs +++ b/Content.IntegrationTests/Tests/Doors/AirlockTest.cs @@ -123,24 +123,24 @@ public async Task AirlockBlockTest() var xformSystem = entityManager.System(); PhysicsComponent physBody = null; - EntityUid AirlockPhysicsDummy = default; + EntityUid airlockPhysicsDummy = default; EntityUid airlock = default; DoorComponent doorComponent = null; - var AirlockPhysicsDummyStartingX = -1; + var airlockPhysicsDummyStartingX = -1; + + var map = await pair.CreateTestMap(); await server.WaitAssertion(() => { - var mapId = mapManager.CreateMap(); - - var humanCoordinates = new MapCoordinates(new Vector2(AirlockPhysicsDummyStartingX, 0), mapId); - AirlockPhysicsDummy = entityManager.SpawnEntity("AirlockPhysicsDummy", humanCoordinates); + var humanCoordinates = new MapCoordinates(new Vector2(airlockPhysicsDummyStartingX, 0), map.MapId); + airlockPhysicsDummy = entityManager.SpawnEntity("AirlockPhysicsDummy", humanCoordinates); - airlock = entityManager.SpawnEntity("AirlockDummy", new MapCoordinates(new Vector2(0, 0), mapId)); + airlock = entityManager.SpawnEntity("AirlockDummy", new MapCoordinates(new Vector2(0, 0), map.MapId)); Assert.Multiple(() => { - Assert.That(entityManager.TryGetComponent(AirlockPhysicsDummy, out physBody), Is.True); + Assert.That(entityManager.TryGetComponent(airlockPhysicsDummy, out physBody), Is.True); Assert.That(entityManager.TryGetComponent(airlock, out doorComponent), Is.True); }); Assert.That(doorComponent.State, Is.EqualTo(DoorState.Closed)); @@ -152,7 +152,7 @@ await server.WaitAssertion(() => await server.WaitAssertion(() => Assert.That(physBody, Is.Not.EqualTo(null))); await server.WaitPost(() => { - physicsSystem.SetLinearVelocity(AirlockPhysicsDummy, new Vector2(0.5f, 0f), body: physBody); + physicsSystem.SetLinearVelocity(airlockPhysicsDummy, new Vector2(0.5f, 0f), body: physBody); }); for (var i = 0; i < 240; i += 10) @@ -176,7 +176,7 @@ await server.WaitPost(() => // Blocked by the airlock await server.WaitAssertion(() => { - Assert.That(Math.Abs(xformSystem.GetWorldPosition(AirlockPhysicsDummy).X - 1), Is.GreaterThan(0.01f)); + Assert.That(Math.Abs(xformSystem.GetWorldPosition(airlockPhysicsDummy).X - 1), Is.GreaterThan(0.01f)); }); await pair.CleanReturnAsync(); } diff --git a/Content.IntegrationTests/Tests/DummyIconTest.cs b/Content.IntegrationTests/Tests/DummyIconTest.cs index a11191a51ea..df2d28a2ea2 100644 --- a/Content.IntegrationTests/Tests/DummyIconTest.cs +++ b/Content.IntegrationTests/Tests/DummyIconTest.cs @@ -21,7 +21,7 @@ await client.WaitAssertion(() => { foreach (var proto in prototypeManager.EnumeratePrototypes()) { - if (proto.NoSpawn || proto.Abstract || pair.IsTestPrototype(proto) || !proto.Components.ContainsKey("Sprite")) + if (proto.HideSpawnMenu || proto.Abstract || pair.IsTestPrototype(proto) || !proto.Components.ContainsKey("Sprite")) continue; Assert.DoesNotThrow(() => diff --git a/Content.IntegrationTests/Tests/EntityTest.cs b/Content.IntegrationTests/Tests/EntityTest.cs index 1fc739fb0c7..42bea8989cd 100644 --- a/Content.IntegrationTests/Tests/EntityTest.cs +++ b/Content.IntegrationTests/Tests/EntityTest.cs @@ -1,15 +1,11 @@ using System.Collections.Generic; using System.Linq; using System.Numerics; -using Content.Server.Humanoid.Components; -using Content.Shared.Coordinates; -using Content.Shared.Prototypes; using Robust.Shared; using Robust.Shared.Configuration; using Robust.Shared.GameObjects; using Robust.Shared.Log; using Robust.Shared.Map; -using Robust.Shared.Map.Components; using Robust.Shared.Maths; using Robust.Shared.Prototypes; @@ -47,7 +43,7 @@ await server.WaitPost(() => foreach (var protoId in protoIds) { - var mapId = mapManager.CreateMap(); + mapSystem.CreateMap(out var mapId); var grid = mapManager.CreateGridEntity(mapId); // TODO: Fix this better in engine. mapSystem.SetTile(grid.Owner, grid.Comp, Vector2i.Zero, new Tile(1)); @@ -155,6 +151,7 @@ public async Task SpawnAndDirtyAllEntities() var prototypeMan = server.ResolveDependency(); var mapManager = server.ResolveDependency(); var sEntMan = server.ResolveDependency(); + var mapSys = server.System(); Assert.That(cfg.GetCVar(CVars.NetPVS), Is.False); @@ -170,7 +167,7 @@ await server.WaitPost(() => { foreach (var protoId in protoIds) { - var mapId = mapManager.CreateMap(); + mapSys.CreateMap(out var mapId); var grid = mapManager.CreateGridEntity(mapId); var ent = sEntMan.SpawnEntity(protoId, new EntityCoordinates(grid.Owner, 0.5f, 0.5f)); foreach (var (_, component) in sEntMan.GetNetComponents(ent)) @@ -227,6 +224,7 @@ public async Task SpawnAndDeleteEntityCountTest() var settings = new PoolSettings { Connected = true, Dirty = true }; await using var pair = await PoolManager.GetServerClient(settings); var mapManager = pair.Server.ResolveDependency(); + var mapSys = pair.Server.System(); var server = pair.Server; var client = pair.Client; @@ -256,7 +254,7 @@ public async Task SpawnAndDeleteEntityCountTest() await server.WaitPost(() => { - mapId = mapManager.CreateMap(); + mapSys.CreateMap(out mapId); }); var coords = new MapCoordinates(Vector2.Zero, mapId); diff --git a/Content.IntegrationTests/Tests/Fluids/FluidSpillTest.cs b/Content.IntegrationTests/Tests/Fluids/FluidSpillTest.cs index 6e88d6928e6..d6f9bf35986 100644 --- a/Content.IntegrationTests/Tests/Fluids/FluidSpillTest.cs +++ b/Content.IntegrationTests/Tests/Fluids/FluidSpillTest.cs @@ -16,14 +16,15 @@ namespace Content.IntegrationTests.Tests.Fluids; [TestOf(typeof(SpreaderSystem))] public sealed class FluidSpill { - private static PuddleComponent? GetPuddle(IEntityManager entityManager, MapGridComponent mapGrid, Vector2i pos) + private static PuddleComponent? GetPuddle(IEntityManager entityManager, Entity mapGrid, Vector2i pos) { return GetPuddleEntity(entityManager, mapGrid, pos)?.Comp; } - private static Entity? GetPuddleEntity(IEntityManager entityManager, MapGridComponent mapGrid, Vector2i pos) + private static Entity? GetPuddleEntity(IEntityManager entityManager, Entity mapGrid, Vector2i pos) { - foreach (var uid in mapGrid.GetAnchoredEntities(pos)) + var mapSys = entityManager.System(); + foreach (var uid in mapSys.GetAnchoredEntities(mapGrid, mapGrid.Comp, pos)) { if (entityManager.TryGetComponent(uid, out PuddleComponent? puddleComponent)) return (uid, puddleComponent); @@ -39,9 +40,9 @@ public async Task SpillCorner() var server = pair.Server; var mapManager = server.ResolveDependency(); var entityManager = server.ResolveDependency(); - var puddleSystem = server.ResolveDependency().GetEntitySystem(); + var puddleSystem = server.System(); + var mapSystem = server.System(); var gameTiming = server.ResolveDependency(); - MapId mapId; EntityUid gridId = default; /* @@ -52,7 +53,7 @@ . . . */ await server.WaitPost(() => { - mapId = mapManager.CreateMap(); + mapSystem.CreateMap(out var mapId); var grid = mapManager.CreateGridEntity(mapId); gridId = grid.Owner; @@ -60,12 +61,12 @@ await server.WaitPost(() => { for (var y = 0; y < 3; y++) { - grid.Comp.SetTile(new Vector2i(x, y), new Tile(1)); + mapSystem.SetTile(grid, new Vector2i(x, y), new Tile(1)); } } - entityManager.SpawnEntity("WallReinforced", grid.Comp.GridTileToLocal(new Vector2i(0, 1))); - entityManager.SpawnEntity("WallReinforced", grid.Comp.GridTileToLocal(new Vector2i(1, 0))); + entityManager.SpawnEntity("WallReinforced", mapSystem.GridTileToLocal(grid, grid.Comp, new Vector2i(0, 1))); + entityManager.SpawnEntity("WallReinforced", mapSystem.GridTileToLocal(grid, grid.Comp, new Vector2i(1, 0))); }); @@ -74,10 +75,10 @@ await server.WaitAssertion(() => { var grid = entityManager.GetComponent(gridId); var solution = new Solution("Blood", FixedPoint2.New(100)); - var tileRef = grid.GetTileRef(puddleOrigin); + var tileRef = mapSystem.GetTileRef(gridId, grid, puddleOrigin); #pragma warning disable NUnit2045 // Interdependent tests Assert.That(puddleSystem.TrySpillAt(tileRef, solution, out _), Is.True); - Assert.That(GetPuddle(entityManager, grid, puddleOrigin), Is.Not.Null); + Assert.That(GetPuddle(entityManager, (gridId, grid), puddleOrigin), Is.Not.Null); #pragma warning restore NUnit2045 }); @@ -87,7 +88,7 @@ await server.WaitAssertion(() => await server.WaitAssertion(() => { var grid = entityManager.GetComponent(gridId); - var puddle = GetPuddleEntity(entityManager, grid, puddleOrigin); + var puddle = GetPuddleEntity(entityManager, (gridId, grid), puddleOrigin); #pragma warning disable NUnit2045 // Interdependent tests Assert.That(puddle, Is.Not.Null); @@ -104,7 +105,7 @@ await server.WaitAssertion(() => } var newPos = new Vector2i(x, y); - var sidePuddle = GetPuddle(entityManager, grid, newPos); + var sidePuddle = GetPuddle(entityManager, (gridId, grid), newPos); Assert.That(sidePuddle, Is.Null); } } diff --git a/Content.IntegrationTests/Tests/Fluids/PuddleTest.cs b/Content.IntegrationTests/Tests/Fluids/PuddleTest.cs index a9069892dff..ee2d0cb1f7a 100644 --- a/Content.IntegrationTests/Tests/Fluids/PuddleTest.cs +++ b/Content.IntegrationTests/Tests/Fluids/PuddleTest.cs @@ -5,7 +5,6 @@ using Content.Shared.Fluids.Components; using Robust.Shared.GameObjects; using Robust.Shared.Map; -using Robust.Shared.Map.Components; namespace Content.IntegrationTests.Tests.Fluids { @@ -21,8 +20,7 @@ public async Task TilePuddleTest() var testMap = await pair.CreateTestMap(); - var entitySystemManager = server.ResolveDependency(); - var spillSystem = entitySystemManager.GetEntitySystem(); + var spillSystem = server.System(); await server.WaitAssertion(() => { @@ -46,17 +44,19 @@ public async Task SpaceNoPuddleTest() var server = pair.Server; var testMap = await pair.CreateTestMap(); - var grid = testMap.Grid.Comp; + var grid = testMap.Grid; var entitySystemManager = server.ResolveDependency(); - var spillSystem = entitySystemManager.GetEntitySystem(); + var spillSystem = server.System(); + var mapSystem = server.System(); // Remove all tiles await server.WaitPost(() => { - foreach (var tile in grid.GetAllTiles()) + var tiles = mapSystem.GetAllTiles(grid.Owner, grid.Comp); + foreach (var tile in tiles) { - grid.SetTile(tile.GridIndices, Tile.Empty); + mapSystem.SetTile(grid, tile.GridIndices, Tile.Empty); } }); diff --git a/Content.IntegrationTests/Tests/FollowerSystemTest.cs b/Content.IntegrationTests/Tests/FollowerSystemTest.cs index 4d308c6d911..f4447426c77 100644 --- a/Content.IntegrationTests/Tests/FollowerSystemTest.cs +++ b/Content.IntegrationTests/Tests/FollowerSystemTest.cs @@ -22,6 +22,7 @@ public async Task FollowerMapDeleteTest() var mapMan = server.ResolveDependency(); var sysMan = server.ResolveDependency(); var logMan = server.ResolveDependency(); + var mapSys = server.System(); var logger = logMan.RootSawmill; await server.WaitPost(() => @@ -29,7 +30,7 @@ await server.WaitPost(() => var followerSystem = sysMan.GetEntitySystem(); // Create a map to spawn the observers on. - var map = mapMan.CreateMap(); + mapSys.CreateMap(out var map); // Spawn an observer to be followed. var followed = entMan.SpawnEntity(GameTicker.ObserverPrototypeName, new MapCoordinates(0, 0, map)); @@ -41,7 +42,7 @@ await server.WaitPost(() => followerSystem.StartFollowingEntity(follower, followed); - entMan.DeleteEntity(mapMan.GetMapEntityId(map)); + entMan.DeleteEntity(mapSys.GetMap(map)); }); await pair.CleanReturnAsync(); } diff --git a/Content.IntegrationTests/Tests/GameObjects/Components/ActionBlocking/HandCuffTest.cs b/Content.IntegrationTests/Tests/GameObjects/Components/ActionBlocking/HandCuffTest.cs index 0ac6b68a3ec..2570e2246a6 100644 --- a/Content.IntegrationTests/Tests/GameObjects/Components/ActionBlocking/HandCuffTest.cs +++ b/Content.IntegrationTests/Tests/GameObjects/Components/ActionBlocking/HandCuffTest.cs @@ -1,5 +1,4 @@ #nullable enable -using System.Numerics; using Content.Server.Cuffs; using Content.Shared.Body.Components; using Content.Shared.Cuffs.Components; @@ -7,7 +6,6 @@ using Robust.Server.Console; using Robust.Shared.GameObjects; using Robust.Shared.Map; -using Robust.Shared.Maths; namespace Content.IntegrationTests.Tests.GameObjects.Components.ActionBlocking { @@ -52,10 +50,11 @@ public async Task Test() var mapManager = server.ResolveDependency(); var host = server.ResolveDependency(); + var map = await pair.CreateTestMap(); + await server.WaitAssertion(() => { - var mapId = mapManager.CreateMap(); - var coordinates = new MapCoordinates(Vector2.Zero, mapId); + var coordinates = map.MapCoords; var cuffableSys = entityManager.System(); var xformSys = entityManager.System(); diff --git a/Content.IntegrationTests/Tests/GameRules/AntagPreferenceTest.cs b/Content.IntegrationTests/Tests/GameRules/AntagPreferenceTest.cs index 1bea33a82bc..b215584c57a 100644 --- a/Content.IntegrationTests/Tests/GameRules/AntagPreferenceTest.cs +++ b/Content.IntegrationTests/Tests/GameRules/AntagPreferenceTest.cs @@ -47,7 +47,7 @@ public async Task TestLobbyPlayersValid() Assert.That(sys.IsEntityValid(client.AttachedEntity, def), Is.True); // By default, traitor/antag preferences are disabled, so the pool should be empty. - var sessions = new List{pair.Player!}; + var sessions = new List { pair.Player! }; var pool = sys.GetPlayerPool(rule, sessions, def); Assert.That(pool.Count, Is.EqualTo(0)); diff --git a/Content.IntegrationTests/Tests/GameRules/FailAndStartPresetTest.cs b/Content.IntegrationTests/Tests/GameRules/FailAndStartPresetTest.cs index 1fed226beee..e18b183b170 100644 --- a/Content.IntegrationTests/Tests/GameRules/FailAndStartPresetTest.cs +++ b/Content.IntegrationTests/Tests/GameRules/FailAndStartPresetTest.cs @@ -110,7 +110,7 @@ public async Task FailAndStartTest() player = pair.Player!.AttachedEntity!.Value; Assert.That(entMan.EntityExists(player)); - ticker.SetGamePreset((GamePresetPrototype?)null); + ticker.SetGamePreset((GamePresetPrototype?) null); server.CfgMan.SetCVar(CCVars.GridFill, false); server.CfgMan.SetCVar(CCVars.GameLobbyFallbackEnabled, true); server.CfgMan.SetCVar(CCVars.GameLobbyDefaultPreset, "secret"); diff --git a/Content.IntegrationTests/Tests/GravityGridTest.cs b/Content.IntegrationTests/Tests/GravityGridTest.cs index 7f817e8a1e0..64f7a6d0820 100644 --- a/Content.IntegrationTests/Tests/GravityGridTest.cs +++ b/Content.IntegrationTests/Tests/GravityGridTest.cs @@ -34,29 +34,25 @@ public async Task Test() var testMap = await pair.CreateTestMap(); - EntityUid generator = default; - var entityMan = server.ResolveDependency(); - var mapMan = server.ResolveDependency(); + var entityMan = server.EntMan; + var mapMan = server.MapMan; var mapSys = entityMan.System(); - MapGridComponent grid1 = null; - MapGridComponent grid2 = null; - EntityUid grid1Entity = default!; - EntityUid grid2Entity = default!; + EntityUid generator = default; + Entity grid1 = default; + Entity grid2 = default; // Create grids await server.WaitAssertion(() => { var mapId = testMap.MapId; - grid1 = mapMan.CreateGrid(mapId); - grid2 = mapMan.CreateGrid(mapId); - grid1Entity = grid1.Owner; - grid2Entity = grid2.Owner; + grid1 = mapMan.CreateGridEntity(mapId); + grid2 = mapMan.CreateGridEntity(mapId); - mapSys.SetTile(grid1Entity, grid1, Vector2i.Zero, new Tile(1)); - mapSys.SetTile(grid2Entity, grid2, Vector2i.Zero, new Tile(1)); + mapSys.SetTile(grid1, grid1, Vector2i.Zero, new Tile(1)); + mapSys.SetTile(grid2, grid2, Vector2i.Zero, new Tile(1)); - generator = entityMan.SpawnEntity("GridGravityGeneratorDummy", new EntityCoordinates(grid1Entity, 0.5f, 0.5f)); + generator = entityMan.SpawnEntity("GridGravityGeneratorDummy", new EntityCoordinates(grid1, 0.5f, 0.5f)); Assert.Multiple(() => { Assert.That(entityMan.HasComponent(generator)); @@ -77,8 +73,8 @@ await server.WaitAssertion(() => Assert.Multiple(() => { Assert.That(generatorComponent.GravityActive, Is.True); - Assert.That(!entityMan.GetComponent(grid1Entity).EnabledVV); - Assert.That(entityMan.GetComponent(grid2Entity).EnabledVV); + Assert.That(!entityMan.GetComponent(grid1).EnabledVV); + Assert.That(entityMan.GetComponent(grid2).EnabledVV); }); // Re-enable needs power so it turns off again. @@ -95,7 +91,7 @@ await server.WaitAssertion(() => Assert.Multiple(() => { Assert.That(generatorComponent.GravityActive, Is.False); - Assert.That(entityMan.GetComponent(grid2Entity).EnabledVV, Is.False); + Assert.That(entityMan.GetComponent(grid2).EnabledVV, Is.False); }); }); diff --git a/Content.IntegrationTests/Tests/Interaction/Click/InteractionSystemTests.cs b/Content.IntegrationTests/Tests/Interaction/Click/InteractionSystemTests.cs index 2b844d34f0c..6ac40e92a1e 100644 --- a/Content.IntegrationTests/Tests/Interaction/Click/InteractionSystemTests.cs +++ b/Content.IntegrationTests/Tests/Interaction/Click/InteractionSystemTests.cs @@ -48,13 +48,9 @@ public async Task InteractionTest() var sysMan = server.ResolveDependency(); var handSys = sysMan.GetEntitySystem(); - var mapId = MapId.Nullspace; - var coords = MapCoordinates.Nullspace; - await server.WaitAssertion(() => - { - mapId = mapManager.CreateMap(); - coords = new MapCoordinates(Vector2.Zero, mapId); - }); + var map = await pair.CreateTestMap(); + var mapId = map.MapId; + var coords = map.MapCoords; await server.WaitIdleAsync(); EntityUid user = default; @@ -119,13 +115,9 @@ public async Task InteractionObstructionTest() var sysMan = server.ResolveDependency(); var handSys = sysMan.GetEntitySystem(); - var mapId = MapId.Nullspace; - var coords = MapCoordinates.Nullspace; - await server.WaitAssertion(() => - { - mapId = mapManager.CreateMap(); - coords = new MapCoordinates(Vector2.Zero, mapId); - }); + var map = await pair.CreateTestMap(); + var mapId = map.MapId; + var coords = map.MapCoords; await server.WaitIdleAsync(); EntityUid user = default; @@ -190,13 +182,9 @@ public async Task InteractionInRangeTest() var sysMan = server.ResolveDependency(); var handSys = sysMan.GetEntitySystem(); - var mapId = MapId.Nullspace; - var coords = MapCoordinates.Nullspace; - await server.WaitAssertion(() => - { - mapId = mapManager.CreateMap(); - coords = new MapCoordinates(Vector2.Zero, mapId); - }); + var map = await pair.CreateTestMap(); + var mapId = map.MapId; + var coords = map.MapCoords; await server.WaitIdleAsync(); EntityUid user = default; @@ -261,13 +249,9 @@ public async Task InteractionOutOfRangeTest() var sysMan = server.ResolveDependency(); var handSys = sysMan.GetEntitySystem(); - var mapId = MapId.Nullspace; - var coords = MapCoordinates.Nullspace; - await server.WaitAssertion(() => - { - mapId = mapManager.CreateMap(); - coords = new MapCoordinates(Vector2.Zero, mapId); - }); + var map = await pair.CreateTestMap(); + var mapId = map.MapId; + var coords = map.MapCoords; await server.WaitIdleAsync(); EntityUid user = default; @@ -331,13 +315,9 @@ public async Task InsideContainerInteractionBlockTest() var handSys = sysMan.GetEntitySystem(); var conSystem = sysMan.GetEntitySystem(); - var mapId = MapId.Nullspace; - var coords = MapCoordinates.Nullspace; - await server.WaitAssertion(() => - { - mapId = mapManager.CreateMap(); - coords = new MapCoordinates(Vector2.Zero, mapId); - }); + var map = await pair.CreateTestMap(); + var mapId = map.MapId; + var coords = map.MapCoords; await server.WaitIdleAsync(); EntityUid user = default; diff --git a/Content.IntegrationTests/Tests/Interaction/InRangeUnobstructed.cs b/Content.IntegrationTests/Tests/Interaction/InRangeUnobstructed.cs index 719367e54e6..801433ae72b 100644 --- a/Content.IntegrationTests/Tests/Interaction/InRangeUnobstructed.cs +++ b/Content.IntegrationTests/Tests/Interaction/InRangeUnobstructed.cs @@ -39,10 +39,11 @@ public async Task EntityEntityTest() EntityUid other = default; MapCoordinates mapCoordinates = default; + var map = await pair.CreateTestMap(); + await server.WaitAssertion(() => { - var mapId = mapManager.CreateMap(); - var coordinates = new MapCoordinates(Vector2.Zero, mapId); + var coordinates = map.MapCoords; origin = sEntities.SpawnEntity(HumanId, coordinates); other = sEntities.SpawnEntity(HumanId, coordinates); diff --git a/Content.IntegrationTests/Tests/Interaction/InteractionTest.Helpers.cs b/Content.IntegrationTests/Tests/Interaction/InteractionTest.Helpers.cs index a61a0593017..a09126a7f7c 100644 --- a/Content.IntegrationTests/Tests/Interaction/InteractionTest.Helpers.cs +++ b/Content.IntegrationTests/Tests/Interaction/InteractionTest.Helpers.cs @@ -571,11 +571,11 @@ protected async Task AssertTile(string? proto, NetCoordinates? coords = null) var tile = Tile.Empty; var serverCoords = SEntMan.GetCoordinates(coords ?? TargetCoords); - var pos = serverCoords.ToMap(SEntMan, Transform); + var pos = Transform.ToMapCoordinates(serverCoords); await Server.WaitPost(() => { - if (MapMan.TryFindGridAt(pos, out _, out var grid)) - tile = grid.GetTileRef(serverCoords).Tile; + if (MapMan.TryFindGridAt(pos, out var gridUid, out var grid)) + tile = MapSystem.GetTileRef(gridUid, grid, serverCoords).Tile; }); Assert.That(tile.TypeId, Is.EqualTo(targetTile.TypeId)); @@ -757,33 +757,41 @@ protected bool TryComp([NotNullWhen(true)] out T? comp) where T : IComponent /// /// Set the tile at the target position to some prototype. /// - protected async Task SetTile(string? proto, NetCoordinates? coords = null, MapGridComponent? grid = null) + protected async Task SetTile(string? proto, NetCoordinates? coords = null, Entity? grid = null) { var tile = proto == null ? Tile.Empty : new Tile(TileMan[proto].TileId); - var pos = SEntMan.GetCoordinates(coords ?? TargetCoords).ToMap(SEntMan, Transform); + var pos = Transform.ToMapCoordinates(SEntMan.GetCoordinates(coords ?? TargetCoords)); + EntityUid gridUid; + MapGridComponent? gridComp; await Server.WaitPost(() => { - if (grid != null || MapMan.TryFindGridAt(pos, out var gridUid, out grid)) + if (grid is { } gridEnt) { - grid.SetTile(SEntMan.GetCoordinates(coords ?? TargetCoords), tile); + MapSystem.SetTile(gridEnt, SEntMan.GetCoordinates(coords ?? TargetCoords), tile); + return; + } + else if (MapMan.TryFindGridAt(pos, out var gUid, out var gComp)) + { + MapSystem.SetTile(gUid, gComp, SEntMan.GetCoordinates(coords ?? TargetCoords), tile); return; } if (proto == null) return; - var gridEnt = MapMan.CreateGridEntity(MapData.MapId); + gridEnt = MapMan.CreateGridEntity(MapData.MapId); grid = gridEnt; gridUid = gridEnt; + gridComp = gridEnt.Comp; var gridXform = SEntMan.GetComponent(gridUid); Transform.SetWorldPosition(gridXform, pos.Position); - grid.SetTile(SEntMan.GetCoordinates(coords ?? TargetCoords), tile); + MapSystem.SetTile((gridUid, gridComp), SEntMan.GetCoordinates(coords ?? TargetCoords), tile); - if (!MapMan.TryFindGridAt(pos, out _, out grid)) + if (!MapMan.TryFindGridAt(pos, out _, out _)) Assert.Fail("Failed to create grid?"); }); await AssertTile(proto, coords); diff --git a/Content.IntegrationTests/Tests/Interaction/InteractionTest.cs b/Content.IntegrationTests/Tests/Interaction/InteractionTest.cs index 37102481ed0..457d3e31920 100644 --- a/Content.IntegrationTests/Tests/Interaction/InteractionTest.cs +++ b/Content.IntegrationTests/Tests/Interaction/InteractionTest.cs @@ -1,5 +1,4 @@ #nullable enable -using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Numerics; using Content.Client.Construction; @@ -108,6 +107,7 @@ public abstract partial class InteractionTest protected SharedItemToggleSystem ItemToggleSys = default!; protected InteractionTestSystem STestSystem = default!; protected SharedTransformSystem Transform = default!; + protected SharedMapSystem MapSystem = default!; protected ISawmill SLogger = default!; protected SharedUserInterfaceSystem SUiSys = default!; @@ -153,7 +153,7 @@ public abstract partial class InteractionTest [SetUp] public virtual async Task Setup() { - Pair = await PoolManager.GetServerClient(new PoolSettings { Connected = true, Dirty = true}); + Pair = await PoolManager.GetServerClient(new PoolSettings { Connected = true, Dirty = true }); // server dependencies SEntMan = Server.ResolveDependency(); @@ -168,6 +168,7 @@ public virtual async Task Setup() ItemToggleSys = SEntMan.System(); DoAfterSys = SEntMan.System(); Transform = SEntMan.System(); + MapSystem = SEntMan.System(); SConstruction = SEntMan.System(); STestSystem = SEntMan.System(); Stack = SEntMan.System(); @@ -188,9 +189,10 @@ public virtual async Task Setup() // Setup map. await Pair.CreateTestMap(); - PlayerCoords = SEntMan.GetNetCoordinates(MapData.GridCoords.Offset(new Vector2(0.5f, 0.5f)).WithEntityId(MapData.MapUid, Transform, SEntMan)); - TargetCoords = SEntMan.GetNetCoordinates(MapData.GridCoords.Offset(new Vector2(1.5f, 0.5f)).WithEntityId(MapData.MapUid, Transform, SEntMan)); - await SetTile(Plating, grid: MapData.Grid.Comp); + + PlayerCoords = SEntMan.GetNetCoordinates(Transform.WithEntityId(MapData.GridCoords.Offset(new Vector2(0.5f, 0.5f)), MapData.MapUid)); + TargetCoords = SEntMan.GetNetCoordinates(Transform.WithEntityId(MapData.GridCoords.Offset(new Vector2(1.5f, 0.5f)), MapData.MapUid)); + await SetTile(Plating, grid: MapData.Grid); // Get player data var sPlayerMan = Server.ResolveDependency(); @@ -263,7 +265,8 @@ public async Task TearDownInternal() await TearDown(); } - protected virtual async Task TearDown() + protected virtual Task TearDown() { + return Task.CompletedTask; } } diff --git a/Content.IntegrationTests/Tests/Linter/StaticFieldValidationTest.cs b/Content.IntegrationTests/Tests/Linter/StaticFieldValidationTest.cs index 30724b50a6d..0632fe1347c 100644 --- a/Content.IntegrationTests/Tests/Linter/StaticFieldValidationTest.cs +++ b/Content.IntegrationTests/Tests/Linter/StaticFieldValidationTest.cs @@ -26,26 +26,26 @@ public async Task TestStaticFieldValidation() protos.Add(kind, ids); } - Assert.That(protoMan.ValidateStaticFields(typeof(StringValid), protos).Count, Is.Zero); - Assert.That(protoMan.ValidateStaticFields(typeof(StringArrayValid), protos).Count, Is.Zero); - Assert.That(protoMan.ValidateStaticFields(typeof(EntProtoIdValid), protos).Count, Is.Zero); - Assert.That(protoMan.ValidateStaticFields(typeof(EntProtoIdArrayValid), protos).Count, Is.Zero); - Assert.That(protoMan.ValidateStaticFields(typeof(ProtoIdTestValid), protos).Count, Is.Zero); - Assert.That(protoMan.ValidateStaticFields(typeof(ProtoIdArrayValid), protos).Count, Is.Zero); - Assert.That(protoMan.ValidateStaticFields(typeof(ProtoIdListValid), protos).Count, Is.Zero); - Assert.That(protoMan.ValidateStaticFields(typeof(ProtoIdSetValid), protos).Count, Is.Zero); - Assert.That(protoMan.ValidateStaticFields(typeof(PrivateProtoIdArrayValid), protos).Count, Is.Zero); - - Assert.That(protoMan.ValidateStaticFields(typeof(StringInvalid), protos).Count, Is.EqualTo(1)); - Assert.That(protoMan.ValidateStaticFields(typeof(StringArrayInvalid), protos).Count, Is.EqualTo(2)); - Assert.That(protoMan.ValidateStaticFields(typeof(EntProtoIdInvalid), protos).Count, Is.EqualTo(1)); - Assert.That(protoMan.ValidateStaticFields(typeof(EntProtoIdArrayInvalid), protos).Count, Is.EqualTo(2)); - Assert.That(protoMan.ValidateStaticFields(typeof(ProtoIdTestInvalid), protos).Count, Is.EqualTo(1)); - Assert.That(protoMan.ValidateStaticFields(typeof(ProtoIdArrayInvalid), protos).Count, Is.EqualTo(2)); - Assert.That(protoMan.ValidateStaticFields(typeof(ProtoIdListInvalid), protos).Count, Is.EqualTo(2)); - Assert.That(protoMan.ValidateStaticFields(typeof(ProtoIdSetInvalid), protos).Count, Is.EqualTo(2)); - Assert.That(protoMan.ValidateStaticFields(typeof(PrivateProtoIdArrayInvalid), protos).Count, Is.EqualTo(2)); - + Assert.That(protoMan.ValidateStaticFields(typeof(StringValid), protos), Is.Empty); + Assert.That(protoMan.ValidateStaticFields(typeof(StringArrayValid), protos), Is.Empty); + Assert.That(protoMan.ValidateStaticFields(typeof(EntProtoIdValid), protos), Is.Empty); + Assert.That(protoMan.ValidateStaticFields(typeof(EntProtoIdArrayValid), protos), Is.Empty); + Assert.That(protoMan.ValidateStaticFields(typeof(ProtoIdTestValid), protos), Is.Empty); + Assert.That(protoMan.ValidateStaticFields(typeof(ProtoIdArrayValid), protos), Is.Empty); + Assert.That(protoMan.ValidateStaticFields(typeof(ProtoIdListValid), protos), Is.Empty); + Assert.That(protoMan.ValidateStaticFields(typeof(ProtoIdSetValid), protos), Is.Empty); + Assert.That(protoMan.ValidateStaticFields(typeof(PrivateProtoIdArrayValid), protos), Is.Empty); + + Assert.That(protoMan.ValidateStaticFields(typeof(StringInvalid), protos), Has.Count.EqualTo(1)); + Assert.That(protoMan.ValidateStaticFields(typeof(StringArrayInvalid), protos), Has.Count.EqualTo(2)); + Assert.That(protoMan.ValidateStaticFields(typeof(EntProtoIdInvalid), protos), Has.Count.EqualTo(1)); + Assert.That(protoMan.ValidateStaticFields(typeof(EntProtoIdArrayInvalid), protos), Has.Count.EqualTo(2)); + Assert.That(protoMan.ValidateStaticFields(typeof(ProtoIdTestInvalid), protos), Has.Count.EqualTo(1)); + Assert.That(protoMan.ValidateStaticFields(typeof(ProtoIdArrayInvalid), protos), Has.Count.EqualTo(2)); + Assert.That(protoMan.ValidateStaticFields(typeof(ProtoIdListInvalid), protos), Has.Count.EqualTo(2)); + Assert.That(protoMan.ValidateStaticFields(typeof(ProtoIdSetInvalid), protos), Has.Count.EqualTo(2)); + Assert.That(protoMan.ValidateStaticFields(typeof(PrivateProtoIdArrayInvalid), protos), Has.Count.EqualTo(2)); + await pair.CleanReturnAsync(); } @@ -58,93 +58,111 @@ public async Task TestStaticFieldValidation() id: StaticFieldTestTag "; - [Reflect(false)] private sealed class StringValid + [Reflect(false)] + private sealed class StringValid { [ValidatePrototypeId] public static string Tag = "StaticFieldTestTag"; } - [Reflect(false)] private sealed class StringInvalid + [Reflect(false)] + private sealed class StringInvalid { [ValidatePrototypeId] public static string Tag = string.Empty; } - [Reflect(false)] private sealed class StringArrayValid + [Reflect(false)] + private sealed class StringArrayValid { - [ValidatePrototypeId] public static string[] Tag = {"StaticFieldTestTag", "StaticFieldTestTag"}; + [ValidatePrototypeId] public static string[] Tag = ["StaticFieldTestTag", "StaticFieldTestTag"]; } - [Reflect(false)] private sealed class StringArrayInvalid + [Reflect(false)] + private sealed class StringArrayInvalid { - [ValidatePrototypeId] public static string[] Tag = {string.Empty, "StaticFieldTestTag", string.Empty}; + [ValidatePrototypeId] public static string[] Tag = [string.Empty, "StaticFieldTestTag", string.Empty]; } - [Reflect(false)] private sealed class EntProtoIdValid + [Reflect(false)] + private sealed class EntProtoIdValid { public static EntProtoId Tag = "StaticFieldTestEnt"; } - [Reflect(false)] private sealed class EntProtoIdInvalid + [Reflect(false)] + private sealed class EntProtoIdInvalid { public static EntProtoId Tag = string.Empty; } - [Reflect(false)] private sealed class EntProtoIdArrayValid + [Reflect(false)] + private sealed class EntProtoIdArrayValid { - public static EntProtoId[] Tag = {"StaticFieldTestEnt", "StaticFieldTestEnt"}; + public static EntProtoId[] Tag = ["StaticFieldTestEnt", "StaticFieldTestEnt"]; } - [Reflect(false)] private sealed class EntProtoIdArrayInvalid + [Reflect(false)] + private sealed class EntProtoIdArrayInvalid { - public static EntProtoId[] Tag = {string.Empty, "StaticFieldTestEnt", string.Empty}; + public static EntProtoId[] Tag = [string.Empty, "StaticFieldTestEnt", string.Empty]; } - [Reflect(false)] private sealed class ProtoIdTestValid + [Reflect(false)] + private sealed class ProtoIdTestValid { public static ProtoId Tag = "StaticFieldTestTag"; } - [Reflect(false)] private sealed class ProtoIdTestInvalid + [Reflect(false)] + private sealed class ProtoIdTestInvalid { public static ProtoId Tag = string.Empty; } - [Reflect(false)] private sealed class ProtoIdArrayValid + [Reflect(false)] + private sealed class ProtoIdArrayValid { - public static ProtoId[] Tag = {"StaticFieldTestTag", "StaticFieldTestTag"}; + public static ProtoId[] Tag = ["StaticFieldTestTag", "StaticFieldTestTag"]; } - [Reflect(false)] private sealed class ProtoIdArrayInvalid + [Reflect(false)] + private sealed class ProtoIdArrayInvalid { - public static ProtoId[] Tag = {string.Empty, "StaticFieldTestTag", string.Empty}; + public static ProtoId[] Tag = [string.Empty, "StaticFieldTestTag", string.Empty]; } - [Reflect(false)] private sealed class ProtoIdListValid + [Reflect(false)] + private sealed class ProtoIdListValid { - public static List> Tag = new() {"StaticFieldTestTag", "StaticFieldTestTag"}; + public static List> Tag = ["StaticFieldTestTag", "StaticFieldTestTag"]; } - [Reflect(false)] private sealed class ProtoIdListInvalid + [Reflect(false)] + private sealed class ProtoIdListInvalid { - public static List> Tag = new() {string.Empty, "StaticFieldTestTag", string.Empty}; + public static List> Tag = [string.Empty, "StaticFieldTestTag", string.Empty]; } - [Reflect(false)] private sealed class ProtoIdSetValid + [Reflect(false)] + private sealed class ProtoIdSetValid { - public static HashSet> Tag = new() {"StaticFieldTestTag", "StaticFieldTestTag"}; + public static HashSet> Tag = ["StaticFieldTestTag", "StaticFieldTestTag"]; } - [Reflect(false)] private sealed class ProtoIdSetInvalid + [Reflect(false)] + private sealed class ProtoIdSetInvalid { - public static HashSet> Tag = new() {string.Empty, "StaticFieldTestTag", string.Empty, " "}; + public static HashSet> Tag = [string.Empty, "StaticFieldTestTag", string.Empty, " "]; } - [Reflect(false)] private sealed class PrivateProtoIdArrayValid + [Reflect(false)] + private sealed class PrivateProtoIdArrayValid { - private static ProtoId[] Tag = {"StaticFieldTestTag", "StaticFieldTestTag"}; + private static readonly ProtoId[] Tag = ["StaticFieldTestTag", "StaticFieldTestTag"]; } - [Reflect(false)] private sealed class PrivateProtoIdArrayInvalid + [Reflect(false)] + private sealed class PrivateProtoIdArrayInvalid { - private static ProtoId[] Tag = {string.Empty, "StaticFieldTestTag", string.Empty}; + private static readonly ProtoId[] Tag = [string.Empty, "StaticFieldTestTag", string.Empty]; } } diff --git a/Content.IntegrationTests/Tests/MachineBoardTest.cs b/Content.IntegrationTests/Tests/MachineBoardTest.cs index e741935be34..e1533bbb8d7 100644 --- a/Content.IntegrationTests/Tests/MachineBoardTest.cs +++ b/Content.IntegrationTests/Tests/MachineBoardTest.cs @@ -2,7 +2,6 @@ using System.Linq; using Content.Server.Construction.Components; using Content.Shared.Construction.Components; -using Content.Shared.Prototypes; using Robust.Shared.GameObjects; using Robust.Shared.Prototypes; @@ -37,6 +36,7 @@ public async Task TestMachineBoardHasValidMachine() var server = pair.Server; var protoMan = server.ResolveDependency(); + var compFact = server.ResolveDependency(); await server.WaitAssertion(() => { @@ -45,7 +45,7 @@ await server.WaitAssertion(() => .Where(p => !pair.IsTestPrototype(p)) .Where(p => !_ignoredPrototypes.Contains(p.ID))) { - if (!p.TryGetComponent(out var mbc)) + if (!p.TryGetComponent(out var mbc, compFact)) continue; var mId = mbc.Prototype; @@ -53,7 +53,7 @@ await server.WaitAssertion(() => { Assert.That(protoMan.TryIndex(mId, out var mProto), $"Machine board {p.ID}'s corresponding machine has an invalid prototype."); - Assert.That(mProto.TryGetComponent(out var mComp), + Assert.That(mProto.TryGetComponent(out var mComp, compFact), $"Machine board {p.ID}'s corresponding machine {mId} does not have MachineComponent"); Assert.That(mComp.Board, Is.EqualTo(p.ID), $"Machine {mId}'s BoardPrototype is not equal to it's corresponding machine board, {p.ID}"); @@ -75,6 +75,7 @@ public async Task TestComputerBoardHasValidComputer() var server = pair.Server; var protoMan = server.ResolveDependency(); + var compFact = server.ResolveDependency(); await server.WaitAssertion(() => { @@ -83,7 +84,7 @@ await server.WaitAssertion(() => .Where(p => !pair.IsTestPrototype(p)) .Where(p => !_ignoredPrototypes.Contains(p.ID))) { - if (!p.TryGetComponent(out var cbc)) + if (!p.TryGetComponent(out var cbc, compFact)) continue; var cId = cbc.Prototype; @@ -92,7 +93,7 @@ await server.WaitAssertion(() => Assert.That(cId, Is.Not.Null, $"Computer board \"{p.ID}\" does not have a corresponding computer."); Assert.That(protoMan.TryIndex(cId, out var cProto), $"Computer board \"{p.ID}\"'s corresponding computer has an invalid prototype."); - Assert.That(cProto.TryGetComponent(out var cComp), + Assert.That(cProto.TryGetComponent(out var cComp, compFact), $"Computer board {p.ID}'s corresponding computer \"{cId}\" does not have ComputerComponent"); Assert.That(cComp.BoardPrototype, Is.EqualTo(p.ID), $"Computer \"{cId}\"'s BoardPrototype is not equal to it's corresponding computer board, \"{p.ID}\""); diff --git a/Content.IntegrationTests/Tests/Mapping/MappingTests.cs b/Content.IntegrationTests/Tests/Mapping/MappingTests.cs index 287e30eb8b1..be8bad229b4 100644 --- a/Content.IntegrationTests/Tests/Mapping/MappingTests.cs +++ b/Content.IntegrationTests/Tests/Mapping/MappingTests.cs @@ -13,7 +13,7 @@ public sealed class MappingTests [Test] public async Task MappingTest() { - await using var pair = await PoolManager.GetServerClient(new PoolSettings {Dirty = true, Connected = true, DummyTicker = false}); + await using var pair = await PoolManager.GetServerClient(new PoolSettings { Dirty = true, Connected = true, DummyTicker = false }); var server = pair.Server; var entMan = server.EntMan; diff --git a/Content.IntegrationTests/Tests/MaterialArbitrageTest.cs b/Content.IntegrationTests/Tests/MaterialArbitrageTest.cs index 19780591bdb..f64b7c79dfe 100644 --- a/Content.IntegrationTests/Tests/MaterialArbitrageTest.cs +++ b/Content.IntegrationTests/Tests/MaterialArbitrageTest.cs @@ -38,15 +38,16 @@ public async Task NoMaterialArbitrage() await server.WaitIdleAsync(); var entManager = server.ResolveDependency(); - var sysManager = server.ResolveDependency(); var mapManager = server.ResolveDependency(); - Assert.That(mapManager.IsMapInitialized(testMap.MapId)); - var protoManager = server.ResolveDependency(); - var pricing = sysManager.GetEntitySystem(); - var stackSys = sysManager.GetEntitySystem(); + + var pricing = entManager.System(); + var stackSys = entManager.System(); + var mapSystem = server.System(); var compFact = server.ResolveDependency(); + Assert.That(mapSystem.IsInitialized(testMap.MapId)); + var constructionName = compFact.GetComponentName(typeof(ConstructionComponent)); var compositionName = compFact.GetComponentName(typeof(PhysicalCompositionComponent)); var materialName = compFact.GetComponentName(typeof(MaterialComponent)); @@ -67,7 +68,7 @@ public async Task NoMaterialArbitrage() Dictionary constructionRecipes = new(); foreach (var proto in protoManager.EnumeratePrototypes()) { - if (proto.NoSpawn || proto.Abstract || pair.IsTestPrototype(proto)) + if (proto.HideSpawnMenu || proto.Abstract || pair.IsTestPrototype(proto)) continue; if (!proto.Components.TryGetValue(constructionName, out var destructible)) @@ -127,7 +128,7 @@ public async Task NoMaterialArbitrage() // Here we get the set of entities/materials spawned when destroying an entity. foreach (var proto in protoManager.EnumeratePrototypes()) { - if (proto.NoSpawn || proto.Abstract || pair.IsTestPrototype(proto)) + if (proto.HideSpawnMenu || proto.Abstract || pair.IsTestPrototype(proto)) continue; if (!proto.Components.TryGetValue(destructibleName, out var destructible)) @@ -298,7 +299,7 @@ public async Task NoMaterialArbitrage() Dictionary physicalCompositions = new(); foreach (var proto in protoManager.EnumeratePrototypes()) { - if (proto.NoSpawn || proto.Abstract || pair.IsTestPrototype(proto)) + if (proto.HideSpawnMenu || proto.Abstract || pair.IsTestPrototype(proto)) continue; if (!proto.Components.TryGetValue(compositionName, out var composition)) diff --git a/Content.IntegrationTests/Tests/Minds/GhostTests.cs b/Content.IntegrationTests/Tests/Minds/GhostTests.cs index 7a156e71e41..3a860267e55 100644 --- a/Content.IntegrationTests/Tests/Minds/GhostTests.cs +++ b/Content.IntegrationTests/Tests/Minds/GhostTests.cs @@ -14,7 +14,7 @@ namespace Content.IntegrationTests.Tests.Minds; [TestFixture] public sealed class GhostTests { - struct GhostTestData + private struct GhostTestData { public IEntityManager SEntMan; public Robust.Server.Player.IPlayerManager SPlayerMan; @@ -23,10 +23,10 @@ struct GhostTestData public TestPair Pair = default!; - public TestMapData MapData => Pair.TestMap!; + public readonly TestMapData MapData => Pair.TestMap!; - public RobustIntegrationTest.ServerIntegrationInstance Server => Pair.Server; - public RobustIntegrationTest.ClientIntegrationInstance Client => Pair.Client; + public readonly RobustIntegrationTest.ServerIntegrationInstance Server => Pair.Server; + public readonly RobustIntegrationTest.ClientIntegrationInstance Client => Pair.Client; /// /// Initial player coordinates. Note that this does not necessarily correspond to the position of the @@ -47,15 +47,16 @@ public GhostTestData() private async Task SetupData() { - var data = new GhostTestData(); - - // Client is needed to create a session for the ghost system. Creating a dummy session was too difficult. - data.Pair = await PoolManager.GetServerClient(new PoolSettings + var data = new GhostTestData { - DummyTicker = false, - Connected = true, - Dirty = true - }); + // Client is needed to create a session for the ghost system. Creating a dummy session was too difficult. + Pair = await PoolManager.GetServerClient(new PoolSettings + { + DummyTicker = false, + Connected = true, + Dirty = true + }) + }; data.SEntMan = data.Pair.Server.ResolveDependency(); data.SPlayerMan = data.Pair.Server.ResolveDependency(); @@ -64,7 +65,8 @@ private async Task SetupData() // Setup map. await data.Pair.CreateTestMap(); - data.PlayerCoords = data.SEntMan.GetNetCoordinates(data.MapData.GridCoords.Offset(new Vector2(0.5f, 0.5f)).WithEntityId(data.MapData.MapUid, data.STransformSys, data.SEntMan)); + var test = data.MapData.GridCoords.Offset(new Vector2(0.5f, 0.5f)); + data.PlayerCoords = data.SEntMan.GetNetCoordinates(data.STransformSys.WithEntityId(data.MapData.GridCoords.Offset(new Vector2(0.5f, 0.5f)), data.MapData.MapUid)); if (data.Client.Session == null) Assert.Fail("No player"); diff --git a/Content.IntegrationTests/Tests/Minds/MindTests.Helpers.cs b/Content.IntegrationTests/Tests/Minds/MindTests.Helpers.cs index 428380631d7..b12c90e16e2 100644 --- a/Content.IntegrationTests/Tests/Minds/MindTests.Helpers.cs +++ b/Content.IntegrationTests/Tests/Minds/MindTests.Helpers.cs @@ -169,7 +169,7 @@ private static async Task Connect(Pair.TestPair pair, string username) { var netManager = pair.Client.ResolveDependency(); var playerMan = pair.Server.ResolveDependency(); - Assert.That(!playerMan.Sessions.Any()); + Assert.That(playerMan.Sessions, Is.Empty); await Task.WhenAll(pair.Client.WaitIdleAsync(), pair.Client.WaitIdleAsync()); pair.Client.SetConnectTarget(pair.Server); diff --git a/Content.IntegrationTests/Tests/Movement/BuckleMovementTest.cs b/Content.IntegrationTests/Tests/Movement/BuckleMovementTest.cs index 8d91855098f..3119ee55924 100644 --- a/Content.IntegrationTests/Tests/Movement/BuckleMovementTest.cs +++ b/Content.IntegrationTests/Tests/Movement/BuckleMovementTest.cs @@ -34,7 +34,7 @@ public async Task ChairTest() Assert.That(Delta(), Is.InRange(-0.01f, 0.01f)); Assert.That(buckle.Buckled, Is.True); Assert.That(buckle.BuckledTo, Is.EqualTo(STarget)); - Assert.That(strap.BuckledEntities, Is.EquivalentTo(new[]{SPlayer})); + Assert.That(strap.BuckledEntities, Is.EquivalentTo(new[] { SPlayer })); Assert.That(cAlert.IsShowingAlert(CPlayer, strap.BuckledAlertType), Is.True); Assert.That(sAlert.IsShowingAlert(SPlayer, strap.BuckledAlertType), Is.True); @@ -43,7 +43,7 @@ public async Task ChairTest() Assert.That(Delta(), Is.InRange(-0.01f, 0.01f)); Assert.That(buckle.Buckled, Is.True); Assert.That(buckle.BuckledTo, Is.EqualTo(STarget)); - Assert.That(strap.BuckledEntities, Is.EquivalentTo(new[]{SPlayer})); + Assert.That(strap.BuckledEntities, Is.EquivalentTo(new[] { SPlayer })); Assert.That(cAlert.IsShowingAlert(CPlayer, strap.BuckledAlertType), Is.True); Assert.That(sAlert.IsShowingAlert(SPlayer, strap.BuckledAlertType), Is.True); diff --git a/Content.IntegrationTests/Tests/Movement/MovementTest.cs b/Content.IntegrationTests/Tests/Movement/MovementTest.cs index ad7b1d0459f..eba92530388 100644 --- a/Content.IntegrationTests/Tests/Movement/MovementTest.cs +++ b/Content.IntegrationTests/Tests/Movement/MovementTest.cs @@ -32,7 +32,7 @@ public override async Task Setup() for (var i = -Tiles; i <= Tiles; i++) { - await SetTile(Plating, SEntMan.GetNetCoordinates(pCoords.Offset(new Vector2(i, 0))), MapData.Grid.Comp); + await SetTile(Plating, SEntMan.GetNetCoordinates(pCoords.Offset(new Vector2(i, 0))), MapData.Grid); } AssertGridCount(1); diff --git a/Content.IntegrationTests/Tests/Networking/PvsCommandTest.cs b/Content.IntegrationTests/Tests/Networking/PvsCommandTest.cs index 4783d21a053..b3955698489 100644 --- a/Content.IntegrationTests/Tests/Networking/PvsCommandTest.cs +++ b/Content.IntegrationTests/Tests/Networking/PvsCommandTest.cs @@ -7,12 +7,12 @@ namespace Content.IntegrationTests.Tests.Networking; [TestFixture] public sealed class PvsCommandTest { - public static EntProtoId TestEnt = "MobHuman"; + private static readonly EntProtoId TestEnt = "MobHuman"; [Test] public async Task TestPvsCommands() { - await using var pair = await PoolManager.GetServerClient(new PoolSettings { Connected = true, DummyTicker = false}); + await using var pair = await PoolManager.GetServerClient(new PoolSettings { Connected = true, DummyTicker = false }); var (server, client) = pair; await pair.RunTicksSync(5); diff --git a/Content.IntegrationTests/Tests/Networking/SimplePredictReconcileTest.cs b/Content.IntegrationTests/Tests/Networking/SimplePredictReconcileTest.cs index 52d464fa41e..29f2573c2d9 100644 --- a/Content.IntegrationTests/Tests/Networking/SimplePredictReconcileTest.cs +++ b/Content.IntegrationTests/Tests/Networking/SimplePredictReconcileTest.cs @@ -51,11 +51,12 @@ public async Task Test() PredictionTestComponent clientComponent = default!; var serverSystem = sEntityManager.System(); var clientSystem = cEntityManager.System(); + var sMapSys = sEntityManager.System(); await server.WaitPost(() => { // Spawn dummy component entity. - var map = sMapManager.CreateMap(); + sMapSys.CreateMap(out var map); serverEnt = sEntityManager.SpawnEntity(null, new MapCoordinates(new Vector2(0, 0), map)); serverComponent = sEntityManager.AddComponent(serverEnt); }); @@ -67,7 +68,7 @@ await server.WaitPost(() => Assert.That(sGameTiming.TickTimingAdjustment, Is.EqualTo(0)); // Check client buffer is full - Assert.That(cGameStateManager.CurrentBufferSize, Is.EqualTo(cGameStateManager.TargetBufferSize)); + Assert.That(cGameStateManager.GetApplicableStateCount(), Is.EqualTo(cGameStateManager.TargetBufferSize)); Assert.That(cGameStateManager.TargetBufferSize, Is.EqualTo(2)); // This isn't required anymore, but the test had this for the sake of "technical things", and I cbf shifting @@ -99,7 +100,7 @@ await client.WaitPost(() => // Client last ran tick 15 meaning it's ahead of the last server tick it processed (12) Assert.That(cGameTiming.CurTick, Is.EqualTo(expected)); - Assert.That(cGameTiming.LastProcessedTick, Is.EqualTo(new GameTick((uint)(baseTick - cGameStateManager.TargetBufferSize)))); + Assert.That(cGameTiming.LastProcessedTick, Is.EqualTo(new GameTick((uint) (baseTick - cGameStateManager.TargetBufferSize)))); }); // *** I am using block scopes to visually distinguish these sections of the test to make it more readable. @@ -264,7 +265,7 @@ await client.WaitPost(() => // Assert timing is still correct. Assert.That(sGameTiming.CurTick, Is.EqualTo(new GameTick(baseTick + 8))); Assert.That(cGameTiming.CurTick, Is.EqualTo(new GameTick(baseTick + 8 + delta))); - Assert.That(cGameTiming.LastProcessedTick, Is.EqualTo(new GameTick((uint)(baseTick + 8 - cGameStateManager.TargetBufferSize)))); + Assert.That(cGameTiming.LastProcessedTick, Is.EqualTo(new GameTick((uint) (baseTick + 8 - cGameStateManager.TargetBufferSize)))); }); { diff --git a/Content.IntegrationTests/Tests/PostMapInitTest.cs b/Content.IntegrationTests/Tests/PostMapInitTest.cs index fc423e540ff..664c0603e11 100644 --- a/Content.IntegrationTests/Tests/PostMapInitTest.cs +++ b/Content.IntegrationTests/Tests/PostMapInitTest.cs @@ -74,13 +74,14 @@ public async Task GridsLoadableTest(string mapFile) var entManager = server.ResolveDependency(); var mapLoader = entManager.System(); + var mapSystem = entManager.System(); var mapManager = server.ResolveDependency(); var cfg = server.ResolveDependency(); Assert.That(cfg.GetCVar(CCVars.GridFill), Is.False); await server.WaitPost(() => { - var mapId = mapManager.CreateMap(); + mapSystem.CreateMap(out var mapId); try { #pragma warning disable NUnit2045 @@ -161,6 +162,7 @@ public async Task GameMapsLoadableTest(string mapProto) var mapManager = server.ResolveDependency(); var entManager = server.ResolveDependency(); var mapLoader = entManager.System(); + var mapSystem = entManager.System(); var protoManager = server.ResolveDependency(); var ticker = entManager.EntitySysManager.GetEntitySystem(); var shuttleSystem = entManager.EntitySysManager.GetEntitySystem(); @@ -170,7 +172,7 @@ public async Task GameMapsLoadableTest(string mapProto) await server.WaitPost(() => { - var mapId = mapManager.CreateMap(); + mapSystem.CreateMap(out var mapId); try { ticker.LoadGameMap(protoManager.Index(mapProto), mapId, null); @@ -180,7 +182,7 @@ await server.WaitPost(() => throw new Exception($"Failed to load map {mapProto}", ex); } - var shuttleMap = mapManager.CreateMap(); + mapSystem.CreateMap(out var shuttleMap); var largest = 0f; EntityUid? targetGrid = null; var memberQuery = entManager.GetEntityQuery(); @@ -249,7 +251,7 @@ await server.WaitPost(() => .Select(x => x.Job!.Value); jobs.ExceptWith(spawnPoints); - Assert.That(jobs, Is.Empty,$"There is no spawnpoints for {string.Join(", ", jobs)} on {mapProto}."); + Assert.That(jobs, Is.Empty, $"There is no spawnpoints for {string.Join(", ", jobs)} on {mapProto}."); } try @@ -322,6 +324,7 @@ public async Task NonGameMapsLoadableTest() var resourceManager = server.ResolveDependency(); var protoManager = server.ResolveDependency(); var cfg = server.ResolveDependency(); + var mapSystem = server.System(); Assert.That(cfg.GetCVar(CCVars.GridFill), Is.False); var gameMaps = protoManager.EnumeratePrototypes().Select(o => o.MapPath).ToHashSet(); @@ -352,7 +355,7 @@ await server.WaitPost(() => { foreach (var mapName in mapNames) { - var mapId = mapManager.CreateMap(); + mapSystem.CreateMap(out var mapId); try { Assert.That(mapLoader.TryLoad(mapId, mapName, out _)); diff --git a/Content.IntegrationTests/Tests/Power/PowerTest.cs b/Content.IntegrationTests/Tests/Power/PowerTest.cs index a94e94489c0..55bb42f8ced 100644 --- a/Content.IntegrationTests/Tests/Power/PowerTest.cs +++ b/Content.IntegrationTests/Tests/Power/PowerTest.cs @@ -166,6 +166,7 @@ public async Task TestSimpleSurplus() var server = pair.Server; var mapManager = server.ResolveDependency(); var entityManager = server.ResolveDependency(); + var mapSys = entityManager.System(); const float loadPower = 200; PowerSupplierComponent supplier = default!; PowerConsumerComponent consumer1 = default!; @@ -173,21 +174,19 @@ public async Task TestSimpleSurplus() await server.WaitAssertion(() => { - var map = mapManager.CreateMap(); - var grid = mapManager.CreateGrid(map); - - var gridOwner = grid.Owner; + var map = mapSys.CreateMap(out var mapId); + var grid = mapManager.CreateGridEntity(mapId); // Power only works when anchored for (var i = 0; i < 3; i++) { - grid.SetTile(new Vector2i(0, i), new Tile(1)); - entityManager.SpawnEntity("CableHV", gridOwner.ToCoordinates(0, i)); + mapSys.SetTile(grid, new Vector2i(0, i), new Tile(1)); + entityManager.SpawnEntity("CableHV", grid.Owner.ToCoordinates(0, i)); } - var generatorEnt = entityManager.SpawnEntity("GeneratorDummy", gridOwner.ToCoordinates()); - var consumerEnt1 = entityManager.SpawnEntity("ConsumerDummy", gridOwner.ToCoordinates(0, 1)); - var consumerEnt2 = entityManager.SpawnEntity("ConsumerDummy", gridOwner.ToCoordinates(0, 2)); + var generatorEnt = entityManager.SpawnEntity("GeneratorDummy", grid.Owner.ToCoordinates()); + var consumerEnt1 = entityManager.SpawnEntity("ConsumerDummy", grid.Owner.ToCoordinates(0, 1)); + var consumerEnt2 = entityManager.SpawnEntity("ConsumerDummy", grid.Owner.ToCoordinates(0, 2)); supplier = entityManager.GetComponent(generatorEnt); consumer1 = entityManager.GetComponent(consumerEnt1); @@ -229,6 +228,7 @@ public async Task TestSimpleDeficit() var server = pair.Server; var mapManager = server.ResolveDependency(); var entityManager = server.ResolveDependency(); + var mapSys = entityManager.System(); const float loadPower = 200; PowerSupplierComponent supplier = default!; PowerConsumerComponent consumer1 = default!; @@ -236,21 +236,19 @@ public async Task TestSimpleDeficit() await server.WaitAssertion(() => { - var map = mapManager.CreateMap(); - var grid = mapManager.CreateGrid(map); - - var gridOwner = grid.Owner; + var map = mapSys.CreateMap(out var mapId); + var grid = mapManager.CreateGridEntity(mapId); // Power only works when anchored for (var i = 0; i < 3; i++) { - grid.SetTile(new Vector2i(0, i), new Tile(1)); - entityManager.SpawnEntity("CableHV", gridOwner.ToCoordinates(0, i)); + mapSys.SetTile(grid, new Vector2i(0, i), new Tile(1)); + entityManager.SpawnEntity("CableHV", grid.Owner.ToCoordinates(0, i)); } - var generatorEnt = entityManager.SpawnEntity("GeneratorDummy", gridOwner.ToCoordinates()); - var consumerEnt1 = entityManager.SpawnEntity("ConsumerDummy", gridOwner.ToCoordinates(0, 1)); - var consumerEnt2 = entityManager.SpawnEntity("ConsumerDummy", gridOwner.ToCoordinates(0, 2)); + var generatorEnt = entityManager.SpawnEntity("GeneratorDummy", grid.Owner.ToCoordinates()); + var consumerEnt1 = entityManager.SpawnEntity("ConsumerDummy", grid.Owner.ToCoordinates(0, 1)); + var consumerEnt2 = entityManager.SpawnEntity("ConsumerDummy", grid.Owner.ToCoordinates(0, 2)); supplier = entityManager.GetComponent(generatorEnt); consumer1 = entityManager.GetComponent(consumerEnt1); @@ -288,25 +286,25 @@ public async Task TestSupplyRamp() var server = pair.Server; var mapManager = server.ResolveDependency(); var entityManager = server.ResolveDependency(); + var mapSys = entityManager.System(); var gameTiming = server.ResolveDependency(); PowerSupplierComponent supplier = default!; PowerConsumerComponent consumer = default!; await server.WaitAssertion(() => { - var map = mapManager.CreateMap(); - var grid = mapManager.CreateGrid(map); - var gridOwner = grid.Owner; + var map = mapSys.CreateMap(out var mapId); + var grid = mapManager.CreateGridEntity(mapId); // Power only works when anchored for (var i = 0; i < 3; i++) { - grid.SetTile(new Vector2i(0, i), new Tile(1)); - entityManager.SpawnEntity("CableHV", gridOwner.ToCoordinates(0, i)); + mapSys.SetTile(grid, new Vector2i(0, i), new Tile(1)); + entityManager.SpawnEntity("CableHV", grid.Owner.ToCoordinates(0, i)); } - var generatorEnt = entityManager.SpawnEntity("GeneratorDummy", gridOwner.ToCoordinates()); - var consumerEnt = entityManager.SpawnEntity("ConsumerDummy", gridOwner.ToCoordinates(0, 2)); + var generatorEnt = entityManager.SpawnEntity("GeneratorDummy", grid.Owner.ToCoordinates()); + var consumerEnt = entityManager.SpawnEntity("ConsumerDummy", grid.Owner.ToCoordinates(0, 2)); supplier = entityManager.GetComponent(generatorEnt); consumer = entityManager.GetComponent(consumerEnt); @@ -378,6 +376,7 @@ public async Task TestBatteryRamp() var entityManager = server.ResolveDependency(); var gameTiming = server.ResolveDependency(); var batterySys = entityManager.System(); + var mapSys = entityManager.System(); const float startingCharge = 100_000; PowerNetworkBatteryComponent netBattery = default!; @@ -386,19 +385,18 @@ public async Task TestBatteryRamp() await server.WaitAssertion(() => { - var map = mapManager.CreateMap(); - var grid = mapManager.CreateGrid(map); - var gridOwner = grid.Owner; + var map = mapSys.CreateMap(out var mapId); + var grid = mapManager.CreateGridEntity(mapId); // Power only works when anchored for (var i = 0; i < 3; i++) { - grid.SetTile(new Vector2i(0, i), new Tile(1)); - entityManager.SpawnEntity("CableHV", gridOwner.ToCoordinates(0, i)); + mapSys.SetTile(grid, new Vector2i(0, i), new Tile(1)); + entityManager.SpawnEntity("CableHV", grid.Owner.ToCoordinates(0, i)); } - var generatorEnt = entityManager.SpawnEntity("DischargingBatteryDummy", gridOwner.ToCoordinates()); - var consumerEnt = entityManager.SpawnEntity("ConsumerDummy", gridOwner.ToCoordinates(0, 2)); + var generatorEnt = entityManager.SpawnEntity("DischargingBatteryDummy", grid.Owner.ToCoordinates()); + var consumerEnt = entityManager.SpawnEntity("ConsumerDummy", grid.Owner.ToCoordinates(0, 2)); netBattery = entityManager.GetComponent(generatorEnt); battery = entityManager.GetComponent(generatorEnt); @@ -479,6 +477,7 @@ public async Task TestNoDemandRampdown() var mapManager = server.ResolveDependency(); var entityManager = server.ResolveDependency(); var batterySys = entityManager.System(); + var mapSys = entityManager.System(); PowerSupplierComponent supplier = default!; PowerNetworkBatteryComponent netBattery = default!; BatteryComponent battery = default!; @@ -490,20 +489,19 @@ public async Task TestNoDemandRampdown() await server.WaitAssertion(() => { - var map = mapManager.CreateMap(); - var grid = mapManager.CreateGrid(map); - var gridOwner = grid.Owner; + var map = mapSys.CreateMap(out var mapId); + var grid = mapManager.CreateGridEntity(mapId); // Power only works when anchored for (var i = 0; i < 3; i++) { - grid.SetTile(new Vector2i(0, i), new Tile(1)); - entityManager.SpawnEntity("CableHV", gridOwner.ToCoordinates(0, i)); + mapSys.SetTile(grid, new Vector2i(0, i), new Tile(1)); + entityManager.SpawnEntity("CableHV", grid.Owner.ToCoordinates(0, i)); } - var generatorEnt = entityManager.SpawnEntity("GeneratorDummy", gridOwner.ToCoordinates()); - var consumerEnt = entityManager.SpawnEntity("ConsumerDummy", gridOwner.ToCoordinates(0, 1)); - var batteryEnt = entityManager.SpawnEntity("DischargingBatteryDummy", gridOwner.ToCoordinates(0, 2)); + var generatorEnt = entityManager.SpawnEntity("GeneratorDummy", grid.Owner.ToCoordinates()); + var consumerEnt = entityManager.SpawnEntity("ConsumerDummy", grid.Owner.ToCoordinates(0, 1)); + var batteryEnt = entityManager.SpawnEntity("DischargingBatteryDummy", grid.Owner.ToCoordinates(0, 2)); netBattery = entityManager.GetComponent(batteryEnt); battery = entityManager.GetComponent(batteryEnt); supplier = entityManager.GetComponent(generatorEnt); @@ -577,24 +575,24 @@ public async Task TestSimpleBatteryChargeDeficit() var gameTiming = server.ResolveDependency(); var entityManager = server.ResolveDependency(); var batterySys = entityManager.System(); + var mapSys = entityManager.System(); PowerSupplierComponent supplier = default!; BatteryComponent battery = default!; await server.WaitAssertion(() => { - var map = mapManager.CreateMap(); - var grid = mapManager.CreateGrid(map); - var gridOwner = grid.Owner; + var map = mapSys.CreateMap(out var mapId); + var grid = mapManager.CreateGridEntity(mapId); // Power only works when anchored for (var i = 0; i < 3; i++) { - grid.SetTile(new Vector2i(0, i), new Tile(1)); - entityManager.SpawnEntity("CableHV", gridOwner.ToCoordinates(0, i)); + mapSys.SetTile(grid, new Vector2i(0, i), new Tile(1)); + entityManager.SpawnEntity("CableHV", grid.Owner.ToCoordinates(0, i)); } - var generatorEnt = entityManager.SpawnEntity("GeneratorDummy", gridOwner.ToCoordinates()); - var batteryEnt = entityManager.SpawnEntity("ChargingBatteryDummy", gridOwner.ToCoordinates(0, 2)); + var generatorEnt = entityManager.SpawnEntity("GeneratorDummy", grid.Owner.ToCoordinates()); + var batteryEnt = entityManager.SpawnEntity("ChargingBatteryDummy", grid.Owner.ToCoordinates(0, 2)); supplier = entityManager.GetComponent(generatorEnt); var netBattery = entityManager.GetComponent(batteryEnt); @@ -634,6 +632,7 @@ public async Task TestFullBattery() var entityManager = server.ResolveDependency(); var gameTiming = server.ResolveDependency(); var batterySys = entityManager.System(); + var mapSys = entityManager.System(); PowerConsumerComponent consumer = default!; PowerSupplierComponent supplier = default!; PowerNetworkBatteryComponent netBattery = default!; @@ -641,23 +640,22 @@ public async Task TestFullBattery() await server.WaitAssertion(() => { - var map = mapManager.CreateMap(); - var grid = mapManager.CreateGrid(map); - var gridOwner = grid.Owner; + var map = mapSys.CreateMap(out var mapId); + var grid = mapManager.CreateGridEntity(mapId); // Power only works when anchored for (var i = 0; i < 4; i++) { - grid.SetTile(new Vector2i(0, i), new Tile(1)); - entityManager.SpawnEntity("CableHV", gridOwner.ToCoordinates(0, i)); + mapSys.SetTile(grid, new Vector2i(0, i), new Tile(1)); + entityManager.SpawnEntity("CableHV", grid.Owner.ToCoordinates(0, i)); } - var terminal = entityManager.SpawnEntity("CableTerminal", gridOwner.ToCoordinates(0, 1)); + var terminal = entityManager.SpawnEntity("CableTerminal", grid.Owner.ToCoordinates(0, 1)); entityManager.GetComponent(terminal).LocalRotation = Angle.FromDegrees(180); - var batteryEnt = entityManager.SpawnEntity("FullBatteryDummy", gridOwner.ToCoordinates(0, 2)); - var supplyEnt = entityManager.SpawnEntity("GeneratorDummy", gridOwner.ToCoordinates(0, 0)); - var consumerEnt = entityManager.SpawnEntity("ConsumerDummy", gridOwner.ToCoordinates(0, 3)); + var batteryEnt = entityManager.SpawnEntity("FullBatteryDummy", grid.Owner.ToCoordinates(0, 2)); + var supplyEnt = entityManager.SpawnEntity("GeneratorDummy", grid.Owner.ToCoordinates(0, 0)); + var consumerEnt = entityManager.SpawnEntity("ConsumerDummy", grid.Owner.ToCoordinates(0, 3)); consumer = entityManager.GetComponent(consumerEnt); supplier = entityManager.GetComponent(supplyEnt); @@ -712,6 +710,7 @@ public async Task TestFullBatteryEfficiencyPassThrough() var entityManager = server.ResolveDependency(); var gameTiming = server.ResolveDependency(); var batterySys = entityManager.System(); + var mapSys = entityManager.System(); PowerConsumerComponent consumer = default!; PowerSupplierComponent supplier = default!; PowerNetworkBatteryComponent netBattery = default!; @@ -719,23 +718,22 @@ public async Task TestFullBatteryEfficiencyPassThrough() await server.WaitAssertion(() => { - var map = mapManager.CreateMap(); - var grid = mapManager.CreateGrid(map); - var gridOwner = grid.Owner; + var map = mapSys.CreateMap(out var mapId); + var grid = mapManager.CreateGridEntity(mapId); // Power only works when anchored for (var i = 0; i < 4; i++) { - grid.SetTile(new Vector2i(0, i), new Tile(1)); - entityManager.SpawnEntity("CableHV", gridOwner.ToCoordinates(0, i)); + mapSys.SetTile(grid, new Vector2i(0, i), new Tile(1)); + entityManager.SpawnEntity("CableHV", grid.Owner.ToCoordinates(0, i)); } - var terminal = entityManager.SpawnEntity("CableTerminal", gridOwner.ToCoordinates(0, 1)); + var terminal = entityManager.SpawnEntity("CableTerminal", grid.Owner.ToCoordinates(0, 1)); entityManager.GetComponent(terminal).LocalRotation = Angle.FromDegrees(180); - var batteryEnt = entityManager.SpawnEntity("FullBatteryDummy", gridOwner.ToCoordinates(0, 2)); - var supplyEnt = entityManager.SpawnEntity("GeneratorDummy", gridOwner.ToCoordinates(0, 0)); - var consumerEnt = entityManager.SpawnEntity("ConsumerDummy", gridOwner.ToCoordinates(0, 3)); + var batteryEnt = entityManager.SpawnEntity("FullBatteryDummy", grid.Owner.ToCoordinates(0, 2)); + var supplyEnt = entityManager.SpawnEntity("GeneratorDummy", grid.Owner.ToCoordinates(0, 0)); + var consumerEnt = entityManager.SpawnEntity("ConsumerDummy", grid.Owner.ToCoordinates(0, 3)); consumer = entityManager.GetComponent(consumerEnt); supplier = entityManager.GetComponent(supplyEnt); @@ -789,15 +787,15 @@ public async Task TestFullBatteryEfficiencyDemandPassThrough() var mapManager = server.ResolveDependency(); var entityManager = server.ResolveDependency(); var batterySys = entityManager.System(); + var mapSys = entityManager.System(); PowerConsumerComponent consumer1 = default!; PowerConsumerComponent consumer2 = default!; PowerSupplierComponent supplier = default!; await server.WaitAssertion(() => { - var map = mapManager.CreateMap(); - var grid = mapManager.CreateGrid(map); - var gridOwner = grid.Owner; + var map = mapSys.CreateMap(out var mapId); + var grid = mapManager.CreateGridEntity(mapId); // Map layout here is // C - consumer @@ -810,19 +808,19 @@ await server.WaitAssertion(() => // Power only works when anchored for (var i = 0; i < 5; i++) { - grid.SetTile(new Vector2i(0, i), new Tile(1)); - entityManager.SpawnEntity("CableHV", gridOwner.ToCoordinates(0, i)); + mapSys.SetTile(grid, new Vector2i(0, i), new Tile(1)); + entityManager.SpawnEntity("CableHV", grid.Owner.ToCoordinates(0, i)); } - entityManager.SpawnEntity("CableTerminal", gridOwner.ToCoordinates(0, 2)); - var terminal = entityManager.SpawnEntity("CableTerminal", gridOwner.ToCoordinates(0, 2)); + entityManager.SpawnEntity("CableTerminal", grid.Owner.ToCoordinates(0, 2)); + var terminal = entityManager.SpawnEntity("CableTerminal", grid.Owner.ToCoordinates(0, 2)); entityManager.GetComponent(terminal).LocalRotation = Angle.FromDegrees(180); - var batteryEnt1 = entityManager.SpawnEntity("FullBatteryDummy", gridOwner.ToCoordinates(0, 1)); - var batteryEnt2 = entityManager.SpawnEntity("FullBatteryDummy", gridOwner.ToCoordinates(0, 3)); - var supplyEnt = entityManager.SpawnEntity("GeneratorDummy", gridOwner.ToCoordinates(0, 2)); - var consumerEnt1 = entityManager.SpawnEntity("ConsumerDummy", gridOwner.ToCoordinates(0, 0)); - var consumerEnt2 = entityManager.SpawnEntity("ConsumerDummy", gridOwner.ToCoordinates(0, 4)); + var batteryEnt1 = entityManager.SpawnEntity("FullBatteryDummy", grid.Owner.ToCoordinates(0, 1)); + var batteryEnt2 = entityManager.SpawnEntity("FullBatteryDummy", grid.Owner.ToCoordinates(0, 3)); + var supplyEnt = entityManager.SpawnEntity("GeneratorDummy", grid.Owner.ToCoordinates(0, 2)); + var consumerEnt1 = entityManager.SpawnEntity("ConsumerDummy", grid.Owner.ToCoordinates(0, 0)); + var consumerEnt2 = entityManager.SpawnEntity("ConsumerDummy", grid.Owner.ToCoordinates(0, 4)); consumer1 = entityManager.GetComponent(consumerEnt1); consumer2 = entityManager.GetComponent(consumerEnt2); @@ -887,6 +885,7 @@ public async Task TestSupplyPrioritized() var entityManager = server.ResolveDependency(); var gameTiming = server.ResolveDependency(); var batterySys = entityManager.System(); + var mapSys = entityManager.System(); PowerConsumerComponent consumer = default!; PowerSupplierComponent supplier1 = default!; PowerSupplierComponent supplier2 = default!; @@ -897,9 +896,8 @@ public async Task TestSupplyPrioritized() await server.WaitAssertion(() => { - var map = mapManager.CreateMap(); - var grid = mapManager.CreateGrid(map); - var gridOwner = grid.Owner; + var map = mapSys.CreateMap(out var mapId); + var grid = mapManager.CreateGridEntity(mapId); // Layout is two generators, two batteries, and one load. As to why two: because previously this test // would fail ONLY if there were more than two batteries present, because each of them tries to supply @@ -911,17 +909,17 @@ await server.WaitAssertion(() => // Place cables for (var i = -2; i <= 2; i++) { - grid.SetTile(new Vector2i(0, i), new Tile(1)); - entityManager.SpawnEntity("CableHV", gridOwner.ToCoordinates(0, i)); + mapSys.SetTile(grid, new Vector2i(0, i), new Tile(1)); + entityManager.SpawnEntity("CableHV", grid.Owner.ToCoordinates(0, i)); } - var batteryEnt1 = entityManager.SpawnEntity("FullBatteryDummy", gridOwner.ToCoordinates(0, 2)); - var batteryEnt2 = entityManager.SpawnEntity("FullBatteryDummy", gridOwner.ToCoordinates(0, -2)); + var batteryEnt1 = entityManager.SpawnEntity("FullBatteryDummy", grid.Owner.ToCoordinates(0, 2)); + var batteryEnt2 = entityManager.SpawnEntity("FullBatteryDummy", grid.Owner.ToCoordinates(0, -2)); - var supplyEnt1 = entityManager.SpawnEntity("GeneratorDummy", gridOwner.ToCoordinates(0, 1)); - var supplyEnt2 = entityManager.SpawnEntity("GeneratorDummy", gridOwner.ToCoordinates(0, -1)); + var supplyEnt1 = entityManager.SpawnEntity("GeneratorDummy", grid.Owner.ToCoordinates(0, 1)); + var supplyEnt2 = entityManager.SpawnEntity("GeneratorDummy", grid.Owner.ToCoordinates(0, -1)); - var consumerEnt = entityManager.SpawnEntity("ConsumerDummy", gridOwner.ToCoordinates(0, 0)); + var consumerEnt = entityManager.SpawnEntity("ConsumerDummy", grid.Owner.ToCoordinates(0, 0)); consumer = entityManager.GetComponent(consumerEnt); supplier1 = entityManager.GetComponent(supplyEnt1); @@ -985,15 +983,15 @@ public async Task TestBatteriesProportional() var mapManager = server.ResolveDependency(); var entityManager = server.ResolveDependency(); var batterySys = entityManager.System(); + var mapSys = entityManager.System(); PowerConsumerComponent consumer1 = default!; PowerConsumerComponent consumer2 = default!; PowerSupplierComponent supplier = default!; await server.WaitAssertion(() => { - var map = mapManager.CreateMap(); - var grid = mapManager.CreateGrid(map); - var gridOwner = grid.Owner; + var map = mapSys.CreateMap(out var mapId); + var grid = mapManager.CreateGridEntity(mapId); // Map layout here is // C - consumer @@ -1006,19 +1004,19 @@ await server.WaitAssertion(() => // Power only works when anchored for (var i = 0; i < 5; i++) { - grid.SetTile(new Vector2i(0, i), new Tile(1)); - entityManager.SpawnEntity("CableHV", gridOwner.ToCoordinates(0, i)); + mapSys.SetTile(grid, new Vector2i(0, i), new Tile(1)); + entityManager.SpawnEntity("CableHV", grid.Owner.ToCoordinates(0, i)); } - entityManager.SpawnEntity("CableTerminal", gridOwner.ToCoordinates(0, 2)); - var terminal = entityManager.SpawnEntity("CableTerminal", gridOwner.ToCoordinates(0, 2)); + entityManager.SpawnEntity("CableTerminal", grid.Owner.ToCoordinates(0, 2)); + var terminal = entityManager.SpawnEntity("CableTerminal", grid.Owner.ToCoordinates(0, 2)); entityManager.GetComponent(terminal).LocalRotation = Angle.FromDegrees(180); - var batteryEnt1 = entityManager.SpawnEntity("FullBatteryDummy", gridOwner.ToCoordinates(0, 1)); - var batteryEnt2 = entityManager.SpawnEntity("FullBatteryDummy", gridOwner.ToCoordinates(0, 3)); - var supplyEnt = entityManager.SpawnEntity("GeneratorDummy", gridOwner.ToCoordinates(0, 2)); - var consumerEnt1 = entityManager.SpawnEntity("ConsumerDummy", gridOwner.ToCoordinates(0, 0)); - var consumerEnt2 = entityManager.SpawnEntity("ConsumerDummy", gridOwner.ToCoordinates(0, 4)); + var batteryEnt1 = entityManager.SpawnEntity("FullBatteryDummy", grid.Owner.ToCoordinates(0, 1)); + var batteryEnt2 = entityManager.SpawnEntity("FullBatteryDummy", grid.Owner.ToCoordinates(0, 3)); + var supplyEnt = entityManager.SpawnEntity("GeneratorDummy", grid.Owner.ToCoordinates(0, 2)); + var consumerEnt1 = entityManager.SpawnEntity("ConsumerDummy", grid.Owner.ToCoordinates(0, 0)); + var consumerEnt2 = entityManager.SpawnEntity("ConsumerDummy", grid.Owner.ToCoordinates(0, 4)); consumer1 = entityManager.GetComponent(consumerEnt1); consumer2 = entityManager.GetComponent(consumerEnt2); @@ -1073,29 +1071,29 @@ public async Task TestBatteryEngineCut() var mapManager = server.ResolveDependency(); var entityManager = server.ResolveDependency(); var batterySys = entityManager.System(); + var mapSys = entityManager.System(); PowerConsumerComponent consumer = default!; PowerSupplierComponent supplier = default!; PowerNetworkBatteryComponent netBattery = default!; await server.WaitPost(() => { - var map = mapManager.CreateMap(); - var grid = mapManager.CreateGrid(map); - var gridOwner = grid.Owner; + var map = mapSys.CreateMap(out var mapId); + var grid = mapManager.CreateGridEntity(mapId); // Power only works when anchored for (var i = 0; i < 4; i++) { - grid.SetTile(new Vector2i(0, i), new Tile(1)); - entityManager.SpawnEntity("CableHV", gridOwner.ToCoordinates(0, i)); + mapSys.SetTile(grid, new Vector2i(0, i), new Tile(1)); + entityManager.SpawnEntity("CableHV", grid.Owner.ToCoordinates(0, i)); } - var terminal = entityManager.SpawnEntity("CableTerminal", gridOwner.ToCoordinates(0, 1)); + var terminal = entityManager.SpawnEntity("CableTerminal", grid.Owner.ToCoordinates(0, 1)); entityManager.GetComponent(terminal).LocalRotation = Angle.FromDegrees(180); - var batteryEnt = entityManager.SpawnEntity("FullBatteryDummy", gridOwner.ToCoordinates(0, 2)); - var supplyEnt = entityManager.SpawnEntity("GeneratorDummy", gridOwner.ToCoordinates(0, 0)); - var consumerEnt = entityManager.SpawnEntity("ConsumerDummy", gridOwner.ToCoordinates(0, 3)); + var batteryEnt = entityManager.SpawnEntity("FullBatteryDummy", grid.Owner.ToCoordinates(0, 2)); + var supplyEnt = entityManager.SpawnEntity("GeneratorDummy", grid.Owner.ToCoordinates(0, 0)); + var consumerEnt = entityManager.SpawnEntity("ConsumerDummy", grid.Owner.ToCoordinates(0, 3)); consumer = entityManager.GetComponent(consumerEnt); supplier = entityManager.GetComponent(supplyEnt); @@ -1158,6 +1156,7 @@ public async Task TestTerminalNodeGroups() var mapManager = server.ResolveDependency(); var entityManager = server.ResolveDependency(); var nodeContainer = entityManager.System(); + var mapSys = entityManager.System(); CableNode leftNode = default!; CableNode rightNode = default!; Node batteryInput = default!; @@ -1165,25 +1164,24 @@ public async Task TestTerminalNodeGroups() await server.WaitAssertion(() => { - var map = mapManager.CreateMap(); - var grid = mapManager.CreateGrid(map); - var gridOwner = grid.Owner; + var map = mapSys.CreateMap(out var mapId); + var grid = mapManager.CreateGridEntity(mapId); // Power only works when anchored for (var i = 0; i < 4; i++) { - grid.SetTile(new Vector2i(0, i), new Tile(1)); + mapSys.SetTile(grid, new Vector2i(0, i), new Tile(1)); } - var leftEnt = entityManager.SpawnEntity("CableHV", gridOwner.ToCoordinates(0, 0)); - entityManager.SpawnEntity("CableHV", gridOwner.ToCoordinates(0, 1)); - entityManager.SpawnEntity("CableHV", gridOwner.ToCoordinates(0, 2)); - var rightEnt = entityManager.SpawnEntity("CableHV", gridOwner.ToCoordinates(0, 3)); + var leftEnt = entityManager.SpawnEntity("CableHV", grid.Owner.ToCoordinates(0, 0)); + entityManager.SpawnEntity("CableHV", grid.Owner.ToCoordinates(0, 1)); + entityManager.SpawnEntity("CableHV", grid.Owner.ToCoordinates(0, 2)); + var rightEnt = entityManager.SpawnEntity("CableHV", grid.Owner.ToCoordinates(0, 3)); - var terminal = entityManager.SpawnEntity("CableTerminal", gridOwner.ToCoordinates(0, 1)); + var terminal = entityManager.SpawnEntity("CableTerminal", grid.Owner.ToCoordinates(0, 1)); entityManager.GetComponent(terminal).LocalRotation = Angle.FromDegrees(180); - var battery = entityManager.SpawnEntity("FullBatteryDummy", gridOwner.ToCoordinates(0, 2)); + var battery = entityManager.SpawnEntity("FullBatteryDummy", grid.Owner.ToCoordinates(0, 2)); var batteryNodeContainer = entityManager.GetComponent(battery); if (nodeContainer.TryGetNode(entityManager.GetComponent(leftEnt), @@ -1224,29 +1222,29 @@ public async Task ApcChargingTest() var mapManager = server.ResolveDependency(); var entityManager = server.ResolveDependency(); var batterySys = entityManager.System(); + var mapSys = entityManager.System(); PowerNetworkBatteryComponent substationNetBattery = default!; BatteryComponent apcBattery = default!; await server.WaitAssertion(() => { - var map = mapManager.CreateMap(); - var grid = mapManager.CreateGrid(map); - var gridOwner = grid.Owner; + var map = mapSys.CreateMap(out var mapId); + var grid = mapManager.CreateGridEntity(mapId); // Power only works when anchored for (var i = 0; i < 3; i++) { - grid.SetTile(new Vector2i(0, i), new Tile(1)); + mapSys.SetTile(grid, new Vector2i(0, i), new Tile(1)); } - entityManager.SpawnEntity("CableHV", gridOwner.ToCoordinates(0, 0)); - entityManager.SpawnEntity("CableHV", gridOwner.ToCoordinates(0, 1)); - entityManager.SpawnEntity("CableMV", gridOwner.ToCoordinates(0, 1)); - entityManager.SpawnEntity("CableMV", gridOwner.ToCoordinates(0, 2)); + entityManager.SpawnEntity("CableHV", grid.Owner.ToCoordinates(0, 0)); + entityManager.SpawnEntity("CableHV", grid.Owner.ToCoordinates(0, 1)); + entityManager.SpawnEntity("CableMV", grid.Owner.ToCoordinates(0, 1)); + entityManager.SpawnEntity("CableMV", grid.Owner.ToCoordinates(0, 2)); - var generatorEnt = entityManager.SpawnEntity("GeneratorDummy", gridOwner.ToCoordinates(0, 0)); - var substationEnt = entityManager.SpawnEntity("SubstationDummy", gridOwner.ToCoordinates(0, 1)); - var apcEnt = entityManager.SpawnEntity("ApcDummy", gridOwner.ToCoordinates(0, 2)); + var generatorEnt = entityManager.SpawnEntity("GeneratorDummy", grid.Owner.ToCoordinates(0, 0)); + var substationEnt = entityManager.SpawnEntity("SubstationDummy", grid.Owner.ToCoordinates(0, 1)); + var apcEnt = entityManager.SpawnEntity("ApcDummy", grid.Owner.ToCoordinates(0, 2)); var generatorSupplier = entityManager.GetComponent(generatorEnt); substationNetBattery = entityManager.GetComponent(substationEnt); @@ -1281,33 +1279,33 @@ public async Task ApcNetTest() var entityManager = server.ResolveDependency(); var batterySys = entityManager.System(); var extensionCableSystem = entityManager.System(); + var mapSys = entityManager.System(); PowerNetworkBatteryComponent apcNetBattery = default!; ApcPowerReceiverComponent receiver = default!; ApcPowerReceiverComponent unpoweredReceiver = default!; await server.WaitAssertion(() => { - var map = mapManager.CreateMap(); - var grid = mapManager.CreateGrid(map); - var gridOwner = grid.Owner; + var map = mapSys.CreateMap(out var mapId); + var grid = mapManager.CreateGridEntity(mapId); const int range = 5; // Power only works when anchored for (var i = 0; i < range; i++) { - grid.SetTile(new Vector2i(0, i), new Tile(1)); + mapSys.SetTile(grid, new Vector2i(0, i), new Tile(1)); } - var apcEnt = entityManager.SpawnEntity("ApcDummy", gridOwner.ToCoordinates(0, 0)); - var apcExtensionEnt = entityManager.SpawnEntity("CableApcExtension", gridOwner.ToCoordinates(0, 0)); + var apcEnt = entityManager.SpawnEntity("ApcDummy", grid.Owner.ToCoordinates(0, 0)); + var apcExtensionEnt = entityManager.SpawnEntity("CableApcExtension", grid.Owner.ToCoordinates(0, 0)); // Create a powered receiver in range (range is 0 indexed) - var powerReceiverEnt = entityManager.SpawnEntity("ApcPowerReceiverDummy", gridOwner.ToCoordinates(0, range - 1)); + var powerReceiverEnt = entityManager.SpawnEntity("ApcPowerReceiverDummy", grid.Owner.ToCoordinates(0, range - 1)); receiver = entityManager.GetComponent(powerReceiverEnt); // Create an unpowered receiver outside range - var unpoweredReceiverEnt = entityManager.SpawnEntity("ApcPowerReceiverDummy", gridOwner.ToCoordinates(0, range)); + var unpoweredReceiverEnt = entityManager.SpawnEntity("ApcPowerReceiverDummy", grid.Owner.ToCoordinates(0, range)); unpoweredReceiver = entityManager.GetComponent(unpoweredReceiverEnt); var battery = entityManager.GetComponent(apcEnt); diff --git a/Content.IntegrationTests/Tests/PrototypeSaveTest.cs b/Content.IntegrationTests/Tests/PrototypeSaveTest.cs index 9e26fa5eaa2..1ef34365ea3 100644 --- a/Content.IntegrationTests/Tests/PrototypeSaveTest.cs +++ b/Content.IntegrationTests/Tests/PrototypeSaveTest.cs @@ -40,6 +40,7 @@ public async Task UninitializedSaveTest() var prototypeMan = server.ResolveDependency(); var seriMan = server.ResolveDependency(); var compFact = server.ResolveDependency(); + var mapSystem = server.System(); var prototypes = new List(); EntityUid uid; @@ -77,7 +78,7 @@ public async Task UninitializedSaveTest() await server.WaitAssertion(() => { - Assert.That(!mapManager.IsMapInitialized(mapId)); + Assert.That(!mapSystem.IsInitialized(mapId)); var testLocation = grid.Owner.ToCoordinates(); Assert.Multiple(() => @@ -184,7 +185,7 @@ public DataNode Write(ISerializationManager serializationManager, EntityUid valu IDependencyCollection dependencies, bool alwaysWrite = false, ISerializationContext? context = null) { - if (WritingComponent != "Transform" && (Prototype?.NoSpawn == false)) + if (WritingComponent != "Transform" && Prototype?.HideSpawnMenu == false) { // Maybe this will be necessary in the future, but at the moment it just indicates that there is some // issue, like a non-nullable entityUid data-field. If a component MUST have an entity uid to work with, diff --git a/Content.IntegrationTests/Tests/Puller/PullerTest.cs b/Content.IntegrationTests/Tests/Puller/PullerTest.cs index 87d174f7272..a4fde86dbfb 100644 --- a/Content.IntegrationTests/Tests/Puller/PullerTest.cs +++ b/Content.IntegrationTests/Tests/Puller/PullerTest.cs @@ -29,7 +29,7 @@ await server.WaitAssertion(() => { foreach (var proto in protoManager.EnumeratePrototypes()) { - if (!proto.TryGetComponent(out PullerComponent? puller)) + if (!proto.TryGetComponent(out PullerComponent? puller, compFactory)) continue; if (!puller.NeedsHands) diff --git a/Content.IntegrationTests/Tests/ResearchTest.cs b/Content.IntegrationTests/Tests/ResearchTest.cs index ee319daa436..7ae29a79ffd 100644 --- a/Content.IntegrationTests/Tests/ResearchTest.cs +++ b/Content.IntegrationTests/Tests/ResearchTest.cs @@ -2,6 +2,7 @@ using System.Linq; using Content.Shared.Lathe; using Content.Shared.Research.Prototypes; +using Robust.Shared.GameObjects; using Robust.Shared.Prototypes; namespace Content.IntegrationTests.Tests; @@ -52,6 +53,7 @@ public async Task AllTechPrintableTest() var server = pair.Server; var protoManager = server.ResolveDependency(); + var compFact = server.ResolveDependency(); await server.WaitAssertion(() => { @@ -65,7 +67,7 @@ await server.WaitAssertion(() => if (pair.IsTestPrototype(proto)) continue; - if (!proto.TryGetComponent(out var lathe)) + if (!proto.TryGetComponent(out var lathe, compFact)) continue; allLathes.Add(lathe); } diff --git a/Content.IntegrationTests/Tests/Round/JobTest.cs b/Content.IntegrationTests/Tests/Round/JobTest.cs index 716e3cf4c21..215890791da 100644 --- a/Content.IntegrationTests/Tests/Round/JobTest.cs +++ b/Content.IntegrationTests/Tests/Round/JobTest.cs @@ -18,14 +18,14 @@ namespace Content.IntegrationTests.Tests.Round; [TestFixture] public sealed class JobTest { - private static ProtoId _passenger = "Passenger"; - private static ProtoId _engineer = "StationEngineer"; - private static ProtoId _captain = "Captain"; + private static readonly ProtoId Passenger = "Passenger"; + private static readonly ProtoId Engineer = "StationEngineer"; + private static readonly ProtoId Captain = "Captain"; private static string _map = "JobTestMap"; [TestPrototypes] - public static string JobTestMap = @$" + private static readonly string JobTestMap = @$" - type: gameMap id: {_map} mapName: {_map} @@ -39,12 +39,12 @@ public sealed class JobTest mapNameTemplate: ""Empty"" - type: StationJobs availableJobs: - {_passenger}: [ -1, -1 ] - {_engineer}: [ -1, -1 ] - {_captain}: [ 1, 1 ] + {Passenger}: [ -1, -1 ] + {Engineer}: [ -1, -1 ] + {Captain}: [ 1, 1 ] "; - public void AssertJob(TestPair pair, ProtoId job, NetUserId? user = null, bool isAntag = false) + private void AssertJob(TestPair pair, ProtoId job, NetUserId? user = null, bool isAntag = false) { var jobSys = pair.Server.System(); var mindSys = pair.Server.System(); @@ -92,7 +92,7 @@ public async Task StartRoundTest() await pair.Server.WaitPost(() => ticker.StartRound()); await pair.RunTicksSync(10); - AssertJob(pair, _passenger); + AssertJob(pair, Passenger); await pair.Server.WaitPost(() => ticker.RestartRound()); await pair.CleanReturnAsync(); @@ -116,21 +116,21 @@ public async Task JobPreferenceTest() Assert.That(ticker.RunLevel, Is.EqualTo(GameRunLevel.PreRoundLobby)); Assert.That(pair.Client.AttachedEntity, Is.Null); - await pair.SetJobPriorities((_passenger, JobPriority.Medium), (_engineer, JobPriority.High)); + await pair.SetJobPriorities((Passenger, JobPriority.Medium), (Engineer, JobPriority.High)); ticker.ToggleReadyAll(true); await pair.Server.WaitPost(() => ticker.StartRound()); await pair.RunTicksSync(10); - AssertJob(pair, _engineer); + AssertJob(pair, Engineer); await pair.Server.WaitPost(() => ticker.RestartRound()); Assert.That(ticker.RunLevel, Is.EqualTo(GameRunLevel.PreRoundLobby)); - await pair.SetJobPriorities((_passenger, JobPriority.High), (_engineer, JobPriority.Medium)); + await pair.SetJobPriorities((Passenger, JobPriority.High), (Engineer, JobPriority.Medium)); ticker.ToggleReadyAll(true); await pair.Server.WaitPost(() => ticker.StartRound()); await pair.RunTicksSync(10); - AssertJob(pair, _passenger); + AssertJob(pair, Passenger); await pair.Server.WaitPost(() => ticker.RestartRound()); await pair.CleanReturnAsync(); @@ -155,18 +155,18 @@ public async Task JobWeightTest() Assert.That(ticker.RunLevel, Is.EqualTo(GameRunLevel.PreRoundLobby)); Assert.That(pair.Client.AttachedEntity, Is.Null); - var captain = pair.Server.ProtoMan.Index(_captain); - var engineer = pair.Server.ProtoMan.Index(_engineer); - var passenger = pair.Server.ProtoMan.Index(_passenger); + var captain = pair.Server.ProtoMan.Index(Captain); + var engineer = pair.Server.ProtoMan.Index(Engineer); + var passenger = pair.Server.ProtoMan.Index(Passenger); Assert.That(captain.Weight, Is.GreaterThan(engineer.Weight)); Assert.That(engineer.Weight, Is.EqualTo(passenger.Weight)); - await pair.SetJobPriorities((_passenger, JobPriority.Medium), (_engineer, JobPriority.High), (_captain, JobPriority.Low)); + await pair.SetJobPriorities((Passenger, JobPriority.Medium), (Engineer, JobPriority.High), (Captain, JobPriority.Low)); ticker.ToggleReadyAll(true); await pair.Server.WaitPost(() => ticker.StartRound()); await pair.RunTicksSync(10); - AssertJob(pair, _captain); + AssertJob(pair, Captain); await pair.Server.WaitPost(() => ticker.RestartRound()); await pair.CleanReturnAsync(); @@ -197,22 +197,22 @@ public async Task JobPriorityTest() var captain = engineers[3]; engineers.RemoveAt(3); - await pair.SetJobPriorities(captain, (_captain, JobPriority.High), (_engineer, JobPriority.Medium)); + await pair.SetJobPriorities(captain, (Captain, JobPriority.High), (Engineer, JobPriority.Medium)); foreach (var engi in engineers) { - await pair.SetJobPriorities(engi, (_captain, JobPriority.Medium), (_engineer, JobPriority.High)); + await pair.SetJobPriorities(engi, (Captain, JobPriority.Medium), (Engineer, JobPriority.High)); } ticker.ToggleReadyAll(true); await pair.Server.WaitPost(() => ticker.StartRound()); await pair.RunTicksSync(10); - AssertJob(pair, _captain, captain); + AssertJob(pair, Captain, captain); Assert.Multiple(() => { foreach (var engi in engineers) { - AssertJob(pair, _engineer, engi); + AssertJob(pair, Engineer, engi); } }); diff --git a/Content.IntegrationTests/Tests/SalvageTest.cs b/Content.IntegrationTests/Tests/SalvageTest.cs index 9d75428beb7..5dfba82308f 100644 --- a/Content.IntegrationTests/Tests/SalvageTest.cs +++ b/Content.IntegrationTests/Tests/SalvageTest.cs @@ -1,5 +1,4 @@ using System.Linq; -using Content.Server.Salvage; using Content.Shared.CCVar; using Content.Shared.Salvage; using Robust.Server.GameObjects; @@ -28,6 +27,7 @@ public async Task AllSalvageMapsLoadableTest() var mapManager = server.ResolveDependency(); var prototypeManager = server.ResolveDependency(); var cfg = server.ResolveDependency(); + var mapSystem = entManager.System(); Assert.That(cfg.GetCVar(CCVars.GridFill), Is.False); await server.WaitPost(() => @@ -36,7 +36,7 @@ await server.WaitPost(() => { var mapFile = salvage.MapPath; - var mapId = mapManager.CreateMap(); + mapSystem.CreateMap(out var mapId); try { Assert.That(mapLoader.TryLoad(mapId, mapFile.ToString(), out var roots)); diff --git a/Content.IntegrationTests/Tests/SaveLoadMapTest.cs b/Content.IntegrationTests/Tests/SaveLoadMapTest.cs index db2109ca599..213da5d7862 100644 --- a/Content.IntegrationTests/Tests/SaveLoadMapTest.cs +++ b/Content.IntegrationTests/Tests/SaveLoadMapTest.cs @@ -23,6 +23,7 @@ public async Task SaveLoadMultiGridMap() var mapManager = server.ResolveDependency(); var sEntities = server.ResolveDependency(); var mapLoader = sEntities.System(); + var mapSystem = sEntities.System(); var xformSystem = sEntities.EntitySysManager.GetEntitySystem(); var resManager = server.ResolveDependency(); var cfg = server.ResolveDependency(); @@ -33,19 +34,17 @@ await server.WaitAssertion(() => var dir = new ResPath(mapPath).Directory; resManager.UserData.CreateDir(dir); - var mapId = mapManager.CreateMap(); + mapSystem.CreateMap(out var mapId); { - var mapGrid = mapManager.CreateGrid(mapId); - var mapGridEnt = mapGrid.Owner; - xformSystem.SetWorldPosition(mapGridEnt, new Vector2(10, 10)); - mapGrid.SetTile(new Vector2i(0, 0), new Tile(1, (TileRenderFlag) 1, 255)); + var mapGrid = mapManager.CreateGridEntity(mapId); + xformSystem.SetWorldPosition(mapGrid, new Vector2(10, 10)); + mapSystem.SetTile(mapGrid, new Vector2i(0, 0), new Tile(1, (TileRenderFlag) 1, 255)); } { - var mapGrid = mapManager.CreateGrid(mapId); - var mapGridEnt = mapGrid.Owner; - xformSystem.SetWorldPosition(mapGridEnt, new Vector2(-8, -8)); - mapGrid.SetTile(new Vector2i(0, 0), new Tile(2, (TileRenderFlag) 1, 254)); + var mapGrid = mapManager.CreateGridEntity(mapId); + xformSystem.SetWorldPosition(mapGrid, new Vector2(-8, -8)); + mapSystem.SetTile(mapGrid, new Vector2i(0, 0), new Tile(2, (TileRenderFlag) 1, 254)); } Assert.Multiple(() => mapLoader.SaveMap(mapId, mapPath)); @@ -74,7 +73,7 @@ await server.WaitAssertion(() => Assert.Multiple(() => { Assert.That(xformSystem.GetWorldPosition(gridXform), Is.EqualTo(new Vector2(10, 10))); - Assert.That(mapGrid.GetTileRef(new Vector2i(0, 0)).Tile, Is.EqualTo(new Tile(1, (TileRenderFlag) 1, 255))); + Assert.That(mapSystem.GetTileRef(gridUid, mapGrid, new Vector2i(0, 0)).Tile, Is.EqualTo(new Tile(1, (TileRenderFlag) 1, 255))); }); } { @@ -88,7 +87,7 @@ await server.WaitAssertion(() => Assert.Multiple(() => { Assert.That(xformSystem.GetWorldPosition(gridXform), Is.EqualTo(new Vector2(-8, -8))); - Assert.That(mapGrid.GetTileRef(new Vector2i(0, 0)).Tile, Is.EqualTo(new Tile(2, (TileRenderFlag) 1, 254))); + Assert.That(mapSystem.GetTileRef(gridUid, mapGrid, new Vector2i(0, 0)).Tile, Is.EqualTo(new Tile(2, (TileRenderFlag) 1, 254))); }); } }); diff --git a/Content.IntegrationTests/Tests/SaveLoadSaveTest.cs b/Content.IntegrationTests/Tests/SaveLoadSaveTest.cs index 01c03aace71..af60db55322 100644 --- a/Content.IntegrationTests/Tests/SaveLoadSaveTest.cs +++ b/Content.IntegrationTests/Tests/SaveLoadSaveTest.cs @@ -25,17 +25,18 @@ public async Task SaveLoadSave() var server = pair.Server; var entManager = server.ResolveDependency(); var mapLoader = entManager.System(); + var mapSystem = entManager.System(); var mapManager = server.ResolveDependency(); var cfg = server.ResolveDependency(); Assert.That(cfg.GetCVar(CCVars.GridFill), Is.False); await server.WaitPost(() => { - var mapId0 = mapManager.CreateMap(); + mapSystem.CreateMap(out var mapId0); // TODO: Properly find the "main" station grid. - var grid0 = mapManager.CreateGrid(mapId0); + var grid0 = mapManager.CreateGridEntity(mapId0); mapLoader.Save(grid0.Owner, "save load save 1.yml"); - var mapId1 = mapManager.CreateMap(); + mapSystem.CreateMap(out var mapId1); EntityUid grid1 = default!; #pragma warning disable NUnit2045 Assert.That(mapLoader.TryLoad(mapId1, "save load save 1.yml", out var roots, new MapLoadOptions() { LoadMap = false }), $"Failed to load test map {TestMap}"); @@ -101,6 +102,7 @@ public async Task LoadSaveTicksSavePebble() var server = pair.Server; var mapLoader = server.ResolveDependency().GetEntitySystem(); var mapManager = server.ResolveDependency(); + var mapSystem = server.System(); MapId mapId = default; var cfg = server.ResolveDependency(); @@ -109,8 +111,7 @@ public async Task LoadSaveTicksSavePebble() // Load pebble.yml as uninitialized map, and save it to ensure it's up to date. server.Post(() => { - mapId = mapManager.CreateMap(); - mapManager.AddUninitializedMap(mapId); + mapSystem.CreateMap(out mapId, runMapInit: false); mapManager.SetMapPaused(mapId, true); Assert.That(mapLoader.TryLoad(mapId, TestMap, out _), $"Failed to load test map {TestMap}"); mapLoader.SaveMap(mapId, "load save ticks save 1.yml"); @@ -182,7 +183,8 @@ public async Task LoadTickLoadPebble() await using var pair = await PoolManager.GetServerClient(); var server = pair.Server; - var mapLoader = server.ResolveDependency().GetEntitySystem(); + var mapLoader = server.System(); + var mapSystem = server.System(); var mapManager = server.ResolveDependency(); var userData = server.ResolveDependency().UserData; var cfg = server.ResolveDependency(); @@ -197,8 +199,7 @@ public async Task LoadTickLoadPebble() // Load & save the first map server.Post(() => { - mapId = mapManager.CreateMap(); - mapManager.AddUninitializedMap(mapId); + mapSystem.CreateMap(out mapId, runMapInit: false); mapManager.SetMapPaused(mapId, true); Assert.That(mapLoader.TryLoad(mapId, TestMap, out _), $"Failed to load test map {TestMap}"); mapLoader.SaveMap(mapId, fileA); @@ -217,8 +218,7 @@ public async Task LoadTickLoadPebble() server.Post(() => { mapManager.DeleteMap(mapId); - mapManager.CreateMap(mapId); - mapManager.AddUninitializedMap(mapId); + mapSystem.CreateMap(out mapId, runMapInit: false); mapManager.SetMapPaused(mapId, true); Assert.That(mapLoader.TryLoad(mapId, TestMap, out _), $"Failed to load test map {TestMap}"); mapLoader.SaveMap(mapId, fileB); diff --git a/Content.IntegrationTests/Tests/Serialization/SerializationTest.cs b/Content.IntegrationTests/Tests/Serialization/SerializationTest.cs index 052ea997c0d..339420362c1 100644 --- a/Content.IntegrationTests/Tests/Serialization/SerializationTest.cs +++ b/Content.IntegrationTests/Tests/Serialization/SerializationTest.cs @@ -24,7 +24,7 @@ public async Task SerializeGenericEnums() Enum value = TestEnum.Bb; - var node = seriMan.WriteValue(value, notNullableOverride:true); + var node = seriMan.WriteValue(value, notNullableOverride: true); var valueNode = node as ValueDataNode; Assert.That(valueNode, Is.Not.Null); @@ -34,22 +34,22 @@ public async Task SerializeGenericEnums() var errors = seriMan.ValidateNode(valueNode).GetErrors(); Assert.That(errors.Any(), Is.False); - var deserialized = seriMan.Read(node, notNullableOverride:true); + var deserialized = seriMan.Read(node, notNullableOverride: true); Assert.That(deserialized, Is.EqualTo(value)); // Repeat test with enums in a data definitions. var data = new TestData { Value = TestEnum.Cc, - Sequence = new() {TestEnum.Dd, TestEnum.Aa} + Sequence = [TestEnum.Dd, TestEnum.Aa] }; - node = seriMan.WriteValue(data, notNullableOverride:true); + node = seriMan.WriteValue(data, notNullableOverride: true); errors = seriMan.ValidateNode(node).GetErrors(); Assert.That(errors.Any(), Is.False); - var deserializedData = seriMan.Read(node, notNullableOverride:false); + var deserializedData = seriMan.Read(node, notNullableOverride: false); Assert.That(deserializedData.Value, Is.EqualTo(data.Value)); Assert.That(deserializedData.Sequence.Count, Is.EqualTo(data.Sequence.Count)); @@ -60,7 +60,7 @@ public async Task SerializeGenericEnums() Enum genericValue = TestEnum.Bb; TestEnum typedValue = TestEnum.Bb; - var genericNode = seriMan.WriteValue(genericValue, notNullableOverride:true); + var genericNode = seriMan.WriteValue(genericValue, notNullableOverride: true); var typedNode = seriMan.WriteValue(typedValue); Assert.That(seriMan.ValidateNode(genericNode).GetErrors().Any(), Is.False); @@ -76,7 +76,7 @@ private enum TestEnum : byte { Aa, Bb, Cc, Dd } [DataDefinition] private sealed partial class TestData { - [DataField("value")] public Enum Value = default!; - [DataField("sequence")] public List Sequence = default!; + [DataField] public Enum Value = default!; + [DataField] public List Sequence = default!; } } diff --git a/Content.IntegrationTests/Tests/ShuttleTest.cs b/Content.IntegrationTests/Tests/ShuttleTest.cs index fb786373a5a..da5b82d91e7 100644 --- a/Content.IntegrationTests/Tests/ShuttleTest.cs +++ b/Content.IntegrationTests/Tests/ShuttleTest.cs @@ -2,7 +2,6 @@ using Content.Server.Shuttles.Components; using Robust.Shared.GameObjects; using Robust.Shared.Map; -using Robust.Shared.Maths; using Robust.Shared.Physics; using Robust.Shared.Physics.Components; using Robust.Shared.Physics.Systems; @@ -23,33 +22,33 @@ public async Task Test() var entManager = server.ResolveDependency(); var physicsSystem = entManager.System(); - EntityUid gridEnt = default; PhysicsComponent gridPhys = null; + var map = await pair.CreateTestMap(); + await server.WaitAssertion(() => { - var mapId = mapMan.CreateMap(); - var grid = mapMan.CreateGridEntity(mapId); - gridEnt = grid.Owner; + var mapId = map.MapId; + var grid = map.Grid; Assert.Multiple(() => { - Assert.That(entManager.HasComponent(gridEnt)); - Assert.That(entManager.TryGetComponent(gridEnt, out gridPhys)); + Assert.That(entManager.HasComponent(grid)); + Assert.That(entManager.TryGetComponent(grid, out gridPhys)); }); Assert.Multiple(() => { Assert.That(gridPhys.BodyType, Is.EqualTo(BodyType.Dynamic)); - Assert.That(entManager.GetComponent(gridEnt).LocalPosition, Is.EqualTo(Vector2.Zero)); + Assert.That(entManager.GetComponent(grid).LocalPosition, Is.EqualTo(Vector2.Zero)); }); - physicsSystem.ApplyLinearImpulse(gridEnt, Vector2.One, body: gridPhys); + physicsSystem.ApplyLinearImpulse(grid, Vector2.One, body: gridPhys); }); await server.WaitRunTicks(1); await server.WaitAssertion(() => { - Assert.That(entManager.GetComponent(gridEnt).LocalPosition, Is.Not.EqualTo(Vector2.Zero)); + Assert.That(entManager.GetComponent(map.Grid).LocalPosition, Is.Not.EqualTo(Vector2.Zero)); }); await pair.CleanReturnAsync(); } diff --git a/Content.IntegrationTests/Tests/Sprite/ItemSpriteTest.cs b/Content.IntegrationTests/Tests/Sprite/ItemSpriteTest.cs index 1762c4213c4..bf75188f029 100644 --- a/Content.IntegrationTests/Tests/Sprite/ItemSpriteTest.cs +++ b/Content.IntegrationTests/Tests/Sprite/ItemSpriteTest.cs @@ -19,12 +19,12 @@ namespace Content.IntegrationTests.Tests.Sprite; /// - Shouldn't have an item component /// - Is missing the required sprite information. /// If none of the abveo are true, it might need to be added to the list of ignored components, see -/// +/// /// [TestFixture] public sealed class PrototypeSaveTest { - private static HashSet _ignored = new() + private static readonly HashSet Ignored = new() { // The only prototypes that should get ignored are those that REQUIRE setup to get a sprite. At that point it is // the responsibility of the spawner to ensure that a valid sprite is set. @@ -34,13 +34,13 @@ public sealed class PrototypeSaveTest [Test] public async Task AllItemsHaveSpritesTest() { - var settings = new PoolSettings() {Connected = true}; // client needs to be in-game + var settings = new PoolSettings() { Connected = true }; // client needs to be in-game await using var pair = await PoolManager.GetServerClient(settings); - List badPrototypes = new(); + List badPrototypes = []; await pair.Client.WaitPost(() => { - foreach (var proto in pair.GetPrototypesWithComponent(_ignored)) + foreach (var proto in pair.GetPrototypesWithComponent(Ignored)) { var dummy = pair.Client.EntMan.Spawn(proto.ID); pair.Client.EntMan.RunMapInit(dummy, pair.Client.MetaData(dummy)); diff --git a/Content.IntegrationTests/Tests/Minds/JobTests.cs b/Content.IntegrationTests/Tests/Station/JobTests.cs similarity index 100% rename from Content.IntegrationTests/Tests/Minds/JobTests.cs rename to Content.IntegrationTests/Tests/Station/JobTests.cs diff --git a/Content.IntegrationTests/Tests/Toolshed/ToolshedTest.cs b/Content.IntegrationTests/Tests/Toolshed/ToolshedTest.cs index dd68ff1ccf1..7de81fb3dc2 100644 --- a/Content.IntegrationTests/Tests/Toolshed/ToolshedTest.cs +++ b/Content.IntegrationTests/Tests/Toolshed/ToolshedTest.cs @@ -36,16 +36,18 @@ public async Task TearDownInternal() await TearDown(); } - protected virtual async Task TearDown() + protected virtual Task TearDown() { Assert.That(_expectedErrors, Is.Empty); ClearErrors(); + + return Task.CompletedTask; } [SetUp] public virtual async Task Setup() { - Pair = await PoolManager.GetServerClient(new PoolSettings {Connected = Connected}); + Pair = await PoolManager.GetServerClient(new PoolSettings { Connected = Connected }); Server = Pair.Server; if (Connected) @@ -142,7 +144,7 @@ public void ReportError(IConError err) ); } - done: + done: _errors.Add(err); } diff --git a/Content.IntegrationTests/Tests/VendingMachineRestockTest.cs b/Content.IntegrationTests/Tests/VendingMachineRestockTest.cs index 3cceaefbdc9..e067a27854f 100644 --- a/Content.IntegrationTests/Tests/VendingMachineRestockTest.cs +++ b/Content.IntegrationTests/Tests/VendingMachineRestockTest.cs @@ -111,6 +111,7 @@ public async Task TestAllRestocksAreAvailableToBuy() await server.WaitIdleAsync(); var prototypeManager = server.ResolveDependency(); + var compFact = server.ResolveDependency(); await server.WaitAssertion(() => { @@ -133,7 +134,7 @@ await server.WaitAssertion(() => // Collect all the prototypes with StorageFills referencing those entities. foreach (var proto in prototypeManager.EnumeratePrototypes()) { - if (!proto.TryGetComponent(out var storage)) + if (!proto.TryGetComponent(out var storage, compFact)) continue; List restockStore = new(); From 8a38f3b8c68895b48cb21a3fc23174ba8db91448 Mon Sep 17 00:00:00 2001 From: Plykiya <58439124+Plykiya@users.noreply.github.com> Date: Tue, 2 Jul 2024 17:01:59 -0700 Subject: [PATCH 029/765] Thieving glove pickups actually stealthy (#29665) Co-authored-by: plykiya --- Content.Server/Strip/StrippableSystem.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Content.Server/Strip/StrippableSystem.cs b/Content.Server/Strip/StrippableSystem.cs index ded9eab3eb2..194df7b3d07 100644 --- a/Content.Server/Strip/StrippableSystem.cs +++ b/Content.Server/Strip/StrippableSystem.cs @@ -351,7 +351,7 @@ private void StripRemoveInventory( RaiseLocalEvent(item, new DroppedEvent(user), true); // Gas tank internals etc. - _handsSystem.PickupOrDrop(user, item, animateUser: stealth, animate: stealth); + _handsSystem.PickupOrDrop(user, item, animateUser: stealth, animate: !stealth); _adminLogger.Add(LogType.Stripping, LogImpact.Medium, $"{ToPrettyString(user):actor} has stripped the item {ToPrettyString(item):item} from {ToPrettyString(target):target}'s {slot} slot"); } @@ -450,7 +450,7 @@ private void StripInsertHand( return; _handsSystem.TryDrop(user, checkActionBlocker: false, handsComp: user.Comp); - _handsSystem.TryPickup(target, held, handName, checkActionBlocker: false, animateUser: stealth, animate: stealth, handsComp: target.Comp); + _handsSystem.TryPickup(target, held, handName, checkActionBlocker: false, animateUser: stealth, animate: !stealth, handsComp: target.Comp); _adminLogger.Add(LogType.Stripping, LogImpact.Medium, $"{ToPrettyString(user):actor} has placed the item {ToPrettyString(held):item} in {ToPrettyString(target):target}'s hands"); // Hand update will trigger strippable update. @@ -550,7 +550,7 @@ private void StripRemoveHand( return; _handsSystem.TryDrop(target, item, checkActionBlocker: false, handsComp: target.Comp); - _handsSystem.PickupOrDrop(user, item, animateUser: stealth, animate: stealth, handsComp: user.Comp); + _handsSystem.PickupOrDrop(user, item, animateUser: stealth, animate: !stealth, handsComp: user.Comp); _adminLogger.Add(LogType.Stripping, LogImpact.Medium, $"{ToPrettyString(user):actor} has stripped the item {ToPrettyString(item):item} from {ToPrettyString(target):target}'s hands"); // Hand update will trigger strippable update. From 14728d9d688f0d802b8c60260ead11248577a1bb Mon Sep 17 00:00:00 2001 From: PJBot Date: Wed, 3 Jul 2024 00:03:05 +0000 Subject: [PATCH 030/765] Automatic changelog update --- Resources/Changelog/Changelog.yml | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 45ebc2d5963..97cd86e2180 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,11 +1,4 @@ Entries: -- author: Dutch-VanDerLinde - changes: - - message: Senior role ID cards now function properly. - type: Fix - id: 6361 - time: '2024-04-16T20:17:06.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/27017 - author: Dutch-VanDerLinde changes: - message: Most job loadouts now have winter clothing available. @@ -3823,3 +3816,12 @@ id: 6860 time: '2024-07-02T15:28:49.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/29667 +- author: Plykiya + changes: + - message: You now see pickup animations when stripping objects off of people. + type: Fix + - message: Thieving gloves no longer have a pickup animation when stripping people. + type: Fix + id: 6861 + time: '2024-07-03T00:01:59.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/29665 From 56575958ce2148b7280169c40503ffd530bb226f Mon Sep 17 00:00:00 2001 From: nikthechampiongr <32041239+nikthechampiongr@users.noreply.github.com> Date: Wed, 3 Jul 2024 00:31:38 +0000 Subject: [PATCH 031/765] Nerf the elite hardsuit (#29429) --- Resources/Prototypes/Catalog/uplink_catalog.yml | 2 +- .../Prototypes/Entities/Clothing/OuterClothing/hardsuits.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Resources/Prototypes/Catalog/uplink_catalog.yml b/Resources/Prototypes/Catalog/uplink_catalog.yml index a29b5d18c62..59c72e8cc16 100644 --- a/Resources/Prototypes/Catalog/uplink_catalog.yml +++ b/Resources/Prototypes/Catalog/uplink_catalog.yml @@ -1315,7 +1315,7 @@ icon: { sprite: /Textures/Clothing/OuterClothing/Hardsuits/syndieelite.rsi, state: icon } productEntity: ClothingBackpackDuffelSyndicateEliteHardsuitBundle cost: - Telecrystal: 10 + Telecrystal: 12 categories: - UplinkWearables diff --git a/Resources/Prototypes/Entities/Clothing/OuterClothing/hardsuits.yml b/Resources/Prototypes/Entities/Clothing/OuterClothing/hardsuits.yml index c79ea484d7b..baa933768ac 100644 --- a/Resources/Prototypes/Entities/Clothing/OuterClothing/hardsuits.yml +++ b/Resources/Prototypes/Entities/Clothing/OuterClothing/hardsuits.yml @@ -566,7 +566,7 @@ size: Huge - type: ClothingSpeedModifier walkModifier: 1.0 - sprintModifier: 1.0 + sprintModifier: 0.9 - type: HeldSpeedModifier - type: ToggleableClothing clothingPrototype: ClothingHeadHelmetHardsuitSyndieElite From 6386f79cf8cacd3aa6ef8c0163e6a7348e12a39b Mon Sep 17 00:00:00 2001 From: PJBot Date: Wed, 3 Jul 2024 00:32:44 +0000 Subject: [PATCH 032/765] Automatic changelog update --- Resources/Changelog/Changelog.yml | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 97cd86e2180..027070103ab 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,11 +1,4 @@ Entries: -- author: Dutch-VanDerLinde - changes: - - message: Most job loadouts now have winter clothing available. - type: Tweak - id: 6362 - time: '2024-04-17T02:49:53.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/27022 - author: metalgearsloth changes: - message: 'Fix the following in lobby: ShowClothes button not working, Skin Color @@ -3825,3 +3818,12 @@ id: 6861 time: '2024-07-03T00:01:59.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/29665 +- author: nikthechampiongr + changes: + - message: The Elite Syndicate hardsuit is now slightly slower. + type: Tweak + - message: The Elite Syndicate hardsuit now costs 12 Telecrystals. + type: Tweak + id: 6862 + time: '2024-07-03T00:31:39.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/29429 From a15113e132c3333139de6d3710af267e8bd64825 Mon Sep 17 00:00:00 2001 From: DrSmugleaf <10968691+DrSmugleaf@users.noreply.github.com> Date: Tue, 2 Jul 2024 19:51:16 -0700 Subject: [PATCH 033/765] Fix camera recoil system overriding all other eye offsets (#29146) --- Content.Shared/Camera/GetEyeOffsetEvent.cs | 19 +++++++++ .../Camera/SharedCameraRecoilSystem.cs | 42 ++++++++++++++----- .../Systems/SharedContentEyeSystem.cs | 8 ++++ 3 files changed, 59 insertions(+), 10 deletions(-) create mode 100644 Content.Shared/Camera/GetEyeOffsetEvent.cs diff --git a/Content.Shared/Camera/GetEyeOffsetEvent.cs b/Content.Shared/Camera/GetEyeOffsetEvent.cs new file mode 100644 index 00000000000..de9c7c9e178 --- /dev/null +++ b/Content.Shared/Camera/GetEyeOffsetEvent.cs @@ -0,0 +1,19 @@ +using System.Numerics; +using Content.Shared.Movement.Systems; + +namespace Content.Shared.Camera; + +/// +/// Raised directed by-ref when is called. +/// Should be subscribed to by any systems that want to modify an entity's eye offset, +/// so that they do not override each other. +/// +/// +/// The total offset to apply. +/// +/// +/// Note that in most cases should be incremented or decremented by subscribers, not set. +/// Otherwise, any offsets applied by previous subscribing systems will be overridden. +/// +[ByRefEvent] +public record struct GetEyeOffsetEvent(Vector2 Offset); diff --git a/Content.Shared/Camera/SharedCameraRecoilSystem.cs b/Content.Shared/Camera/SharedCameraRecoilSystem.cs index 3507bf10233..d42fe9dceee 100644 --- a/Content.Shared/Camera/SharedCameraRecoilSystem.cs +++ b/Content.Shared/Camera/SharedCameraRecoilSystem.cs @@ -1,6 +1,7 @@ using System.Numerics; +using Content.Shared.Movement.Systems; using JetBrains.Annotations; -using Robust.Shared.Player; +using Robust.Shared.Network; using Robust.Shared.Serialization; namespace Content.Shared.Camera; @@ -28,7 +29,18 @@ public abstract class SharedCameraRecoilSystem : EntitySystem /// protected const float KickMagnitudeMax = 1f; - [Dependency] private readonly SharedEyeSystem _eye = default!; + [Dependency] private readonly SharedContentEyeSystem _eye = default!; + [Dependency] private readonly INetManager _net = default!; + + public override void Initialize() + { + SubscribeLocalEvent(OnCameraRecoilGetEyeOffset); + } + + private void OnCameraRecoilGetEyeOffset(Entity ent, ref GetEyeOffsetEvent args) + { + args.Offset += ent.Comp.BaseOffset + ent.Comp.CurrentKick; + } /// /// Applies explosion/recoil/etc kickback to the view of the entity. @@ -39,10 +51,8 @@ public abstract class SharedCameraRecoilSystem : EntitySystem /// public abstract void KickCamera(EntityUid euid, Vector2 kickback, CameraRecoilComponent? component = null); - public override void FrameUpdate(float frameTime) + private void UpdateEyes(float frameTime) { - base.FrameUpdate(frameTime); - var query = AllEntityQuery(); while (query.MoveNext(out var uid, out var eye, out var recoil)) @@ -51,7 +61,7 @@ public override void FrameUpdate(float frameTime) if (magnitude <= 0.005f) { recoil.CurrentKick = Vector2.Zero; - _eye.SetOffset(uid, recoil.BaseOffset + recoil.CurrentKick, eye); + _eye.UpdateEyeOffset((uid, eye)); } else // Continually restore camera to 0. { @@ -60,16 +70,28 @@ public override void FrameUpdate(float frameTime) var restoreRate = MathHelper.Lerp(RestoreRateMin, RestoreRateMax, Math.Min(1, recoil.LastKickTime / RestoreRateRamp)); var restore = normalized * restoreRate * frameTime; var (x, y) = recoil.CurrentKick - restore; - if (Math.Sign(x) != Math.Sign(recoil.CurrentKick.X)) x = 0; + if (Math.Sign(x) != Math.Sign(recoil.CurrentKick.X)) + x = 0; - if (Math.Sign(y) != Math.Sign(recoil.CurrentKick.Y)) y = 0; + if (Math.Sign(y) != Math.Sign(recoil.CurrentKick.Y)) + y = 0; recoil.CurrentKick = new Vector2(x, y); - - _eye.SetOffset(uid, recoil.BaseOffset + recoil.CurrentKick, eye); + _eye.UpdateEyeOffset((uid, eye)); } } } + + public override void Update(float frameTime) + { + if (_net.IsServer) + UpdateEyes(frameTime); + } + + public override void FrameUpdate(float frameTime) + { + UpdateEyes(frameTime); + } } [Serializable] diff --git a/Content.Shared/Movement/Systems/SharedContentEyeSystem.cs b/Content.Shared/Movement/Systems/SharedContentEyeSystem.cs index 207f14a258a..0c4304d3748 100644 --- a/Content.Shared/Movement/Systems/SharedContentEyeSystem.cs +++ b/Content.Shared/Movement/Systems/SharedContentEyeSystem.cs @@ -1,6 +1,7 @@ using System.Numerics; using Content.Shared.Administration; using Content.Shared.Administration.Managers; +using Content.Shared.Camera; using Content.Shared.Ghost; using Content.Shared.Input; using Content.Shared.Movement.Components; @@ -128,6 +129,13 @@ public void SetMaxZoom(EntityUid uid, Vector2 value, ContentEyeComponent? compon Dirty(uid, component); } + public void UpdateEyeOffset(Entity eye) + { + var ev = new GetEyeOffsetEvent(); + RaiseLocalEvent(eye, ref ev); + _eye.SetOffset(eye, ev.Offset, eye); + } + /// /// Sendable from client to server to request a target zoom. /// From db168beca15a16a15bf63aa840d87d60661f4731 Mon Sep 17 00:00:00 2001 From: DrSmugleaf <10968691+DrSmugleaf@users.noreply.github.com> Date: Tue, 2 Jul 2024 22:16:18 -0700 Subject: [PATCH 034/765] Make camera recoil system only refresh offset when its values change (#29673) --- Content.Shared/Camera/CameraRecoilComponent.cs | 1 + Content.Shared/Camera/SharedCameraRecoilSystem.cs | 13 +++++++++---- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/Content.Shared/Camera/CameraRecoilComponent.cs b/Content.Shared/Camera/CameraRecoilComponent.cs index 5d615f87bef..8b8b290845e 100644 --- a/Content.Shared/Camera/CameraRecoilComponent.cs +++ b/Content.Shared/Camera/CameraRecoilComponent.cs @@ -8,6 +8,7 @@ namespace Content.Shared.Camera; public sealed partial class CameraRecoilComponent : Component { public Vector2 CurrentKick { get; set; } + public Vector2 LastKick { get; set; } public float LastKickTime { get; set; } /// diff --git a/Content.Shared/Camera/SharedCameraRecoilSystem.cs b/Content.Shared/Camera/SharedCameraRecoilSystem.cs index d42fe9dceee..5ba97dabe2c 100644 --- a/Content.Shared/Camera/SharedCameraRecoilSystem.cs +++ b/Content.Shared/Camera/SharedCameraRecoilSystem.cs @@ -1,5 +1,4 @@ using System.Numerics; -using Content.Shared.Movement.Systems; using JetBrains.Annotations; using Robust.Shared.Network; using Robust.Shared.Serialization; @@ -29,7 +28,7 @@ public abstract class SharedCameraRecoilSystem : EntitySystem /// protected const float KickMagnitudeMax = 1f; - [Dependency] private readonly SharedContentEyeSystem _eye = default!; + [Dependency] private readonly SharedEyeSystem _eye = default!; [Dependency] private readonly INetManager _net = default!; public override void Initialize() @@ -61,7 +60,6 @@ private void UpdateEyes(float frameTime) if (magnitude <= 0.005f) { recoil.CurrentKick = Vector2.Zero; - _eye.UpdateEyeOffset((uid, eye)); } else // Continually restore camera to 0. { @@ -77,8 +75,15 @@ private void UpdateEyes(float frameTime) y = 0; recoil.CurrentKick = new Vector2(x, y); - _eye.UpdateEyeOffset((uid, eye)); } + + if (recoil.CurrentKick == recoil.LastKick) + continue; + + recoil.LastKick = recoil.CurrentKick; + var ev = new GetEyeOffsetEvent(); + RaiseLocalEvent(uid, ref ev); + _eye.SetOffset(uid, ev.Offset, eye); } } From ca6ffc1ddec8b8baa5982ab32d37113ad48b0e73 Mon Sep 17 00:00:00 2001 From: eoineoineoin Date: Wed, 3 Jul 2024 06:27:33 +0100 Subject: [PATCH 035/765] Make artifact analyzer obey laws of physics (#28117) --- Resources/Maps/Test/dev_map.yml | 1 - .../Entities/Structures/Machines/artifact_analyzer.yml | 9 ++++++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/Resources/Maps/Test/dev_map.yml b/Resources/Maps/Test/dev_map.yml index 910a059ee72..0cbc93142fc 100644 --- a/Resources/Maps/Test/dev_map.yml +++ b/Resources/Maps/Test/dev_map.yml @@ -4228,7 +4228,6 @@ entities: - uid: 1078 components: - type: Transform - rot: 1.5707963267948966 rad pos: 12.5,24.5 parent: 179 - type: DeviceLinkSink diff --git a/Resources/Prototypes/Entities/Structures/Machines/artifact_analyzer.yml b/Resources/Prototypes/Entities/Structures/Machines/artifact_analyzer.yml index 9c878c7e7c5..741e0a39711 100644 --- a/Resources/Prototypes/Entities/Structures/Machines/artifact_analyzer.yml +++ b/Resources/Prototypes/Entities/Structures/Machines/artifact_analyzer.yml @@ -25,6 +25,14 @@ - type: Fixtures fixtures: fix1: + shape: + !type:PhysShapeAabb + bounds: "-0.35,-0.35,0.35,0.35" + mask: + - Impassable + - HighImpassable + - MidImpassable + fix2: shape: !type:PhysShapeAabb bounds: "-0.35,-0.35,0.35,0.35" @@ -39,7 +47,6 @@ hard: False - type: Transform anchored: true - noRot: false - type: ApcPowerReceiver powerLoad: 12000 needsPower: false #only turns on when scanning From 7ca7aacf2775b3f885a9e867783d4208f4b78151 Mon Sep 17 00:00:00 2001 From: PJBot Date: Wed, 3 Jul 2024 05:28:41 +0000 Subject: [PATCH 036/765] Automatic changelog update --- Resources/Changelog/Changelog.yml | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 027070103ab..e1a72faa15e 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,12 +1,4 @@ Entries: -- author: metalgearsloth - changes: - - message: 'Fix the following in lobby: ShowClothes button not working, Skin Color - not updating, Skin Color slider not updating upon closing and re-opening character.' - type: Fix - id: 6363 - time: '2024-04-17T02:54:54.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/27033 - author: MACMAN2003 changes: - message: Nuclear operatives now only need 20 players to be readied up again instead @@ -3827,3 +3819,10 @@ id: 6862 time: '2024-07-03T00:31:39.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/29429 +- author: eoineoineoin + changes: + - message: Artifact Analyzer now collides with walls + type: Fix + id: 6863 + time: '2024-07-03T05:27:33.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/28117 From 3934fb96035b7910ebb44dda3c25c3655d2d3df6 Mon Sep 17 00:00:00 2001 From: Leon Friedrich <60421075+ElectroJr@users.noreply.github.com> Date: Wed, 3 Jul 2024 18:44:55 +1200 Subject: [PATCH 037/765] Allow `zoom` command to modify an eye's PVS range (#29245) Allow zoom command to modify an eye's PVS range Co-authored-by: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com> --- Content.Client/Commands/ZoomCommand.cs | 11 ++++++++-- .../Movement/Systems/ContentEyeSystem.cs | 10 ++++++++- .../Camera/CameraRecoilComponent.cs | 7 ++++++ .../Camera/SharedCameraRecoilSystem.cs | 4 ++-- .../Systems/SharedContentEyeSystem.cs | 22 ++++++++++++++++++- .../Locale/en-US/commands/zoom-command.ftl | 4 ++-- 6 files changed, 50 insertions(+), 8 deletions(-) diff --git a/Content.Client/Commands/ZoomCommand.cs b/Content.Client/Commands/ZoomCommand.cs index 2bdc85e1fee..c63eeea8369 100644 --- a/Content.Client/Commands/ZoomCommand.cs +++ b/Content.Client/Commands/ZoomCommand.cs @@ -20,7 +20,7 @@ public sealed class ZoomCommand : LocalizedCommands public override void Execute(IConsoleShell shell, string argStr, string[] args) { Vector2 zoom; - if (args.Length is not (1 or 2)) + if (args.Length is not (1 or 2 or 3)) { shell.WriteLine(Help); return; @@ -57,11 +57,18 @@ public override void Execute(IConsoleShell shell, string argStr, string[] args) } } + var scalePvs = true; + if (args.Length == 3 && !bool.TryParse(args[2], out scalePvs)) + { + shell.WriteError(LocalizationManager.GetString("cmd-parse-failure-bool", ("arg", args[2]))); + return; + } + var player = _playerManager.LocalSession?.AttachedEntity; if (_entityManager.TryGetComponent(player, out var content)) { - _entityManager.System().RequestZoom(player.Value, zoom, true, content); + _entityManager.System().RequestZoom(player.Value, zoom, true, scalePvs, content); return; } diff --git a/Content.Client/Movement/Systems/ContentEyeSystem.cs b/Content.Client/Movement/Systems/ContentEyeSystem.cs index 182ac92ae05..9fbd4b5c37d 100644 --- a/Content.Client/Movement/Systems/ContentEyeSystem.cs +++ b/Content.Client/Movement/Systems/ContentEyeSystem.cs @@ -9,7 +9,7 @@ public sealed class ContentEyeSystem : SharedContentEyeSystem { [Dependency] private readonly IPlayerManager _player = default!; - public void RequestZoom(EntityUid uid, Vector2 zoom, bool ignoreLimit, ContentEyeComponent? content = null) + public void RequestZoom(EntityUid uid, Vector2 zoom, bool ignoreLimit, bool scalePvs, ContentEyeComponent? content = null) { if (!Resolve(uid, ref content, false)) return; @@ -19,6 +19,14 @@ public void RequestZoom(EntityUid uid, Vector2 zoom, bool ignoreLimit, ContentEy TargetZoom = zoom, IgnoreLimit = ignoreLimit, }); + + if (scalePvs) + RequestPvsScale(Math.Max(zoom.X, zoom.Y)); + } + + public void RequestPvsScale(float scale) + { + RaiseNetworkEvent(new RequestPvsScaleEvent(scale)); } public void RequestToggleFov() diff --git a/Content.Shared/Camera/CameraRecoilComponent.cs b/Content.Shared/Camera/CameraRecoilComponent.cs index 8b8b290845e..2cbb6324086 100644 --- a/Content.Shared/Camera/CameraRecoilComponent.cs +++ b/Content.Shared/Camera/CameraRecoilComponent.cs @@ -7,12 +7,19 @@ namespace Content.Shared.Camera; [NetworkedComponent] public sealed partial class CameraRecoilComponent : Component { + [ViewVariables(VVAccess.ReadWrite)] public Vector2 CurrentKick { get; set; } + + [ViewVariables(VVAccess.ReadWrite)] public Vector2 LastKick { get; set; } + + [ViewVariables(VVAccess.ReadWrite)] public float LastKickTime { get; set; } /// /// Basically I needed a way to chain this effect for the attack lunge animation. Sorry! /// + /// + [ViewVariables(VVAccess.ReadWrite)] public Vector2 BaseOffset { get; set; } } diff --git a/Content.Shared/Camera/SharedCameraRecoilSystem.cs b/Content.Shared/Camera/SharedCameraRecoilSystem.cs index 5ba97dabe2c..a2ce0e77e20 100644 --- a/Content.Shared/Camera/SharedCameraRecoilSystem.cs +++ b/Content.Shared/Camera/SharedCameraRecoilSystem.cs @@ -52,9 +52,9 @@ private void OnCameraRecoilGetEyeOffset(Entity ent, ref G private void UpdateEyes(float frameTime) { - var query = AllEntityQuery(); + var query = AllEntityQuery(); - while (query.MoveNext(out var uid, out var eye, out var recoil)) + while (query.MoveNext(out var uid, out var recoil, out var eye)) { var magnitude = recoil.CurrentKick.Length(); if (magnitude <= 0.005f) diff --git a/Content.Shared/Movement/Systems/SharedContentEyeSystem.cs b/Content.Shared/Movement/Systems/SharedContentEyeSystem.cs index 0c4304d3748..faade44c858 100644 --- a/Content.Shared/Movement/Systems/SharedContentEyeSystem.cs +++ b/Content.Shared/Movement/Systems/SharedContentEyeSystem.cs @@ -18,6 +18,9 @@ public abstract class SharedContentEyeSystem : EntitySystem { [Dependency] private readonly ISharedAdminManager _admin = default!; + // Admin flags required to ignore normal eye restrictions. + public const AdminFlags EyeFlag = AdminFlags.Debug; + public const float ZoomMod = 1.5f; public static readonly Vector2 DefaultZoom = Vector2.One; public static readonly Vector2 MinZoom = DefaultZoom * (float)Math.Pow(ZoomMod, -3); @@ -29,6 +32,7 @@ public override void Initialize() base.Initialize(); SubscribeLocalEvent(OnContentEyeStartup); SubscribeAllEvent(OnContentZoomRequest); + SubscribeAllEvent(OnPvsScale); SubscribeAllEvent(OnRequestEye); CommandBinds.Builder @@ -84,12 +88,18 @@ public void SetZoom(EntityUid uid, Vector2 zoom, bool ignoreLimits = false, Cont private void OnContentZoomRequest(RequestTargetZoomEvent msg, EntitySessionEventArgs args) { - var ignoreLimit = msg.IgnoreLimit && _admin.HasAdminFlag(args.SenderSession, AdminFlags.Debug); + var ignoreLimit = msg.IgnoreLimit && _admin.HasAdminFlag(args.SenderSession, EyeFlag); if (TryComp(args.SenderSession.AttachedEntity, out var content)) SetZoom(args.SenderSession.AttachedEntity.Value, msg.TargetZoom, ignoreLimit, eye: content); } + private void OnPvsScale(RequestPvsScaleEvent ev, EntitySessionEventArgs args) + { + if (args.SenderSession.AttachedEntity is {} uid && _admin.HasAdminFlag(args.SenderSession, EyeFlag)) + _eye.SetPvsScale(uid, ev.Scale); + } + private void OnRequestEye(RequestEyeEvent msg, EntitySessionEventArgs args) { if (args.SenderSession.AttachedEntity is not { } player) @@ -116,6 +126,7 @@ private void OnContentEyeStartup(EntityUid uid, ContentEyeComponent component, C public void ResetZoom(EntityUid uid, ContentEyeComponent? component = null) { + _eye.SetPvsScale(uid, 1); SetZoom(uid, DefaultZoom, eye: component); } @@ -146,6 +157,15 @@ public sealed class RequestTargetZoomEvent : EntityEventArgs public bool IgnoreLimit; } + /// + /// Client->Server request for new PVS scale. + /// + [Serializable, NetSerializable] + public sealed class RequestPvsScaleEvent(float scale) : EntityEventArgs + { + public float Scale = scale; + } + /// /// Sendable from client to server to request changing fov. /// diff --git a/Resources/Locale/en-US/commands/zoom-command.ftl b/Resources/Locale/en-US/commands/zoom-command.ftl index 0132f222405..64bf6bca7af 100644 --- a/Resources/Locale/en-US/commands/zoom-command.ftl +++ b/Resources/Locale/en-US/commands/zoom-command.ftl @@ -1,3 +1,3 @@ -cmd-zoom-desc = Sets the zoom of the main eye. -cmd-zoom-help = zoom ( | ) +cmd-zoom-desc = Sets the zoom of the main eye. Optionally also changes the eye's PVS range. +cmd-zoom-help = zoom ( | [bool]) cmd-zoom-error = scale has to be greater than 0 From 3b3e8d77fd2f5f472b1b45affd5de2768317a5a2 Mon Sep 17 00:00:00 2001 From: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com> Date: Wed, 3 Jul 2024 22:23:11 +1000 Subject: [PATCH 038/765] VGRoid support (#27659) * Dungeon spawn support for grid spawns * Recursive dungeons working * Mask approach working * zack * More work * Fix recursive dungeons * Heap of work * weh * the cud * rar * Job * weh * weh * weh * Master merges * orch * weh * vgroid most of the work * Tweaks * Tweaks * weh * do do do do do do * Basic layout * Ore spawning working * Big breaking changes * Mob gen working * weh * Finalising * emo * More finalising * reverty * Reduce distance --- .../Pathfinding/PathfindingSystem.Breadth.cs | 123 ++ .../NPC/Pathfinding/PathfindingSystem.Line.cs | 74 + .../Pathfinding/PathfindingSystem.Simple.cs | 154 ++ .../Pathfinding/PathfindingSystem.Splines.cs | 180 +++ .../Pathfinding/PathfindingSystem.Widen.cs | 89 ++ .../NPC/Systems/NPCSteeringSystem.Context.cs | 15 + .../Procedural/DungeonJob.PostGen.cs | 1258 ----------------- .../Procedural/DungeonJob.PostGenBiome.cs | 138 -- Content.Server/Procedural/DungeonJob.cs | 192 --- .../DungeonJob/DungeonJob.DunGenExterior.cs | 58 + .../DungeonJob/DungeonJob.DunGenFill.cs | 50 + .../DungeonJob.DunGenNoise.cs} | 53 +- .../DungeonJob.DunGenNoiseDistance.cs | 112 ++ .../DungeonJob.DunGenPrefab.cs} | 85 +- .../DungeonJob.DunGenReplaceTile.cs | 60 + .../DungeonJob/DungeonJob.MobDunGen.cs | 58 + .../DungeonJob/DungeonJob.OreDunGen.cs | 149 ++ .../DungeonJob/DungeonJob.PostGen.cs | 134 ++ .../DungeonJob.PostGenAutoCabling.cs | 162 +++ .../DungeonJob/DungeonJob.PostGenBiome.cs | 67 + .../DungeonJob.PostGenBiomeMarkerLayer.cs | 105 ++ .../DungeonJob.PostGenBoundaryWall.cs | 113 ++ .../DungeonJob.PostGenCornerClutter.cs | 56 + .../DungeonJob/DungeonJob.PostGenCorridor.cs | 116 ++ .../DungeonJob.PostGenCorridorClutter.cs} | 9 +- ...DungeonJob.PostGenCorridorDecalSkirting.cs | 124 ++ .../DungeonJob.PostGenDungeonConnector.cs | 6 + .../DungeonJob.PostGenDungeonEntrance.cs | 114 ++ .../DungeonJob.PostGenEntranceFlank.cs | 58 + .../DungeonJob.PostGenExternalWindow.cs | 138 ++ .../DungeonJob.PostGenInternalWindow.cs | 108 ++ .../DungeonJob/DungeonJob.PostGenJunction.cs | 144 ++ .../DungeonJob.PostGenMiddleConnection.cs | 147 ++ .../DungeonJob.PostGenRoomEntrance.cs | 48 + ...ungeonJob.PostGenSplineDungeonConnector.cs | 147 ++ .../DungeonJob/DungeonJob.PostGenWallMount.cs | 56 + .../DungeonJob.PostGenWorm.cs} | 22 +- .../Procedural/DungeonJob/DungeonJob.cs | 309 ++++ .../Procedural/DungeonSystem.Commands.cs | 2 + .../Procedural/DungeonSystem.Rooms.cs | 19 +- Content.Server/Procedural/DungeonSystem.cs | 13 +- Content.Server/Procedural/RoomFillSystem.cs | 1 + .../Salvage/SpawnSalvageMissionJob.cs | 4 +- .../Shuttles/Components/GridSpawnComponent.cs | 81 +- .../Systems/ShuttleSystem.GridFill.cs | 159 ++- .../Shuttles/Systems/ShuttleSystem.cs | 8 +- .../Components/EntityRemapComponent.cs | 13 + .../DunGenEuclideanSquaredDistance.cs | 10 + .../Procedural/Distance/DunGenSquareBump.cs | 10 + .../Procedural/Distance/IDunGenDistance.cs | 14 + Content.Shared/Procedural/Dungeon.cs | 66 +- .../Procedural/DungeonConfigPrototype.cs | 46 +- Content.Shared/Procedural/DungeonData.cs | 105 ++ .../DungeonGenerators/ExteriorDunGen.cs | 13 + .../DungeonGenerators/FillGridDunGen.cs | 10 + .../Procedural/DungeonGenerators/IDunGen.cs | 7 - .../DungeonGenerators/NoiseDistanceDunGen.cs | 18 + .../DungeonGenerators/NoiseDunGen.cs | 7 +- .../DungeonGenerators/PrefabDunGen.cs | 28 +- .../DungeonGenerators/PrototypeDunGen.cs | 13 + .../DungeonGenerators/ReplaceTileDunGen.cs | 30 + .../Procedural/DungeonLayers/MobsDunGen.cs | 21 + .../Procedural/DungeonLayers/OreDunGen.cs | 42 + Content.Shared/Procedural/DungeonRoom.cs | 1 + Content.Shared/Procedural/IDunGenLayer.cs | 7 + .../PostGeneration/AutoCablingDunGen.cs | 10 + .../PostGeneration/AutoCablingPostGen.cs | 12 - .../{BiomePostGen.cs => BiomeDunGen.cs} | 3 +- ...erPostGen.cs => BiomeMarkerLayerDunGen.cs} | 4 +- .../PostGeneration/BoundaryWallDunGen.cs | 23 + .../PostGeneration/BoundaryWallPostGen.cs | 33 - .../PostGeneration/CornerClutterDunGen.cs | 14 + .../PostGeneration/CornerClutterPostGen.cs | 18 - ...terPostGen.cs => CorridorClutterDunGen.cs} | 2 +- ...tGen.cs => CorridorDecalSkirtingDunGen.cs} | 14 +- .../{CorridorPostGen.cs => CorridorDunGen.cs} | 12 +- .../PostGeneration/DungeonEntranceDunGen.cs | 18 + .../PostGeneration/DungeonEntrancePostGen.cs | 28 - .../PostGeneration/EntranceFlankDunGen.cs | 11 + .../PostGeneration/EntranceFlankPostGen.cs | 16 - .../PostGeneration/ExternalWindowDunGen.cs | 11 + .../PostGeneration/ExternalWindowPostGen.cs | 22 - .../Procedural/PostGeneration/IPostDunGen.cs | 10 - .../PostGeneration/InternalWindowDunGen.cs | 11 + .../PostGeneration/InternalWindowPostGen.cs | 22 - .../PostGeneration/JunctionDunGen.cs | 18 + .../PostGeneration/JunctionPostGen.cs | 28 - .../PostGeneration/MiddleConnectionDunGen.cs | 19 + .../PostGeneration/MiddleConnectionPostGen.cs | 39 - .../PostGeneration/RoomEntranceDunGen.cs | 11 + .../PostGeneration/RoomEntrancePostGen.cs | 22 - .../SplineDungeonConnectorDunGen.cs | 19 + .../PostGeneration/WallMountDunGen.cs | 13 + .../PostGeneration/WallMountPostGen.cs | 23 - ...rridorPostGen.cs => WormCorridorDunGen.cs} | 9 +- .../Salvage/SharedSalvageSystem.Magnet.cs | 6 +- .../Shuttles/Systems/SharedShuttleSystem.cs | 2 +- Content.Shared/Storage/EntitySpawnEntry.cs | 13 + .../Prototypes/Entities/Stations/base.yml | 47 +- .../Entities/Structures/Walls/asteroid.yml | 342 +++-- .../Prototypes/Procedural/Magnet/asteroid.yml | 71 +- .../Prototypes/Procedural/dungeon_configs.yml | 591 ++++---- Resources/Prototypes/Procedural/vgroid.yml | 191 +++ 103 files changed, 4910 insertions(+), 2627 deletions(-) create mode 100644 Content.Server/NPC/Pathfinding/PathfindingSystem.Breadth.cs create mode 100644 Content.Server/NPC/Pathfinding/PathfindingSystem.Line.cs create mode 100644 Content.Server/NPC/Pathfinding/PathfindingSystem.Simple.cs create mode 100644 Content.Server/NPC/Pathfinding/PathfindingSystem.Splines.cs create mode 100644 Content.Server/NPC/Pathfinding/PathfindingSystem.Widen.cs delete mode 100644 Content.Server/Procedural/DungeonJob.PostGen.cs delete mode 100644 Content.Server/Procedural/DungeonJob.PostGenBiome.cs delete mode 100644 Content.Server/Procedural/DungeonJob.cs create mode 100644 Content.Server/Procedural/DungeonJob/DungeonJob.DunGenExterior.cs create mode 100644 Content.Server/Procedural/DungeonJob/DungeonJob.DunGenFill.cs rename Content.Server/Procedural/{DungeonJob.NoiseDunGen.cs => DungeonJob/DungeonJob.DunGenNoise.cs} (73%) create mode 100644 Content.Server/Procedural/DungeonJob/DungeonJob.DunGenNoiseDistance.cs rename Content.Server/Procedural/{DungeonJob.PrefabDunGen.cs => DungeonJob/DungeonJob.DunGenPrefab.cs} (82%) create mode 100644 Content.Server/Procedural/DungeonJob/DungeonJob.DunGenReplaceTile.cs create mode 100644 Content.Server/Procedural/DungeonJob/DungeonJob.MobDunGen.cs create mode 100644 Content.Server/Procedural/DungeonJob/DungeonJob.OreDunGen.cs create mode 100644 Content.Server/Procedural/DungeonJob/DungeonJob.PostGen.cs create mode 100644 Content.Server/Procedural/DungeonJob/DungeonJob.PostGenAutoCabling.cs create mode 100644 Content.Server/Procedural/DungeonJob/DungeonJob.PostGenBiome.cs create mode 100644 Content.Server/Procedural/DungeonJob/DungeonJob.PostGenBiomeMarkerLayer.cs create mode 100644 Content.Server/Procedural/DungeonJob/DungeonJob.PostGenBoundaryWall.cs create mode 100644 Content.Server/Procedural/DungeonJob/DungeonJob.PostGenCornerClutter.cs create mode 100644 Content.Server/Procedural/DungeonJob/DungeonJob.PostGenCorridor.cs rename Content.Server/Procedural/{DungeonJob.CorridorClutterPost.cs => DungeonJob/DungeonJob.PostGenCorridorClutter.cs} (83%) create mode 100644 Content.Server/Procedural/DungeonJob/DungeonJob.PostGenCorridorDecalSkirting.cs create mode 100644 Content.Server/Procedural/DungeonJob/DungeonJob.PostGenDungeonConnector.cs create mode 100644 Content.Server/Procedural/DungeonJob/DungeonJob.PostGenDungeonEntrance.cs create mode 100644 Content.Server/Procedural/DungeonJob/DungeonJob.PostGenEntranceFlank.cs create mode 100644 Content.Server/Procedural/DungeonJob/DungeonJob.PostGenExternalWindow.cs create mode 100644 Content.Server/Procedural/DungeonJob/DungeonJob.PostGenInternalWindow.cs create mode 100644 Content.Server/Procedural/DungeonJob/DungeonJob.PostGenJunction.cs create mode 100644 Content.Server/Procedural/DungeonJob/DungeonJob.PostGenMiddleConnection.cs create mode 100644 Content.Server/Procedural/DungeonJob/DungeonJob.PostGenRoomEntrance.cs create mode 100644 Content.Server/Procedural/DungeonJob/DungeonJob.PostGenSplineDungeonConnector.cs create mode 100644 Content.Server/Procedural/DungeonJob/DungeonJob.PostGenWallMount.cs rename Content.Server/Procedural/{DungeonJob.WormPost.cs => DungeonJob/DungeonJob.PostGenWorm.cs} (88%) create mode 100644 Content.Server/Procedural/DungeonJob/DungeonJob.cs create mode 100644 Content.Shared/Procedural/Components/EntityRemapComponent.cs create mode 100644 Content.Shared/Procedural/Distance/DunGenEuclideanSquaredDistance.cs create mode 100644 Content.Shared/Procedural/Distance/DunGenSquareBump.cs create mode 100644 Content.Shared/Procedural/Distance/IDunGenDistance.cs create mode 100644 Content.Shared/Procedural/DungeonData.cs create mode 100644 Content.Shared/Procedural/DungeonGenerators/ExteriorDunGen.cs create mode 100644 Content.Shared/Procedural/DungeonGenerators/FillGridDunGen.cs delete mode 100644 Content.Shared/Procedural/DungeonGenerators/IDunGen.cs create mode 100644 Content.Shared/Procedural/DungeonGenerators/NoiseDistanceDunGen.cs create mode 100644 Content.Shared/Procedural/DungeonGenerators/PrototypeDunGen.cs create mode 100644 Content.Shared/Procedural/DungeonGenerators/ReplaceTileDunGen.cs create mode 100644 Content.Shared/Procedural/DungeonLayers/MobsDunGen.cs create mode 100644 Content.Shared/Procedural/DungeonLayers/OreDunGen.cs create mode 100644 Content.Shared/Procedural/IDunGenLayer.cs create mode 100644 Content.Shared/Procedural/PostGeneration/AutoCablingDunGen.cs delete mode 100644 Content.Shared/Procedural/PostGeneration/AutoCablingPostGen.cs rename Content.Shared/Procedural/PostGeneration/{BiomePostGen.cs => BiomeDunGen.cs} (78%) rename Content.Shared/Procedural/PostGeneration/{BiomeMarkerLayerPostGen.cs => BiomeMarkerLayerDunGen.cs} (73%) create mode 100644 Content.Shared/Procedural/PostGeneration/BoundaryWallDunGen.cs delete mode 100644 Content.Shared/Procedural/PostGeneration/BoundaryWallPostGen.cs create mode 100644 Content.Shared/Procedural/PostGeneration/CornerClutterDunGen.cs delete mode 100644 Content.Shared/Procedural/PostGeneration/CornerClutterPostGen.cs rename Content.Shared/Procedural/PostGeneration/{CorridorClutterPostGen.cs => CorridorClutterDunGen.cs} (85%) rename Content.Shared/Procedural/PostGeneration/{CorridorDecalSkirtingPostGen.cs => CorridorDecalSkirtingDunGen.cs} (72%) rename Content.Shared/Procedural/PostGeneration/{CorridorPostGen.cs => CorridorDunGen.cs} (73%) create mode 100644 Content.Shared/Procedural/PostGeneration/DungeonEntranceDunGen.cs delete mode 100644 Content.Shared/Procedural/PostGeneration/DungeonEntrancePostGen.cs create mode 100644 Content.Shared/Procedural/PostGeneration/EntranceFlankDunGen.cs delete mode 100644 Content.Shared/Procedural/PostGeneration/EntranceFlankPostGen.cs create mode 100644 Content.Shared/Procedural/PostGeneration/ExternalWindowDunGen.cs delete mode 100644 Content.Shared/Procedural/PostGeneration/ExternalWindowPostGen.cs delete mode 100644 Content.Shared/Procedural/PostGeneration/IPostDunGen.cs create mode 100644 Content.Shared/Procedural/PostGeneration/InternalWindowDunGen.cs delete mode 100644 Content.Shared/Procedural/PostGeneration/InternalWindowPostGen.cs create mode 100644 Content.Shared/Procedural/PostGeneration/JunctionDunGen.cs delete mode 100644 Content.Shared/Procedural/PostGeneration/JunctionPostGen.cs create mode 100644 Content.Shared/Procedural/PostGeneration/MiddleConnectionDunGen.cs delete mode 100644 Content.Shared/Procedural/PostGeneration/MiddleConnectionPostGen.cs create mode 100644 Content.Shared/Procedural/PostGeneration/RoomEntranceDunGen.cs delete mode 100644 Content.Shared/Procedural/PostGeneration/RoomEntrancePostGen.cs create mode 100644 Content.Shared/Procedural/PostGeneration/SplineDungeonConnectorDunGen.cs create mode 100644 Content.Shared/Procedural/PostGeneration/WallMountDunGen.cs delete mode 100644 Content.Shared/Procedural/PostGeneration/WallMountPostGen.cs rename Content.Shared/Procedural/PostGeneration/{WormCorridorPostGen.cs => WormCorridorDunGen.cs} (73%) create mode 100644 Resources/Prototypes/Procedural/vgroid.yml diff --git a/Content.Server/NPC/Pathfinding/PathfindingSystem.Breadth.cs b/Content.Server/NPC/Pathfinding/PathfindingSystem.Breadth.cs new file mode 100644 index 00000000000..ee8eaa9ad1a --- /dev/null +++ b/Content.Server/NPC/Pathfinding/PathfindingSystem.Breadth.cs @@ -0,0 +1,123 @@ +namespace Content.Server.NPC.Pathfinding; + +public sealed partial class PathfindingSystem +{ + /* + * Handle BFS searches from Start->End. Doesn't consider NPC pathfinding. + */ + + /// + /// Pathfinding args for a 1-many path. + /// + public record struct BreadthPathArgs() + { + public Vector2i Start; + public List Ends; + + public bool Diagonals = false; + + public Func? TileCost; + + public int Limit = 10000; + } + + /// + /// Gets a BFS path from start to any end. Can also supply an optional tile-cost for tiles. + /// + public SimplePathResult GetBreadthPath(BreadthPathArgs args) + { + var cameFrom = new Dictionary(); + var costSoFar = new Dictionary(); + var frontier = new PriorityQueue(); + + costSoFar[args.Start] = 0f; + frontier.Enqueue(args.Start, 0f); + var count = 0; + + while (frontier.TryDequeue(out var node, out _) && count < args.Limit) + { + count++; + + if (args.Ends.Contains(node)) + { + // Found target + var path = ReconstructPath(node, cameFrom); + + return new SimplePathResult() + { + CameFrom = cameFrom, + Path = path, + }; + } + + var gCost = costSoFar[node]; + + if (args.Diagonals) + { + for (var x = -1; x <= 1; x++) + { + for (var y = -1; y <= 1; y++) + { + var neighbor = node + new Vector2i(x, y); + var neighborCost = OctileDistance(node, neighbor) * args.TileCost?.Invoke(neighbor) ?? 1f; + + if (neighborCost.Equals(0f)) + { + continue; + } + + // f = g + h + // gScore is distance to the start node + // hScore is distance to the end node + var gScore = gCost + neighborCost; + + // Slower to get here so just ignore it. + if (costSoFar.TryGetValue(neighbor, out var nextValue) && gScore >= nextValue) + { + continue; + } + + cameFrom[neighbor] = node; + costSoFar[neighbor] = gScore; + // pFactor is tie-breaker where the fscore is otherwise equal. + // See http://theory.stanford.edu/~amitp/GameProgramming/Heuristics.html#breaking-ties + // There's other ways to do it but future consideration + // The closer the fScore is to the actual distance then the better the pathfinder will be + // (i.e. somewhere between 1 and infinite) + // Can use hierarchical pathfinder or whatever to improve the heuristic but this is fine for now. + frontier.Enqueue(neighbor, gScore); + } + } + } + else + { + for (var x = -1; x <= 1; x++) + { + for (var y = -1; y <= 1; y++) + { + if (x != 0 && y != 0) + continue; + + var neighbor = node + new Vector2i(x, y); + var neighborCost = ManhattanDistance(node, neighbor) * args.TileCost?.Invoke(neighbor) ?? 1f; + + if (neighborCost.Equals(0f)) + continue; + + var gScore = gCost + neighborCost; + + if (costSoFar.TryGetValue(neighbor, out var nextValue) && gScore >= nextValue) + continue; + + cameFrom[neighbor] = node; + costSoFar[neighbor] = gScore; + + frontier.Enqueue(neighbor, gScore); + } + } + } + } + + return SimplePathResult.NoPath; + } +} diff --git a/Content.Server/NPC/Pathfinding/PathfindingSystem.Line.cs b/Content.Server/NPC/Pathfinding/PathfindingSystem.Line.cs new file mode 100644 index 00000000000..479d5ad77f6 --- /dev/null +++ b/Content.Server/NPC/Pathfinding/PathfindingSystem.Line.cs @@ -0,0 +1,74 @@ +namespace Content.Server.NPC.Pathfinding; + +public sealed partial class PathfindingSystem +{ + public void GridCast(Vector2i start, Vector2i end, Vector2iCallback callback) + { + // https://gist.github.com/Pyr3z/46884d67641094d6cf353358566db566 + // declare all locals at the top so it's obvious how big the footprint is + int dx, dy, xinc, yinc, side, i, error; + + // starting cell is always returned + if (!callback(start)) + return; + + xinc = (end.X < start.X) ? -1 : 1; + yinc = (end.Y < start.Y) ? -1 : 1; + dx = xinc * (end.X - start.X); + dy = yinc * (end.Y - start.Y); + var ax = start.X; + var ay = start.Y; + + if (dx == dy) // Handle perfect diagonals + { + // I include this "optimization" for more aesthetic reasons, actually. + // While Bresenham's Line can handle perfect diagonals just fine, it adds + // additional cells to the line that make it not a perfect diagonal + // anymore. So, while this branch is ~twice as fast as the next branch, + // the real reason it is here is for style. + + // Also, there *is* the reason of performance. If used for cell-based + // raycasts, for example, then perfect diagonals will check half as many + // cells. + + while (dx --> 0) + { + ax += xinc; + ay += yinc; + if (!callback(new Vector2i(ax, ay))) + return; + } + + return; + } + + // Handle all other lines + + side = -1 * ((dx == 0 ? yinc : xinc) - 1); + + i = dx + dy; + error = dx - dy; + + dx *= 2; + dy *= 2; + + while (i --> 0) + { + if (error > 0 || error == side) + { + ax += xinc; + error -= dy; + } + else + { + ay += yinc; + error += dx; + } + + if (!callback(new Vector2i(ax, ay))) + return; + } + } + + public delegate bool Vector2iCallback(Vector2i index); +} diff --git a/Content.Server/NPC/Pathfinding/PathfindingSystem.Simple.cs b/Content.Server/NPC/Pathfinding/PathfindingSystem.Simple.cs new file mode 100644 index 00000000000..7afd3d78df1 --- /dev/null +++ b/Content.Server/NPC/Pathfinding/PathfindingSystem.Simple.cs @@ -0,0 +1,154 @@ +namespace Content.Server.NPC.Pathfinding; + +public sealed partial class PathfindingSystem +{ + /// + /// Pathfinding args for a 1-1 path. + /// + public record struct SimplePathArgs() + { + public Vector2i Start; + public Vector2i End; + + public bool Diagonals = false; + + public int Limit = 10000; + + /// + /// Custom tile-costs if applicable. + /// + public Func? TileCost; + } + + public record struct SimplePathResult + { + public static SimplePathResult NoPath = new(); + + public List Path; + public Dictionary CameFrom; + } + + /// + /// Gets simple A* path from start to end. Can also supply an optional tile-cost for tiles. + /// + public SimplePathResult GetPath(SimplePathArgs args) + { + var cameFrom = new Dictionary(); + var costSoFar = new Dictionary(); + var frontier = new PriorityQueue(); + + costSoFar[args.Start] = 0f; + frontier.Enqueue(args.Start, 0f); + var count = 0; + + while (frontier.TryDequeue(out var node, out _) && count < args.Limit) + { + count++; + + if (node == args.End) + { + // Found target + var path = ReconstructPath(args.End, cameFrom); + + return new SimplePathResult() + { + CameFrom = cameFrom, + Path = path, + }; + } + + var gCost = costSoFar[node]; + + if (args.Diagonals) + { + for (var x = -1; x <= 1; x++) + { + for (var y = -1; y <= 1; y++) + { + var neighbor = node + new Vector2i(x, y); + var neighborCost = OctileDistance(node, neighbor) * args.TileCost?.Invoke(neighbor) ?? 1f; + + if (neighborCost.Equals(0f)) + { + continue; + } + + // f = g + h + // gScore is distance to the start node + // hScore is distance to the end node + var gScore = gCost + neighborCost; + + // Slower to get here so just ignore it. + if (costSoFar.TryGetValue(neighbor, out var nextValue) && gScore >= nextValue) + { + continue; + } + + cameFrom[neighbor] = node; + costSoFar[neighbor] = gScore; + // pFactor is tie-breaker where the fscore is otherwise equal. + // See http://theory.stanford.edu/~amitp/GameProgramming/Heuristics.html#breaking-ties + // There's other ways to do it but future consideration + // The closer the fScore is to the actual distance then the better the pathfinder will be + // (i.e. somewhere between 1 and infinite) + // Can use hierarchical pathfinder or whatever to improve the heuristic but this is fine for now. + var hScore = OctileDistance(args.End, neighbor) * (1.0f + 1.0f / 1000.0f); + var fScore = gScore + hScore; + frontier.Enqueue(neighbor, fScore); + } + } + } + else + { + for (var x = -1; x <= 1; x++) + { + for (var y = -1; y <= 1; y++) + { + if (x != 0 && y != 0) + continue; + + var neighbor = node + new Vector2i(x, y); + var neighborCost = ManhattanDistance(node, neighbor) * args.TileCost?.Invoke(neighbor) ?? 1f; + + if (neighborCost.Equals(0f)) + continue; + + var gScore = gCost + neighborCost; + + if (costSoFar.TryGetValue(neighbor, out var nextValue) && gScore >= nextValue) + continue; + + cameFrom[neighbor] = node; + costSoFar[neighbor] = gScore; + + // Still use octile even for manhattan distance. + var hScore = OctileDistance(args.End, neighbor) * 1.001f; + var fScore = gScore + hScore; + frontier.Enqueue(neighbor, fScore); + } + } + } + } + + return SimplePathResult.NoPath; + } + + private List ReconstructPath(Vector2i end, Dictionary cameFrom) + { + var path = new List() + { + end, + }; + var node = end; + + while (cameFrom.TryGetValue(node, out var source)) + { + path.Add(source); + node = source; + } + + path.Reverse(); + + return path; + } +} diff --git a/Content.Server/NPC/Pathfinding/PathfindingSystem.Splines.cs b/Content.Server/NPC/Pathfinding/PathfindingSystem.Splines.cs new file mode 100644 index 00000000000..9979755f995 --- /dev/null +++ b/Content.Server/NPC/Pathfinding/PathfindingSystem.Splines.cs @@ -0,0 +1,180 @@ +using Robust.Shared.Collections; +using Robust.Shared.Random; + +namespace Content.Server.NPC.Pathfinding; + +public sealed partial class PathfindingSystem +{ + public record struct SimplifyPathArgs + { + public Vector2i Start; + public Vector2i End; + public List Path; + } + + public record struct SplinePathResult() + { + public static SplinePathResult NoPath = new(); + + public List Points = new(); + + public List Path = new(); + public Dictionary CameFrom; + } + + public record struct SplinePathArgs(SimplePathArgs Args) + { + public SimplePathArgs Args = Args; + + public float MaxRatio = 0.25f; + + /// + /// Minimum distance between subdivisions. + /// + public int Distance = 20; + } + + /// + /// Gets a spline path from start to end. + /// + public SplinePathResult GetSplinePath(SplinePathArgs args, Random random) + { + var start = args.Args.Start; + var end = args.Args.End; + + var path = new List(); + + var pairs = new ValueList<(Vector2i Start, Vector2i End)> { (start, end) }; + var subdivided = true; + + // Sub-divide recursively + while (subdivided) + { + // Sometimes we might inadvertantly get 2 nodes too close together so better to just check each one as it comes up instead. + var i = 0; + subdivided = false; + + while (i < pairs.Count) + { + var pointA = pairs[i].Start; + var pointB = pairs[i].End; + var vector = pointB - pointA; + + var halfway = vector / 2f; + + // Finding the point + var adj = halfway.Length(); + + // Should we even subdivide. + if (adj <= args.Distance) + { + // Just check the next entry no double skip. + i++; + continue; + } + + subdivided = true; + var opposite = args.MaxRatio * adj; + var hypotenuse = MathF.Sqrt(MathF.Pow(adj, 2) + MathF.Pow(opposite, 2)); + + // Okay so essentially we have 2 points and no poly + // We add 2 other points to form a diamond and want some point halfway between randomly offset. + var angle = new Angle(MathF.Atan(opposite / adj)); + var pointAPerp = pointA + angle.RotateVec(halfway).Normalized() * hypotenuse; + var pointBPerp = pointA + (-angle).RotateVec(halfway).Normalized() * hypotenuse; + + var perpLine = pointBPerp - pointAPerp; + var perpHalfway = perpLine.Length() / 2f; + + var splinePoint = (pointAPerp + perpLine.Normalized() * random.NextFloat(-args.MaxRatio, args.MaxRatio) * perpHalfway).Floored(); + + // We essentially take (A, B) and turn it into (A, C) & (C, B) + pairs[i] = (pointA, splinePoint); + pairs.Insert(i + 1, (splinePoint, pointB)); + + i+= 2; + } + } + + var spline = new ValueList(pairs.Count - 1) + { + start + }; + + foreach (var pair in pairs) + { + spline.Add(pair.End); + } + + // Now we need to pathfind between each node on the spline. + + // TODO: Add rotation version or straight-line version for pathfinder config + // Move the worm pathfinder to here I think. + var cameFrom = new Dictionary(); + + // TODO: Need to get rid of the branch bullshit. + var points = new List(); + + for (var i = 0; i < spline.Count - 1; i++) + { + var point = spline[i]; + var target = spline[i + 1]; + points.Add(point); + var aStarArgs = args.Args with { Start = point, End = target }; + + var aStarResult = GetPath(aStarArgs); + + if (aStarResult == SimplePathResult.NoPath) + return SplinePathResult.NoPath; + + path.AddRange(aStarResult.Path[0..]); + + foreach (var a in aStarResult.CameFrom) + { + cameFrom[a.Key] = a.Value; + } + } + + points.Add(spline[^1]); + + var simple = SimplifyPath(new SimplifyPathArgs() + { + Start = args.Args.Start, + End = args.Args.End, + Path = path, + }); + + return new SplinePathResult() + { + Path = simple, + CameFrom = cameFrom, + Points = points, + }; + } + + /// + /// Does a simpler pathfinder over the nodes to prune unnecessary branches. + /// + public List SimplifyPath(SimplifyPathArgs args) + { + var nodes = new HashSet(args.Path); + + var result = GetBreadthPath(new BreadthPathArgs() + { + Start = args.Start, + Ends = new List() + { + args.End, + }, + TileCost = node => + { + if (!nodes.Contains(node)) + return 0f; + + return 1f; + } + }); + + return result.Path; + } +} diff --git a/Content.Server/NPC/Pathfinding/PathfindingSystem.Widen.cs b/Content.Server/NPC/Pathfinding/PathfindingSystem.Widen.cs new file mode 100644 index 00000000000..f7bcd019f5f --- /dev/null +++ b/Content.Server/NPC/Pathfinding/PathfindingSystem.Widen.cs @@ -0,0 +1,89 @@ +using System.Numerics; +using Robust.Shared.Random; + +namespace Content.Server.NPC.Pathfinding; + +public sealed partial class PathfindingSystem +{ + /// + /// Widens the path by the specified amount. + /// + public HashSet GetWiden(WidenArgs args, Random random) + { + var tiles = new HashSet(args.Path.Count * 2); + var variance = (args.MaxWiden - args.MinWiden) / 2f + args.MinWiden; + var counter = 0; + + foreach (var tile in args.Path) + { + counter++; + + if (counter != args.TileSkip) + continue; + + counter = 0; + + var center = new Vector2(tile.X + 0.5f, tile.Y + 0.5f); + + if (args.Square) + { + for (var x = -variance; x <= variance; x++) + { + for (var y = -variance; y <= variance; y++) + { + var neighbor = center + new Vector2(x, y); + + tiles.Add(neighbor.Floored()); + } + } + } + else + { + for (var x = -variance; x <= variance; x++) + { + for (var y = -variance; y <= variance; y++) + { + var offset = new Vector2(x, y); + + if (offset.Length() > variance) + continue; + + var neighbor = center + offset; + + tiles.Add(neighbor.Floored()); + } + } + } + + variance += random.NextFloat(-args.Variance * args.TileSkip, args.Variance * args.TileSkip); + variance = Math.Clamp(variance, args.MinWiden, args.MaxWiden); + } + + return tiles; + } + + public record struct WidenArgs() + { + public bool Square = false; + + /// + /// How many tiles to skip between iterations., 1-in-n + /// + public int TileSkip = 3; + + /// + /// Maximum amount to vary per tile. + /// + public float Variance = 0.25f; + + /// + /// Minimum width. + /// + public float MinWiden = 2f; + + + public float MaxWiden = 7f; + + public List Path; + } +} diff --git a/Content.Server/NPC/Systems/NPCSteeringSystem.Context.cs b/Content.Server/NPC/Systems/NPCSteeringSystem.Context.cs index 5f871a6ecfa..e0bcb97a112 100644 --- a/Content.Server/NPC/Systems/NPCSteeringSystem.Context.cs +++ b/Content.Server/NPC/Systems/NPCSteeringSystem.Context.cs @@ -142,6 +142,13 @@ private bool TrySeek( // Grab the target position, either the next path node or our end goal.. var targetCoordinates = GetTargetCoordinates(steering); + + if (!targetCoordinates.IsValid(EntityManager)) + { + steering.Status = SteeringStatus.NoPath; + return false; + } + var needsPath = false; // If the next node is invalid then get new ones @@ -243,6 +250,14 @@ private bool TrySeek( // Alright just adjust slightly and grab the next node so we don't stop moving for a tick. // TODO: If it's the last node just grab the target instead. targetCoordinates = GetTargetCoordinates(steering); + + if (!targetCoordinates.IsValid(EntityManager)) + { + SetDirection(mover, steering, Vector2.Zero); + steering.Status = SteeringStatus.NoPath; + return false; + } + targetMap = targetCoordinates.ToMap(EntityManager, _transform); // Can't make it again. diff --git a/Content.Server/Procedural/DungeonJob.PostGen.cs b/Content.Server/Procedural/DungeonJob.PostGen.cs deleted file mode 100644 index cb9e64f04e2..00000000000 --- a/Content.Server/Procedural/DungeonJob.PostGen.cs +++ /dev/null @@ -1,1258 +0,0 @@ -using System.Linq; -using System.Numerics; -using System.Threading.Tasks; -using Content.Server.NodeContainer; -using Content.Shared.Doors.Components; -using Content.Shared.Maps; -using Content.Shared.Physics; -using Content.Shared.Procedural; -using Content.Shared.Procedural.PostGeneration; -using Content.Shared.Storage; -using Content.Shared.Tag; -using Robust.Shared.Collections; -using Robust.Shared.Map; -using Robust.Shared.Map.Components; -using Robust.Shared.Physics.Components; -using Robust.Shared.Prototypes; -using Robust.Shared.Random; -using Robust.Shared.Utility; - -namespace Content.Server.Procedural; - -public sealed partial class DungeonJob -{ - /* - * Run after the main dungeon generation - */ - - private static readonly ProtoId WallTag = "Wall"; - - private bool HasWall(MapGridComponent grid, Vector2i tile) - { - var anchored = _maps.GetAnchoredEntitiesEnumerator(_gridUid, _grid, tile); - - while (anchored.MoveNext(out var uid)) - { - if (_tag.HasTag(uid.Value, WallTag)) - return true; - } - - return false; - } - - private async Task PostGen(AutoCablingPostGen gen, Dungeon dungeon, EntityUid gridUid, MapGridComponent grid, - Random random) - { - // There's a lot of ways you could do this. - // For now we'll just connect every LV cable in the dungeon. - var cableTiles = new HashSet(); - var allTiles = new HashSet(dungeon.CorridorTiles); - allTiles.UnionWith(dungeon.RoomTiles); - allTiles.UnionWith(dungeon.RoomExteriorTiles); - allTiles.UnionWith(dungeon.CorridorExteriorTiles); - var nodeQuery = _entManager.GetEntityQuery(); - - // Gather existing nodes - foreach (var tile in allTiles) - { - var anchored = _maps.GetAnchoredEntitiesEnumerator(_gridUid, _grid, tile); - - while (anchored.MoveNext(out var anc)) - { - if (!nodeQuery.TryGetComponent(anc, out var nodeContainer) || - !nodeContainer.Nodes.ContainsKey("power")) - { - continue; - } - - cableTiles.Add(tile); - break; - } - } - - // Iterating them all might be expensive. - await SuspendIfOutOfTime(); - - if (!ValidateResume()) - return; - - var startNodes = new List(cableTiles); - random.Shuffle(startNodes); - var start = startNodes[0]; - var remaining = new HashSet(startNodes); - var frontier = new PriorityQueue(); - frontier.Enqueue(start, 0f); - var cameFrom = new Dictionary(); - var costSoFar = new Dictionary(); - var lastDirection = new Dictionary(); - costSoFar[start] = 0f; - lastDirection[start] = Direction.Invalid; - - while (remaining.Count > 0) - { - if (frontier.Count == 0) - { - var newStart = remaining.First(); - frontier.Enqueue(newStart, 0f); - lastDirection[newStart] = Direction.Invalid; - } - - var node = frontier.Dequeue(); - - if (remaining.Remove(node)) - { - var weh = node; - - while (cameFrom.TryGetValue(weh, out var receiver)) - { - cableTiles.Add(weh); - weh = receiver; - - if (weh == start) - break; - } - } - - if (!grid.TryGetTileRef(node, out var tileRef) || tileRef.Tile.IsEmpty) - { - continue; - } - - for (var i = 0; i < 4; i++) - { - var dir = (Direction) (i * 2); - - var neighbor = node + dir.ToIntVec(); - var tileCost = 1f; - - // Prefer straight lines. - if (lastDirection[node] != dir) - { - tileCost *= 1.1f; - } - - if (cableTiles.Contains(neighbor)) - { - tileCost *= 0.1f; - } - - // Prefer tiles without walls on them - if (HasWall(grid, neighbor)) - { - tileCost *= 20f; - } - - var gScore = costSoFar[node] + tileCost; - - if (costSoFar.TryGetValue(neighbor, out var nextValue) && gScore >= nextValue) - { - continue; - } - - cameFrom[neighbor] = node; - costSoFar[neighbor] = gScore; - lastDirection[neighbor] = dir; - frontier.Enqueue(neighbor, gScore); - } - } - - foreach (var tile in cableTiles) - { - var anchored = grid.GetAnchoredEntitiesEnumerator(tile); - var found = false; - - while (anchored.MoveNext(out var anc)) - { - if (!nodeQuery.TryGetComponent(anc, out var nodeContainer) || - !nodeContainer.Nodes.ContainsKey("power")) - { - continue; - } - - found = true; - break; - } - - if (found) - continue; - - _entManager.SpawnEntity(gen.Entity, _grid.GridTileToLocal(tile)); - } - } - - private async Task PostGen(BoundaryWallPostGen gen, Dungeon dungeon, EntityUid gridUid, MapGridComponent grid, Random random) - { - var tileDef = _tileDefManager[gen.Tile]; - var tiles = new List<(Vector2i Index, Tile Tile)>(dungeon.RoomExteriorTiles.Count); - - // Spawn wall outline - // - Tiles first - foreach (var neighbor in dungeon.RoomExteriorTiles) - { - DebugTools.Assert(!dungeon.RoomTiles.Contains(neighbor)); - - if (dungeon.Entrances.Contains(neighbor)) - continue; - - if (!_anchorable.TileFree(grid, neighbor, DungeonSystem.CollisionLayer, DungeonSystem.CollisionMask)) - continue; - - tiles.Add((neighbor, _tile.GetVariantTile((ContentTileDefinition) tileDef, random))); - } - - foreach (var index in dungeon.CorridorExteriorTiles) - { - if (dungeon.RoomTiles.Contains(index)) - continue; - - if (!_anchorable.TileFree(grid, index, DungeonSystem.CollisionLayer, DungeonSystem.CollisionMask)) - continue; - - tiles.Add((index, _tile.GetVariantTile((ContentTileDefinition)tileDef, random))); - } - - grid.SetTiles(tiles); - - // Double iteration coz we bulk set tiles for speed. - for (var i = 0; i < tiles.Count; i++) - { - var index = tiles[i]; - if (!_anchorable.TileFree(grid, index.Index, DungeonSystem.CollisionLayer, DungeonSystem.CollisionMask)) - continue; - - // If no cardinal neighbors in dungeon then we're a corner. - var isCorner = false; - - if (gen.CornerWall != null) - { - isCorner = true; - - for (var x = -1; x <= 1; x++) - { - for (var y = -1; y <= 1; y++) - { - if (x != 0 && y != 0) - { - continue; - } - - var neighbor = new Vector2i(index.Index.X + x, index.Index.Y + y); - - if (dungeon.RoomTiles.Contains(neighbor) || dungeon.CorridorTiles.Contains(neighbor)) - { - isCorner = false; - break; - } - } - - if (!isCorner) - break; - } - - if (isCorner) - _entManager.SpawnEntity(gen.CornerWall, grid.GridTileToLocal(index.Index)); - } - - if (!isCorner) - _entManager.SpawnEntity(gen.Wall, grid.GridTileToLocal(index.Index)); - - if (i % 20 == 0) - { - await SuspendIfOutOfTime(); - - if (!ValidateResume()) - return; - } - } - } - - private async Task PostGen(CornerClutterPostGen gen, Dungeon dungeon, EntityUid gridUid, MapGridComponent grid, - Random random) - { - var physicsQuery = _entManager.GetEntityQuery(); - - foreach (var tile in dungeon.CorridorTiles) - { - var enumerator = _grid.GetAnchoredEntitiesEnumerator(tile); - var blocked = false; - - while (enumerator.MoveNext(out var ent)) - { - // TODO: TileFree - if (!physicsQuery.TryGetComponent(ent, out var physics) || - !physics.CanCollide || - !physics.Hard) - { - continue; - } - - blocked = true; - break; - } - - if (blocked) - continue; - - // If at least 2 adjacent tiles are blocked consider it a corner - for (var i = 0; i < 4; i++) - { - var dir = (Direction) (i * 2); - blocked = HasWall(grid, tile + dir.ToIntVec()); - - if (!blocked) - continue; - - var nextDir = (Direction) ((i + 1) * 2 % 8); - blocked = HasWall(grid, tile + nextDir.ToIntVec()); - - if (!blocked) - continue; - - if (random.Prob(gen.Chance)) - { - var coords = _grid.GridTileToLocal(tile); - var protos = EntitySpawnCollection.GetSpawns(gen.Contents, random); - _entManager.SpawnEntities(coords, protos); - } - - break; - } - } - } - - private async Task PostGen(CorridorDecalSkirtingPostGen decks, Dungeon dungeon, EntityUid gridUid, MapGridComponent grid, Random random) - { - var directions = new ValueList(4); - var pocketDirections = new ValueList(4); - var doorQuery = _entManager.GetEntityQuery(); - var physicsQuery = _entManager.GetEntityQuery(); - var offset = -_grid.TileSizeHalfVector; - var color = decks.Color; - - foreach (var tile in dungeon.CorridorTiles) - { - DebugTools.Assert(!dungeon.RoomTiles.Contains(tile)); - directions.Clear(); - - // Do cardinals 1 step - // Do corners the other step - for (var i = 0; i < 4; i++) - { - var dir = (DirectionFlag) Math.Pow(2, i); - var neighbor = tile + dir.AsDir().ToIntVec(); - - var anc = _grid.GetAnchoredEntitiesEnumerator(neighbor); - - while (anc.MoveNext(out var ent)) - { - if (!physicsQuery.TryGetComponent(ent, out var physics) || - !physics.CanCollide || - !physics.Hard || - doorQuery.HasComponent(ent.Value)) - { - continue; - } - - directions.Add(dir); - break; - } - } - - // Pockets - if (directions.Count == 0) - { - pocketDirections.Clear(); - - for (var i = 1; i < 5; i++) - { - var dir = (Direction) (i * 2 - 1); - var neighbor = tile + dir.ToIntVec(); - - var anc = _grid.GetAnchoredEntitiesEnumerator(neighbor); - - while (anc.MoveNext(out var ent)) - { - if (!physicsQuery.TryGetComponent(ent, out var physics) || - !physics.CanCollide || - !physics.Hard || - doorQuery.HasComponent(ent.Value)) - { - continue; - } - - pocketDirections.Add(dir); - break; - } - } - - if (pocketDirections.Count == 1) - { - if (decks.PocketDecals.TryGetValue(pocketDirections[0], out var cDir)) - { - // Decals not being centered biting my ass again - var gridPos = _grid.GridTileToLocal(tile).Offset(offset); - _decals.TryAddDecal(cDir, gridPos, out _, color: color); - } - } - - continue; - } - - if (directions.Count == 1) - { - if (decks.CardinalDecals.TryGetValue(directions[0], out var cDir)) - { - // Decals not being centered biting my ass again - var gridPos = _grid.GridTileToLocal(tile).Offset(offset); - _decals.TryAddDecal(cDir, gridPos, out _, color: color); - } - - continue; - } - - // Corners - if (directions.Count == 2) - { - // Auehghegueugegegeheh help me - var dirFlag = directions[0] | directions[1]; - - if (decks.CornerDecals.TryGetValue(dirFlag, out var cDir)) - { - var gridPos = _grid.GridTileToLocal(tile).Offset(offset); - _decals.TryAddDecal(cDir, gridPos, out _, color: color); - } - } - } - } - - private async Task PostGen(DungeonEntrancePostGen gen, Dungeon dungeon, EntityUid gridUid, MapGridComponent grid, Random random) - { - var rooms = new List(dungeon.Rooms); - var roomTiles = new List(); - var tileDef = _tileDefManager[gen.Tile]; - - for (var i = 0; i < gen.Count; i++) - { - var roomIndex = random.Next(rooms.Count); - var room = rooms[roomIndex]; - - // Move out 3 tiles in a direction away from center of the room - // If none of those intersect another tile it's probably external - // TODO: Maybe need to take top half of furthest rooms in case there's interior exits? - roomTiles.AddRange(room.Exterior); - random.Shuffle(roomTiles); - - foreach (var tile in roomTiles) - { - var isValid = false; - - // Check if one side is dungeon and the other side is nothing. - for (var j = 0; j < 4; j++) - { - var dir = (Direction) (j * 2); - var oppositeDir = dir.GetOpposite(); - var dirVec = tile + dir.ToIntVec(); - var oppositeDirVec = tile + oppositeDir.ToIntVec(); - - if (!dungeon.RoomTiles.Contains(dirVec)) - { - continue; - } - - if (dungeon.RoomTiles.Contains(oppositeDirVec) || - dungeon.RoomExteriorTiles.Contains(oppositeDirVec) || - dungeon.CorridorExteriorTiles.Contains(oppositeDirVec) || - dungeon.CorridorTiles.Contains(oppositeDirVec)) - { - continue; - } - - // Check if exterior spot free. - if (!_anchorable.TileFree(_grid, tile, DungeonSystem.CollisionLayer, DungeonSystem.CollisionMask)) - { - continue; - } - - // Check if interior spot free (no guarantees on exterior but ClearDoor should handle it) - if (!_anchorable.TileFree(_grid, dirVec, DungeonSystem.CollisionLayer, DungeonSystem.CollisionMask)) - { - continue; - } - - // Valid pick! - isValid = true; - - // Entrance wew - grid.SetTile(tile, _tile.GetVariantTile((ContentTileDefinition) tileDef, random)); - ClearDoor(dungeon, grid, tile); - var gridCoords = grid.GridTileToLocal(tile); - // Need to offset the spawn to avoid spawning in the room. - - _entManager.SpawnEntities(gridCoords, gen.Entities); - - // Clear out any biome tiles nearby to avoid blocking it - foreach (var nearTile in grid.GetTilesIntersecting(new Circle(gridCoords.Position, 1.5f), false)) - { - if (dungeon.RoomTiles.Contains(nearTile.GridIndices) || - dungeon.RoomExteriorTiles.Contains(nearTile.GridIndices) || - dungeon.CorridorTiles.Contains(nearTile.GridIndices) || - dungeon.CorridorExteriorTiles.Contains(nearTile.GridIndices)) - { - continue; - } - - grid.SetTile(nearTile.GridIndices, _tile.GetVariantTile((ContentTileDefinition) tileDef, random));; - } - - break; - } - - if (isValid) - break; - } - - roomTiles.Clear(); - } - } - - private async Task PostGen(ExternalWindowPostGen gen, Dungeon dungeon, EntityUid gridUid, MapGridComponent grid, - Random random) - { - // Iterate every tile with N chance to spawn windows on that wall per cardinal dir. - var chance = 0.25 / 3f; - - var allExterior = new HashSet(dungeon.CorridorExteriorTiles); - allExterior.UnionWith(dungeon.RoomExteriorTiles); - var validTiles = allExterior.ToList(); - random.Shuffle(validTiles); - - var tiles = new List<(Vector2i, Tile)>(); - var tileDef = _tileDefManager[gen.Tile]; - var count = Math.Floor(validTiles.Count * chance); - var index = 0; - var takenTiles = new HashSet(); - - // There's a bunch of shit here but tl;dr - // - don't spawn over cap - // - Check if we have 3 tiles in a row that aren't corners and aren't obstructed - foreach (var tile in validTiles) - { - if (index > count) - break; - - // Room tile / already used. - if (!_anchorable.TileFree(_grid, tile, DungeonSystem.CollisionLayer, DungeonSystem.CollisionMask) || - takenTiles.Contains(tile)) - { - continue; - } - - // Check we're not on a corner - for (var i = 0; i < 2; i++) - { - var dir = (Direction) (i * 2); - var dirVec = dir.ToIntVec(); - var isValid = true; - - // Check 1 beyond either side to ensure it's not a corner. - for (var j = -1; j < 4; j++) - { - var neighbor = tile + dirVec * j; - - if (!allExterior.Contains(neighbor) || - takenTiles.Contains(neighbor) || - !_anchorable.TileFree(grid, neighbor, DungeonSystem.CollisionLayer, DungeonSystem.CollisionMask)) - { - isValid = false; - break; - } - - // Also check perpendicular that it is free - foreach (var k in new [] {2, 6}) - { - var perp = (Direction) ((i * 2 + k) % 8); - var perpVec = perp.ToIntVec(); - var perpTile = tile + perpVec; - - if (allExterior.Contains(perpTile) || - takenTiles.Contains(neighbor) || - !_anchorable.TileFree(_grid, perpTile, DungeonSystem.CollisionLayer, DungeonSystem.CollisionMask)) - { - isValid = false; - break; - } - } - - if (!isValid) - break; - } - - if (!isValid) - continue; - - for (var j = 0; j < 3; j++) - { - var neighbor = tile + dirVec * j; - - tiles.Add((neighbor, _tile.GetVariantTile((ContentTileDefinition) tileDef, random))); - index++; - takenTiles.Add(neighbor); - } - } - } - - grid.SetTiles(tiles); - index = 0; - - foreach (var tile in tiles) - { - var gridPos = grid.GridTileToLocal(tile.Item1); - - index += gen.Entities.Count; - _entManager.SpawnEntities(gridPos, gen.Entities); - - if (index > 20) - { - index -= 20; - await SuspendIfOutOfTime(); - - if (!ValidateResume()) - return; - } - } - } - - /* - * You may be wondering why these are different. - * It's because for internals we want to force it as it looks nicer and not leave it up to chance. - */ - - // TODO: Can probably combine these a bit, their differences are in really annoying to pull out spots. - - private async Task PostGen(InternalWindowPostGen gen, Dungeon dungeon, EntityUid gridUid, MapGridComponent grid, - Random random) - { - // Iterate every room and check if there's a gap beyond it that leads to another room within N tiles - // If so then consider windows - var minDistance = 4; - var maxDistance = 6; - var tileDef = _tileDefManager[gen.Tile]; - - foreach (var room in dungeon.Rooms) - { - var validTiles = new List(); - - for (var i = 0; i < 4; i++) - { - var dir = (DirectionFlag) Math.Pow(2, i); - var dirVec = dir.AsDir().ToIntVec(); - - foreach (var tile in room.Tiles) - { - var tileAngle = ((Vector2) tile + grid.TileSizeHalfVector - room.Center).ToAngle(); - var roundedAngle = Math.Round(tileAngle.Theta / (Math.PI / 2)) * (Math.PI / 2); - - var tileVec = (Vector2i) new Angle(roundedAngle).ToVec().Rounded(); - - if (!tileVec.Equals(dirVec)) - continue; - - var valid = false; - - for (var j = 1; j < maxDistance; j++) - { - var edgeNeighbor = tile + dirVec * j; - - if (dungeon.RoomTiles.Contains(edgeNeighbor)) - { - if (j < minDistance) - { - valid = false; - } - else - { - valid = true; - } - - break; - } - } - - if (!valid) - continue; - - var windowTile = tile + dirVec; - - if (!_anchorable.TileFree(grid, windowTile, DungeonSystem.CollisionLayer, DungeonSystem.CollisionMask)) - continue; - - validTiles.Add(windowTile); - } - - validTiles.Sort((x, y) => ((Vector2) x + grid.TileSizeHalfVector - room.Center).LengthSquared().CompareTo((y + grid.TileSizeHalfVector - room.Center).LengthSquared)); - - for (var j = 0; j < Math.Min(validTiles.Count, 3); j++) - { - var tile = validTiles[j]; - var gridPos = grid.GridTileToLocal(tile); - grid.SetTile(tile, _tile.GetVariantTile((ContentTileDefinition) tileDef, random)); - - _entManager.SpawnEntities(gridPos, gen.Entities); - } - - if (validTiles.Count > 0) - { - await SuspendIfOutOfTime(); - - if (!ValidateResume()) - return; - } - - validTiles.Clear(); - } - } - } - - /// - /// Simply places tiles / entities on the entrances to rooms. - /// - private async Task PostGen(RoomEntrancePostGen gen, Dungeon dungeon, EntityUid gridUid, MapGridComponent grid, - Random random) - { - var setTiles = new List<(Vector2i, Tile)>(); - var tileDef = _tileDefManager[gen.Tile]; - - foreach (var room in dungeon.Rooms) - { - foreach (var entrance in room.Entrances) - { - setTiles.Add((entrance, _tile.GetVariantTile((ContentTileDefinition) tileDef, random))); - } - } - - grid.SetTiles(setTiles); - - foreach (var room in dungeon.Rooms) - { - foreach (var entrance in room.Entrances) - { - _entManager.SpawnEntities(grid.GridTileToLocal(entrance), gen.Entities); - } - } - } - - /// - /// Generates corridor connections between entrances to all the rooms. - /// - private async Task PostGen(CorridorPostGen gen, Dungeon dungeon, EntityUid gridUid, MapGridComponent grid, Random random) - { - var entrances = new List(dungeon.Rooms.Count); - - // Grab entrances - foreach (var room in dungeon.Rooms) - { - entrances.AddRange(room.Entrances); - } - - var edges = _dungeon.MinimumSpanningTree(entrances, random); - await SuspendIfOutOfTime(); - - if (!ValidateResume()) - return; - - // TODO: Add in say 1/3 of edges back in to add some cyclic to it. - - var expansion = gen.Width - 2; - // Okay so tl;dr is that we don't want to cut close to rooms as it might go from 3 width to 2 width suddenly - // So we will add a buffer range around each room to deter pathfinding there unless necessary - var deterredTiles = new HashSet(); - - if (expansion >= 1) - { - foreach (var tile in dungeon.RoomExteriorTiles) - { - for (var x = -expansion; x <= expansion; x++) - { - for (var y = -expansion; y <= expansion; y++) - { - var neighbor = new Vector2(tile.X + x, tile.Y + y).Floored(); - - if (dungeon.RoomTiles.Contains(neighbor) || - dungeon.RoomExteriorTiles.Contains(neighbor) || - entrances.Contains(neighbor)) - { - continue; - } - - deterredTiles.Add(neighbor); - } - } - } - } - - foreach (var room in dungeon.Rooms) - { - foreach (var entrance in room.Entrances) - { - // Just so we can still actually get in to the entrance we won't deter from a tile away from it. - var normal = (entrance + grid.TileSizeHalfVector - room.Center).ToWorldAngle().GetCardinalDir().ToIntVec(); - deterredTiles.Remove(entrance + normal); - } - } - - var excludedTiles = new HashSet(dungeon.RoomExteriorTiles); - excludedTiles.UnionWith(dungeon.RoomTiles); - var corridorTiles = new HashSet(); - - _dungeon.GetCorridorNodes(corridorTiles, edges, gen.PathLimit, excludedTiles, tile => - { - var mod = 1f; - - if (corridorTiles.Contains(tile)) - { - mod *= 0.1f; - } - - if (deterredTiles.Contains(tile)) - { - mod *= 2f; - } - - return mod; - }); - - WidenCorridor(dungeon, gen.Width, corridorTiles); - - var setTiles = new List<(Vector2i, Tile)>(); - var tileDef = _prototype.Index(gen.Tile); - - foreach (var tile in corridorTiles) - { - setTiles.Add((tile, _tile.GetVariantTile(tileDef, random))); - } - - grid.SetTiles(setTiles); - dungeon.CorridorTiles.UnionWith(corridorTiles); - BuildCorridorExterior(dungeon); - } - - private void BuildCorridorExterior(Dungeon dungeon) - { - var exterior = dungeon.CorridorExteriorTiles; - - // Just ignore entrances or whatever for now. - foreach (var tile in dungeon.CorridorTiles) - { - for (var x = -1; x <= 1; x++) - { - for (var y = -1; y <= 1; y++) - { - var neighbor = new Vector2i(tile.X + x, tile.Y + y); - - if (dungeon.CorridorTiles.Contains(neighbor) || - dungeon.RoomExteriorTiles.Contains(neighbor) || - dungeon.RoomTiles.Contains(neighbor) || - dungeon.Entrances.Contains(neighbor)) - { - continue; - } - - exterior.Add(neighbor); - } - } - } - } - - private void WidenCorridor(Dungeon dungeon, float width, ICollection corridorTiles) - { - var expansion = width - 2; - - // Widen the path - if (expansion >= 1) - { - var toAdd = new ValueList(); - - foreach (var node in corridorTiles) - { - // Uhhh not sure on the cleanest way to do this but tl;dr we don't want to hug - // exterior walls and make the path smaller. - - for (var x = -expansion; x <= expansion; x++) - { - for (var y = -expansion; y <= expansion; y++) - { - var neighbor = new Vector2(node.X + x, node.Y + y).Floored(); - - // Diagonals still matter here. - if (dungeon.RoomTiles.Contains(neighbor) || - dungeon.RoomExteriorTiles.Contains(neighbor)) - { - // Try - - continue; - } - - toAdd.Add(neighbor); - } - } - } - - foreach (var node in toAdd) - { - corridorTiles.Add(node); - } - } - } - - private async Task PostGen(EntranceFlankPostGen gen, Dungeon dungeon, EntityUid gridUid, MapGridComponent grid, - Random random) - { - var tiles = new List<(Vector2i Index, Tile)>(); - var tileDef = _tileDefManager[gen.Tile]; - var spawnPositions = new ValueList(dungeon.Rooms.Count); - - foreach (var room in dungeon.Rooms) - { - foreach (var entrance in room.Entrances) - { - for (var i = 0; i < 8; i++) - { - var dir = (Direction) i; - var neighbor = entrance + dir.ToIntVec(); - - if (!dungeon.RoomExteriorTiles.Contains(neighbor)) - continue; - - tiles.Add((neighbor, _tile.GetVariantTile((ContentTileDefinition) tileDef, random))); - spawnPositions.Add(neighbor); - } - } - } - - grid.SetTiles(tiles); - - foreach (var entrance in spawnPositions) - { - _entManager.SpawnEntities(_grid.GridTileToLocal(entrance), gen.Entities); - } - } - - private async Task PostGen(JunctionPostGen gen, Dungeon dungeon, EntityUid gridUid, MapGridComponent grid, - Random random) - { - var tileDef = _tileDefManager[gen.Tile]; - - // N-wide junctions - foreach (var tile in dungeon.CorridorTiles) - { - if (!_anchorable.TileFree(_grid, tile, DungeonSystem.CollisionLayer, DungeonSystem.CollisionMask)) - continue; - - // Check each direction: - // - Check if immediate neighbors are free - // - Check if the neighbors beyond that are not free - // - Then check either side if they're slightly more free - var exteriorWidth = (int) Math.Floor(gen.Width / 2f); - var width = (int) Math.Ceiling(gen.Width / 2f); - - for (var i = 0; i < 2; i++) - { - var isValid = true; - var neighborDir = (Direction) (i * 2); - var neighborVec = neighborDir.ToIntVec(); - - for (var j = -width; j <= width; j++) - { - if (j == 0) - continue; - - var neighbor = tile + neighborVec * j; - - // If it's an end tile then check it's occupied. - if (j == -width || - j == width) - { - if (!HasWall(grid, neighbor)) - { - isValid = false; - break; - } - - continue; - } - - // If we're not at the end tile then check it + perpendicular are free. - if (!_anchorable.TileFree(_grid, neighbor, DungeonSystem.CollisionLayer, DungeonSystem.CollisionMask)) - { - isValid = false; - break; - } - - var perp1 = tile + neighborVec * j + ((Direction) ((i * 2 + 2) % 8)).ToIntVec(); - var perp2 = tile + neighborVec * j + ((Direction) ((i * 2 + 6) % 8)).ToIntVec(); - - if (!_anchorable.TileFree(_grid, perp1, DungeonSystem.CollisionLayer, DungeonSystem.CollisionMask)) - { - isValid = false; - break; - } - - if (!_anchorable.TileFree(_grid, perp2, DungeonSystem.CollisionLayer, DungeonSystem.CollisionMask)) - { - isValid = false; - break; - } - } - - if (!isValid) - continue; - - // Check corners to see if either side opens up (if it's just a 1x wide corridor do nothing, needs to be a funnel. - foreach (var j in new [] {-exteriorWidth, exteriorWidth}) - { - var freeCount = 0; - - // Need at least 3 of 4 free - for (var k = 0; k < 4; k++) - { - var cornerDir = (Direction) (k * 2 + 1); - var cornerVec = cornerDir.ToIntVec(); - var cornerNeighbor = tile + neighborVec * j + cornerVec; - - if (_anchorable.TileFree(_grid, cornerNeighbor, DungeonSystem.CollisionLayer, DungeonSystem.CollisionMask)) - { - freeCount++; - } - } - - if (freeCount < gen.Width) - continue; - - // Valid! - isValid = true; - - for (var x = -width + 1; x < width; x++) - { - var weh = tile + neighborDir.ToIntVec() * x; - grid.SetTile(weh, _tile.GetVariantTile((ContentTileDefinition) tileDef, random)); - - var coords = grid.GridTileToLocal(weh); - _entManager.SpawnEntities(coords, gen.Entities); - } - - break; - } - - if (isValid) - { - await SuspendIfOutOfTime(); - - if (!ValidateResume()) - return; - } - - break; - } - } - } - - private async Task PostGen(MiddleConnectionPostGen gen, Dungeon dungeon, EntityUid gridUid, MapGridComponent grid, Random random) - { - // TODO: Need a minimal spanning tree version tbh - - // Grab all of the room bounds - // Then, work out connections between them - var roomBorders = new Dictionary>(dungeon.Rooms.Count); - - foreach (var room in dungeon.Rooms) - { - var roomEdges = new HashSet(); - - foreach (var index in room.Tiles) - { - for (var x = -1; x <= 1; x++) - { - for (var y = -1; y <= 1; y++) - { - // Cardinals only - if (x != 0 && y != 0 || - x == 0 && y == 0) - { - continue; - } - - var neighbor = new Vector2i(index.X + x, index.Y + y); - - if (dungeon.RoomTiles.Contains(neighbor)) - continue; - - if (!_anchorable.TileFree(grid, neighbor, DungeonSystem.CollisionLayer, DungeonSystem.CollisionMask)) - continue; - - roomEdges.Add(neighbor); - } - } - } - - roomBorders.Add(room, roomEdges); - } - - // Do pathfind from first room to work out graph. - // TODO: Optional loops - - var roomConnections = new Dictionary>(); - var frontier = new Queue(); - frontier.Enqueue(dungeon.Rooms.First()); - var tileDef = _tileDefManager[gen.Tile]; - - foreach (var (room, border) in roomBorders) - { - var conns = roomConnections.GetOrNew(room); - - foreach (var (otherRoom, otherBorders) in roomBorders) - { - if (room.Equals(otherRoom) || - conns.Contains(otherRoom)) - { - continue; - } - - var flipp = new HashSet(border); - flipp.IntersectWith(otherBorders); - - if (flipp.Count == 0 || - gen.OverlapCount != -1 && flipp.Count != gen.OverlapCount) - continue; - - var center = Vector2.Zero; - - foreach (var node in flipp) - { - center += (Vector2) node + grid.TileSizeHalfVector; - } - - center /= flipp.Count; - // Weight airlocks towards center more. - var nodeDistances = new List<(Vector2i Node, float Distance)>(flipp.Count); - - foreach (var node in flipp) - { - nodeDistances.Add((node, ((Vector2) node + grid.TileSizeHalfVector - center).LengthSquared())); - } - - nodeDistances.Sort((x, y) => x.Distance.CompareTo(y.Distance)); - - var width = gen.Count; - - for (var i = 0; i < nodeDistances.Count; i++) - { - var node = nodeDistances[i].Node; - var gridPos = grid.GridTileToLocal(node); - if (!_anchorable.TileFree(grid, node, DungeonSystem.CollisionLayer, DungeonSystem.CollisionMask)) - continue; - - width--; - grid.SetTile(node, _tile.GetVariantTile((ContentTileDefinition) tileDef, random)); - - if (gen.EdgeEntities != null && nodeDistances.Count - i <= 2) - { - _entManager.SpawnEntities(gridPos, gen.EdgeEntities); - } - else - { - // Iterate neighbors and check for blockers, if so bulldoze - ClearDoor(dungeon, grid, node); - - _entManager.SpawnEntities(gridPos, gen.Entities); - } - - if (width == 0) - break; - } - - conns.Add(otherRoom); - var otherConns = roomConnections.GetOrNew(otherRoom); - otherConns.Add(room); - await SuspendIfOutOfTime(); - - if (!ValidateResume()) - return; - } - } - } - - /// - /// Removes any unwanted obstacles around a door tile. - /// - private void ClearDoor(Dungeon dungeon, MapGridComponent grid, Vector2i indices, bool strict = false) - { - var flags = strict - ? LookupFlags.Dynamic | LookupFlags.Static | LookupFlags.StaticSundries - : LookupFlags.Dynamic | LookupFlags.Static; - var physicsQuery = _entManager.GetEntityQuery(); - - for (var x = -1; x <= 1; x++) - { - for (var y = -1; y <= 1; y++) - { - if (x != 0 && y != 0) - continue; - - var neighbor = new Vector2i(indices.X + x, indices.Y + y); - - if (!dungeon.RoomTiles.Contains(neighbor)) - continue; - - // Shrink by 0.01 to avoid polygon overlap from neighboring tiles. - foreach (var ent in _lookup.GetEntitiesIntersecting(_gridUid, new Box2(neighbor * grid.TileSize, (neighbor + 1) * grid.TileSize).Enlarged(-0.1f), flags)) - { - if (!physicsQuery.TryGetComponent(ent, out var physics) || - !physics.Hard || - (DungeonSystem.CollisionMask & physics.CollisionLayer) == 0x0 && - (DungeonSystem.CollisionLayer & physics.CollisionMask) == 0x0) - { - continue; - } - - _entManager.DeleteEntity(ent); - } - } - } - } - - private async Task PostGen(WallMountPostGen gen, Dungeon dungeon, EntityUid gridUid, MapGridComponent grid, - Random random) - { - var tileDef = _tileDefManager[gen.Tile]; - var checkedTiles = new HashSet(); - var allExterior = new HashSet(dungeon.CorridorExteriorTiles); - allExterior.UnionWith(dungeon.RoomExteriorTiles); - var count = 0; - - foreach (var neighbor in allExterior) - { - // Occupado - if (dungeon.RoomTiles.Contains(neighbor) || checkedTiles.Contains(neighbor) || !_anchorable.TileFree(grid, neighbor, DungeonSystem.CollisionLayer, DungeonSystem.CollisionMask)) - continue; - - if (!random.Prob(gen.Prob) || !checkedTiles.Add(neighbor)) - continue; - - grid.SetTile(neighbor, _tile.GetVariantTile((ContentTileDefinition) tileDef, random)); - var gridPos = grid.GridTileToLocal(neighbor); - var protoNames = EntitySpawnCollection.GetSpawns(gen.Spawns, random); - - _entManager.SpawnEntities(gridPos, protoNames); - count += protoNames.Count; - - if (count > 20) - { - count -= 20; - await SuspendIfOutOfTime(); - - if (!ValidateResume()) - return; - } - } - } -} diff --git a/Content.Server/Procedural/DungeonJob.PostGenBiome.cs b/Content.Server/Procedural/DungeonJob.PostGenBiome.cs deleted file mode 100644 index 4d3f573f4d4..00000000000 --- a/Content.Server/Procedural/DungeonJob.PostGenBiome.cs +++ /dev/null @@ -1,138 +0,0 @@ -using System.Threading.Tasks; -using Content.Server.Parallax; -using Content.Shared.Parallax.Biomes; -using Content.Shared.Parallax.Biomes.Markers; -using Content.Shared.Procedural; -using Content.Shared.Procedural.PostGeneration; -using Content.Shared.Random.Helpers; -using Robust.Shared.Map; -using Robust.Shared.Map.Components; -using Robust.Shared.Utility; - -namespace Content.Server.Procedural; - -public sealed partial class DungeonJob -{ - /* - * Handles PostGen code for marker layers + biomes. - */ - - private async Task PostGen(BiomePostGen postGen, Dungeon dungeon, EntityUid gridUid, MapGridComponent grid, Random random) - { - if (_entManager.TryGetComponent(gridUid, out BiomeComponent? biomeComp)) - return; - - biomeComp = _entManager.AddComponent(gridUid); - var biomeSystem = _entManager.System(); - biomeSystem.SetTemplate(gridUid, biomeComp, _prototype.Index(postGen.BiomeTemplate)); - var seed = random.Next(); - var xformQuery = _entManager.GetEntityQuery(); - - foreach (var node in dungeon.RoomTiles) - { - // Need to set per-tile to override data. - if (biomeSystem.TryGetTile(node, biomeComp.Layers, seed, grid, out var tile)) - { - _maps.SetTile(gridUid, grid, node, tile.Value); - } - - if (biomeSystem.TryGetDecals(node, biomeComp.Layers, seed, grid, out var decals)) - { - foreach (var decal in decals) - { - _decals.TryAddDecal(decal.ID, new EntityCoordinates(gridUid, decal.Position), out _); - } - } - - if (biomeSystem.TryGetEntity(node, biomeComp, grid, out var entityProto)) - { - var ent = _entManager.SpawnEntity(entityProto, new EntityCoordinates(gridUid, node + grid.TileSizeHalfVector)); - var xform = xformQuery.Get(ent); - - if (!xform.Comp.Anchored) - { - _transform.AnchorEntity(ent, xform); - } - - // TODO: Engine bug with SpawnAtPosition - DebugTools.Assert(xform.Comp.Anchored); - } - - await SuspendIfOutOfTime(); - ValidateResume(); - } - - biomeComp.Enabled = false; - } - - private async Task PostGen(BiomeMarkerLayerPostGen postGen, Dungeon dungeon, EntityUid gridUid, MapGridComponent grid, Random random) - { - if (!_entManager.TryGetComponent(gridUid, out BiomeComponent? biomeComp)) - return; - - var biomeSystem = _entManager.System(); - var weightedRandom = _prototype.Index(postGen.MarkerTemplate); - var xformQuery = _entManager.GetEntityQuery(); - var templates = new Dictionary(); - - for (var i = 0; i < postGen.Count; i++) - { - var template = weightedRandom.Pick(random); - var count = templates.GetOrNew(template); - count++; - templates[template] = count; - } - - foreach (var (template, count) in templates) - { - var markerTemplate = _prototype.Index(template); - - var bounds = new Box2i(); - - foreach (var tile in dungeon.RoomTiles) - { - bounds = bounds.UnionTile(tile); - } - - await SuspendIfOutOfTime(); - ValidateResume(); - - biomeSystem.GetMarkerNodes(gridUid, biomeComp, grid, markerTemplate, true, bounds, count, - random, out var spawnSet, out var existing, false); - - await SuspendIfOutOfTime(); - ValidateResume(); - - foreach (var ent in existing) - { - _entManager.DeleteEntity(ent); - } - - await SuspendIfOutOfTime(); - ValidateResume(); - - foreach (var (node, mask) in spawnSet) - { - string? proto; - - if (mask != null && markerTemplate.EntityMask.TryGetValue(mask, out var maskedProto)) - { - proto = maskedProto; - } - else - { - proto = markerTemplate.Prototype; - } - - var ent = _entManager.SpawnAtPosition(proto, new EntityCoordinates(gridUid, node + grid.TileSizeHalfVector)); - var xform = xformQuery.Get(ent); - - if (!xform.Comp.Anchored) - _transform.AnchorEntity(ent, xform); - - await SuspendIfOutOfTime(); - ValidateResume(); - } - } - } -} diff --git a/Content.Server/Procedural/DungeonJob.cs b/Content.Server/Procedural/DungeonJob.cs deleted file mode 100644 index bf2822ff423..00000000000 --- a/Content.Server/Procedural/DungeonJob.cs +++ /dev/null @@ -1,192 +0,0 @@ -using System.Threading; -using System.Threading.Tasks; -using Content.Server.Construction; -using Robust.Shared.CPUJob.JobQueues; -using Content.Server.Decals; -using Content.Shared.Construction.EntitySystems; -using Content.Shared.Maps; -using Content.Shared.Procedural; -using Content.Shared.Procedural.DungeonGenerators; -using Content.Shared.Procedural.PostGeneration; -using Content.Shared.Tag; -using Robust.Server.Physics; -using Robust.Shared.Map; -using Robust.Shared.Map.Components; -using Robust.Shared.Prototypes; -using Robust.Shared.Utility; - -namespace Content.Server.Procedural; - -public sealed partial class DungeonJob : Job -{ - private readonly IEntityManager _entManager; - private readonly IMapManager _mapManager; - private readonly IPrototypeManager _prototype; - private readonly ITileDefinitionManager _tileDefManager; - - private readonly AnchorableSystem _anchorable; - private readonly DecalSystem _decals; - private readonly DungeonSystem _dungeon; - private readonly EntityLookupSystem _lookup; - private readonly TagSystem _tag; - private readonly TileSystem _tile; - private readonly SharedMapSystem _maps; - private readonly SharedTransformSystem _transform; - - private readonly DungeonConfigPrototype _gen; - private readonly int _seed; - private readonly Vector2i _position; - - private readonly MapGridComponent _grid; - private readonly EntityUid _gridUid; - - private readonly ISawmill _sawmill; - - public DungeonJob( - ISawmill sawmill, - double maxTime, - IEntityManager entManager, - IMapManager mapManager, - IPrototypeManager prototype, - ITileDefinitionManager tileDefManager, - AnchorableSystem anchorable, - DecalSystem decals, - DungeonSystem dungeon, - EntityLookupSystem lookup, - TagSystem tag, - TileSystem tile, - SharedTransformSystem transform, - DungeonConfigPrototype gen, - MapGridComponent grid, - EntityUid gridUid, - int seed, - Vector2i position, - CancellationToken cancellation = default) : base(maxTime, cancellation) - { - _sawmill = sawmill; - _entManager = entManager; - _mapManager = mapManager; - _prototype = prototype; - _tileDefManager = tileDefManager; - - _anchorable = anchorable; - _decals = decals; - _dungeon = dungeon; - _lookup = lookup; - _tag = tag; - _tile = tile; - _maps = _entManager.System(); - _transform = transform; - - _gen = gen; - _grid = grid; - _gridUid = gridUid; - _seed = seed; - _position = position; - } - - protected override async Task Process() - { - Dungeon dungeon; - _sawmill.Info($"Generating dungeon {_gen.ID} with seed {_seed} on {_entManager.ToPrettyString(_gridUid)}"); - _grid.CanSplit = false; - - switch (_gen.Generator) - { - case NoiseDunGen noise: - dungeon = await GenerateNoiseDungeon(noise, _gridUid, _grid, _seed); - break; - case PrefabDunGen prefab: - dungeon = await GeneratePrefabDungeon(prefab, _gridUid, _grid, _seed); - DebugTools.Assert(dungeon.RoomExteriorTiles.Count > 0); - break; - default: - throw new NotImplementedException(); - } - - DebugTools.Assert(dungeon.RoomTiles.Count > 0); - - // To make it slightly more deterministic treat this RNG as separate ig. - var random = new Random(_seed); - - foreach (var post in _gen.PostGeneration) - { - _sawmill.Debug($"Doing postgen {post.GetType()} for {_gen.ID} with seed {_seed}"); - - switch (post) - { - case AutoCablingPostGen cabling: - await PostGen(cabling, dungeon, _gridUid, _grid, random); - break; - case BiomePostGen biome: - await PostGen(biome, dungeon, _gridUid, _grid, random); - break; - case BoundaryWallPostGen boundary: - await PostGen(boundary, dungeon, _gridUid, _grid, random); - break; - case CornerClutterPostGen clutter: - await PostGen(clutter, dungeon, _gridUid, _grid, random); - break; - case CorridorClutterPostGen corClutter: - await PostGen(corClutter, dungeon, _gridUid, _grid, random); - break; - case CorridorPostGen cordor: - await PostGen(cordor, dungeon, _gridUid, _grid, random); - break; - case CorridorDecalSkirtingPostGen decks: - await PostGen(decks, dungeon, _gridUid, _grid, random); - break; - case EntranceFlankPostGen flank: - await PostGen(flank, dungeon, _gridUid, _grid, random); - break; - case JunctionPostGen junc: - await PostGen(junc, dungeon, _gridUid, _grid, random); - break; - case MiddleConnectionPostGen dordor: - await PostGen(dordor, dungeon, _gridUid, _grid, random); - break; - case DungeonEntrancePostGen entrance: - await PostGen(entrance, dungeon, _gridUid, _grid, random); - break; - case ExternalWindowPostGen externalWindow: - await PostGen(externalWindow, dungeon, _gridUid, _grid, random); - break; - case InternalWindowPostGen internalWindow: - await PostGen(internalWindow, dungeon, _gridUid, _grid, random); - break; - case BiomeMarkerLayerPostGen markerPost: - await PostGen(markerPost, dungeon, _gridUid, _grid, random); - break; - case RoomEntrancePostGen rEntrance: - await PostGen(rEntrance, dungeon, _gridUid, _grid, random); - break; - case WallMountPostGen wall: - await PostGen(wall, dungeon, _gridUid, _grid, random); - break; - case WormCorridorPostGen worm: - await PostGen(worm, dungeon, _gridUid, _grid, random); - break; - default: - throw new NotImplementedException(); - } - - await SuspendIfOutOfTime(); - - if (!ValidateResume()) - break; - } - - // Defer splitting so they don't get spammed and so we don't have to worry about tracking the grid along the way. - _grid.CanSplit = true; - _entManager.System().CheckSplits(_gridUid); - return dungeon; - } - - private bool ValidateResume() - { - if (_entManager.Deleted(_gridUid)) - return false; - - return true; - } -} diff --git a/Content.Server/Procedural/DungeonJob/DungeonJob.DunGenExterior.cs b/Content.Server/Procedural/DungeonJob/DungeonJob.DunGenExterior.cs new file mode 100644 index 00000000000..acffd057fad --- /dev/null +++ b/Content.Server/Procedural/DungeonJob/DungeonJob.DunGenExterior.cs @@ -0,0 +1,58 @@ +using System.Threading.Tasks; +using Content.Server.NPC.Pathfinding; +using Content.Shared.Maps; +using Content.Shared.Procedural; +using Content.Shared.Procedural.DungeonGenerators; +using Robust.Shared.Collections; +using Robust.Shared.Random; +using Robust.Shared.Utility; + +namespace Content.Server.Procedural.DungeonJob; + +public sealed partial class DungeonJob +{ + /// + /// + /// + private async Task> GenerateExteriorDungen(Vector2i position, ExteriorDunGen dungen, HashSet reservedTiles, Random random) + { + DebugTools.Assert(_grid.ChunkCount > 0); + + var aabb = new Box2i(_grid.LocalAABB.BottomLeft.Floored(), _grid.LocalAABB.TopRight.Floored()); + var angle = random.NextAngle(); + + var distance = Math.Max(aabb.Width / 2f + 1f, aabb.Height / 2f + 1f); + + var startTile = new Vector2i(0, (int) distance).Rotate(angle); + + Vector2i? dungeonSpawn = null; + var pathfinder = _entManager.System(); + + // Gridcast + pathfinder.GridCast(startTile, position, tile => + { + if (!_maps.TryGetTileRef(_gridUid, _grid, tile, out var tileRef) || + tileRef.Tile.IsSpace(_tileDefManager)) + { + return true; + } + + dungeonSpawn = tile; + return false; + }); + + if (dungeonSpawn == null) + { + return new List() + { + Dungeon.Empty + }; + } + + var config = _prototype.Index(dungen.Proto); + var nextSeed = random.Next(); + var dungeons = await GetDungeons(dungeonSpawn.Value, config, config.Data, config.Layers, reservedTiles, nextSeed, new Random(nextSeed)); + + return dungeons; + } +} diff --git a/Content.Server/Procedural/DungeonJob/DungeonJob.DunGenFill.cs b/Content.Server/Procedural/DungeonJob/DungeonJob.DunGenFill.cs new file mode 100644 index 00000000000..5a0d77c6151 --- /dev/null +++ b/Content.Server/Procedural/DungeonJob/DungeonJob.DunGenFill.cs @@ -0,0 +1,50 @@ +using System.Numerics; +using System.Threading.Tasks; +using Content.Shared.Procedural; +using Content.Shared.Procedural.DungeonGenerators; + +namespace Content.Server.Procedural.DungeonJob; + +public sealed partial class DungeonJob +{ + /// + /// + /// + private async Task GenerateFillDunGen(DungeonData data, HashSet reservedTiles) + { + if (!data.Entities.TryGetValue(DungeonDataKey.Fill, out var fillEnt)) + { + LogDataError(typeof(FillGridDunGen)); + return Dungeon.Empty; + } + + var roomTiles = new HashSet(); + var tiles = _maps.GetAllTilesEnumerator(_gridUid, _grid); + + while (tiles.MoveNext(out var tileRef)) + { + var tile = tileRef.Value.GridIndices; + + if (reservedTiles.Contains(tile)) + continue; + + if (!_anchorable.TileFree(_grid, tile, DungeonSystem.CollisionLayer, DungeonSystem.CollisionMask)) + continue; + + var gridPos = _maps.GridTileToLocal(_gridUid, _grid, tile); + _entManager.SpawnEntity(fillEnt, gridPos); + + roomTiles.Add(tile); + + await SuspendDungeon(); + if (!ValidateResume()) + break; + } + + var dungeon = new Dungeon(); + var room = new DungeonRoom(roomTiles, Vector2.Zero, Box2i.Empty, new HashSet()); + dungeon.AddRoom(room); + + return dungeon; + } +} diff --git a/Content.Server/Procedural/DungeonJob.NoiseDunGen.cs b/Content.Server/Procedural/DungeonJob/DungeonJob.DunGenNoise.cs similarity index 73% rename from Content.Server/Procedural/DungeonJob.NoiseDunGen.cs rename to Content.Server/Procedural/DungeonJob/DungeonJob.DunGenNoise.cs index 73c3386ead5..b2526ec17d1 100644 --- a/Content.Server/Procedural/DungeonJob.NoiseDunGen.cs +++ b/Content.Server/Procedural/DungeonJob/DungeonJob.DunGenNoise.cs @@ -4,19 +4,25 @@ using Content.Shared.Procedural; using Content.Shared.Procedural.DungeonGenerators; using Robust.Shared.Map; -using Robust.Shared.Map.Components; using Robust.Shared.Random; using Robust.Shared.Utility; -namespace Content.Server.Procedural; +namespace Content.Server.Procedural.DungeonJob; public sealed partial class DungeonJob { - private async Task GenerateNoiseDungeon(NoiseDunGen dungen, EntityUid gridUid, MapGridComponent grid, - int seed) + /// + /// + /// + private async Task GenerateNoiseDunGen( + Vector2i position, + NoiseDunGen dungen, + HashSet reservedTiles, + int seed, + Random random) { - var rand = new Random(seed); var tiles = new List<(Vector2i, Tile)>(); + var matrix = Matrix3Helpers.CreateTranslation(position); foreach (var layer in dungen.Layers) { @@ -30,7 +36,7 @@ private async Task GenerateNoiseDungeon(NoiseDunGen dungen, EntityUid g var frontier = new Queue(); var rooms = new List(); var tileCount = 0; - var tileCap = rand.NextGaussian(dungen.TileCap, dungen.CapStd); + var tileCap = random.NextGaussian(dungen.TileCap, dungen.CapStd); var visited = new HashSet(); while (iterations > 0 && tileCount < tileCap) @@ -39,22 +45,22 @@ private async Task GenerateNoiseDungeon(NoiseDunGen dungen, EntityUid g iterations--; // Get a random exterior tile to start floodfilling from. - var edge = rand.Next(4); + var edge = random.Next(4); Vector2i seedTile; switch (edge) { case 0: - seedTile = new Vector2i(rand.Next(area.Left - 2, area.Right + 1), area.Bottom - 2); + seedTile = new Vector2i(random.Next(area.Left - 2, area.Right + 1), area.Bottom - 2); break; case 1: - seedTile = new Vector2i(area.Right + 1, rand.Next(area.Bottom - 2, area.Top + 1)); + seedTile = new Vector2i(area.Right + 1, random.Next(area.Bottom - 2, area.Top + 1)); break; case 2: - seedTile = new Vector2i(rand.Next(area.Left - 2, area.Right + 1), area.Top + 1); + seedTile = new Vector2i(random.Next(area.Left - 2, area.Right + 1), area.Top + 1); break; case 3: - seedTile = new Vector2i(area.Left - 2, rand.Next(area.Bottom - 2, area.Top + 1)); + seedTile = new Vector2i(area.Left - 2, random.Next(area.Bottom - 2, area.Top + 1)); break; default: throw new ArgumentOutOfRangeException(); @@ -80,14 +86,20 @@ private async Task GenerateNoiseDungeon(NoiseDunGen dungen, EntityUid g if (value < layer.Threshold) continue; - roomArea = roomArea.UnionTile(node); foundNoise = true; noiseFill = true; + + // Still want the tile to gen as normal but can't do anything with it. + if (reservedTiles.Contains(node)) + break; + + roomArea = roomArea.UnionTile(node); var tileDef = _tileDefManager[layer.Tile]; - var variant = _tile.PickVariant((ContentTileDefinition) tileDef, rand); + var variant = _tile.PickVariant((ContentTileDefinition) tileDef, random); + var adjusted = Vector2.Transform(node + _grid.TileSizeHalfVector, matrix).Floored(); - tiles.Add((node, new Tile(tileDef.TileId, variant: variant))); - roomTiles.Add(node); + tiles.Add((adjusted, new Tile(tileDef.TileId, variant: variant))); + roomTiles.Add(adjusted); tileCount++; break; } @@ -123,7 +135,7 @@ private async Task GenerateNoiseDungeon(NoiseDunGen dungen, EntityUid g foreach (var tile in roomTiles) { - center += tile + grid.TileSizeHalfVector; + center += tile + _grid.TileSizeHalfVector; } center /= roomTiles.Count; @@ -132,15 +144,8 @@ private async Task GenerateNoiseDungeon(NoiseDunGen dungen, EntityUid g ValidateResume(); } - grid.SetTiles(tiles); - + _maps.SetTiles(_gridUid, _grid, tiles); var dungeon = new Dungeon(rooms); - - foreach (var tile in tiles) - { - dungeon.RoomTiles.Add(tile.Item1); - } - return dungeon; } } diff --git a/Content.Server/Procedural/DungeonJob/DungeonJob.DunGenNoiseDistance.cs b/Content.Server/Procedural/DungeonJob/DungeonJob.DunGenNoiseDistance.cs new file mode 100644 index 00000000000..f1808ec90cd --- /dev/null +++ b/Content.Server/Procedural/DungeonJob/DungeonJob.DunGenNoiseDistance.cs @@ -0,0 +1,112 @@ +using System.Numerics; +using System.Threading.Tasks; +using Content.Shared.Maps; +using Content.Shared.Procedural; +using Content.Shared.Procedural.Distance; +using Content.Shared.Procedural.DungeonGenerators; +using Robust.Shared.Map; + +namespace Content.Server.Procedural.DungeonJob; + +public sealed partial class DungeonJob +{ + /* + * See https://www.redblobgames.com/maps/terrain-from-noise/#islands + * Really it's just blending from the original noise (which may occupy the entire area) + * with some other shape to confine it into a bounds more naturally. + * https://old.reddit.com/r/proceduralgeneration/comments/kaen7h/new_video_on_procedural_island_noise_generation/gfjmgen/ also has more variations + */ + + /// + /// + /// + private async Task GenerateNoiseDistanceDunGen( + Vector2i position, + NoiseDistanceDunGen dungen, + HashSet reservedTiles, + int seed, + Random random) + { + var tiles = new List<(Vector2i, Tile)>(); + var matrix = Matrix3Helpers.CreateTranslation(position); + + foreach (var layer in dungen.Layers) + { + layer.Noise.SetSeed(seed); + } + + // First we have to find a seed tile, then floodfill from there until we get to noise + // at which point we floodfill the entire noise. + var area = Box2i.FromDimensions(-dungen.Size / 2, dungen.Size); + var roomTiles = new HashSet(); + var width = (float) area.Width; + var height = (float) area.Height; + + for (var x = area.Left; x <= area.Right; x++) + { + for (var y = area.Bottom; y <= area.Top; y++) + { + var node = new Vector2i(x, y); + + foreach (var layer in dungen.Layers) + { + var value = layer.Noise.GetNoise(node.X, node.Y); + + if (dungen.DistanceConfig != null) + { + // Need to get dx - dx in a range from -1 -> 1 + var dx = 2 * x / width; + var dy = 2 * y / height; + + var distance = GetDistance(dx, dy, dungen.DistanceConfig); + + value = MathHelper.Lerp(value, 1f - distance, dungen.DistanceConfig.BlendWeight); + } + + if (value < layer.Threshold) + continue; + + var tileDef = _tileDefManager[layer.Tile]; + var variant = _tile.PickVariant((ContentTileDefinition) tileDef, random); + var adjusted = Vector2.Transform(node + _grid.TileSizeHalfVector, matrix).Floored(); + + // Do this down here because noise has a much higher chance of failing than reserved tiles. + if (reservedTiles.Contains(adjusted)) + { + break; + } + + tiles.Add((adjusted, new Tile(tileDef.TileId, variant: variant))); + roomTiles.Add(adjusted); + break; + } + } + + await SuspendDungeon(); + } + + var room = new DungeonRoom(roomTiles, area.Center, area, new HashSet()); + + _maps.SetTiles(_gridUid, _grid, tiles); + var dungeon = new Dungeon(new List() + { + room, + }); + + await SuspendDungeon(); + return dungeon; + } + + private float GetDistance(float dx, float dy, IDunGenDistance distance) + { + switch (distance) + { + case DunGenEuclideanSquaredDistance: + return MathF.Min(1f, (dx * dx + dy * dy) / MathF.Sqrt(2)); + case DunGenSquareBump: + return 1f - (1f - dx * dx) * (1f - dy * dy); + default: + throw new ArgumentOutOfRangeException(); + } + } +} diff --git a/Content.Server/Procedural/DungeonJob.PrefabDunGen.cs b/Content.Server/Procedural/DungeonJob/DungeonJob.DunGenPrefab.cs similarity index 82% rename from Content.Server/Procedural/DungeonJob.PrefabDunGen.cs rename to Content.Server/Procedural/DungeonJob/DungeonJob.DunGenPrefab.cs index a19f7e4701d..33bbeba4b53 100644 --- a/Content.Server/Procedural/DungeonJob.PrefabDunGen.cs +++ b/Content.Server/Procedural/DungeonJob/DungeonJob.DunGenPrefab.cs @@ -1,25 +1,33 @@ using System.Numerics; using System.Threading.Tasks; -using Content.Shared.Decals; using Content.Shared.Procedural; using Content.Shared.Procedural.DungeonGenerators; +using Content.Shared.Whitelist; using Robust.Shared.Map; -using Robust.Shared.Map.Components; using Robust.Shared.Random; using Robust.Shared.Utility; -namespace Content.Server.Procedural; +namespace Content.Server.Procedural.DungeonJob; public sealed partial class DungeonJob { - private async Task GeneratePrefabDungeon(PrefabDunGen prefab, EntityUid gridUid, MapGridComponent grid, int seed) + /// + /// + /// + private async Task GeneratePrefabDunGen(Vector2i position, DungeonData data, PrefabDunGen prefab, HashSet reservedTiles, Random random) { - var random = new Random(seed); + if (!data.Tiles.TryGetValue(DungeonDataKey.FallbackTile, out var tileProto) || + !data.Whitelists.TryGetValue(DungeonDataKey.Rooms, out var roomWhitelist)) + { + LogDataError(typeof(PrefabDunGen)); + return Dungeon.Empty; + } + var preset = prefab.Presets[random.Next(prefab.Presets.Count)]; - var gen = _prototype.Index(preset); + var gen = _prototype.Index(preset); - var dungeonRotation = _dungeon.GetDungeonRotation(seed); - var dungeonTransform = Matrix3Helpers.CreateTransform(_position, dungeonRotation); + var dungeonRotation = _dungeon.GetDungeonRotation(random.Next()); + var dungeonTransform = Matrix3Helpers.CreateTransform(position, dungeonRotation); var roomPackProtos = new Dictionary>(); foreach (var pack in _prototype.EnumeratePrototypes()) @@ -42,12 +50,15 @@ private async Task GeneratePrefabDungeon(PrefabDunGen prefab, EntityUid { var whitelisted = false; - foreach (var tag in prefab.RoomWhitelist) + if (roomWhitelist?.Tags != null) { - if (proto.Tags.Contains(tag)) + foreach (var tag in roomWhitelist.Tags) { - whitelisted = true; - break; + if (proto.Tags.Contains(tag)) + { + whitelisted = true; + break; + } } } @@ -182,12 +193,16 @@ private async Task GeneratePrefabDungeon(PrefabDunGen prefab, EntityUid { for (var y = roomSize.Bottom; y < roomSize.Top; y++) { - var index = Vector2.Transform(new Vector2(x, y) + grid.TileSizeHalfVector - packCenter, matty).Floored(); - tiles.Add((index, new Tile(_tileDefManager["FloorPlanetGrass"].TileId))); + var index = Vector2.Transform(new Vector2(x, y) + _grid.TileSizeHalfVector - packCenter, matty).Floored(); + + if (reservedTiles.Contains(index)) + continue; + + tiles.Add((index, new Tile(_tileDefManager[tileProto].TileId))); } } - grid.SetTiles(tiles); + _maps.SetTiles(_gridUid, _grid, tiles); tiles.Clear(); _sawmill.Error($"Unable to find room variant for {roomDimensions}, leaving empty."); continue; @@ -215,12 +230,12 @@ private async Task GeneratePrefabDungeon(PrefabDunGen prefab, EntityUid var dungeonMatty = Matrix3x2.Multiply(matty, dungeonTransform); // The expensive bit yippy. - _dungeon.SpawnRoom(gridUid, grid, dungeonMatty, room); + _dungeon.SpawnRoom(_gridUid, _grid, dungeonMatty, room, reservedTiles); - var roomCenter = (room.Offset + room.Size / 2f) * grid.TileSize; + var roomCenter = (room.Offset + room.Size / 2f) * _grid.TileSize; var roomTiles = new HashSet(room.Size.X * room.Size.Y); var exterior = new HashSet(room.Size.X * 2 + room.Size.Y * 2); - var tileOffset = -roomCenter + grid.TileSizeHalfVector; + var tileOffset = -roomCenter + _grid.TileSizeHalfVector; Box2i? mapBounds = null; for (var x = -1; x <= room.Size.X; x++) @@ -232,8 +247,12 @@ private async Task GeneratePrefabDungeon(PrefabDunGen prefab, EntityUid continue; } - var tilePos = Vector2.Transform(new Vector2i(x + room.Offset.X, y + room.Offset.Y) + tileOffset, dungeonMatty); - exterior.Add(tilePos.Floored()); + var tilePos = Vector2.Transform(new Vector2i(x + room.Offset.X, y + room.Offset.Y) + tileOffset, dungeonMatty).Floored(); + + if (reservedTiles.Contains(tilePos)) + continue; + + exterior.Add(tilePos); } } @@ -249,38 +268,36 @@ private async Task GeneratePrefabDungeon(PrefabDunGen prefab, EntityUid roomTiles.Add(tileIndex); mapBounds = mapBounds?.Union(tileIndex) ?? new Box2i(tileIndex, tileIndex); - center += tilePos + grid.TileSizeHalfVector; + center += tilePos + _grid.TileSizeHalfVector; } } center /= roomTiles.Count; - dungeon.Rooms.Add(new DungeonRoom(roomTiles, center, mapBounds!.Value, exterior)); + dungeon.AddRoom(new DungeonRoom(roomTiles, center, mapBounds!.Value, exterior)); + + await SuspendDungeon(); - await SuspendIfOutOfTime(); - ValidateResume(); + if (!ValidateResume()) + return Dungeon.Empty; } } // Calculate center and do entrances var dungeonCenter = Vector2.Zero; - foreach (var room in dungeon.Rooms) - { - dungeon.RoomTiles.UnionWith(room.Tiles); - dungeon.RoomExteriorTiles.UnionWith(room.Exterior); - } - foreach (var room in dungeon.Rooms) { dungeonCenter += room.Center; - SetDungeonEntrance(dungeon, room, random); + SetDungeonEntrance(dungeon, room, reservedTiles, random); } + dungeon.Rebuild(); + return dungeon; } - private void SetDungeonEntrance(Dungeon dungeon, DungeonRoom room, Random random) + private void SetDungeonEntrance(Dungeon dungeon, DungeonRoom room, HashSet reservedTiles, Random random) { // TODO: Move to dungeonsystem. @@ -323,8 +340,10 @@ private void SetDungeonEntrance(Dungeon dungeon, DungeonRoom room, Random random continue; } + if (reservedTiles.Contains(entrancePos)) + continue; + room.Entrances.Add(entrancePos); - dungeon.Entrances.Add(entrancePos); break; } } diff --git a/Content.Server/Procedural/DungeonJob/DungeonJob.DunGenReplaceTile.cs b/Content.Server/Procedural/DungeonJob/DungeonJob.DunGenReplaceTile.cs new file mode 100644 index 00000000000..6b36d101095 --- /dev/null +++ b/Content.Server/Procedural/DungeonJob/DungeonJob.DunGenReplaceTile.cs @@ -0,0 +1,60 @@ +using System.Threading.Tasks; +using Content.Shared.Procedural; +using Content.Shared.Procedural.DungeonGenerators; +using Content.Shared.Procedural.PostGeneration; +using Robust.Shared.Map; +using Robust.Shared.Random; + +namespace Content.Server.Procedural.DungeonJob; + +public sealed partial class DungeonJob +{ + /// + /// + /// + private async Task GenerateTileReplacementDunGen(ReplaceTileDunGen gen, DungeonData data, HashSet reservedTiles, Random random) + { + var tiles = _maps.GetAllTilesEnumerator(_gridUid, _grid); + var replacements = new List<(Vector2i Index, Tile Tile)>(); + var reserved = new HashSet(); + + while (tiles.MoveNext(out var tileRef)) + { + var node = tileRef.Value.GridIndices; + + if (reservedTiles.Contains(node)) + continue; + + foreach (var layer in gen.Layers) + { + var value = layer.Noise.GetNoise(node.X, node.Y); + + if (value < layer.Threshold) + continue; + + Tile tile; + + if (random.Prob(gen.VariantWeight)) + { + tile = _tileDefManager.GetVariantTile(_prototype.Index(layer.Tile), random); + } + else + { + tile = new Tile(_prototype.Index(layer.Tile).TileId); + } + + replacements.Add((node, tile)); + reserved.Add(node); + break; + } + + await SuspendDungeon(); + } + + _maps.SetTiles(_gridUid, _grid, replacements); + return new Dungeon(new List() + { + new DungeonRoom(reserved, _position, Box2i.Empty, new HashSet()), + }); + } +} diff --git a/Content.Server/Procedural/DungeonJob/DungeonJob.MobDunGen.cs b/Content.Server/Procedural/DungeonJob/DungeonJob.MobDunGen.cs new file mode 100644 index 00000000000..150849d2c51 --- /dev/null +++ b/Content.Server/Procedural/DungeonJob/DungeonJob.MobDunGen.cs @@ -0,0 +1,58 @@ +using System.Threading.Tasks; +using Content.Server.Ghost.Roles.Components; +using Content.Server.NPC.Components; +using Content.Server.NPC.Systems; +using Content.Shared.Physics; +using Content.Shared.Procedural; +using Content.Shared.Procedural.DungeonLayers; +using Content.Shared.Storage; +using Robust.Shared.Collections; +using Robust.Shared.Random; + +namespace Content.Server.Procedural.DungeonJob; + +public sealed partial class DungeonJob +{ + private async Task PostGen( + MobsDunGen gen, + Dungeon dungeon, + Random random) + { + var availableRooms = new ValueList(); + availableRooms.AddRange(dungeon.Rooms); + var availableTiles = new ValueList(dungeon.AllTiles); + + var entities = EntitySpawnCollection.GetSpawns(gen.Groups, random); + var count = random.Next(gen.MinCount, gen.MaxCount + 1); + var npcs = _entManager.System(); + + for (var i = 0; i < count; i++) + { + while (availableTiles.Count > 0) + { + var tile = availableTiles.RemoveSwap(random.Next(availableTiles.Count)); + + if (!_anchorable.TileFree(_grid, tile, (int) CollisionGroup.MachineLayer, + (int) CollisionGroup.MachineLayer)) + { + continue; + } + + foreach (var ent in entities) + { + var uid = _entManager.SpawnAtPosition(ent, _maps.GridTileToLocal(_gridUid, _grid, tile)); + _entManager.RemoveComponent(uid); + _entManager.RemoveComponent(uid); + npcs.SleepNPC(uid); + } + + break; + } + + await SuspendDungeon(); + + if (!ValidateResume()) + return; + } + } +} diff --git a/Content.Server/Procedural/DungeonJob/DungeonJob.OreDunGen.cs b/Content.Server/Procedural/DungeonJob/DungeonJob.OreDunGen.cs new file mode 100644 index 00000000000..e89c1d7e470 --- /dev/null +++ b/Content.Server/Procedural/DungeonJob/DungeonJob.OreDunGen.cs @@ -0,0 +1,149 @@ +using System.Threading.Tasks; +using Content.Shared.Procedural; +using Content.Shared.Procedural.Components; +using Content.Shared.Procedural.DungeonLayers; +using Robust.Shared.Collections; +using Robust.Shared.Prototypes; +using Robust.Shared.Random; + +namespace Content.Server.Procedural.DungeonJob; + +public sealed partial class DungeonJob +{ + /// + /// + /// + private async Task PostGen( + OreDunGen gen, + Dungeon dungeon, + Random random) + { + // Doesn't use dungeon data because layers and we don't need top-down support at the moment. + + var emptyTiles = false; + var replaceEntities = new Dictionary(); + var availableTiles = new List(); + + foreach (var node in dungeon.AllTiles) + { + // Empty tile, skip if relevant. + if (!emptyTiles && (!_maps.TryGetTile(_grid, node, out var tile) || tile.IsEmpty)) + continue; + + // Check if it's a valid spawn, if so then use it. + var enumerator = _maps.GetAnchoredEntitiesEnumerator(_gridUid, _grid, node); + var found = false; + + // We use existing entities as a mark to spawn in place + // OR + // We check for any existing entities to see if we can spawn there. + while (enumerator.MoveNext(out var uid)) + { + // We can't replace so just stop here. + if (gen.Replacement == null) + break; + + var prototype = _entManager.GetComponent(uid.Value).EntityPrototype; + + if (prototype?.ID == gen.Replacement) + { + replaceEntities[node] = uid.Value; + found = true; + break; + } + } + + if (!found) + continue; + + // Add it to valid nodes. + availableTiles.Add(node); + + await SuspendDungeon(); + + if (!ValidateResume()) + return; + } + + var remapping = new Dictionary(); + + // TODO: Move this to engine + if (_prototype.TryIndex(gen.Entity, out var proto) && + proto.Components.TryGetComponent("EntityRemap", out var comps)) + { + var remappingComp = (EntityRemapComponent) comps; + remapping = remappingComp.Mask; + } + + var frontier = new ValueList(32); + + // Iterate the group counts and pathfind out each group. + for (var i = 0; i < gen.Count; i++) + { + await SuspendDungeon(); + + if (!ValidateResume()) + return; + + var groupSize = random.Next(gen.MinGroupSize, gen.MaxGroupSize + 1); + + // While we have remaining tiles keep iterating + while (groupSize >= 0 && availableTiles.Count > 0) + { + var startNode = random.PickAndTake(availableTiles); + frontier.Clear(); + frontier.Add(startNode); + + // This essentially may lead to a vein being split in multiple areas but the count matters more than position. + while (frontier.Count > 0 && groupSize >= 0) + { + // Need to pick a random index so we don't just get straight lines of ores. + var frontierIndex = random.Next(frontier.Count); + var node = frontier[frontierIndex]; + frontier.RemoveSwap(frontierIndex); + availableTiles.Remove(node); + + // Add neighbors if they're valid, worst case we add no more and pick another random seed tile. + for (var x = -1; x <= 1; x++) + { + for (var y = -1; y <= 1; y++) + { + if (x != 0 && y != 0) + continue; + + var neighbor = new Vector2i(node.X + x, node.Y + y); + + if (frontier.Contains(neighbor) || !availableTiles.Contains(neighbor)) + continue; + + frontier.Add(neighbor); + } + } + + var prototype = gen.Entity; + + if (replaceEntities.TryGetValue(node, out var existingEnt)) + { + var existingProto = _entManager.GetComponent(existingEnt).EntityPrototype; + _entManager.DeleteEntity(existingEnt); + + if (existingProto != null && remapping.TryGetValue(existingProto.ID, out var remapped)) + { + prototype = remapped; + } + } + + // Tile valid salad so add it. + _entManager.SpawnAtPosition(prototype, _maps.GridTileToLocal(_gridUid, _grid, node)); + + groupSize--; + } + } + + if (groupSize > 0) + { + _sawmill.Warning($"Found remaining group size for ore veins!"); + } + } + } +} diff --git a/Content.Server/Procedural/DungeonJob/DungeonJob.PostGen.cs b/Content.Server/Procedural/DungeonJob/DungeonJob.PostGen.cs new file mode 100644 index 00000000000..b1c83346d87 --- /dev/null +++ b/Content.Server/Procedural/DungeonJob/DungeonJob.PostGen.cs @@ -0,0 +1,134 @@ +using System.Numerics; +using Content.Shared.Procedural; +using Robust.Shared.Collections; +using Robust.Shared.Map.Components; +using Robust.Shared.Physics.Components; + +namespace Content.Server.Procedural.DungeonJob; + +public sealed partial class DungeonJob +{ + /* + * Run after the main dungeon generation + */ + + private bool HasWall(Vector2i tile) + { + var anchored = _maps.GetAnchoredEntitiesEnumerator(_gridUid, _grid, tile); + + while (anchored.MoveNext(out var uid)) + { + if (_tags.HasTag(uid.Value, "Wall")) + return true; + } + + return false; + } + + private void BuildCorridorExterior(Dungeon dungeon) + { + var exterior = dungeon.CorridorExteriorTiles; + + // Just ignore entrances or whatever for now. + foreach (var tile in dungeon.CorridorTiles) + { + for (var x = -1; x <= 1; x++) + { + for (var y = -1; y <= 1; y++) + { + var neighbor = new Vector2i(tile.X + x, tile.Y + y); + + if (dungeon.CorridorTiles.Contains(neighbor) || + dungeon.RoomExteriorTiles.Contains(neighbor) || + dungeon.RoomTiles.Contains(neighbor) || + dungeon.Entrances.Contains(neighbor)) + { + continue; + } + + exterior.Add(neighbor); + } + } + } + } + + private void WidenCorridor(Dungeon dungeon, float width, ICollection corridorTiles) + { + var expansion = width - 2; + + // Widen the path + if (expansion >= 1) + { + var toAdd = new ValueList(); + + foreach (var node in corridorTiles) + { + // Uhhh not sure on the cleanest way to do this but tl;dr we don't want to hug + // exterior walls and make the path smaller. + + for (var x = -expansion; x <= expansion; x++) + { + for (var y = -expansion; y <= expansion; y++) + { + var neighbor = new Vector2(node.X + x, node.Y + y).Floored(); + + // Diagonals still matter here. + if (dungeon.RoomTiles.Contains(neighbor) || + dungeon.RoomExteriorTiles.Contains(neighbor)) + { + // Try + + continue; + } + + toAdd.Add(neighbor); + } + } + } + + foreach (var node in toAdd) + { + corridorTiles.Add(node); + } + } + } + + /// + /// Removes any unwanted obstacles around a door tile. + /// + private void ClearDoor(Dungeon dungeon, MapGridComponent grid, Vector2i indices, bool strict = false) + { + var flags = strict + ? LookupFlags.Dynamic | LookupFlags.Static | LookupFlags.StaticSundries + : LookupFlags.Dynamic | LookupFlags.Static; + + for (var x = -1; x <= 1; x++) + { + for (var y = -1; y <= 1; y++) + { + if (x != 0 && y != 0) + continue; + + var neighbor = new Vector2i(indices.X + x, indices.Y + y); + + if (!dungeon.RoomTiles.Contains(neighbor)) + continue; + + // Shrink by 0.01 to avoid polygon overlap from neighboring tiles. + // TODO: Uhh entityset re-usage. + foreach (var ent in _lookup.GetEntitiesIntersecting(_gridUid, new Box2(neighbor * grid.TileSize, (neighbor + 1) * grid.TileSize).Enlarged(-0.1f), flags)) + { + if (!_physicsQuery.TryGetComponent(ent, out var physics) || + !physics.Hard || + (DungeonSystem.CollisionMask & physics.CollisionLayer) == 0x0 && + (DungeonSystem.CollisionLayer & physics.CollisionMask) == 0x0) + { + continue; + } + + _entManager.DeleteEntity(ent); + } + } + } + } +} diff --git a/Content.Server/Procedural/DungeonJob/DungeonJob.PostGenAutoCabling.cs b/Content.Server/Procedural/DungeonJob/DungeonJob.PostGenAutoCabling.cs new file mode 100644 index 00000000000..aaea23ddd56 --- /dev/null +++ b/Content.Server/Procedural/DungeonJob/DungeonJob.PostGenAutoCabling.cs @@ -0,0 +1,162 @@ +using System.Linq; +using System.Threading.Tasks; +using Content.Server.NodeContainer; +using Content.Shared.Procedural; +using Content.Shared.Procedural.PostGeneration; +using Robust.Shared.Random; + +namespace Content.Server.Procedural.DungeonJob; + +public sealed partial class DungeonJob +{ + /// + /// + /// + private async Task PostGen(AutoCablingDunGen gen, DungeonData data, Dungeon dungeon, HashSet reservedTiles, Random random) + { + if (!data.Entities.TryGetValue(DungeonDataKey.Cabling, out var ent)) + { + LogDataError(typeof(AutoCablingDunGen)); + return; + } + + // There's a lot of ways you could do this. + // For now we'll just connect every LV cable in the dungeon. + var cableTiles = new HashSet(); + var allTiles = new HashSet(dungeon.CorridorTiles); + allTiles.UnionWith(dungeon.RoomTiles); + allTiles.UnionWith(dungeon.RoomExteriorTiles); + allTiles.UnionWith(dungeon.CorridorExteriorTiles); + var nodeQuery = _entManager.GetEntityQuery(); + + // Gather existing nodes + foreach (var tile in allTiles) + { + var anchored = _maps.GetAnchoredEntitiesEnumerator(_gridUid, _grid, tile); + + while (anchored.MoveNext(out var anc)) + { + if (!nodeQuery.TryGetComponent(anc, out var nodeContainer) || + !nodeContainer.Nodes.ContainsKey("power")) + { + continue; + } + + cableTiles.Add(tile); + break; + } + } + + // Iterating them all might be expensive. + await SuspendDungeon(); + + if (!ValidateResume()) + return; + + var startNodes = new List(cableTiles); + random.Shuffle(startNodes); + var start = startNodes[0]; + var remaining = new HashSet(startNodes); + var frontier = new PriorityQueue(); + frontier.Enqueue(start, 0f); + var cameFrom = new Dictionary(); + var costSoFar = new Dictionary(); + var lastDirection = new Dictionary(); + costSoFar[start] = 0f; + lastDirection[start] = Direction.Invalid; + + while (remaining.Count > 0) + { + if (frontier.Count == 0) + { + var newStart = remaining.First(); + frontier.Enqueue(newStart, 0f); + lastDirection[newStart] = Direction.Invalid; + } + + var node = frontier.Dequeue(); + + if (remaining.Remove(node)) + { + var weh = node; + + while (cameFrom.TryGetValue(weh, out var receiver)) + { + cableTiles.Add(weh); + weh = receiver; + + if (weh == start) + break; + } + } + + if (!_maps.TryGetTileRef(_gridUid, _grid, node, out var tileRef) || tileRef.Tile.IsEmpty) + { + continue; + } + + for (var i = 0; i < 4; i++) + { + var dir = (Direction) (i * 2); + + var neighbor = node + dir.ToIntVec(); + var tileCost = 1f; + + // Prefer straight lines. + if (lastDirection[node] != dir) + { + tileCost *= 1.1f; + } + + if (cableTiles.Contains(neighbor)) + { + tileCost *= 0.1f; + } + + // Prefer tiles without walls on them + if (HasWall(neighbor)) + { + tileCost *= 20f; + } + + var gScore = costSoFar[node] + tileCost; + + if (costSoFar.TryGetValue(neighbor, out var nextValue) && gScore >= nextValue) + { + continue; + } + + cameFrom[neighbor] = node; + costSoFar[neighbor] = gScore; + lastDirection[neighbor] = dir; + frontier.Enqueue(neighbor, gScore); + } + } + + foreach (var tile in cableTiles) + { + if (reservedTiles.Contains(tile)) + continue; + + var anchored = _maps.GetAnchoredEntitiesEnumerator(_gridUid, _grid, tile); + var found = false; + + while (anchored.MoveNext(out var anc)) + { + if (!nodeQuery.TryGetComponent(anc, out var nodeContainer) || + !nodeContainer.Nodes.ContainsKey("power")) + { + continue; + } + + found = true; + break; + } + + if (found) + continue; + + _entManager.SpawnEntity(ent, _maps.GridTileToLocal(_gridUid, _grid, tile)); + } + } +} diff --git a/Content.Server/Procedural/DungeonJob/DungeonJob.PostGenBiome.cs b/Content.Server/Procedural/DungeonJob/DungeonJob.PostGenBiome.cs new file mode 100644 index 00000000000..65f6d2d14f9 --- /dev/null +++ b/Content.Server/Procedural/DungeonJob/DungeonJob.PostGenBiome.cs @@ -0,0 +1,67 @@ +using System.Threading.Tasks; +using Content.Server.Parallax; +using Content.Shared.Parallax.Biomes; +using Content.Shared.Procedural; +using Content.Shared.Procedural.PostGeneration; +using Robust.Shared.Map; +using Robust.Shared.Utility; + +namespace Content.Server.Procedural.DungeonJob; + +public sealed partial class DungeonJob +{ + /// + /// + /// + private async Task PostGen(BiomeDunGen dunGen, DungeonData data, Dungeon dungeon, HashSet reservedTiles, Random random) + { + if (_entManager.TryGetComponent(_gridUid, out BiomeComponent? biomeComp)) + return; + + biomeComp = _entManager.AddComponent(_gridUid); + var biomeSystem = _entManager.System(); + biomeSystem.SetTemplate(_gridUid, biomeComp, _prototype.Index(dunGen.BiomeTemplate)); + var seed = random.Next(); + var xformQuery = _entManager.GetEntityQuery(); + + foreach (var node in dungeon.RoomTiles) + { + if (reservedTiles.Contains(node)) + continue; + + // Need to set per-tile to override data. + if (biomeSystem.TryGetTile(node, biomeComp.Layers, seed, _grid, out var tile)) + { + _maps.SetTile(_gridUid, _grid, node, tile.Value); + } + + if (biomeSystem.TryGetDecals(node, biomeComp.Layers, seed, _grid, out var decals)) + { + foreach (var decal in decals) + { + _decals.TryAddDecal(decal.ID, new EntityCoordinates(_gridUid, decal.Position), out _); + } + } + + if (biomeSystem.TryGetEntity(node, biomeComp, _grid, out var entityProto)) + { + var ent = _entManager.SpawnEntity(entityProto, new EntityCoordinates(_gridUid, node + _grid.TileSizeHalfVector)); + var xform = xformQuery.Get(ent); + + if (!xform.Comp.Anchored) + { + _transform.AnchorEntity(ent, xform); + } + + // TODO: Engine bug with SpawnAtPosition + DebugTools.Assert(xform.Comp.Anchored); + } + + await SuspendDungeon(); + if (!ValidateResume()) + return; + } + + biomeComp.Enabled = false; + } +} diff --git a/Content.Server/Procedural/DungeonJob/DungeonJob.PostGenBiomeMarkerLayer.cs b/Content.Server/Procedural/DungeonJob/DungeonJob.PostGenBiomeMarkerLayer.cs new file mode 100644 index 00000000000..fb0eaa01573 --- /dev/null +++ b/Content.Server/Procedural/DungeonJob/DungeonJob.PostGenBiomeMarkerLayer.cs @@ -0,0 +1,105 @@ +using System.Threading.Tasks; +using Content.Server.Parallax; +using Content.Shared.Parallax.Biomes; +using Content.Shared.Parallax.Biomes.Markers; +using Content.Shared.Procedural; +using Content.Shared.Procedural.PostGeneration; +using Content.Shared.Random.Helpers; +using Robust.Shared.Map; +using Robust.Shared.Utility; + +namespace Content.Server.Procedural.DungeonJob; + +public sealed partial class DungeonJob +{ + /// + /// + /// + private async Task PostGen(BiomeMarkerLayerDunGen dunGen, DungeonData data, Dungeon dungeon, HashSet reservedTiles, Random random) + { + // If we're adding biome then disable it and just use for markers. + if (_entManager.EnsureComponent(_gridUid, out BiomeComponent biomeComp)) + { + biomeComp.Enabled = false; + } + + var biomeSystem = _entManager.System(); + var weightedRandom = _prototype.Index(dunGen.MarkerTemplate); + var xformQuery = _entManager.GetEntityQuery(); + var templates = new Dictionary(); + + for (var i = 0; i < dunGen.Count; i++) + { + var template = weightedRandom.Pick(random); + var count = templates.GetOrNew(template); + count++; + templates[template] = count; + } + + foreach (var (template, count) in templates) + { + var markerTemplate = _prototype.Index(template); + + var bounds = new Box2i(); + + foreach (var tile in dungeon.RoomTiles) + { + bounds = bounds.UnionTile(tile); + } + + await SuspendDungeon(); + if (!ValidateResume()) + return; + + biomeSystem.GetMarkerNodes(_gridUid, biomeComp, _grid, markerTemplate, true, bounds, count, + random, out var spawnSet, out var existing, false); + + await SuspendDungeon(); + if (!ValidateResume()) + return; + + var checkTile = reservedTiles.Count > 0; + + foreach (var ent in existing) + { + if (checkTile && reservedTiles.Contains(_maps.LocalToTile(_gridUid, _grid, _xformQuery.GetComponent(ent).Coordinates))) + { + continue; + } + + _entManager.DeleteEntity(ent); + + await SuspendDungeon(); + if (!ValidateResume()) + return; + } + + foreach (var (node, mask) in spawnSet) + { + if (reservedTiles.Contains(node)) + continue; + + string? proto; + + if (mask != null && markerTemplate.EntityMask.TryGetValue(mask, out var maskedProto)) + { + proto = maskedProto; + } + else + { + proto = markerTemplate.Prototype; + } + + var ent = _entManager.SpawnAtPosition(proto, new EntityCoordinates(_gridUid, node + _grid.TileSizeHalfVector)); + var xform = xformQuery.Get(ent); + + if (!xform.Comp.Anchored) + _transform.AnchorEntity(ent, xform); + + await SuspendDungeon(); + if (!ValidateResume()) + return; + } + } + } +} diff --git a/Content.Server/Procedural/DungeonJob/DungeonJob.PostGenBoundaryWall.cs b/Content.Server/Procedural/DungeonJob/DungeonJob.PostGenBoundaryWall.cs new file mode 100644 index 00000000000..84697a56bc7 --- /dev/null +++ b/Content.Server/Procedural/DungeonJob/DungeonJob.PostGenBoundaryWall.cs @@ -0,0 +1,113 @@ +using System.Threading.Tasks; +using Content.Shared.Maps; +using Content.Shared.Procedural; +using Content.Shared.Procedural.PostGeneration; +using Robust.Shared.Map; +using Robust.Shared.Utility; + +namespace Content.Server.Procedural.DungeonJob; + +public sealed partial class DungeonJob +{ + /// + /// + /// + private async Task PostGen(BoundaryWallDunGen gen, DungeonData data, Dungeon dungeon, HashSet reservedTiles, Random random) + { + if (!data.Tiles.TryGetValue(DungeonDataKey.FallbackTile, out var protoTileDef) || + !data.Entities.TryGetValue(DungeonDataKey.Walls, out var wall)) + { + _sawmill.Error($"Error finding dungeon data for {nameof(gen)}"); + return; + } + + var tileDef = _tileDefManager[protoTileDef]; + var tiles = new List<(Vector2i Index, Tile Tile)>(dungeon.RoomExteriorTiles.Count); + + if (!data.Entities.TryGetValue(DungeonDataKey.CornerWalls, out var cornerWall)) + { + cornerWall = wall; + } + + if (cornerWall == default) + { + cornerWall = wall; + } + + // Spawn wall outline + // - Tiles first + foreach (var neighbor in dungeon.RoomExteriorTiles) + { + DebugTools.Assert(!dungeon.RoomTiles.Contains(neighbor)); + + if (dungeon.Entrances.Contains(neighbor)) + continue; + + if (!_anchorable.TileFree(_grid, neighbor, DungeonSystem.CollisionLayer, DungeonSystem.CollisionMask)) + continue; + + tiles.Add((neighbor, _tile.GetVariantTile((ContentTileDefinition) tileDef, random))); + } + + foreach (var index in dungeon.CorridorExteriorTiles) + { + if (dungeon.RoomTiles.Contains(index)) + continue; + + if (!_anchorable.TileFree(_grid, index, DungeonSystem.CollisionLayer, DungeonSystem.CollisionMask)) + continue; + + tiles.Add((index, _tile.GetVariantTile((ContentTileDefinition)tileDef, random))); + } + + _maps.SetTiles(_gridUid, _grid, tiles); + + // Double iteration coz we bulk set tiles for speed. + for (var i = 0; i < tiles.Count; i++) + { + var index = tiles[i]; + + if (!_anchorable.TileFree(_grid, index.Index, DungeonSystem.CollisionLayer, DungeonSystem.CollisionMask)) + continue; + + // If no cardinal neighbors in dungeon then we're a corner. + var isCorner = true; + + for (var x = -1; x <= 1; x++) + { + for (var y = -1; y <= 1; y++) + { + if (x != 0 && y != 0) + { + continue; + } + + var neighbor = new Vector2i(index.Index.X + x, index.Index.Y + y); + + if (dungeon.RoomTiles.Contains(neighbor) || dungeon.CorridorTiles.Contains(neighbor)) + { + isCorner = false; + break; + } + } + + if (!isCorner) + break; + } + + if (isCorner) + _entManager.SpawnEntity(cornerWall, _maps.GridTileToLocal(_gridUid, _grid, index.Index)); + + if (!isCorner) + _entManager.SpawnEntity(wall, _maps.GridTileToLocal(_gridUid, _grid, index.Index)); + + if (i % 20 == 0) + { + await SuspendDungeon(); + + if (!ValidateResume()) + return; + } + } + } +} diff --git a/Content.Server/Procedural/DungeonJob/DungeonJob.PostGenCornerClutter.cs b/Content.Server/Procedural/DungeonJob/DungeonJob.PostGenCornerClutter.cs new file mode 100644 index 00000000000..f7858298504 --- /dev/null +++ b/Content.Server/Procedural/DungeonJob/DungeonJob.PostGenCornerClutter.cs @@ -0,0 +1,56 @@ +using System.Threading.Tasks; +using Content.Shared.Procedural; +using Content.Shared.Procedural.PostGeneration; +using Content.Shared.Storage; +using Robust.Shared.Physics.Components; +using Robust.Shared.Random; + +namespace Content.Server.Procedural.DungeonJob; + +public sealed partial class DungeonJob +{ + /// + /// + /// + private async Task PostGen(CornerClutterDunGen gen, DungeonData data, Dungeon dungeon, HashSet reservedTiles, Random random) + { + if (!data.SpawnGroups.TryGetValue(DungeonDataKey.CornerClutter, out var corner)) + { + _sawmill.Error(Environment.StackTrace); + return; + } + + foreach (var tile in dungeon.CorridorTiles) + { + var blocked = _anchorable.TileFree(_grid, tile, DungeonSystem.CollisionLayer, DungeonSystem.CollisionMask); + + if (blocked) + continue; + + // If at least 2 adjacent tiles are blocked consider it a corner + for (var i = 0; i < 4; i++) + { + var dir = (Direction) (i * 2); + blocked = HasWall(tile + dir.ToIntVec()); + + if (!blocked) + continue; + + var nextDir = (Direction) ((i + 1) * 2 % 8); + blocked = HasWall(tile + nextDir.ToIntVec()); + + if (!blocked) + continue; + + if (random.Prob(gen.Chance)) + { + var coords = _maps.GridTileToLocal(_gridUid, _grid, tile); + var protos = EntitySpawnCollection.GetSpawns(_prototype.Index(corner).Entries, random); + _entManager.SpawnEntities(coords, protos); + } + + break; + } + } + } +} diff --git a/Content.Server/Procedural/DungeonJob/DungeonJob.PostGenCorridor.cs b/Content.Server/Procedural/DungeonJob/DungeonJob.PostGenCorridor.cs new file mode 100644 index 00000000000..8ea79ffe54f --- /dev/null +++ b/Content.Server/Procedural/DungeonJob/DungeonJob.PostGenCorridor.cs @@ -0,0 +1,116 @@ +using System.Numerics; +using System.Threading.Tasks; +using Content.Shared.Maps; +using Content.Shared.Procedural; +using Content.Shared.Procedural.PostGeneration; +using Robust.Shared.Map; + +namespace Content.Server.Procedural.DungeonJob; + +public sealed partial class DungeonJob +{ + /// + /// + /// + private async Task PostGen(CorridorDunGen gen, DungeonData data, Dungeon dungeon, HashSet reservedTiles, Random random) + { + if (!data.Tiles.TryGetValue(DungeonDataKey.FallbackTile, out var tileProto)) + { + LogDataError(typeof(CorridorDunGen)); + return; + } + + var entrances = new List(dungeon.Rooms.Count); + + // Grab entrances + foreach (var room in dungeon.Rooms) + { + entrances.AddRange(room.Entrances); + } + + var edges = _dungeon.MinimumSpanningTree(entrances, random); + await SuspendDungeon(); + + if (!ValidateResume()) + return; + + // TODO: Add in say 1/3 of edges back in to add some cyclic to it. + + var expansion = gen.Width - 2; + // Okay so tl;dr is that we don't want to cut close to rooms as it might go from 3 width to 2 width suddenly + // So we will add a buffer range around each room to deter pathfinding there unless necessary + var deterredTiles = new HashSet(); + + if (expansion >= 1) + { + foreach (var tile in dungeon.RoomExteriorTiles) + { + for (var x = -expansion; x <= expansion; x++) + { + for (var y = -expansion; y <= expansion; y++) + { + var neighbor = new Vector2(tile.X + x, tile.Y + y).Floored(); + + if (dungeon.RoomTiles.Contains(neighbor) || + dungeon.RoomExteriorTiles.Contains(neighbor) || + entrances.Contains(neighbor)) + { + continue; + } + + deterredTiles.Add(neighbor); + } + } + } + } + + foreach (var room in dungeon.Rooms) + { + foreach (var entrance in room.Entrances) + { + // Just so we can still actually get in to the entrance we won't deter from a tile away from it. + var normal = (entrance + _grid.TileSizeHalfVector - room.Center).ToWorldAngle().GetCardinalDir().ToIntVec(); + deterredTiles.Remove(entrance + normal); + } + } + + var excludedTiles = new HashSet(dungeon.RoomExteriorTiles); + excludedTiles.UnionWith(dungeon.RoomTiles); + var corridorTiles = new HashSet(); + + _dungeon.GetCorridorNodes(corridorTiles, edges, gen.PathLimit, excludedTiles, tile => + { + var mod = 1f; + + if (corridorTiles.Contains(tile)) + { + mod *= 0.1f; + } + + if (deterredTiles.Contains(tile)) + { + mod *= 2f; + } + + return mod; + }); + + WidenCorridor(dungeon, gen.Width, corridorTiles); + + var setTiles = new List<(Vector2i, Tile)>(); + var tileDef = (ContentTileDefinition) _tileDefManager[tileProto]; + + foreach (var tile in corridorTiles) + { + if (reservedTiles.Contains(tile)) + continue; + + setTiles.Add((tile, _tile.GetVariantTile(tileDef, random))); + } + + _maps.SetTiles(_gridUid, _grid, setTiles); + dungeon.CorridorTiles.UnionWith(corridorTiles); + dungeon.RefreshAllTiles(); + BuildCorridorExterior(dungeon); + } +} diff --git a/Content.Server/Procedural/DungeonJob.CorridorClutterPost.cs b/Content.Server/Procedural/DungeonJob/DungeonJob.PostGenCorridorClutter.cs similarity index 83% rename from Content.Server/Procedural/DungeonJob.CorridorClutterPost.cs rename to Content.Server/Procedural/DungeonJob/DungeonJob.PostGenCorridorClutter.cs index 8099157cc50..cb7c4b210c8 100644 --- a/Content.Server/Procedural/DungeonJob.CorridorClutterPost.cs +++ b/Content.Server/Procedural/DungeonJob/DungeonJob.PostGenCorridorClutter.cs @@ -2,16 +2,17 @@ using Content.Shared.Procedural; using Content.Shared.Procedural.PostGeneration; using Content.Shared.Storage; -using Robust.Shared.Map.Components; using Robust.Shared.Physics.Components; using Robust.Shared.Random; -namespace Content.Server.Procedural; +namespace Content.Server.Procedural.DungeonJob; public sealed partial class DungeonJob { - private async Task PostGen(CorridorClutterPostGen gen, Dungeon dungeon, EntityUid gridUid, MapGridComponent grid, - Random random) + /// + /// + /// + private async Task PostGen(CorridorClutterDunGen gen, DungeonData data, Dungeon dungeon, HashSet reservedTiles, Random random) { var physicsQuery = _entManager.GetEntityQuery(); var count = (int) Math.Ceiling(dungeon.CorridorTiles.Count * gen.Chance); diff --git a/Content.Server/Procedural/DungeonJob/DungeonJob.PostGenCorridorDecalSkirting.cs b/Content.Server/Procedural/DungeonJob/DungeonJob.PostGenCorridorDecalSkirting.cs new file mode 100644 index 00000000000..3b516c3fa8a --- /dev/null +++ b/Content.Server/Procedural/DungeonJob/DungeonJob.PostGenCorridorDecalSkirting.cs @@ -0,0 +1,124 @@ +using System.Threading.Tasks; +using Content.Shared.Doors.Components; +using Content.Shared.Procedural; +using Content.Shared.Procedural.PostGeneration; +using Robust.Shared.Collections; +using Robust.Shared.Physics.Components; +using Robust.Shared.Utility; + +namespace Content.Server.Procedural.DungeonJob; + +public sealed partial class DungeonJob +{ + /// + /// + /// + private async Task PostGen(CorridorDecalSkirtingDunGen decks, DungeonData data, Dungeon dungeon, HashSet reservedTiles, Random random) + { + if (!data.Colors.TryGetValue(DungeonDataKey.Decals, out var color)) + { + _sawmill.Error(Environment.StackTrace); + } + + var directions = new ValueList(4); + var pocketDirections = new ValueList(4); + var doorQuery = _entManager.GetEntityQuery(); + var physicsQuery = _entManager.GetEntityQuery(); + var offset = -_grid.TileSizeHalfVector; + + foreach (var tile in dungeon.CorridorTiles) + { + DebugTools.Assert(!dungeon.RoomTiles.Contains(tile)); + directions.Clear(); + + // Do cardinals 1 step + // Do corners the other step + for (var i = 0; i < 4; i++) + { + var dir = (DirectionFlag) Math.Pow(2, i); + var neighbor = tile + dir.AsDir().ToIntVec(); + + var anc = _maps.GetAnchoredEntitiesEnumerator(_gridUid, _grid, neighbor); + + while (anc.MoveNext(out var ent)) + { + if (!physicsQuery.TryGetComponent(ent, out var physics) || + !physics.CanCollide || + !physics.Hard || + doorQuery.HasComponent(ent.Value)) + { + continue; + } + + directions.Add(dir); + break; + } + } + + // Pockets + if (directions.Count == 0) + { + pocketDirections.Clear(); + + for (var i = 1; i < 5; i++) + { + var dir = (Direction) (i * 2 - 1); + var neighbor = tile + dir.ToIntVec(); + + var anc = _maps.GetAnchoredEntitiesEnumerator(_gridUid, _grid, neighbor); + + while (anc.MoveNext(out var ent)) + { + if (!physicsQuery.TryGetComponent(ent, out var physics) || + !physics.CanCollide || + !physics.Hard || + doorQuery.HasComponent(ent.Value)) + { + continue; + } + + pocketDirections.Add(dir); + break; + } + } + + if (pocketDirections.Count == 1) + { + if (decks.PocketDecals.TryGetValue(pocketDirections[0], out var cDir)) + { + // Decals not being centered biting my ass again + var gridPos = _maps.GridTileToLocal(_gridUid, _grid, tile).Offset(offset); + _decals.TryAddDecal(cDir, gridPos, out _, color: color); + } + } + + continue; + } + + if (directions.Count == 1) + { + if (decks.CardinalDecals.TryGetValue(directions[0], out var cDir)) + { + // Decals not being centered biting my ass again + var gridPos = _maps.GridTileToLocal(_gridUid, _grid, tile).Offset(offset); + _decals.TryAddDecal(cDir, gridPos, out _, color: color); + } + + continue; + } + + // Corners + if (directions.Count == 2) + { + // Auehghegueugegegeheh help me + var dirFlag = directions[0] | directions[1]; + + if (decks.CornerDecals.TryGetValue(dirFlag, out var cDir)) + { + var gridPos = _maps.GridTileToLocal(_gridUid, _grid, tile).Offset(offset); + _decals.TryAddDecal(cDir, gridPos, out _, color: color); + } + } + } + } +} diff --git a/Content.Server/Procedural/DungeonJob/DungeonJob.PostGenDungeonConnector.cs b/Content.Server/Procedural/DungeonJob/DungeonJob.PostGenDungeonConnector.cs new file mode 100644 index 00000000000..917b1ffc9ca --- /dev/null +++ b/Content.Server/Procedural/DungeonJob/DungeonJob.PostGenDungeonConnector.cs @@ -0,0 +1,6 @@ +namespace Content.Server.Procedural.DungeonJob; + +public sealed partial class DungeonJob +{ + +} diff --git a/Content.Server/Procedural/DungeonJob/DungeonJob.PostGenDungeonEntrance.cs b/Content.Server/Procedural/DungeonJob/DungeonJob.PostGenDungeonEntrance.cs new file mode 100644 index 00000000000..abc52f07c6c --- /dev/null +++ b/Content.Server/Procedural/DungeonJob/DungeonJob.PostGenDungeonEntrance.cs @@ -0,0 +1,114 @@ +using System.Threading.Tasks; +using Content.Shared.Maps; +using Content.Shared.Procedural; +using Content.Shared.Procedural.PostGeneration; +using Content.Shared.Storage; +using Robust.Shared.Random; + +namespace Content.Server.Procedural.DungeonJob; + +public sealed partial class DungeonJob +{ + /// + /// + /// + private async Task PostGen(DungeonEntranceDunGen gen, DungeonData data, Dungeon dungeon, HashSet reservedTiles, Random random) + { + if (!data.Tiles.TryGetValue(DungeonDataKey.FallbackTile, out var tileProto) || + !data.SpawnGroups.TryGetValue(DungeonDataKey.Entrance, out var entrance)) + { + LogDataError(typeof(DungeonEntranceDunGen)); + return; + } + + var rooms = new List(dungeon.Rooms); + var roomTiles = new List(); + var tileDef = (ContentTileDefinition) _tileDefManager[tileProto]; + + for (var i = 0; i < gen.Count; i++) + { + var roomIndex = random.Next(rooms.Count); + var room = rooms[roomIndex]; + + // Move out 3 tiles in a direction away from center of the room + // If none of those intersect another tile it's probably external + // TODO: Maybe need to take top half of furthest rooms in case there's interior exits? + roomTiles.AddRange(room.Exterior); + random.Shuffle(roomTiles); + + foreach (var tile in roomTiles) + { + var isValid = false; + + // Check if one side is dungeon and the other side is nothing. + for (var j = 0; j < 4; j++) + { + var dir = (Direction) (j * 2); + var oppositeDir = dir.GetOpposite(); + var dirVec = tile + dir.ToIntVec(); + var oppositeDirVec = tile + oppositeDir.ToIntVec(); + + if (!dungeon.RoomTiles.Contains(dirVec)) + { + continue; + } + + if (dungeon.RoomTiles.Contains(oppositeDirVec) || + dungeon.RoomExteriorTiles.Contains(oppositeDirVec) || + dungeon.CorridorExteriorTiles.Contains(oppositeDirVec) || + dungeon.CorridorTiles.Contains(oppositeDirVec)) + { + continue; + } + + // Check if exterior spot free. + if (!_anchorable.TileFree(_grid, tile, DungeonSystem.CollisionLayer, DungeonSystem.CollisionMask)) + { + continue; + } + + // Check if interior spot free (no guarantees on exterior but ClearDoor should handle it) + if (!_anchorable.TileFree(_grid, dirVec, DungeonSystem.CollisionLayer, DungeonSystem.CollisionMask)) + { + continue; + } + + // Valid pick! + isValid = true; + + // Entrance wew + _maps.SetTile(_gridUid, _grid, tile, _tile.GetVariantTile(tileDef, random)); + ClearDoor(dungeon, _grid, tile); + var gridCoords = _maps.GridTileToLocal(_gridUid, _grid, tile); + // Need to offset the spawn to avoid spawning in the room. + + foreach (var ent in EntitySpawnCollection.GetSpawns(_prototype.Index(entrance).Entries, random)) + { + _entManager.SpawnAtPosition(ent, gridCoords); + } + + // Clear out any biome tiles nearby to avoid blocking it + foreach (var nearTile in _maps.GetLocalTilesIntersecting(_gridUid, _grid, new Circle(gridCoords.Position, 1.5f), false)) + { + if (dungeon.RoomTiles.Contains(nearTile.GridIndices) || + dungeon.RoomExteriorTiles.Contains(nearTile.GridIndices) || + dungeon.CorridorTiles.Contains(nearTile.GridIndices) || + dungeon.CorridorExteriorTiles.Contains(nearTile.GridIndices)) + { + continue; + } + + _maps.SetTile(_gridUid, _grid, nearTile.GridIndices, _tile.GetVariantTile(tileDef, random)); + } + + break; + } + + if (isValid) + break; + } + + roomTiles.Clear(); + } + } +} diff --git a/Content.Server/Procedural/DungeonJob/DungeonJob.PostGenEntranceFlank.cs b/Content.Server/Procedural/DungeonJob/DungeonJob.PostGenEntranceFlank.cs new file mode 100644 index 00000000000..3a1c7a37793 --- /dev/null +++ b/Content.Server/Procedural/DungeonJob/DungeonJob.PostGenEntranceFlank.cs @@ -0,0 +1,58 @@ +using System.Threading.Tasks; +using Content.Shared.Maps; +using Content.Shared.Procedural; +using Content.Shared.Procedural.PostGeneration; +using Content.Shared.Storage; +using Robust.Shared.Collections; +using Robust.Shared.Map; + +namespace Content.Server.Procedural.DungeonJob; + +public sealed partial class DungeonJob +{ + /// + /// + /// + private async Task PostGen(EntranceFlankDunGen gen, DungeonData data, Dungeon dungeon, HashSet reservedTiles, Random random) + { + if (!data.Tiles.TryGetValue(DungeonDataKey.FallbackTile, out var tileProto) || + !data.SpawnGroups.TryGetValue(DungeonDataKey.EntranceFlank, out var flankProto)) + { + _sawmill.Error($"Unable to get dungeon data for {nameof(gen)}"); + return; + } + + var tiles = new List<(Vector2i Index, Tile)>(); + var tileDef = _tileDefManager[tileProto]; + var spawnPositions = new ValueList(dungeon.Rooms.Count); + + foreach (var room in dungeon.Rooms) + { + foreach (var entrance in room.Entrances) + { + for (var i = 0; i < 8; i++) + { + var dir = (Direction) i; + var neighbor = entrance + dir.ToIntVec(); + + if (!dungeon.RoomExteriorTiles.Contains(neighbor)) + continue; + + if (reservedTiles.Contains(neighbor)) + continue; + + tiles.Add((neighbor, _tile.GetVariantTile((ContentTileDefinition) tileDef, random))); + spawnPositions.Add(neighbor); + } + } + } + + _maps.SetTiles(_gridUid, _grid, tiles); + var entGroup = _prototype.Index(flankProto); + + foreach (var entrance in spawnPositions) + { + _entManager.SpawnEntities(_maps.GridTileToLocal(_gridUid, _grid, entrance), EntitySpawnCollection.GetSpawns(entGroup.Entries, random)); + } + } +} diff --git a/Content.Server/Procedural/DungeonJob/DungeonJob.PostGenExternalWindow.cs b/Content.Server/Procedural/DungeonJob/DungeonJob.PostGenExternalWindow.cs new file mode 100644 index 00000000000..9a1b44ec91b --- /dev/null +++ b/Content.Server/Procedural/DungeonJob/DungeonJob.PostGenExternalWindow.cs @@ -0,0 +1,138 @@ +using System.Linq; +using System.Threading.Tasks; +using Content.Shared.Maps; +using Content.Shared.Procedural; +using Content.Shared.Procedural.PostGeneration; +using Content.Shared.Storage; +using Robust.Shared.Map; +using Robust.Shared.Map.Components; +using Robust.Shared.Random; + +namespace Content.Server.Procedural.DungeonJob; + +public sealed partial class DungeonJob +{ + // (Comment refers to internal & external). + + /* + * You may be wondering why these are different. + * It's because for internals we want to force it as it looks nicer and not leave it up to chance. + */ + + // TODO: Can probably combine these a bit, their differences are in really annoying to pull out spots. + + /// + /// + /// + private async Task PostGen(ExternalWindowDunGen gen, DungeonData data, Dungeon dungeon, HashSet reservedTiles, Random random) + { + if (!data.Tiles.TryGetValue(DungeonDataKey.FallbackTile, out var tileProto) || + !data.SpawnGroups.TryGetValue(DungeonDataKey.Window, out var windowGroup)) + { + _sawmill.Error($"Unable to get dungeon data for {nameof(gen)}"); + return; + } + + // Iterate every tile with N chance to spawn windows on that wall per cardinal dir. + var chance = 0.25 / 3f; + + var allExterior = new HashSet(dungeon.CorridorExteriorTiles); + allExterior.UnionWith(dungeon.RoomExteriorTiles); + var validTiles = allExterior.ToList(); + random.Shuffle(validTiles); + + var tiles = new List<(Vector2i, Tile)>(); + var tileDef = _tileDefManager[tileProto]; + var count = Math.Floor(validTiles.Count * chance); + var index = 0; + var takenTiles = new HashSet(); + + // There's a bunch of shit here but tl;dr + // - don't spawn over cap + // - Check if we have 3 tiles in a row that aren't corners and aren't obstructed + foreach (var tile in validTiles) + { + if (index > count) + break; + + // Room tile / already used. + if (!_anchorable.TileFree(_grid, tile, DungeonSystem.CollisionLayer, DungeonSystem.CollisionMask) || + takenTiles.Contains(tile)) + { + continue; + } + + // Check we're not on a corner + for (var i = 0; i < 2; i++) + { + var dir = (Direction) (i * 2); + var dirVec = dir.ToIntVec(); + var isValid = true; + + // Check 1 beyond either side to ensure it's not a corner. + for (var j = -1; j < 4; j++) + { + var neighbor = tile + dirVec * j; + + if (!allExterior.Contains(neighbor) || + takenTiles.Contains(neighbor) || + !_anchorable.TileFree(_grid, neighbor, DungeonSystem.CollisionLayer, DungeonSystem.CollisionMask)) + { + isValid = false; + break; + } + + // Also check perpendicular that it is free + foreach (var k in new [] {2, 6}) + { + var perp = (Direction) ((i * 2 + k) % 8); + var perpVec = perp.ToIntVec(); + var perpTile = tile + perpVec; + + if (allExterior.Contains(perpTile) || + takenTiles.Contains(neighbor) || + !_anchorable.TileFree(_grid, perpTile, DungeonSystem.CollisionLayer, DungeonSystem.CollisionMask)) + { + isValid = false; + break; + } + } + + if (!isValid) + break; + } + + if (!isValid) + continue; + + for (var j = 0; j < 3; j++) + { + var neighbor = tile + dirVec * j; + + if (reservedTiles.Contains(neighbor)) + continue; + + tiles.Add((neighbor, _tile.GetVariantTile((ContentTileDefinition) tileDef, random))); + index++; + takenTiles.Add(neighbor); + } + } + } + + _maps.SetTiles(_gridUid, _grid, tiles); + index = 0; + var spawnEntry = _prototype.Index(windowGroup); + + foreach (var tile in tiles) + { + var gridPos = _maps.GridTileToLocal(_gridUid, _grid, tile.Item1); + + index += spawnEntry.Entries.Count; + _entManager.SpawnEntities(gridPos, EntitySpawnCollection.GetSpawns(spawnEntry.Entries, random)); + await SuspendDungeon(); + + if (!ValidateResume()) + return; + } + } +} diff --git a/Content.Server/Procedural/DungeonJob/DungeonJob.PostGenInternalWindow.cs b/Content.Server/Procedural/DungeonJob/DungeonJob.PostGenInternalWindow.cs new file mode 100644 index 00000000000..d3b8c6d2f5d --- /dev/null +++ b/Content.Server/Procedural/DungeonJob/DungeonJob.PostGenInternalWindow.cs @@ -0,0 +1,108 @@ +using System.Numerics; +using System.Threading.Tasks; +using Content.Shared.Maps; +using Content.Shared.Procedural; +using Content.Shared.Procedural.PostGeneration; +using Content.Shared.Storage; + +namespace Content.Server.Procedural.DungeonJob; + +public sealed partial class DungeonJob +{ + /// + /// + /// + private async Task PostGen(InternalWindowDunGen gen, DungeonData data, Dungeon dungeon, HashSet reservedTiles, Random random) + { + if (!data.Tiles.TryGetValue(DungeonDataKey.FallbackTile, out var tileProto) || + !data.SpawnGroups.TryGetValue(DungeonDataKey.Window, out var windowGroup)) + { + _sawmill.Error($"Unable to find dungeon data keys for {nameof(gen)}"); + return; + } + + // Iterate every room and check if there's a gap beyond it that leads to another room within N tiles + // If so then consider windows + var minDistance = 4; + var maxDistance = 6; + var tileDef = _tileDefManager[tileProto]; + var window = _prototype.Index(windowGroup); + + foreach (var room in dungeon.Rooms) + { + var validTiles = new List(); + + for (var i = 0; i < 4; i++) + { + var dir = (DirectionFlag) Math.Pow(2, i); + var dirVec = dir.AsDir().ToIntVec(); + + foreach (var tile in room.Tiles) + { + var tileAngle = (tile + _grid.TileSizeHalfVector - room.Center).ToAngle(); + var roundedAngle = Math.Round(tileAngle.Theta / (Math.PI / 2)) * (Math.PI / 2); + + var tileVec = (Vector2i) new Angle(roundedAngle).ToVec().Rounded(); + + if (!tileVec.Equals(dirVec)) + continue; + + var valid = false; + + for (var j = 1; j < maxDistance; j++) + { + var edgeNeighbor = tile + dirVec * j; + + if (dungeon.RoomTiles.Contains(edgeNeighbor)) + { + if (j < minDistance) + { + valid = false; + } + else + { + valid = true; + } + + break; + } + } + + if (!valid) + continue; + + var windowTile = tile + dirVec; + + if (reservedTiles.Contains(windowTile)) + continue; + + if (!_anchorable.TileFree(_grid, windowTile, DungeonSystem.CollisionLayer, DungeonSystem.CollisionMask)) + continue; + + validTiles.Add(windowTile); + } + + validTiles.Sort((x, y) => (x + _grid.TileSizeHalfVector - room.Center).LengthSquared().CompareTo((y + _grid.TileSizeHalfVector - room.Center).LengthSquared())); + + for (var j = 0; j < Math.Min(validTiles.Count, 3); j++) + { + var tile = validTiles[j]; + var gridPos = _maps.GridTileToLocal(_gridUid, _grid, tile); + _maps.SetTile(_gridUid, _grid, tile, _tile.GetVariantTile((ContentTileDefinition) tileDef, random)); + + _entManager.SpawnEntities(gridPos, EntitySpawnCollection.GetSpawns(window.Entries, random)); + } + + if (validTiles.Count > 0) + { + await SuspendDungeon(); + + if (!ValidateResume()) + return; + } + + validTiles.Clear(); + } + } + } +} diff --git a/Content.Server/Procedural/DungeonJob/DungeonJob.PostGenJunction.cs b/Content.Server/Procedural/DungeonJob/DungeonJob.PostGenJunction.cs new file mode 100644 index 00000000000..700406eb894 --- /dev/null +++ b/Content.Server/Procedural/DungeonJob/DungeonJob.PostGenJunction.cs @@ -0,0 +1,144 @@ +using System.Threading.Tasks; +using Content.Shared.Maps; +using Content.Shared.Procedural; +using Content.Shared.Procedural.PostGeneration; +using Content.Shared.Storage; +using Robust.Shared.Map.Components; + +namespace Content.Server.Procedural.DungeonJob; + +public sealed partial class DungeonJob +{ + /// + /// + /// + private async Task PostGen(JunctionDunGen gen, DungeonData data, Dungeon dungeon, HashSet reservedTiles, Random random) + { + if (!data.Tiles.TryGetValue(DungeonDataKey.FallbackTile, out var tileProto) || + !data.SpawnGroups.TryGetValue(DungeonDataKey.Junction, out var junctionProto)) + { + _sawmill.Error($"Dungeon data keys are missing for {nameof(gen)}"); + return; + } + + var tileDef = _tileDefManager[tileProto]; + var entranceGroup = _prototype.Index(junctionProto); + + // N-wide junctions + foreach (var tile in dungeon.CorridorTiles) + { + if (!_anchorable.TileFree(_grid, tile, DungeonSystem.CollisionLayer, DungeonSystem.CollisionMask)) + continue; + + // Check each direction: + // - Check if immediate neighbors are free + // - Check if the neighbors beyond that are not free + // - Then check either side if they're slightly more free + var exteriorWidth = (int) Math.Floor(gen.Width / 2f); + var width = (int) Math.Ceiling(gen.Width / 2f); + + for (var i = 0; i < 2; i++) + { + var isValid = true; + var neighborDir = (Direction) (i * 2); + var neighborVec = neighborDir.ToIntVec(); + + for (var j = -width; j <= width; j++) + { + if (j == 0) + continue; + + var neighbor = tile + neighborVec * j; + + // If it's an end tile then check it's occupied. + if (j == -width || + j == width) + { + if (!HasWall(neighbor)) + { + isValid = false; + break; + } + + continue; + } + + // If we're not at the end tile then check it + perpendicular are free. + if (!_anchorable.TileFree(_grid, neighbor, DungeonSystem.CollisionLayer, DungeonSystem.CollisionMask)) + { + isValid = false; + break; + } + + var perp1 = tile + neighborVec * j + ((Direction) ((i * 2 + 2) % 8)).ToIntVec(); + var perp2 = tile + neighborVec * j + ((Direction) ((i * 2 + 6) % 8)).ToIntVec(); + + if (!_anchorable.TileFree(_grid, perp1, DungeonSystem.CollisionLayer, DungeonSystem.CollisionMask)) + { + isValid = false; + break; + } + + if (!_anchorable.TileFree(_grid, perp2, DungeonSystem.CollisionLayer, DungeonSystem.CollisionMask)) + { + isValid = false; + break; + } + } + + if (!isValid) + continue; + + // Check corners to see if either side opens up (if it's just a 1x wide corridor do nothing, needs to be a funnel. + foreach (var j in new [] {-exteriorWidth, exteriorWidth}) + { + var freeCount = 0; + + // Need at least 3 of 4 free + for (var k = 0; k < 4; k++) + { + var cornerDir = (Direction) (k * 2 + 1); + var cornerVec = cornerDir.ToIntVec(); + var cornerNeighbor = tile + neighborVec * j + cornerVec; + + if (_anchorable.TileFree(_grid, cornerNeighbor, DungeonSystem.CollisionLayer, DungeonSystem.CollisionMask)) + { + freeCount++; + } + } + + if (freeCount < gen.Width) + continue; + + // Valid! + isValid = true; + + for (var x = -width + 1; x < width; x++) + { + var weh = tile + neighborDir.ToIntVec() * x; + + if (reservedTiles.Contains(weh)) + continue; + + _maps.SetTile(_gridUid, _grid, weh, _tile.GetVariantTile((ContentTileDefinition) tileDef, random)); + + var coords = _maps.GridTileToLocal(_gridUid, _grid, weh); + _entManager.SpawnEntities(coords, EntitySpawnCollection.GetSpawns(entranceGroup.Entries, random)); + } + + break; + } + + if (isValid) + { + await SuspendDungeon(); + + if (!ValidateResume()) + return; + } + + break; + } + } + } +} diff --git a/Content.Server/Procedural/DungeonJob/DungeonJob.PostGenMiddleConnection.cs b/Content.Server/Procedural/DungeonJob/DungeonJob.PostGenMiddleConnection.cs new file mode 100644 index 00000000000..15d0f634232 --- /dev/null +++ b/Content.Server/Procedural/DungeonJob/DungeonJob.PostGenMiddleConnection.cs @@ -0,0 +1,147 @@ +using System.Numerics; +using System.Threading.Tasks; +using Content.Shared.Maps; +using Content.Shared.Procedural; +using Content.Shared.Procedural.PostGeneration; +using Content.Shared.Storage; +using Robust.Shared.Utility; + +namespace Content.Server.Procedural.DungeonJob; + +public sealed partial class DungeonJob +{ + /// + /// + /// + private async Task PostGen(MiddleConnectionDunGen gen, DungeonData data, Dungeon dungeon, HashSet reservedTiles, Random random) + { + if (!data.Tiles.TryGetValue(DungeonDataKey.FallbackTile, out var tileProto) || + !data.SpawnGroups.TryGetValue(DungeonDataKey.Entrance, out var entranceProto) || + !_prototype.TryIndex(entranceProto, out var entrance)) + { + _sawmill.Error($"Tried to run {nameof(MiddleConnectionDunGen)} without any dungeon data set which is unsupported"); + return; + } + + data.SpawnGroups.TryGetValue(DungeonDataKey.EntranceFlank, out var flankProto); + _prototype.TryIndex(flankProto, out var flank); + + // Grab all of the room bounds + // Then, work out connections between them + var roomBorders = new Dictionary>(dungeon.Rooms.Count); + + foreach (var room in dungeon.Rooms) + { + var roomEdges = new HashSet(); + + foreach (var index in room.Tiles) + { + for (var x = -1; x <= 1; x++) + { + for (var y = -1; y <= 1; y++) + { + // Cardinals only + if (x != 0 && y != 0 || + x == 0 && y == 0) + { + continue; + } + + var neighbor = new Vector2i(index.X + x, index.Y + y); + + if (dungeon.RoomTiles.Contains(neighbor)) + continue; + + if (!_anchorable.TileFree(_grid, neighbor, DungeonSystem.CollisionLayer, DungeonSystem.CollisionMask)) + continue; + + roomEdges.Add(neighbor); + } + } + } + + roomBorders.Add(room, roomEdges); + } + + // Do pathfind from first room to work out graph. + // TODO: Optional loops + + var roomConnections = new Dictionary>(); + var tileDef = _tileDefManager[tileProto]; + + foreach (var (room, border) in roomBorders) + { + var conns = roomConnections.GetOrNew(room); + + foreach (var (otherRoom, otherBorders) in roomBorders) + { + if (room.Equals(otherRoom) || + conns.Contains(otherRoom)) + { + continue; + } + + var flipp = new HashSet(border); + flipp.IntersectWith(otherBorders); + + if (flipp.Count == 0 || + gen.OverlapCount != -1 && flipp.Count != gen.OverlapCount) + continue; + + var center = Vector2.Zero; + + foreach (var node in flipp) + { + center += node + _grid.TileSizeHalfVector; + } + + center /= flipp.Count; + // Weight airlocks towards center more. + var nodeDistances = new List<(Vector2i Node, float Distance)>(flipp.Count); + + foreach (var node in flipp) + { + nodeDistances.Add((node, (node + _grid.TileSizeHalfVector - center).LengthSquared())); + } + + nodeDistances.Sort((x, y) => x.Distance.CompareTo(y.Distance)); + + var width = gen.Count; + + for (var i = 0; i < nodeDistances.Count; i++) + { + var node = nodeDistances[i].Node; + var gridPos = _maps.GridTileToLocal(_gridUid, _grid, node); + if (!_anchorable.TileFree(_grid, node, DungeonSystem.CollisionLayer, DungeonSystem.CollisionMask)) + continue; + + width--; + _maps.SetTile(_gridUid, _grid, node, _tile.GetVariantTile((ContentTileDefinition) tileDef, random)); + + if (flank != null && nodeDistances.Count - i <= 2) + { + _entManager.SpawnEntities(gridPos, EntitySpawnCollection.GetSpawns(flank.Entries, random)); + } + else + { + // Iterate neighbors and check for blockers, if so bulldoze + ClearDoor(dungeon, _grid, node); + + _entManager.SpawnEntities(gridPos, EntitySpawnCollection.GetSpawns(entrance.Entries, random)); + } + + if (width == 0) + break; + } + + conns.Add(otherRoom); + var otherConns = roomConnections.GetOrNew(otherRoom); + otherConns.Add(room); + await SuspendDungeon(); + + if (!ValidateResume()) + return; + } + } + } +} diff --git a/Content.Server/Procedural/DungeonJob/DungeonJob.PostGenRoomEntrance.cs b/Content.Server/Procedural/DungeonJob/DungeonJob.PostGenRoomEntrance.cs new file mode 100644 index 00000000000..09d223e86cf --- /dev/null +++ b/Content.Server/Procedural/DungeonJob/DungeonJob.PostGenRoomEntrance.cs @@ -0,0 +1,48 @@ +using System.Threading.Tasks; +using Content.Shared.Maps; +using Content.Shared.Procedural; +using Content.Shared.Procedural.PostGeneration; +using Content.Shared.Storage; +using Robust.Shared.Map; + +namespace Content.Server.Procedural.DungeonJob; + +public sealed partial class DungeonJob +{ + /// + /// + /// + private async Task PostGen(RoomEntranceDunGen gen, DungeonData data, Dungeon dungeon, HashSet reservedTiles, Random random) + { + if (!data.Tiles.TryGetValue(DungeonDataKey.FallbackTile, out var tileProto) || + !data.SpawnGroups.TryGetValue(DungeonDataKey.Entrance, out var entranceProtos) || + !_prototype.TryIndex(entranceProtos, out var entranceIn)) + { + LogDataError(typeof(RoomEntranceDunGen)); + return; + } + + var setTiles = new List<(Vector2i, Tile)>(); + var tileDef = _tileDefManager[tileProto]; + + foreach (var room in dungeon.Rooms) + { + foreach (var entrance in room.Entrances) + { + setTiles.Add((entrance, _tile.GetVariantTile((ContentTileDefinition) tileDef, random))); + } + } + + _maps.SetTiles(_gridUid, _grid, setTiles); + + foreach (var room in dungeon.Rooms) + { + foreach (var entrance in room.Entrances) + { + _entManager.SpawnEntities( + _maps.GridTileToLocal(_gridUid, _grid, entrance), + EntitySpawnCollection.GetSpawns(entranceIn.Entries, random)); + } + } + } +} diff --git a/Content.Server/Procedural/DungeonJob/DungeonJob.PostGenSplineDungeonConnector.cs b/Content.Server/Procedural/DungeonJob/DungeonJob.PostGenSplineDungeonConnector.cs new file mode 100644 index 00000000000..8fe2f36665f --- /dev/null +++ b/Content.Server/Procedural/DungeonJob/DungeonJob.PostGenSplineDungeonConnector.cs @@ -0,0 +1,147 @@ +using System.Numerics; +using System.Threading.Tasks; +using Content.Server.NPC.Pathfinding; +using Content.Shared.Procedural; +using Content.Shared.Procedural.PostGeneration; +using Robust.Shared.Map; +using Robust.Shared.Random; + +namespace Content.Server.Procedural.DungeonJob; + +public sealed partial class DungeonJob +{ + /// + /// + /// + private async Task PostGen( + SplineDungeonConnectorDunGen gen, + DungeonData data, + List dungeons, + HashSet reservedTiles, + Random random) + { + // TODO: The path itself use the tile + // Widen it randomly (probably for each tile offset it by some changing amount). + + // NOOP + if (dungeons.Count <= 1) + return Dungeon.Empty; + + if (!data.Tiles.TryGetValue(DungeonDataKey.FallbackTile, out var fallback) || + !data.Tiles.TryGetValue(DungeonDataKey.WidenTile, out var widen)) + { + LogDataError(typeof(SplineDungeonConnectorDunGen)); + return Dungeon.Empty; + } + + var nodes = new List(); + + foreach (var dungeon in dungeons) + { + foreach (var room in dungeon.Rooms) + { + if (room.Entrances.Count == 0) + continue; + + nodes.Add(room.Entrances[0]); + break; + } + } + + var tree = _dungeon.MinimumSpanningTree(nodes, random); + await SuspendDungeon(); + + if (!ValidateResume()) + return Dungeon.Empty; + + var tiles = new List<(Vector2i Index, Tile Tile)>(); + var pathfinding = _entManager.System(); + var allTiles = new HashSet(); + var fallbackTile = new Tile(_prototype.Index(fallback).TileId); + + foreach (var pair in tree) + { + var path = pathfinding.GetSplinePath(new PathfindingSystem.SplinePathArgs() + { + Distance = gen.DivisionDistance, + MaxRatio = gen.VarianceMax, + Args = new PathfindingSystem.SimplePathArgs() + { + Start = pair.Start, + End = pair.End, + TileCost = node => + { + // We want these to get prioritised internally and into space if it's a space dungeon. + if (_maps.TryGetTile(_grid, node, out var tile) && !tile.IsEmpty) + return 1f; + + return 5f; + } + }, + }, + random); + + // Welp + if (path.Path.Count == 0) + { + _sawmill.Error($"Unable to connect spline dungeon path for {_entManager.ToPrettyString(_gridUid)} between {pair.Start} and {pair.End}"); + continue; + } + + await SuspendDungeon(); + + if (!ValidateResume()) + return Dungeon.Empty; + + var wide = pathfinding.GetWiden(new PathfindingSystem.WidenArgs() + { + Path = path.Path, + }, + random); + + tiles.Clear(); + allTiles.EnsureCapacity(allTiles.Count + wide.Count); + + foreach (var node in wide) + { + if (reservedTiles.Contains(node)) + continue; + + allTiles.Add(node); + Tile tile; + + if (random.Prob(0.9f)) + { + tile = new Tile(_prototype.Index(widen).TileId); + } + else + { + tile = _tileDefManager.GetVariantTile(widen, random); + } + + tiles.Add((node, tile)); + } + + _maps.SetTiles(_gridUid, _grid, tiles); + tiles.Clear(); + allTiles.EnsureCapacity(allTiles.Count + path.Path.Count); + + foreach (var node in path.Path) + { + if (reservedTiles.Contains(node)) + continue; + + allTiles.Add(node); + tiles.Add((node, fallbackTile)); + } + + _maps.SetTiles(_gridUid, _grid, tiles); + } + + var dungy = new Dungeon(); + var dungyRoom = new DungeonRoom(allTiles, Vector2.Zero, Box2i.Empty, new HashSet()); + dungy.AddRoom(dungyRoom); + + return dungy; + } +} diff --git a/Content.Server/Procedural/DungeonJob/DungeonJob.PostGenWallMount.cs b/Content.Server/Procedural/DungeonJob/DungeonJob.PostGenWallMount.cs new file mode 100644 index 00000000000..afc7608d64a --- /dev/null +++ b/Content.Server/Procedural/DungeonJob/DungeonJob.PostGenWallMount.cs @@ -0,0 +1,56 @@ +using System.Threading.Tasks; +using Content.Shared.Procedural; +using Content.Shared.Procedural.PostGeneration; +using Content.Shared.Storage; +using Robust.Shared.Random; + +namespace Content.Server.Procedural.DungeonJob; + +public sealed partial class DungeonJob +{ + /// + /// + /// + private async Task PostGen(WallMountDunGen gen, DungeonData data, Dungeon dungeon, HashSet reservedTiles, Random random) + { + if (!data.Tiles.TryGetValue(DungeonDataKey.FallbackTile, out var tileProto)) + { + _sawmill.Error($"Tried to run {nameof(WallMountDunGen)} without any dungeon data set which is unsupported"); + return; + } + + var tileDef = _prototype.Index(tileProto); + data.SpawnGroups.TryGetValue(DungeonDataKey.WallMounts, out var spawnProto); + + var checkedTiles = new HashSet(); + var allExterior = new HashSet(dungeon.CorridorExteriorTiles); + allExterior.UnionWith(dungeon.RoomExteriorTiles); + var count = 0; + + foreach (var neighbor in allExterior) + { + // Occupado + if (dungeon.RoomTiles.Contains(neighbor) || checkedTiles.Contains(neighbor) || !_anchorable.TileFree(_grid, neighbor, DungeonSystem.CollisionLayer, DungeonSystem.CollisionMask)) + continue; + + if (!random.Prob(gen.Prob) || !checkedTiles.Add(neighbor)) + continue; + + _maps.SetTile(_gridUid, _grid, neighbor, _tile.GetVariantTile(tileDef, random)); + var gridPos = _maps.GridTileToLocal(_gridUid, _grid, neighbor); + var protoNames = EntitySpawnCollection.GetSpawns(_prototype.Index(spawnProto).Entries, random); + + _entManager.SpawnEntities(gridPos, protoNames); + count += protoNames.Count; + + if (count > 20) + { + count -= 20; + await SuspendDungeon(); + + if (!ValidateResume()) + return; + } + } + } +} diff --git a/Content.Server/Procedural/DungeonJob.WormPost.cs b/Content.Server/Procedural/DungeonJob/DungeonJob.PostGenWorm.cs similarity index 88% rename from Content.Server/Procedural/DungeonJob.WormPost.cs rename to Content.Server/Procedural/DungeonJob/DungeonJob.PostGenWorm.cs index 5d2271cae65..6fd00e54824 100644 --- a/Content.Server/Procedural/DungeonJob.WormPost.cs +++ b/Content.Server/Procedural/DungeonJob/DungeonJob.PostGenWorm.cs @@ -1,23 +1,27 @@ using System.Linq; -using System.Numerics; using System.Threading.Tasks; using Content.Shared.Procedural; using Content.Shared.Procedural.PostGeneration; using Robust.Shared.Collections; using Robust.Shared.Map; -using Robust.Shared.Map.Components; using Robust.Shared.Random; using Robust.Shared.Utility; -namespace Content.Server.Procedural; +namespace Content.Server.Procedural.DungeonJob; public sealed partial class DungeonJob { /// - /// Tries to connect rooms via worm-like corridors. + /// /// - private async Task PostGen(WormCorridorPostGen gen, Dungeon dungeon, EntityUid gridUid, MapGridComponent grid, Random random) + private async Task PostGen(WormCorridorDunGen gen, DungeonData data, Dungeon dungeon, HashSet reservedTiles, Random random) { + if (!data.Tiles.TryGetValue(DungeonDataKey.FallbackTile, out var tileProto) || !_prototype.TryIndex(tileProto, out var tileDef)) + { + _sawmill.Error($"Tried to run {nameof(WormCorridorDunGen)} without any dungeon data set which is unsupported"); + return; + } + var networks = new List<(Vector2i Start, HashSet Network)>(); // List of places to start from. @@ -32,7 +36,7 @@ private async Task PostGen(WormCorridorPostGen gen, Dungeon dungeon, EntityUid g networks.Add((entrance, network)); // Point away from the room to start with. - startAngles.Add(entrance, (entrance + grid.TileSizeHalfVector - room.Center).ToAngle()); + startAngles.Add(entrance, (entrance + _grid.TileSizeHalfVector - room.Center).ToAngle()); } } @@ -46,7 +50,7 @@ private async Task PostGen(WormCorridorPostGen gen, Dungeon dungeon, EntityUid g // Find a random network to worm from. var startIndex = (i % networks.Count); var startPos = networks[startIndex].Start; - var position = startPos + grid.TileSizeHalfVector; + var position = startPos + _grid.TileSizeHalfVector; var remainingLength = gen.Length; worm.Clear(); @@ -108,7 +112,7 @@ private async Task PostGen(WormCorridorPostGen gen, Dungeon dungeon, EntityUid g costSoFar[startNode] = 0f; var count = 0; - await SuspendIfOutOfTime(); + await SuspendDungeon(); if (!ValidateResume()) return; @@ -174,9 +178,9 @@ private async Task PostGen(WormCorridorPostGen gen, Dungeon dungeon, EntityUid g WidenCorridor(dungeon, gen.Width, main.Network); dungeon.CorridorTiles.UnionWith(main.Network); BuildCorridorExterior(dungeon); + dungeon.RefreshAllTiles(); var tiles = new List<(Vector2i Index, Tile Tile)>(); - var tileDef = _prototype.Index(gen.Tile); foreach (var tile in dungeon.CorridorTiles) { diff --git a/Content.Server/Procedural/DungeonJob/DungeonJob.cs b/Content.Server/Procedural/DungeonJob/DungeonJob.cs new file mode 100644 index 00000000000..1468a80902c --- /dev/null +++ b/Content.Server/Procedural/DungeonJob/DungeonJob.cs @@ -0,0 +1,309 @@ +using System.Threading; +using System.Threading.Tasks; +using Content.Server.Decals; +using Content.Server.NPC.Components; +using Content.Server.NPC.HTN; +using Content.Server.NPC.Systems; +using Content.Shared.Construction.EntitySystems; +using Content.Shared.Maps; +using Content.Shared.Procedural; +using Content.Shared.Procedural.DungeonGenerators; +using Content.Shared.Procedural.DungeonLayers; +using Content.Shared.Procedural.PostGeneration; +using Content.Shared.Tag; +using JetBrains.Annotations; +using Robust.Server.Physics; +using Robust.Shared.CPUJob.JobQueues; +using Robust.Shared.Map; +using Robust.Shared.Map.Components; +using Robust.Shared.Physics.Components; +using Robust.Shared.Prototypes; +using Robust.Shared.Random; +using Robust.Shared.Utility; +using IDunGenLayer = Content.Shared.Procedural.IDunGenLayer; + +namespace Content.Server.Procedural.DungeonJob; + +public sealed partial class DungeonJob : Job> +{ + public bool TimeSlice = true; + + private readonly IEntityManager _entManager; + private readonly IPrototypeManager _prototype; + private readonly ITileDefinitionManager _tileDefManager; + + private readonly AnchorableSystem _anchorable; + private readonly DecalSystem _decals; + private readonly DungeonSystem _dungeon; + private readonly EntityLookupSystem _lookup; + private readonly TagSystem _tags; + private readonly TileSystem _tile; + private readonly SharedMapSystem _maps; + private readonly SharedTransformSystem _transform; + + private EntityQuery _physicsQuery; + private EntityQuery _xformQuery; + + private readonly DungeonConfigPrototype _gen; + private readonly int _seed; + private readonly Vector2i _position; + + private readonly EntityUid _gridUid; + private readonly MapGridComponent _grid; + + private readonly ISawmill _sawmill; + + public DungeonJob( + ISawmill sawmill, + double maxTime, + IEntityManager entManager, + IPrototypeManager prototype, + ITileDefinitionManager tileDefManager, + AnchorableSystem anchorable, + DecalSystem decals, + DungeonSystem dungeon, + EntityLookupSystem lookup, + TileSystem tile, + SharedTransformSystem transform, + DungeonConfigPrototype gen, + MapGridComponent grid, + EntityUid gridUid, + int seed, + Vector2i position, + CancellationToken cancellation = default) : base(maxTime, cancellation) + { + _sawmill = sawmill; + _entManager = entManager; + _prototype = prototype; + _tileDefManager = tileDefManager; + + _anchorable = anchorable; + _decals = decals; + _dungeon = dungeon; + _lookup = lookup; + _tile = tile; + _tags = _entManager.System(); + _maps = _entManager.System(); + _transform = transform; + + _physicsQuery = _entManager.GetEntityQuery(); + _xformQuery = _entManager.GetEntityQuery(); + + _gen = gen; + _grid = grid; + _gridUid = gridUid; + _seed = seed; + _position = position; + } + + /// + /// Gets the relevant dungeon, running recursively as relevant. + /// + /// Should we reserve tiles even if the config doesn't specify. + private async Task> GetDungeons( + Vector2i position, + DungeonConfigPrototype config, + DungeonData data, + List layers, + HashSet reservedTiles, + int seed, + Random random) + { + var dungeons = new List(); + var count = random.Next(config.MinCount, config.MaxCount + 1); + + for (var i = 0; i < count; i++) + { + position += random.NextPolarVector2(config.MinOffset, config.MaxOffset).Floored(); + + foreach (var layer in layers) + { + await RunLayer(dungeons, data, position, layer, reservedTiles, seed, random); + + if (config.ReserveTiles) + { + foreach (var dungeon in dungeons) + { + reservedTiles.UnionWith(dungeon.AllTiles); + } + } + + await SuspendDungeon(); + if (!ValidateResume()) + return new List(); + } + } + + return dungeons; + } + + protected override async Task?> Process() + { + _sawmill.Info($"Generating dungeon {_gen.ID} with seed {_seed} on {_entManager.ToPrettyString(_gridUid)}"); + _grid.CanSplit = false; + var random = new Random(_seed); + var position = (_position + random.NextPolarVector2(_gen.MinOffset, _gen.MaxOffset)).Floored(); + + // Tiles we can no longer generate on due to being reserved elsewhere. + var reservedTiles = new HashSet(); + + var dungeons = await GetDungeons(position, _gen, _gen.Data, _gen.Layers, reservedTiles, _seed, random); + // To make it slightly more deterministic treat this RNG as separate ig. + + // Post-processing after finishing loading. + + // Defer splitting so they don't get spammed and so we don't have to worry about tracking the grid along the way. + _grid.CanSplit = true; + _entManager.System().CheckSplits(_gridUid); + var npcSystem = _entManager.System(); + var npcs = new HashSet>(); + + _lookup.GetChildEntities(_gridUid, npcs); + + foreach (var npc in npcs) + { + npcSystem.WakeNPC(npc.Owner, npc.Comp); + } + + return dungeons; + } + + private async Task RunLayer( + List dungeons, + DungeonData data, + Vector2i position, + IDunGenLayer layer, + HashSet reservedTiles, + int seed, + Random random) + { + _sawmill.Debug($"Doing postgen {layer.GetType()} for {_gen.ID} with seed {_seed}"); + + // If there's a way to just call the methods directly for the love of god tell me. + // Some of these don't care about reservedtiles because they only operate on dungeon tiles (which should + // never be reserved) + + // Some may or may not return dungeons. + // It's clamplicated but yeah procgen layering moment I'll take constructive feedback. + + switch (layer) + { + case AutoCablingDunGen cabling: + await PostGen(cabling, data, dungeons[^1], reservedTiles, random); + break; + case BiomeMarkerLayerDunGen markerPost: + await PostGen(markerPost, data, dungeons[^1], reservedTiles, random); + break; + case BiomeDunGen biome: + await PostGen(biome, data, dungeons[^1], reservedTiles, random); + break; + case BoundaryWallDunGen boundary: + await PostGen(boundary, data, dungeons[^1], reservedTiles, random); + break; + case CornerClutterDunGen clutter: + await PostGen(clutter, data, dungeons[^1], reservedTiles, random); + break; + case CorridorClutterDunGen corClutter: + await PostGen(corClutter, data, dungeons[^1], reservedTiles, random); + break; + case CorridorDunGen cordor: + await PostGen(cordor, data, dungeons[^1], reservedTiles, random); + break; + case CorridorDecalSkirtingDunGen decks: + await PostGen(decks, data, dungeons[^1], reservedTiles, random); + break; + case EntranceFlankDunGen flank: + await PostGen(flank, data, dungeons[^1], reservedTiles, random); + break; + case ExteriorDunGen exterior: + dungeons.AddRange(await GenerateExteriorDungen(position, exterior, reservedTiles, random)); + break; + case FillGridDunGen fill: + dungeons.Add(await GenerateFillDunGen(data, reservedTiles)); + break; + case JunctionDunGen junc: + await PostGen(junc, data, dungeons[^1], reservedTiles, random); + break; + case MiddleConnectionDunGen dordor: + await PostGen(dordor, data, dungeons[^1], reservedTiles, random); + break; + case DungeonEntranceDunGen entrance: + await PostGen(entrance, data, dungeons[^1], reservedTiles, random); + break; + case ExternalWindowDunGen externalWindow: + await PostGen(externalWindow, data, dungeons[^1], reservedTiles, random); + break; + case InternalWindowDunGen internalWindow: + await PostGen(internalWindow, data, dungeons[^1], reservedTiles, random); + break; + case MobsDunGen mob: + await PostGen(mob, dungeons[^1], random); + break; + case NoiseDistanceDunGen distance: + dungeons.Add(await GenerateNoiseDistanceDunGen(position, distance, reservedTiles, seed, random)); + break; + case NoiseDunGen noise: + dungeons.Add(await GenerateNoiseDunGen(position, noise, reservedTiles, seed, random)); + break; + case OreDunGen ore: + await PostGen(ore, dungeons[^1], random); + break; + case PrefabDunGen prefab: + dungeons.Add(await GeneratePrefabDunGen(position, data, prefab, reservedTiles, random)); + break; + case PrototypeDunGen prototypo: + var groupConfig = _prototype.Index(prototypo.Proto); + position = (position + random.NextPolarVector2(groupConfig.MinOffset, groupConfig.MaxOffset)).Floored(); + + var dataCopy = groupConfig.Data.Clone(); + dataCopy.Apply(data); + + dungeons.AddRange(await GetDungeons(position, groupConfig, dataCopy, groupConfig.Layers, reservedTiles, seed, random)); + break; + case ReplaceTileDunGen replace: + dungeons.Add(await GenerateTileReplacementDunGen(replace, data, reservedTiles, random)); + break; + case RoomEntranceDunGen rEntrance: + await PostGen(rEntrance, data, dungeons[^1], reservedTiles, random); + break; + case SplineDungeonConnectorDunGen spline: + dungeons.Add(await PostGen(spline, data, dungeons, reservedTiles, random)); + break; + case WallMountDunGen wall: + await PostGen(wall, data, dungeons[^1], reservedTiles, random); + break; + case WormCorridorDunGen worm: + await PostGen(worm, data, dungeons[^1], reservedTiles, random); + break; + default: + throw new NotImplementedException(); + } + } + + private void LogDataError(Type type) + { + _sawmill.Error($"Unable to find dungeon data keys for {type}"); + } + + [Pure] + private bool ValidateResume() + { + if (_entManager.Deleted(_gridUid)) + { + return false; + } + + return true; + } + + /// + /// Wrapper around + /// + private async Task SuspendDungeon() + { + if (!TimeSlice) + return; + + await SuspendIfOutOfTime(); + } +} diff --git a/Content.Server/Procedural/DungeonSystem.Commands.cs b/Content.Server/Procedural/DungeonSystem.Commands.cs index d783eb60c63..51a6a57bbeb 100644 --- a/Content.Server/Procedural/DungeonSystem.Commands.cs +++ b/Content.Server/Procedural/DungeonSystem.Commands.cs @@ -51,6 +51,8 @@ private async void GenerateDungeon(IConsoleShell shell, string argstr, string[] dungeonUid = EntityManager.CreateEntityUninitialized(null, new EntityCoordinates(dungeonUid, position)); dungeonGrid = EntityManager.AddComponent(dungeonUid); EntityManager.InitializeAndStartEntity(dungeonUid, mapId); + // If we created a grid (e.g. space dungen) then offset it so we don't double-apply positions + position = Vector2i.Zero; } int seed; diff --git a/Content.Server/Procedural/DungeonSystem.Rooms.cs b/Content.Server/Procedural/DungeonSystem.Rooms.cs index ddd4a4732f8..8a1606c4889 100644 --- a/Content.Server/Procedural/DungeonSystem.Rooms.cs +++ b/Content.Server/Procedural/DungeonSystem.Rooms.cs @@ -64,6 +64,7 @@ public void SpawnRoom( Vector2i origin, DungeonRoomPrototype room, Random random, + HashSet? reservedTiles, bool clearExisting = false, bool rotation = false) { @@ -78,7 +79,7 @@ public void SpawnRoom( var roomTransform = Matrix3Helpers.CreateTransform((Vector2) room.Size / 2f, roomRotation); var finalTransform = Matrix3x2.Multiply(roomTransform, originTransform); - SpawnRoom(gridUid, grid, finalTransform, room, clearExisting); + SpawnRoom(gridUid, grid, finalTransform, room, reservedTiles, clearExisting); } public Angle GetRoomRotation(DungeonRoomPrototype room, Random random) @@ -103,6 +104,7 @@ public void SpawnRoom( MapGridComponent grid, Matrix3x2 roomTransform, DungeonRoomPrototype room, + HashSet? reservedTiles = null, bool clearExisting = false) { // Ensure the underlying template exists. @@ -150,6 +152,10 @@ public void SpawnRoom( var tilePos = Vector2.Transform(indices + tileOffset, roomTransform); var rounded = tilePos.Floored(); + + if (!clearExisting && reservedTiles?.Contains(rounded) == true) + continue; + _tiles.Add((rounded, tileRef.Tile)); } } @@ -165,6 +171,10 @@ public void SpawnRoom( { var templateXform = _xformQuery.GetComponent(templateEnt); var childPos = Vector2.Transform(templateXform.LocalPosition - roomCenter, roomTransform); + + if (!clearExisting && reservedTiles?.Contains(childPos.Floored()) == true) + continue; + var childRot = templateXform.LocalRotation + finalRoomRotation; var protoId = _metaQuery.GetComponent(templateEnt).EntityPrototype?.ID; @@ -192,8 +202,11 @@ public void SpawnRoom( // Offset by 0.5 because decals are offset from bot-left corner // So we convert it to center of tile then convert it back again after transform. // Do these shenanigans because 32x32 decals assume as they are centered on bottom-left of tiles. - var position = Vector2.Transform(decal.Coordinates + Vector2Helpers.Half - roomCenter, roomTransform); - position -= Vector2Helpers.Half; + var position = Vector2.Transform(decal.Coordinates + grid.TileSizeHalfVector - roomCenter, roomTransform); + position -= grid.TileSizeHalfVector; + + if (!clearExisting && reservedTiles?.Contains(position.Floored()) == true) + continue; // Umm uhh I love decals so uhhhh idk what to do about this var angle = (decal.Angle + finalRoomRotation).Reduced(); diff --git a/Content.Server/Procedural/DungeonSystem.cs b/Content.Server/Procedural/DungeonSystem.cs index 36009896a2c..b73e843fffd 100644 --- a/Content.Server/Procedural/DungeonSystem.cs +++ b/Content.Server/Procedural/DungeonSystem.cs @@ -12,6 +12,7 @@ using Content.Shared.Procedural; using Content.Shared.Tag; using Robust.Server.GameObjects; +using Robust.Shared.Collections; using Robust.Shared.Configuration; using Robust.Shared.Console; using Robust.Shared.Map; @@ -49,7 +50,7 @@ public sealed partial class DungeonSystem : SharedDungeonSystem public const int CollisionLayer = (int) CollisionGroup.Impassable; private readonly JobQueue _dungeonJobQueue = new(DungeonJobTime); - private readonly Dictionary _dungeonJobs = new(); + private readonly Dictionary _dungeonJobs = new(); [ValidatePrototypeId] public const string FallbackTileId = "FloorSteel"; @@ -190,18 +191,16 @@ public void GenerateDungeon(DungeonConfigPrototype gen, int seed) { var cancelToken = new CancellationTokenSource(); - var job = new DungeonJob( + var job = new DungeonJob.DungeonJob( Log, DungeonJobTime, EntityManager, - _mapManager, _prototype, _tileDefManager, _anchorable, _decals, this, _lookup, - _tag, _tile, _transform, gen, @@ -215,7 +214,7 @@ public void GenerateDungeon(DungeonConfigPrototype gen, _dungeonJobQueue.EnqueueJob(job); } - public async Task GenerateDungeonAsync( + public async Task> GenerateDungeonAsync( DungeonConfigPrototype gen, EntityUid gridUid, MapGridComponent grid, @@ -223,18 +222,16 @@ public async Task GenerateDungeonAsync( int seed) { var cancelToken = new CancellationTokenSource(); - var job = new DungeonJob( + var job = new DungeonJob.DungeonJob( Log, DungeonJobTime, EntityManager, - _mapManager, _prototype, _tileDefManager, _anchorable, _decals, this, _lookup, - _tag, _tile, _transform, gen, diff --git a/Content.Server/Procedural/RoomFillSystem.cs b/Content.Server/Procedural/RoomFillSystem.cs index 20ffa98586d..b539cc9780e 100644 --- a/Content.Server/Procedural/RoomFillSystem.cs +++ b/Content.Server/Procedural/RoomFillSystem.cs @@ -35,6 +35,7 @@ private void OnRoomFillMapInit(EntityUid uid, RoomFillComponent component, MapIn _maps.LocalToTile(xform.GridUid.Value, mapGrid, xform.Coordinates), room, random, + null, clearExisting: component.ClearExisting, rotation: component.Rotation); } diff --git a/Content.Server/Salvage/SpawnSalvageMissionJob.cs b/Content.Server/Salvage/SpawnSalvageMissionJob.cs index ce844e57a13..e9318792b72 100644 --- a/Content.Server/Salvage/SpawnSalvageMissionJob.cs +++ b/Content.Server/Salvage/SpawnSalvageMissionJob.cs @@ -176,9 +176,11 @@ protected override async Task Process() dungeonOffset = dungeonRotation.RotateVec(dungeonOffset); var dungeonMod = _prototypeManager.Index(mission.Dungeon); var dungeonConfig = _prototypeManager.Index(dungeonMod.Proto); - var dungeon = await WaitAsyncTask(_dungeon.GenerateDungeonAsync(dungeonConfig, mapUid, grid, (Vector2i) dungeonOffset, + var dungeons = await WaitAsyncTask(_dungeon.GenerateDungeonAsync(dungeonConfig, mapUid, grid, (Vector2i) dungeonOffset, _missionParams.Seed)); + var dungeon = dungeons.First(); + // Aborty if (dungeon.Rooms.Count == 0) { diff --git a/Content.Server/Shuttles/Components/GridSpawnComponent.cs b/Content.Server/Shuttles/Components/GridSpawnComponent.cs index 5f0fa7dd624..d8144354b8e 100644 --- a/Content.Server/Shuttles/Components/GridSpawnComponent.cs +++ b/Content.Server/Shuttles/Components/GridSpawnComponent.cs @@ -1,4 +1,6 @@ using Content.Server.Shuttles.Systems; +using Content.Shared.Dataset; +using Content.Shared.Procedural; using Robust.Shared.Prototypes; using Robust.Shared.Utility; @@ -14,39 +16,92 @@ public sealed partial class GridSpawnComponent : Component /// Dictionary of groups where each group will have entries selected. /// String is just an identifier to make yaml easier. /// - [DataField(required: true)] public Dictionary Groups = new(); + [DataField(required: true)] public Dictionary Groups = new(); } -[DataRecord] -public record struct GridSpawnGroup +public interface IGridSpawnGroup { - public List Paths = new(); - public int MinCount = 1; - public int MaxCount = 1; + /// + /// Minimum distance to spawn away from the station. + /// + public float MinimumDistance { get; } + + /// + public ProtoId? NameDataset { get; } + + /// + int MinCount { get; set; } + + /// + int MaxCount { get; set; } /// /// Components to be added to any spawned grids. /// - public ComponentRegistry AddComponents = new(); + public ComponentRegistry AddComponents { get; set; } /// /// Hide the IFF label of the grid. /// - public bool Hide = false; + public bool Hide { get; set; } /// /// Should we set the metadata name of a grid. Useful for admin purposes. /// - public bool NameGrid = false; + public bool NameGrid { get; set; } /// /// Should we add this to the station's grids (if possible / relevant). /// - public bool StationGrid = true; + public bool StationGrid { get; set; } +} + +[DataRecord] +public sealed class DungeonSpawnGroup : IGridSpawnGroup +{ + /// + /// Prototypes we can choose from to spawn. + /// + public List> Protos = new(); + + /// + public float MinimumDistance { get; } + + /// + public ProtoId? NameDataset { get; } + + /// + public int MinCount { get; set; } = 1; + + /// + public int MaxCount { get; set; } = 1; + + /// + public ComponentRegistry AddComponents { get; set; } = new(); + + /// + public bool Hide { get; set; } = false; + + /// + public bool NameGrid { get; set; } = false; + + /// + public bool StationGrid { get; set; } = false; +} + +[DataRecord] +public sealed class GridSpawnGroup : IGridSpawnGroup +{ + public List Paths = new(); - public GridSpawnGroup() - { - } + public float MinimumDistance { get; } + public ProtoId? NameDataset { get; } + public int MinCount { get; set; } = 1; + public int MaxCount { get; set; } = 1; + public ComponentRegistry AddComponents { get; set; } = new(); + public bool Hide { get; set; } = false; + public bool NameGrid { get; set; } = true; + public bool StationGrid { get; set; } = true; } diff --git a/Content.Server/Shuttles/Systems/ShuttleSystem.GridFill.cs b/Content.Server/Shuttles/Systems/ShuttleSystem.GridFill.cs index 853548add37..b4fcccd8055 100644 --- a/Content.Server/Shuttles/Systems/ShuttleSystem.GridFill.cs +++ b/Content.Server/Shuttles/Systems/ShuttleSystem.GridFill.cs @@ -1,9 +1,14 @@ +using System.Numerics; using Content.Server.Shuttles.Components; using Content.Server.Station.Components; using Content.Server.Station.Events; using Content.Shared.Cargo.Components; using Content.Shared.CCVar; +using Content.Shared.Procedural; +using Content.Shared.Salvage; using Content.Shared.Shuttles.Components; +using Robust.Shared.Collections; +using Robust.Shared.Map; using Robust.Shared.Random; using Robust.Shared.Utility; @@ -80,6 +85,76 @@ private void CargoSpawn(EntityUid uid, StationCargoShuttleComponent component) _mapManager.DeleteMap(mapId); } + private bool TryDungeonSpawn(EntityUid targetGrid, EntityUid stationUid, MapId mapId, DungeonSpawnGroup group, out EntityUid spawned) + { + spawned = EntityUid.Invalid; + var dungeonProtoId = _random.Pick(group.Protos); + + if (!_protoManager.TryIndex(dungeonProtoId, out var dungeonProto)) + { + return false; + } + + var spawnCoords = new EntityCoordinates(targetGrid, Vector2.Zero); + + if (group.MinimumDistance > 0f) + { + spawnCoords = spawnCoords.Offset(_random.NextVector2(group.MinimumDistance, group.MinimumDistance * 1.5f)); + } + + var spawnMapCoords = _transform.ToMapCoordinates(spawnCoords); + var spawnedGrid = _mapManager.CreateGridEntity(mapId); + + _transform.SetMapCoordinates(spawnedGrid, spawnMapCoords); + _dungeon.GenerateDungeon(dungeonProto, spawnedGrid.Owner, spawnedGrid.Comp, Vector2i.Zero, _random.Next()); + + spawned = spawnedGrid.Owner; + return true; + } + + private bool TryGridSpawn(EntityUid targetGrid, EntityUid stationUid, MapId mapId, GridSpawnGroup group, out EntityUid spawned) + { + spawned = EntityUid.Invalid; + + if (group.Paths.Count == 0) + { + Log.Error($"Found no paths for GridSpawn"); + return false; + } + + var paths = new ValueList(); + + // Round-robin so we try to avoid dupes where possible. + if (paths.Count == 0) + { + paths.AddRange(group.Paths); + _random.Shuffle(paths); + } + + var path = paths[^1]; + paths.RemoveAt(paths.Count - 1); + + if (_loader.TryLoad(mapId, path.ToString(), out var ent) && ent.Count == 1) + { + if (TryComp(ent[0], out var shuttle)) + { + TryFTLProximity(ent[0], targetGrid); + } + + if (group.NameGrid) + { + var name = path.FilenameWithoutExtension; + _metadata.SetEntityName(ent[0], name); + } + + spawned = ent[0]; + return true; + } + + Log.Error($"Error loading gridspawn for {ToPrettyString(stationUid)} / {path}"); + return false; + } + private void GridSpawns(EntityUid uid, GridSpawnComponent component) { if (!_cfg.GetCVar(CCVars.GridFill)) @@ -97,81 +172,49 @@ private void GridSpawns(EntityUid uid, GridSpawnComponent component) // Spawn on a dummy map and try to FTL if possible, otherwise dump it. var mapId = _mapManager.CreateMap(); - var valid = true; - var paths = new List(); foreach (var group in component.Groups.Values) { - if (group.Paths.Count == 0) - { - Log.Error($"Found no paths for GridSpawn"); - continue; - } - - var count = _random.Next(group.MinCount, group.MaxCount); - paths.Clear(); + var count = _random.Next(group.MinCount, group.MaxCount + 1); for (var i = 0; i < count; i++) { - // Round-robin so we try to avoid dupes where possible. - if (paths.Count == 0) - { - paths.AddRange(group.Paths); - _random.Shuffle(paths); - } - - var path = paths[^1]; - paths.RemoveAt(paths.Count - 1); + EntityUid spawned; - if (_loader.TryLoad(mapId, path.ToString(), out var ent) && ent.Count == 1) + switch (group) { - if (TryComp(ent[0], out var shuttle)) - { - TryFTLProximity(ent[0], targetGrid.Value); - } - else - { - valid = false; - } - - if (group.Hide) - { - var iffComp = EnsureComp(ent[0]); - iffComp.Flags |= IFFFlags.HideLabel; - Dirty(ent[0], iffComp); - } - - if (group.StationGrid) - { - _station.AddGridToStation(uid, ent[0]); - } - - if (group.NameGrid) - { - var name = path.FilenameWithoutExtension; - _metadata.SetEntityName(ent[0], name); - } - - foreach (var compReg in group.AddComponents.Values) - { - var compType = compReg.Component.GetType(); + case DungeonSpawnGroup dungeon: + if (!TryDungeonSpawn(targetGrid.Value, uid, mapId, dungeon, out spawned)) + continue; - if (HasComp(ent[0], compType)) + break; + case GridSpawnGroup grid: + if (!TryGridSpawn(targetGrid.Value, uid, mapId, grid, out spawned)) continue; - var comp = _factory.GetComponent(compType); - AddComp(ent[0], comp, true); - } + break; + default: + throw new NotImplementedException(); + } + + if (_protoManager.TryIndex(group.NameDataset, out var dataset)) + { + _metadata.SetEntityName(spawned, SharedSalvageSystem.GetFTLName(dataset, _random.Next())); } - else + + if (group.Hide) { - valid = false; + var iffComp = EnsureComp(spawned); + iffComp.Flags |= IFFFlags.HideLabel; + Dirty(spawned, iffComp); } - if (!valid) + if (group.StationGrid) { - Log.Error($"Error loading gridspawn for {ToPrettyString(uid)} / {path}"); + _station.AddGridToStation(uid, spawned); } + + EntityManager.AddComponents(spawned, group.AddComponents); } } diff --git a/Content.Server/Shuttles/Systems/ShuttleSystem.cs b/Content.Server/Shuttles/Systems/ShuttleSystem.cs index b8f216db737..85703389e9d 100644 --- a/Content.Server/Shuttles/Systems/ShuttleSystem.cs +++ b/Content.Server/Shuttles/Systems/ShuttleSystem.cs @@ -2,6 +2,7 @@ using Content.Server.Body.Systems; using Content.Server.Doors.Systems; using Content.Server.Parallax; +using Content.Server.Procedural; using Content.Server.Shuttles.Components; using Content.Server.Station.Systems; using Content.Server.Stunnable; @@ -20,6 +21,7 @@ using Robust.Shared.Physics; using Robust.Shared.Physics.Components; using Robust.Shared.Physics.Systems; +using Robust.Shared.Prototypes; using Robust.Shared.Random; using Robust.Shared.Timing; @@ -28,15 +30,18 @@ namespace Content.Server.Shuttles.Systems; [UsedImplicitly] public sealed partial class ShuttleSystem : SharedShuttleSystem { + [Dependency] private readonly IAdminLogManager _logger = default!; [Dependency] private readonly IComponentFactory _factory = default!; [Dependency] private readonly IConfigurationManager _cfg = default!; + [Dependency] private readonly IGameTiming _gameTiming = default!; [Dependency] private readonly IMapManager _mapManager = default!; + [Dependency] private readonly IPrototypeManager _protoManager = default!; [Dependency] private readonly IRobustRandom _random = default!; [Dependency] private readonly ITileDefinitionManager _tileDefManager = default!; - [Dependency] private readonly IGameTiming _gameTiming = default!; [Dependency] private readonly BiomeSystem _biomes = default!; [Dependency] private readonly BodySystem _bobby = default!; [Dependency] private readonly DockingSystem _dockSystem = default!; + [Dependency] private readonly DungeonSystem _dungeon = default!; [Dependency] private readonly EntityLookupSystem _lookup = default!; [Dependency] private readonly FixtureSystem _fixtures = default!; [Dependency] private readonly MapLoaderSystem _loader = default!; @@ -52,7 +57,6 @@ public sealed partial class ShuttleSystem : SharedShuttleSystem [Dependency] private readonly ThrowingSystem _throwing = default!; [Dependency] private readonly ThrusterSystem _thruster = default!; [Dependency] private readonly UserInterfaceSystem _uiSystem = default!; - [Dependency] private readonly IAdminLogManager _logger = default!; public const float TileMassMultiplier = 0.5f; diff --git a/Content.Shared/Procedural/Components/EntityRemapComponent.cs b/Content.Shared/Procedural/Components/EntityRemapComponent.cs new file mode 100644 index 00000000000..3d7199743af --- /dev/null +++ b/Content.Shared/Procedural/Components/EntityRemapComponent.cs @@ -0,0 +1,13 @@ +using Robust.Shared.Prototypes; + +namespace Content.Shared.Procedural.Components; + +/// +/// Indicates this entity prototype should be re-mapped to another +/// +[RegisterComponent] +public sealed partial class EntityRemapComponent : Component +{ + [DataField(required: true)] + public Dictionary Mask = new(); +} diff --git a/Content.Shared/Procedural/Distance/DunGenEuclideanSquaredDistance.cs b/Content.Shared/Procedural/Distance/DunGenEuclideanSquaredDistance.cs new file mode 100644 index 00000000000..617304729e2 --- /dev/null +++ b/Content.Shared/Procedural/Distance/DunGenEuclideanSquaredDistance.cs @@ -0,0 +1,10 @@ +namespace Content.Shared.Procedural.Distance; + +/// +/// Produces a rounder shape useful for more natural areas. +/// +public sealed partial class DunGenEuclideanSquaredDistance : IDunGenDistance +{ + [DataField] + public float BlendWeight { get; set; } = 0.50f; +} diff --git a/Content.Shared/Procedural/Distance/DunGenSquareBump.cs b/Content.Shared/Procedural/Distance/DunGenSquareBump.cs new file mode 100644 index 00000000000..48b0c4bcb7e --- /dev/null +++ b/Content.Shared/Procedural/Distance/DunGenSquareBump.cs @@ -0,0 +1,10 @@ +namespace Content.Shared.Procedural.Distance; + +/// +/// Produces a squarish-shape that's better for filling in most of the area. +/// +public sealed partial class DunGenSquareBump : IDunGenDistance +{ + [DataField] + public float BlendWeight { get; set; } = 0.50f; +} diff --git a/Content.Shared/Procedural/Distance/IDunGenDistance.cs b/Content.Shared/Procedural/Distance/IDunGenDistance.cs new file mode 100644 index 00000000000..b1071a14e34 --- /dev/null +++ b/Content.Shared/Procedural/Distance/IDunGenDistance.cs @@ -0,0 +1,14 @@ +namespace Content.Shared.Procedural.Distance; + +/// +/// Used if you want to limit the distance noise is generated by some arbitrary config +/// +[ImplicitDataDefinitionForInheritors] +public partial interface IDunGenDistance +{ + /// + /// How much to blend between the original noise value and the adjusted one. + /// + float BlendWeight { get; } +} + diff --git a/Content.Shared/Procedural/Dungeon.cs b/Content.Shared/Procedural/Dungeon.cs index aecfef2c782..0d290b67905 100644 --- a/Content.Shared/Procedural/Dungeon.cs +++ b/Content.Shared/Procedural/Dungeon.cs @@ -1,8 +1,16 @@ namespace Content.Shared.Procedural; +/// +/// Procedurally generated dungeon data. +/// public sealed class Dungeon { - public readonly List Rooms; + public static Dungeon Empty = new Dungeon(); + + private List _rooms; + private HashSet _allTiles = new(); + + public IReadOnlyList Rooms => _rooms; /// /// Hashset of the tiles across all rooms. @@ -17,18 +25,64 @@ public sealed class Dungeon public readonly HashSet Entrances = new(); - public Dungeon() + public IReadOnlySet AllTiles => _allTiles; + + public Dungeon() : this(new List()) { - Rooms = new List(); } public Dungeon(List rooms) { - Rooms = rooms; + // This reftype is mine now. + _rooms = rooms; + + foreach (var room in _rooms) + { + InternalAddRoom(room); + } + + RefreshAllTiles(); + } + + public void RefreshAllTiles() + { + _allTiles.Clear(); + _allTiles.UnionWith(RoomTiles); + _allTiles.UnionWith(RoomExteriorTiles); + _allTiles.UnionWith(CorridorTiles); + _allTiles.UnionWith(CorridorExteriorTiles); + _allTiles.UnionWith(Entrances); + } + + public void Rebuild() + { + _allTiles.Clear(); + + RoomTiles.Clear(); + RoomExteriorTiles.Clear(); + Entrances.Clear(); - foreach (var room in Rooms) + foreach (var room in _rooms) { - Entrances.UnionWith(room.Entrances); + InternalAddRoom(room, false); } + + RefreshAllTiles(); + } + + public void AddRoom(DungeonRoom room) + { + _rooms.Add(room); + InternalAddRoom(room); + } + + private void InternalAddRoom(DungeonRoom room, bool refreshAll = true) + { + Entrances.UnionWith(room.Entrances); + RoomTiles.UnionWith(room.Tiles); + RoomExteriorTiles.UnionWith(room.Exterior); + + if (refreshAll) + RefreshAllTiles(); } } diff --git a/Content.Shared/Procedural/DungeonConfigPrototype.cs b/Content.Shared/Procedural/DungeonConfigPrototype.cs index 07a7000d637..d0d8e0ff12d 100644 --- a/Content.Shared/Procedural/DungeonConfigPrototype.cs +++ b/Content.Shared/Procedural/DungeonConfigPrototype.cs @@ -1,21 +1,53 @@ -using Content.Shared.Procedural.DungeonGenerators; using Content.Shared.Procedural.PostGeneration; using Robust.Shared.Prototypes; namespace Content.Shared.Procedural; -[Prototype("dungeonConfig")] +[Prototype] public sealed partial class DungeonConfigPrototype : IPrototype { [IdDataField] public string ID { get; private set; } = default!; - [DataField("generator", required: true)] - public IDunGen Generator = default!; + /// + /// + /// + [DataField] + public DungeonData Data = DungeonData.Empty; + + /// + /// The secret sauce, procedural generation layers that get run. + /// + [DataField(required: true)] + public List Layers = new(); + + /// + /// Should we reserve the tiles generated by this config so no other dungeons can spawn on it within the same job? + /// + [DataField] + public bool ReserveTiles; + + /// + /// Minimum times to run the config. + /// + [DataField] + public int MinCount = 1; + + /// + /// Maximum times to run the config. + /// + [DataField] + public int MaxCount = 1; + + /// + /// Minimum amount we can offset the dungeon by. + /// + [DataField] + public int MinOffset; /// - /// Ran after the main dungeon is created. + /// Maximum amount we can offset the dungeon by. /// - [DataField("postGeneration")] - public List PostGeneration = new(); + [DataField] + public int MaxOffset; } diff --git a/Content.Shared/Procedural/DungeonData.cs b/Content.Shared/Procedural/DungeonData.cs new file mode 100644 index 00000000000..58ec9667861 --- /dev/null +++ b/Content.Shared/Procedural/DungeonData.cs @@ -0,0 +1,105 @@ +using System.Linq; +using Content.Shared.Maps; +using Content.Shared.Storage; +using Content.Shared.Whitelist; +using Robust.Shared.Prototypes; +using Robust.Shared.Utility; + +namespace Content.Shared.Procedural; + +/// +/// Used to set dungeon values for all layers. +/// +/// +/// This lets us share data between different dungeon configs without having to repeat entire configs. +/// +[DataRecord] +public sealed class DungeonData +{ + // I hate this but it also significantly reduces yaml bloat if we add like 10 variations on the same set of layers + // e.g. science rooms, engi rooms, cargo rooms all under PlanetBase for example. + // without having to do weird nesting. It also means we don't need to copy-paste the same prototype across several layers + // The alternative is doing like, + // 2 layer prototype, 1 layer with the specified data, 3 layer prototype, 2 layers with specified data, etc. + // As long as we just keep the code clean over time it won't be bad to maintain. + + public static DungeonData Empty = new(); + + public Dictionary Colors = new(); + public Dictionary Entities = new(); + public Dictionary> SpawnGroups = new(); + public Dictionary> Tiles = new(); + public Dictionary Whitelists = new(); + + /// + /// Applies the specified data to this data. + /// + public void Apply(DungeonData data) + { + // Copy-paste moment. + foreach (var color in data.Colors) + { + Colors[color.Key] = color.Value; + } + + foreach (var color in data.Entities) + { + Entities[color.Key] = color.Value; + } + + foreach (var color in data.SpawnGroups) + { + SpawnGroups[color.Key] = color.Value; + } + + foreach (var color in data.Tiles) + { + Tiles[color.Key] = color.Value; + } + + foreach (var color in data.Whitelists) + { + Whitelists[color.Key] = color.Value; + } + } + + public DungeonData Clone() + { + return new DungeonData + { + // Only shallow clones but won't matter for DungeonJob purposes. + Colors = Colors.ShallowClone(), + Entities = Entities.ShallowClone(), + SpawnGroups = SpawnGroups.ShallowClone(), + Tiles = Tiles.ShallowClone(), + Whitelists = Whitelists.ShallowClone(), + }; + } +} + +public enum DungeonDataKey : byte +{ + // Colors + Decals, + + // Entities + Cabling, + CornerWalls, + Fill, + Junction, + Walls, + + // SpawnGroups + CornerClutter, + Entrance, + EntranceFlank, + WallMounts, + Window, + + // Tiles + FallbackTile, + WidenTile, + + // Whitelists + Rooms, +} diff --git a/Content.Shared/Procedural/DungeonGenerators/ExteriorDunGen.cs b/Content.Shared/Procedural/DungeonGenerators/ExteriorDunGen.cs new file mode 100644 index 00000000000..e9a5181f8d0 --- /dev/null +++ b/Content.Shared/Procedural/DungeonGenerators/ExteriorDunGen.cs @@ -0,0 +1,13 @@ +using Robust.Shared.Prototypes; + +namespace Content.Shared.Procedural.DungeonGenerators; + +/// +/// Generates the specified config on an exterior tile of the attached dungeon. +/// Useful if you're using or otherwise want a dungeon on the outside of a grid. +/// +public sealed partial class ExteriorDunGen : IDunGenLayer +{ + [DataField(required: true)] + public ProtoId Proto; +} diff --git a/Content.Shared/Procedural/DungeonGenerators/FillGridDunGen.cs b/Content.Shared/Procedural/DungeonGenerators/FillGridDunGen.cs new file mode 100644 index 00000000000..368ec5cc3e4 --- /dev/null +++ b/Content.Shared/Procedural/DungeonGenerators/FillGridDunGen.cs @@ -0,0 +1,10 @@ +namespace Content.Shared.Procedural.DungeonGenerators; + +/// +/// Fills unreserved tiles with the specified entity prototype. +/// +/// +/// DungeonData keys are: +/// - Fill +/// +public sealed partial class FillGridDunGen : IDunGenLayer; diff --git a/Content.Shared/Procedural/DungeonGenerators/IDunGen.cs b/Content.Shared/Procedural/DungeonGenerators/IDunGen.cs deleted file mode 100644 index 5aa82f1596f..00000000000 --- a/Content.Shared/Procedural/DungeonGenerators/IDunGen.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace Content.Shared.Procedural.DungeonGenerators; - -[ImplicitDataDefinitionForInheritors] -public partial interface IDunGen -{ - -} diff --git a/Content.Shared/Procedural/DungeonGenerators/NoiseDistanceDunGen.cs b/Content.Shared/Procedural/DungeonGenerators/NoiseDistanceDunGen.cs new file mode 100644 index 00000000000..0dfb3daef84 --- /dev/null +++ b/Content.Shared/Procedural/DungeonGenerators/NoiseDistanceDunGen.cs @@ -0,0 +1,18 @@ +using Content.Shared.Procedural.Distance; + +namespace Content.Shared.Procedural.DungeonGenerators; + +/// +/// Like except with maximum dimensions +/// +public sealed partial class NoiseDistanceDunGen : IDunGenLayer +{ + [DataField] + public IDunGenDistance? DistanceConfig; + + [DataField] + public Vector2i Size; + + [DataField(required: true)] + public List Layers = new(); +} diff --git a/Content.Shared/Procedural/DungeonGenerators/NoiseDunGen.cs b/Content.Shared/Procedural/DungeonGenerators/NoiseDunGen.cs index 3ea0d989a2a..56d63bec8f5 100644 --- a/Content.Shared/Procedural/DungeonGenerators/NoiseDunGen.cs +++ b/Content.Shared/Procedural/DungeonGenerators/NoiseDunGen.cs @@ -1,15 +1,12 @@ -using Content.Shared.Maps; +using Content.Shared.Procedural.Distance; using Robust.Shared.Noise; -using Robust.Shared.Prototypes; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.List; namespace Content.Shared.Procedural.DungeonGenerators; /// /// Generates dungeon flooring based on the specified noise. /// -public sealed partial class NoiseDunGen : IDunGen +public sealed partial class NoiseDunGen : IDunGenLayer { /* * Floodfills out from 0 until it finds a valid tile. diff --git a/Content.Shared/Procedural/DungeonGenerators/PrefabDunGen.cs b/Content.Shared/Procedural/DungeonGenerators/PrefabDunGen.cs index ef61fff4b04..aeb24d01448 100644 --- a/Content.Shared/Procedural/DungeonGenerators/PrefabDunGen.cs +++ b/Content.Shared/Procedural/DungeonGenerators/PrefabDunGen.cs @@ -1,30 +1,20 @@ -using Content.Shared.Maps; -using Content.Shared.Tag; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.List; +using Robust.Shared.Prototypes; namespace Content.Shared.Procedural.DungeonGenerators; /// /// Places rooms in pre-selected pack layouts. Chooses rooms from the specified whitelist. /// -public sealed partial class PrefabDunGen : IDunGen +/// +/// DungeonData keys are: +/// - FallbackTile +/// - Rooms +/// +public sealed partial class PrefabDunGen : IDunGenLayer { - /// - /// Rooms need to match any of these tags - /// - [DataField("roomWhitelist", customTypeSerializer:typeof(PrototypeIdListSerializer))] - public List RoomWhitelist = new(); - /// /// Room pack presets we can use for this prefab. /// - [DataField("presets", required: true, customTypeSerializer:typeof(PrototypeIdListSerializer))] - public List Presets = new(); - - /// - /// Fallback tile. - /// - [DataField("tile", customTypeSerializer:typeof(PrototypeIdSerializer))] - public string Tile = "FloorSteel"; + [DataField(required: true)] + public List> Presets = new(); } diff --git a/Content.Shared/Procedural/DungeonGenerators/PrototypeDunGen.cs b/Content.Shared/Procedural/DungeonGenerators/PrototypeDunGen.cs new file mode 100644 index 00000000000..346c60a6cb5 --- /dev/null +++ b/Content.Shared/Procedural/DungeonGenerators/PrototypeDunGen.cs @@ -0,0 +1,13 @@ +using Robust.Shared.Prototypes; + +namespace Content.Shared.Procedural.DungeonGenerators; + +/// +/// Runs another . +/// Used for storing data on 1 system. +/// +public sealed partial class PrototypeDunGen : IDunGenLayer +{ + [DataField(required: true)] + public ProtoId Proto; +} diff --git a/Content.Shared/Procedural/DungeonGenerators/ReplaceTileDunGen.cs b/Content.Shared/Procedural/DungeonGenerators/ReplaceTileDunGen.cs new file mode 100644 index 00000000000..64b76b4cccc --- /dev/null +++ b/Content.Shared/Procedural/DungeonGenerators/ReplaceTileDunGen.cs @@ -0,0 +1,30 @@ +using Content.Shared.Maps; +using Robust.Shared.Noise; +using Robust.Shared.Prototypes; + +namespace Content.Shared.Procedural.DungeonGenerators; + +/// +/// Replaces existing tiles if they're not empty. +/// +public sealed partial class ReplaceTileDunGen : IDunGenLayer +{ + /// + /// Chance for a non-variant tile to be used, in case they're too noisy. + /// + [DataField] + public float VariantWeight = 0.1f; + + [DataField(required: true)] + public List Layers = new(); +} + +[DataRecord] +public record struct ReplaceTileLayer +{ + public ProtoId Tile; + + public float Threshold; + + public FastNoiseLite Noise; +} diff --git a/Content.Shared/Procedural/DungeonLayers/MobsDunGen.cs b/Content.Shared/Procedural/DungeonLayers/MobsDunGen.cs new file mode 100644 index 00000000000..30b502efe07 --- /dev/null +++ b/Content.Shared/Procedural/DungeonLayers/MobsDunGen.cs @@ -0,0 +1,21 @@ +using Content.Shared.Storage; + +namespace Content.Shared.Procedural.DungeonLayers; + + +/// +/// Spawns mobs inside of the dungeon randomly. +/// +public sealed partial class MobsDunGen : IDunGenLayer +{ + // Counts separate to config to avoid some duplication. + + [DataField] + public int MinCount = 1; + + [DataField] + public int MaxCount = 1; + + [DataField(required: true)] + public List Groups = new(); +} diff --git a/Content.Shared/Procedural/DungeonLayers/OreDunGen.cs b/Content.Shared/Procedural/DungeonLayers/OreDunGen.cs new file mode 100644 index 00000000000..31bf367d0e4 --- /dev/null +++ b/Content.Shared/Procedural/DungeonLayers/OreDunGen.cs @@ -0,0 +1,42 @@ +using Robust.Shared.Prototypes; + +namespace Content.Shared.Procedural.DungeonLayers; + +/// +/// Generates veins inside of the specified dungeon. +/// +/// +/// Generates on top of existing entities for sanity reasons moreso than performance. +/// +public sealed partial class OreDunGen : IDunGenLayer +{ + /// + /// If the vein generation should occur on top of existing entities what are we replacing. + /// + [DataField] + public EntProtoId? Replacement; + + /// + /// Entity to spawn. + /// + [DataField(required: true)] + public EntProtoId Entity; + + /// + /// Maximum amount of group spawns + /// + [DataField] + public int Count = 10; + + /// + /// Minimum entities to spawn in one group. + /// + [DataField] + public int MinGroupSize = 1; + + /// + /// Maximum entities to spawn in one group. + /// + [DataField] + public int MaxGroupSize = 1; +} diff --git a/Content.Shared/Procedural/DungeonRoom.cs b/Content.Shared/Procedural/DungeonRoom.cs index 4802949d2f3..0c6af8f23db 100644 --- a/Content.Shared/Procedural/DungeonRoom.cs +++ b/Content.Shared/Procedural/DungeonRoom.cs @@ -2,6 +2,7 @@ namespace Content.Shared.Procedural; +// TODO: Cache center and bounds and shit and don't make the caller deal with it. public sealed record DungeonRoom(HashSet Tiles, Vector2 Center, Box2i Bounds, HashSet Exterior) { public readonly List Entrances = new(); diff --git a/Content.Shared/Procedural/IDunGenLayer.cs b/Content.Shared/Procedural/IDunGenLayer.cs new file mode 100644 index 00000000000..a4e8045af1c --- /dev/null +++ b/Content.Shared/Procedural/IDunGenLayer.cs @@ -0,0 +1,7 @@ +namespace Content.Shared.Procedural; + +[ImplicitDataDefinitionForInheritors] +public partial interface IDunGenLayer +{ + +} diff --git a/Content.Shared/Procedural/PostGeneration/AutoCablingDunGen.cs b/Content.Shared/Procedural/PostGeneration/AutoCablingDunGen.cs new file mode 100644 index 00000000000..5afad7edb18 --- /dev/null +++ b/Content.Shared/Procedural/PostGeneration/AutoCablingDunGen.cs @@ -0,0 +1,10 @@ +namespace Content.Shared.Procedural.PostGeneration; + +/// +/// Runs cables throughout the dungeon. +/// +/// +/// DungeonData keys are: +/// - Cabling +/// +public sealed partial class AutoCablingDunGen : IDunGenLayer; diff --git a/Content.Shared/Procedural/PostGeneration/AutoCablingPostGen.cs b/Content.Shared/Procedural/PostGeneration/AutoCablingPostGen.cs deleted file mode 100644 index 8278352b036..00000000000 --- a/Content.Shared/Procedural/PostGeneration/AutoCablingPostGen.cs +++ /dev/null @@ -1,12 +0,0 @@ -using Robust.Shared.Prototypes; - -namespace Content.Shared.Procedural.PostGeneration; - -/// -/// Runs cables throughout the dungeon. -/// -public sealed partial class AutoCablingPostGen : IPostDunGen -{ - [DataField] - public EntProtoId Entity = "CableApcExtension"; -} diff --git a/Content.Shared/Procedural/PostGeneration/BiomePostGen.cs b/Content.Shared/Procedural/PostGeneration/BiomeDunGen.cs similarity index 78% rename from Content.Shared/Procedural/PostGeneration/BiomePostGen.cs rename to Content.Shared/Procedural/PostGeneration/BiomeDunGen.cs index d02de241355..833cf2dec76 100644 --- a/Content.Shared/Procedural/PostGeneration/BiomePostGen.cs +++ b/Content.Shared/Procedural/PostGeneration/BiomeDunGen.cs @@ -1,5 +1,4 @@ using Content.Shared.Parallax.Biomes; -using Content.Shared.Procedural.PostGeneration; using Robust.Shared.Prototypes; namespace Content.Shared.Procedural.PostGeneration; @@ -8,7 +7,7 @@ namespace Content.Shared.Procedural.PostGeneration; /// Generates a biome on top of valid tiles, then removes the biome when done. /// Only works if no existing biome is present. /// -public sealed partial class BiomePostGen : IPostDunGen +public sealed partial class BiomeDunGen : IDunGenLayer { [DataField(required: true)] public ProtoId BiomeTemplate; diff --git a/Content.Shared/Procedural/PostGeneration/BiomeMarkerLayerPostGen.cs b/Content.Shared/Procedural/PostGeneration/BiomeMarkerLayerDunGen.cs similarity index 73% rename from Content.Shared/Procedural/PostGeneration/BiomeMarkerLayerPostGen.cs rename to Content.Shared/Procedural/PostGeneration/BiomeMarkerLayerDunGen.cs index dc64febe7b0..af5d7c5d8f9 100644 --- a/Content.Shared/Procedural/PostGeneration/BiomeMarkerLayerPostGen.cs +++ b/Content.Shared/Procedural/PostGeneration/BiomeMarkerLayerDunGen.cs @@ -1,5 +1,3 @@ -using Content.Shared.Parallax.Biomes.Markers; -using Content.Shared.Procedural.PostGeneration; using Content.Shared.Random; using Robust.Shared.Prototypes; @@ -8,7 +6,7 @@ namespace Content.Shared.Procedural.PostGeneration; /// /// Spawns the specified marker layer on top of the dungeon rooms. /// -public sealed partial class BiomeMarkerLayerPostGen : IPostDunGen +public sealed partial class BiomeMarkerLayerDunGen : IDunGenLayer { /// /// How many times to spawn marker layers; can duplicate. diff --git a/Content.Shared/Procedural/PostGeneration/BoundaryWallDunGen.cs b/Content.Shared/Procedural/PostGeneration/BoundaryWallDunGen.cs new file mode 100644 index 00000000000..4151527f8a0 --- /dev/null +++ b/Content.Shared/Procedural/PostGeneration/BoundaryWallDunGen.cs @@ -0,0 +1,23 @@ +namespace Content.Shared.Procedural.PostGeneration; + +/// +/// Iterates room edges and places the relevant tiles and walls on any free indices. +/// +/// +/// Dungeon data keys are: +/// - CornerWalls (Optional) +/// - FallbackTile +/// - Walls +/// +public sealed partial class BoundaryWallDunGen : IDunGenLayer +{ + [DataField] + public BoundaryWallFlags Flags = BoundaryWallFlags.Corridors | BoundaryWallFlags.Rooms; +} + +[Flags] +public enum BoundaryWallFlags : byte +{ + Rooms = 1 << 0, + Corridors = 1 << 1, +} diff --git a/Content.Shared/Procedural/PostGeneration/BoundaryWallPostGen.cs b/Content.Shared/Procedural/PostGeneration/BoundaryWallPostGen.cs deleted file mode 100644 index 390ff42feea..00000000000 --- a/Content.Shared/Procedural/PostGeneration/BoundaryWallPostGen.cs +++ /dev/null @@ -1,33 +0,0 @@ -using Content.Shared.Maps; -using Robust.Shared.Prototypes; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; - -namespace Content.Shared.Procedural.PostGeneration; - -/// -/// Iterates room edges and places the relevant tiles and walls on any free indices. -/// -public sealed partial class BoundaryWallPostGen : IPostDunGen -{ - [DataField] - public ProtoId Tile = "FloorSteel"; - - [DataField] - public EntProtoId Wall = "WallSolid"; - - /// - /// Walls to use in corners if applicable. - /// - [DataField] - public string? CornerWall; - - [DataField] - public BoundaryWallFlags Flags = BoundaryWallFlags.Corridors | BoundaryWallFlags.Rooms; -} - -[Flags] -public enum BoundaryWallFlags : byte -{ - Rooms = 1 << 0, - Corridors = 1 << 1, -} diff --git a/Content.Shared/Procedural/PostGeneration/CornerClutterDunGen.cs b/Content.Shared/Procedural/PostGeneration/CornerClutterDunGen.cs new file mode 100644 index 00000000000..2a904281c80 --- /dev/null +++ b/Content.Shared/Procedural/PostGeneration/CornerClutterDunGen.cs @@ -0,0 +1,14 @@ +namespace Content.Shared.Procedural.PostGeneration; + +/// +/// Spawns entities inside corners. +/// +/// +/// Dungeon data keys are: +/// - CornerClutter +/// +public sealed partial class CornerClutterDunGen : IDunGenLayer +{ + [DataField] + public float Chance = 0.50f; +} diff --git a/Content.Shared/Procedural/PostGeneration/CornerClutterPostGen.cs b/Content.Shared/Procedural/PostGeneration/CornerClutterPostGen.cs deleted file mode 100644 index a16c7f9ab3f..00000000000 --- a/Content.Shared/Procedural/PostGeneration/CornerClutterPostGen.cs +++ /dev/null @@ -1,18 +0,0 @@ -using Content.Shared.Storage; - -namespace Content.Shared.Procedural.PostGeneration; - -/// -/// Spawns entities inside corners. -/// -public sealed partial class CornerClutterPostGen : IPostDunGen -{ - [DataField] - public float Chance = 0.50f; - - /// - /// The default starting bulbs - /// - [DataField(required: true)] - public List Contents = new(); -} diff --git a/Content.Shared/Procedural/PostGeneration/CorridorClutterPostGen.cs b/Content.Shared/Procedural/PostGeneration/CorridorClutterDunGen.cs similarity index 85% rename from Content.Shared/Procedural/PostGeneration/CorridorClutterPostGen.cs rename to Content.Shared/Procedural/PostGeneration/CorridorClutterDunGen.cs index a8a74ba6ccb..5b397b40dfc 100644 --- a/Content.Shared/Procedural/PostGeneration/CorridorClutterPostGen.cs +++ b/Content.Shared/Procedural/PostGeneration/CorridorClutterDunGen.cs @@ -5,7 +5,7 @@ namespace Content.Shared.Procedural.PostGeneration; /// /// Adds entities randomly to the corridors. /// -public sealed partial class CorridorClutterPostGen : IPostDunGen +public sealed partial class CorridorClutterDunGen : IDunGenLayer { [DataField] public float Chance = 0.05f; diff --git a/Content.Shared/Procedural/PostGeneration/CorridorDecalSkirtingPostGen.cs b/Content.Shared/Procedural/PostGeneration/CorridorDecalSkirtingDunGen.cs similarity index 72% rename from Content.Shared/Procedural/PostGeneration/CorridorDecalSkirtingPostGen.cs rename to Content.Shared/Procedural/PostGeneration/CorridorDecalSkirtingDunGen.cs index 4b139a8be65..e6090436555 100644 --- a/Content.Shared/Procedural/PostGeneration/CorridorDecalSkirtingPostGen.cs +++ b/Content.Shared/Procedural/PostGeneration/CorridorDecalSkirtingDunGen.cs @@ -7,29 +7,23 @@ namespace Content.Shared.Procedural.PostGeneration; /// /// Applies decal skirting to corridors. /// -public sealed partial class CorridorDecalSkirtingPostGen : IPostDunGen +public sealed partial class CorridorDecalSkirtingDunGen : IDunGenLayer { - /// - /// Color to apply to decals. - /// - [DataField("color")] - public Color? Color; - /// /// Decal where 1 edge is found. /// - [DataField("cardinalDecals")] + [DataField] public Dictionary CardinalDecals = new(); /// /// Decal where 1 corner edge is found. /// - [DataField("pocketDecals")] + [DataField] public Dictionary PocketDecals = new(); /// /// Decal where 2 or 3 edges are found. /// - [DataField("cornerDecals")] + [DataField] public Dictionary CornerDecals = new(); } diff --git a/Content.Shared/Procedural/PostGeneration/CorridorPostGen.cs b/Content.Shared/Procedural/PostGeneration/CorridorDunGen.cs similarity index 73% rename from Content.Shared/Procedural/PostGeneration/CorridorPostGen.cs rename to Content.Shared/Procedural/PostGeneration/CorridorDunGen.cs index 705ae99dcef..6d75cd9cb2b 100644 --- a/Content.Shared/Procedural/PostGeneration/CorridorPostGen.cs +++ b/Content.Shared/Procedural/PostGeneration/CorridorDunGen.cs @@ -1,12 +1,13 @@ -using Content.Shared.Maps; -using Robust.Shared.Prototypes; - namespace Content.Shared.Procedural.PostGeneration; /// /// Connects room entrances via corridor segments. /// -public sealed partial class CorridorPostGen : IPostDunGen +/// +/// Dungeon data keys are: +/// - FallbackTile +/// +public sealed partial class CorridorDunGen : IDunGenLayer { /// /// How far we're allowed to generate a corridor before calling it. @@ -17,9 +18,6 @@ public sealed partial class CorridorPostGen : IPostDunGen [DataField] public int PathLimit = 2048; - [DataField] - public ProtoId Tile = "FloorSteel"; - /// /// How wide to make the corridor. /// diff --git a/Content.Shared/Procedural/PostGeneration/DungeonEntranceDunGen.cs b/Content.Shared/Procedural/PostGeneration/DungeonEntranceDunGen.cs new file mode 100644 index 00000000000..40cc95f5fc9 --- /dev/null +++ b/Content.Shared/Procedural/PostGeneration/DungeonEntranceDunGen.cs @@ -0,0 +1,18 @@ +namespace Content.Shared.Procedural.PostGeneration; + +/// +/// Selects [count] rooms and places external doors to them. +/// +/// +/// Dungeon data keys are: +/// - Entrance +/// - FallbackTile +/// +public sealed partial class DungeonEntranceDunGen : IDunGenLayer +{ + /// + /// How many rooms we place doors on. + /// + [DataField] + public int Count = 1; +} diff --git a/Content.Shared/Procedural/PostGeneration/DungeonEntrancePostGen.cs b/Content.Shared/Procedural/PostGeneration/DungeonEntrancePostGen.cs deleted file mode 100644 index 3398b513179..00000000000 --- a/Content.Shared/Procedural/PostGeneration/DungeonEntrancePostGen.cs +++ /dev/null @@ -1,28 +0,0 @@ -using Content.Shared.Maps; -using Robust.Shared.Prototypes; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.List; - -namespace Content.Shared.Procedural.PostGeneration; - -/// -/// Selects [count] rooms and places external doors to them. -/// -public sealed partial class DungeonEntrancePostGen : IPostDunGen -{ - /// - /// How many rooms we place doors on. - /// - [DataField("count")] - public int Count = 1; - - [DataField("entities", customTypeSerializer: typeof(PrototypeIdListSerializer))] - public List Entities = new() - { - "CableApcExtension", - "AirlockGlass", - }; - - [DataField("tile", customTypeSerializer:typeof(PrototypeIdSerializer))] - public string Tile = "FloorSteel"; -} diff --git a/Content.Shared/Procedural/PostGeneration/EntranceFlankDunGen.cs b/Content.Shared/Procedural/PostGeneration/EntranceFlankDunGen.cs new file mode 100644 index 00000000000..27baa48ec62 --- /dev/null +++ b/Content.Shared/Procedural/PostGeneration/EntranceFlankDunGen.cs @@ -0,0 +1,11 @@ +namespace Content.Shared.Procedural.PostGeneration; + +/// +/// Spawns entities on either side of an entrance. +/// +/// +/// Dungeon data keys are: +/// - FallbackTile +/// - +/// +public sealed partial class EntranceFlankDunGen : IDunGenLayer; diff --git a/Content.Shared/Procedural/PostGeneration/EntranceFlankPostGen.cs b/Content.Shared/Procedural/PostGeneration/EntranceFlankPostGen.cs deleted file mode 100644 index 96e9bd5d6d1..00000000000 --- a/Content.Shared/Procedural/PostGeneration/EntranceFlankPostGen.cs +++ /dev/null @@ -1,16 +0,0 @@ -using Content.Shared.Maps; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; - -namespace Content.Shared.Procedural.PostGeneration; - -/// -/// Spawns entities on either side of an entrance. -/// -public sealed partial class EntranceFlankPostGen : IPostDunGen -{ - [DataField("tile", customTypeSerializer:typeof(PrototypeIdSerializer))] - public string Tile = "FloorSteel"; - - [DataField("entities")] - public List Entities = new(); -} diff --git a/Content.Shared/Procedural/PostGeneration/ExternalWindowDunGen.cs b/Content.Shared/Procedural/PostGeneration/ExternalWindowDunGen.cs new file mode 100644 index 00000000000..0b29344b90b --- /dev/null +++ b/Content.Shared/Procedural/PostGeneration/ExternalWindowDunGen.cs @@ -0,0 +1,11 @@ +namespace Content.Shared.Procedural.PostGeneration; + +/// +/// If external areas are found will try to generate windows. +/// +/// +/// Dungeon data keys are: +/// - EntranceFlank +/// - FallbackTile +/// +public sealed partial class ExternalWindowDunGen : IDunGenLayer; diff --git a/Content.Shared/Procedural/PostGeneration/ExternalWindowPostGen.cs b/Content.Shared/Procedural/PostGeneration/ExternalWindowPostGen.cs deleted file mode 100644 index d5580baeaaa..00000000000 --- a/Content.Shared/Procedural/PostGeneration/ExternalWindowPostGen.cs +++ /dev/null @@ -1,22 +0,0 @@ -using Content.Shared.Maps; -using Robust.Shared.Prototypes; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.List; - -namespace Content.Shared.Procedural.PostGeneration; - -/// -/// If external areas are found will try to generate windows. -/// -public sealed partial class ExternalWindowPostGen : IPostDunGen -{ - [DataField("entities", customTypeSerializer: typeof(PrototypeIdListSerializer))] - public List Entities = new() - { - "Grille", - "Window", - }; - - [DataField("tile", customTypeSerializer:typeof(PrototypeIdSerializer))] - public string Tile = "FloorSteel"; -} diff --git a/Content.Shared/Procedural/PostGeneration/IPostDunGen.cs b/Content.Shared/Procedural/PostGeneration/IPostDunGen.cs deleted file mode 100644 index b55cab8e63e..00000000000 --- a/Content.Shared/Procedural/PostGeneration/IPostDunGen.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace Content.Shared.Procedural.PostGeneration; - -/// -/// Ran after generating dungeon rooms. Can be used for additional loot, contents, etc. -/// -[ImplicitDataDefinitionForInheritors] -public partial interface IPostDunGen -{ - -} diff --git a/Content.Shared/Procedural/PostGeneration/InternalWindowDunGen.cs b/Content.Shared/Procedural/PostGeneration/InternalWindowDunGen.cs new file mode 100644 index 00000000000..11b1c6a785a --- /dev/null +++ b/Content.Shared/Procedural/PostGeneration/InternalWindowDunGen.cs @@ -0,0 +1,11 @@ +namespace Content.Shared.Procedural.PostGeneration; + +/// +/// If internal areas are found will try to generate windows. +/// +/// +/// Dungeon data keys are: +/// - FallbackTile +/// - Window +/// +public sealed partial class InternalWindowDunGen : IDunGenLayer; diff --git a/Content.Shared/Procedural/PostGeneration/InternalWindowPostGen.cs b/Content.Shared/Procedural/PostGeneration/InternalWindowPostGen.cs deleted file mode 100644 index 4c6223eb92a..00000000000 --- a/Content.Shared/Procedural/PostGeneration/InternalWindowPostGen.cs +++ /dev/null @@ -1,22 +0,0 @@ -using Content.Shared.Maps; -using Robust.Shared.Prototypes; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.List; - -namespace Content.Shared.Procedural.PostGeneration; - -/// -/// If internal areas are found will try to generate windows. -/// -public sealed partial class InternalWindowPostGen : IPostDunGen -{ - [DataField("entities", customTypeSerializer: typeof(PrototypeIdListSerializer))] - public List Entities = new() - { - "Grille", - "Window", - }; - - [DataField("tile", customTypeSerializer:typeof(PrototypeIdSerializer))] - public string Tile = "FloorSteel"; -} diff --git a/Content.Shared/Procedural/PostGeneration/JunctionDunGen.cs b/Content.Shared/Procedural/PostGeneration/JunctionDunGen.cs new file mode 100644 index 00000000000..899f2716216 --- /dev/null +++ b/Content.Shared/Procedural/PostGeneration/JunctionDunGen.cs @@ -0,0 +1,18 @@ +namespace Content.Shared.Procedural.PostGeneration; + +/// +/// Places the specified entities at junction areas. +/// +/// +/// Dungeon data keys are: +/// - Entrance +/// - FallbackTile +/// +public sealed partial class JunctionDunGen : IDunGenLayer +{ + /// + /// Width to check for junctions. + /// + [DataField] + public int Width = 3; +} diff --git a/Content.Shared/Procedural/PostGeneration/JunctionPostGen.cs b/Content.Shared/Procedural/PostGeneration/JunctionPostGen.cs deleted file mode 100644 index 5c4cf43b7f0..00000000000 --- a/Content.Shared/Procedural/PostGeneration/JunctionPostGen.cs +++ /dev/null @@ -1,28 +0,0 @@ -using Content.Shared.Maps; -using Robust.Shared.Prototypes; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.List; - -namespace Content.Shared.Procedural.PostGeneration; - -/// -/// Places the specified entities at junction areas. -/// -public sealed partial class JunctionPostGen : IPostDunGen -{ - /// - /// Width to check for junctions. - /// - [DataField("width")] - public int Width = 3; - - [DataField("tile", customTypeSerializer:typeof(PrototypeIdSerializer))] - public string Tile = "FloorSteel"; - - [DataField("entities", customTypeSerializer: typeof(PrototypeIdListSerializer))] - public List Entities = new() - { - "CableApcExtension", - "AirlockGlass" - }; -} diff --git a/Content.Shared/Procedural/PostGeneration/MiddleConnectionDunGen.cs b/Content.Shared/Procedural/PostGeneration/MiddleConnectionDunGen.cs new file mode 100644 index 00000000000..a5758c14989 --- /dev/null +++ b/Content.Shared/Procedural/PostGeneration/MiddleConnectionDunGen.cs @@ -0,0 +1,19 @@ +namespace Content.Shared.Procedural.PostGeneration; + +/// +/// Places the specified entities on the middle connections between rooms +/// +public sealed partial class MiddleConnectionDunGen : IDunGenLayer +{ + /// + /// How much overlap there needs to be between 2 rooms exactly. + /// + [DataField] + public int OverlapCount = -1; + + /// + /// How many connections to spawn between rooms. + /// + [DataField] + public int Count = 1; +} diff --git a/Content.Shared/Procedural/PostGeneration/MiddleConnectionPostGen.cs b/Content.Shared/Procedural/PostGeneration/MiddleConnectionPostGen.cs deleted file mode 100644 index d29a65434c7..00000000000 --- a/Content.Shared/Procedural/PostGeneration/MiddleConnectionPostGen.cs +++ /dev/null @@ -1,39 +0,0 @@ -using Content.Shared.Maps; -using Robust.Shared.Prototypes; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.List; - -namespace Content.Shared.Procedural.PostGeneration; - -/// -/// Places the specified entities on the middle connections between rooms -/// -public sealed partial class MiddleConnectionPostGen : IPostDunGen -{ - /// - /// How much overlap there needs to be between 2 rooms exactly. - /// - [DataField("overlapCount")] - public int OverlapCount = -1; - - /// - /// How many connections to spawn between rooms. - /// - [DataField("count")] - public int Count = 1; - - [DataField("tile", customTypeSerializer:typeof(PrototypeIdSerializer))] - public string Tile = "FloorSteel"; - - [DataField("entities", customTypeSerializer: typeof(PrototypeIdListSerializer))] - public List Entities = new() - { - "CableApcExtension", - "AirlockGlass" - }; - - /// - /// If overlap > 1 then what should spawn on the edges. - /// - [DataField("edgeEntities")] public List EdgeEntities = new(); -} diff --git a/Content.Shared/Procedural/PostGeneration/RoomEntranceDunGen.cs b/Content.Shared/Procedural/PostGeneration/RoomEntranceDunGen.cs new file mode 100644 index 00000000000..d3b5672dcb0 --- /dev/null +++ b/Content.Shared/Procedural/PostGeneration/RoomEntranceDunGen.cs @@ -0,0 +1,11 @@ +namespace Content.Shared.Procedural.PostGeneration; + +/// +/// Places tiles / entities onto room entrances. +/// +/// +/// DungeonData keys are: +/// - Entrance +/// - FallbackTile +/// +public sealed partial class RoomEntranceDunGen : IDunGenLayer; diff --git a/Content.Shared/Procedural/PostGeneration/RoomEntrancePostGen.cs b/Content.Shared/Procedural/PostGeneration/RoomEntrancePostGen.cs deleted file mode 100644 index 5fd78b0540a..00000000000 --- a/Content.Shared/Procedural/PostGeneration/RoomEntrancePostGen.cs +++ /dev/null @@ -1,22 +0,0 @@ -using Content.Shared.Maps; -using Robust.Shared.Prototypes; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.List; - -namespace Content.Shared.Procedural.PostGeneration; - -/// -/// Places tiles / entities onto room entrances. -/// -public sealed partial class RoomEntrancePostGen : IPostDunGen -{ - [DataField("entities", customTypeSerializer: typeof(PrototypeIdListSerializer))] - public List Entities = new() - { - "CableApcExtension", - "AirlockGlass", - }; - - [DataField("tile", customTypeSerializer:typeof(PrototypeIdSerializer))] - public string Tile = "FloorSteel"; -} diff --git a/Content.Shared/Procedural/PostGeneration/SplineDungeonConnectorDunGen.cs b/Content.Shared/Procedural/PostGeneration/SplineDungeonConnectorDunGen.cs new file mode 100644 index 00000000000..ec8349c671b --- /dev/null +++ b/Content.Shared/Procedural/PostGeneration/SplineDungeonConnectorDunGen.cs @@ -0,0 +1,19 @@ +namespace Content.Shared.Procedural.PostGeneration; + +/// +/// Connects dungeons via points that get subdivided. +/// +public sealed partial class SplineDungeonConnectorDunGen : IDunGenLayer +{ + /// + /// Will divide the distance between the start and end points so that no subdivision is more than these metres away. + /// + [DataField] + public int DivisionDistance = 10; + + /// + /// How much each subdivision can vary from the middle. + /// + [DataField] + public float VarianceMax = 0.35f; +} diff --git a/Content.Shared/Procedural/PostGeneration/WallMountDunGen.cs b/Content.Shared/Procedural/PostGeneration/WallMountDunGen.cs new file mode 100644 index 00000000000..a5c790cb22f --- /dev/null +++ b/Content.Shared/Procedural/PostGeneration/WallMountDunGen.cs @@ -0,0 +1,13 @@ +namespace Content.Shared.Procedural.PostGeneration; + +/// +/// Spawns on the boundary tiles of rooms. +/// +public sealed partial class WallMountDunGen : IDunGenLayer +{ + /// + /// Chance per free tile to spawn a wallmount. + /// + [DataField] + public double Prob = 0.1; +} diff --git a/Content.Shared/Procedural/PostGeneration/WallMountPostGen.cs b/Content.Shared/Procedural/PostGeneration/WallMountPostGen.cs deleted file mode 100644 index 1fbdedf5610..00000000000 --- a/Content.Shared/Procedural/PostGeneration/WallMountPostGen.cs +++ /dev/null @@ -1,23 +0,0 @@ -using Content.Shared.Maps; -using Content.Shared.Storage; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; - -namespace Content.Shared.Procedural.PostGeneration; - -/// -/// Spawns on the boundary tiles of rooms. -/// -public sealed partial class WallMountPostGen : IPostDunGen -{ - [DataField("tile", customTypeSerializer:typeof(PrototypeIdSerializer))] - public string Tile = "FloorSteel"; - - [DataField("spawns")] - public List Spawns = new(); - - /// - /// Chance per free tile to spawn a wallmount. - /// - [DataField("prob")] - public double Prob = 0.1; -} diff --git a/Content.Shared/Procedural/PostGeneration/WormCorridorPostGen.cs b/Content.Shared/Procedural/PostGeneration/WormCorridorDunGen.cs similarity index 73% rename from Content.Shared/Procedural/PostGeneration/WormCorridorPostGen.cs rename to Content.Shared/Procedural/PostGeneration/WormCorridorDunGen.cs index c57d92ef956..b71e845a733 100644 --- a/Content.Shared/Procedural/PostGeneration/WormCorridorPostGen.cs +++ b/Content.Shared/Procedural/PostGeneration/WormCorridorDunGen.cs @@ -1,14 +1,10 @@ -using Content.Shared.Maps; -using Content.Shared.Procedural.DungeonGenerators; -using Robust.Shared.Prototypes; - namespace Content.Shared.Procedural.PostGeneration; // Ime a worm /// /// Generates worm corridors. /// -public sealed partial class WormCorridorPostGen : IPostDunGen +public sealed partial class WormCorridorDunGen : IDunGenLayer { [DataField] public int PathLimit = 2048; @@ -31,9 +27,6 @@ public sealed partial class WormCorridorPostGen : IPostDunGen [DataField] public Angle MaxAngleChange = Angle.FromDegrees(45); - [DataField] - public ProtoId Tile = "FloorSteel"; - /// /// How wide to make the corridor. /// diff --git a/Content.Shared/Salvage/SharedSalvageSystem.Magnet.cs b/Content.Shared/Salvage/SharedSalvageSystem.Magnet.cs index 81390e5f65a..62edb36db93 100644 --- a/Content.Shared/Salvage/SharedSalvageSystem.Magnet.cs +++ b/Content.Shared/Salvage/SharedSalvageSystem.Magnet.cs @@ -32,14 +32,14 @@ public ISalvageMagnetOffering GetSalvageOffering(int seed) var layers = new Dictionary(); // If we ever add more random layers will need to Next on these. - foreach (var layer in configProto.PostGeneration) + foreach (var layer in configProto.Layers) { switch (layer) { - case BiomePostGen: + case BiomeDunGen: rand.Next(); break; - case BiomeMarkerLayerPostGen marker: + case BiomeMarkerLayerDunGen marker: for (var i = 0; i < marker.Count; i++) { var proto = _proto.Index(marker.MarkerTemplate).Pick(rand); diff --git a/Content.Shared/Shuttles/Systems/SharedShuttleSystem.cs b/Content.Shared/Shuttles/Systems/SharedShuttleSystem.cs index a382e943ff9..db2cbaa138b 100644 --- a/Content.Shared/Shuttles/Systems/SharedShuttleSystem.cs +++ b/Content.Shared/Shuttles/Systems/SharedShuttleSystem.cs @@ -18,7 +18,7 @@ public abstract partial class SharedShuttleSystem : EntitySystem [Dependency] protected readonly SharedTransformSystem XformSystem = default!; [Dependency] private readonly EntityWhitelistSystem _whitelistSystem = default!; - public const float FTLRange = 512f; + public const float FTLRange = 256f; public const float FTLBufferRange = 8f; private EntityQuery _gridQuery; diff --git a/Content.Shared/Storage/EntitySpawnEntry.cs b/Content.Shared/Storage/EntitySpawnEntry.cs index 792459c72f7..6e24681c2db 100644 --- a/Content.Shared/Storage/EntitySpawnEntry.cs +++ b/Content.Shared/Storage/EntitySpawnEntry.cs @@ -5,6 +5,19 @@ namespace Content.Shared.Storage; +/// +/// Prototype wrapper around +/// +[Prototype] +public sealed class EntitySpawnEntryPrototype : IPrototype +{ + [IdDataField] + public string ID { get; } = string.Empty; + + [DataField] + public List Entries = new(); +} + /// /// Dictates a list of items that can be spawned. /// diff --git a/Resources/Prototypes/Entities/Stations/base.yml b/Resources/Prototypes/Entities/Stations/base.yml index 5cbe349416f..40d5e3b6746 100644 --- a/Resources/Prototypes/Entities/Stations/base.yml +++ b/Resources/Prototypes/Entities/Stations/base.yml @@ -46,6 +46,24 @@ path: /Maps/Shuttles/cargo.yml - type: GridSpawn groups: + vgroid: !type:DungeonSpawnGroup + minimumDistance: 1000 + nameDataset: names_borer + addComponents: + - type: Gravity + enabled: true + inherent: true + protos: + - VGRoid + trade: !type:GridSpawnGroup + addComponents: + - type: ProtectedGrid + - type: TradeStation + paths: + - /Maps/Shuttles/trading_outpost.yml + mining: !type:GridSpawnGroup + paths: + - /Maps/Shuttles/mining.yml # trade: # addComponents: # - type: ProtectedGrid @@ -56,34 +74,7 @@ # paths: # - /Maps/Shuttles/mining.yml # Spawn last - ruins: - hide: true - nameGrid: true - minCount: 2 - maxCount: 2 - stationGrid: false - paths: - - /Maps/Ruins/DeltaV/biodome_satellite.yml #Delta V - Move to DV folder - - /Maps/Ruins/DeltaV/derelict.yml #Delta V - Move to DV folder - - /Maps/Ruins/DeltaV/djstation.yml #Delta V - Move to DV folder - - /Maps/Ruins/DeltaV/old_ai_sat.yml #Delta V - Move to DV folder - - /Maps/Ruins/DeltaV/relaystation.yml #Delta V - Move to DV folder - - /Maps/Ruins/DeltaV/whiteship_ancient.yml #Delta V - Move to DV folder - - /Maps/Ruins/DeltaV/whiteship_bluespacejumper.yml #Delta V - Move to DV folder - -- type: entity - id: BaseStationShuttlesCore - abstract: true - components: - - type: GridSpawn - groups: - cargo: - paths: - - /Maps/Shuttles/cargo_core.yml -# mining: -# paths: -# - /Maps/Shuttles/mining.yml - ruins: + ruins: !type:GridSpawnGroup hide: true nameGrid: true minCount: 2 diff --git a/Resources/Prototypes/Entities/Structures/Walls/asteroid.yml b/Resources/Prototypes/Entities/Structures/Walls/asteroid.yml index d131805bf51..e14bf26e0db 100644 --- a/Resources/Prototypes/Entities/Structures/Walls/asteroid.yml +++ b/Resources/Prototypes/Entities/Structures/Walls/asteroid.yml @@ -1,5 +1,7 @@ #TODO: Someone should probably move the ore vein prototypes into their own file, or otherwise split this up in some way. This should not be 1.5k lines long. +# Anyway +# See WallRock variants for the remappings. #Asteroid rock - type: entity @@ -639,21 +641,28 @@ description: An ore vein rich with coal. suffix: Coal components: - - type: OreVein - oreChance: 1.0 - currentOre: OreCoal - - type: Sprite - layers: - - state: rock - - map: [ "enum.EdgeLayer.South" ] - state: rock_south - - map: [ "enum.EdgeLayer.East" ] - state: rock_east - - map: [ "enum.EdgeLayer.North" ] - state: rock_north - - map: [ "enum.EdgeLayer.West" ] - state: rock_west - - state: rock_coal + - type: EntityRemap + mask: + AsteroidRock: AsteroidRockCoal + WallRockBasalt: WallRockBasaltCoal + WallRockChromite: WallRockChromiteCoal + WallRockSand: WallRockSandCoal + WallRockSnow: WallRockSnowCoal + - type: OreVein + oreChance: 1.0 + currentOre: OreCoal + - type: Sprite + layers: + - state: rock + - map: [ "enum.EdgeLayer.South" ] + state: rock_south + - map: [ "enum.EdgeLayer.East" ] + state: rock_east + - map: [ "enum.EdgeLayer.North" ] + state: rock_north + - map: [ "enum.EdgeLayer.West" ] + state: rock_west + - state: rock_coal - type: entity id: WallRockGold @@ -661,21 +670,28 @@ description: An ore vein rich with gold. suffix: Gold components: - - type: OreVein - oreChance: 1.0 - currentOre: OreGold - - type: Sprite - layers: - - state: rock - - map: [ "enum.EdgeLayer.South" ] - state: rock_south - - map: [ "enum.EdgeLayer.East" ] - state: rock_east - - map: [ "enum.EdgeLayer.North" ] - state: rock_north - - map: [ "enum.EdgeLayer.West" ] - state: rock_west - - state: rock_gold + - type: EntityRemap + mask: + AsteroidRock: AsteroidRockGold + WallRockBasalt: WallRockBasaltGold + WallRockChromite: WallRockChromiteGold + WallRockSand: WallRockSandGold + WallRockSnow: WallRockSnowGold + - type: OreVein + oreChance: 1.0 + currentOre: OreGold + - type: Sprite + layers: + - state: rock + - map: [ "enum.EdgeLayer.South" ] + state: rock_south + - map: [ "enum.EdgeLayer.East" ] + state: rock_east + - map: [ "enum.EdgeLayer.North" ] + state: rock_north + - map: [ "enum.EdgeLayer.West" ] + state: rock_west + - state: rock_gold - type: entity id: WallRockPlasma @@ -683,21 +699,28 @@ description: An ore vein rich with plasma. suffix: Plasma components: - - type: OreVein - oreChance: 1.0 - currentOre: OrePlasma - - type: Sprite - layers: - - state: rock - - map: [ "enum.EdgeLayer.South" ] - state: rock_south - - map: [ "enum.EdgeLayer.East" ] - state: rock_east - - map: [ "enum.EdgeLayer.North" ] - state: rock_north - - map: [ "enum.EdgeLayer.West" ] - state: rock_west - - state: rock_phoron + - type: EntityRemap + mask: + AsteroidRock: AsteroidRockPlasma + WallRockBasalt: WallRockBasaltPlasma + WallRockChromite: WallRockChromitePlasma + WallRockSand: WallRockSandPlasma + WallRockSnow: WallRockSnowPlasma + - type: OreVein + oreChance: 1.0 + currentOre: OrePlasma + - type: Sprite + layers: + - state: rock + - map: [ "enum.EdgeLayer.South" ] + state: rock_south + - map: [ "enum.EdgeLayer.East" ] + state: rock_east + - map: [ "enum.EdgeLayer.North" ] + state: rock_north + - map: [ "enum.EdgeLayer.West" ] + state: rock_west + - state: rock_phoron - type: entity id: WallRockQuartz @@ -705,21 +728,28 @@ description: An ore vein rich with quartz. suffix: Quartz components: - - type: OreVein - oreChance: 1.0 - currentOre: OreSpaceQuartz - - type: Sprite - layers: - - state: rock - - map: [ "enum.EdgeLayer.South" ] - state: rock_south - - map: [ "enum.EdgeLayer.East" ] - state: rock_east - - map: [ "enum.EdgeLayer.North" ] - state: rock_north - - map: [ "enum.EdgeLayer.West" ] - state: rock_west - - state: rock_quartz + - type: EntityRemap + mask: + AsteroidRock: AsteroidRockQuartz + WallRockBasalt: WallRockBasaltQuartz + WallRockChromite: WallRockChromiteQuartz + WallRockSand: WallRockSandQuartz + WallRockSnow: WallRockSnowQuartz + - type: OreVein + oreChance: 1.0 + currentOre: OreSpaceQuartz + - type: Sprite + layers: + - state: rock + - map: [ "enum.EdgeLayer.South" ] + state: rock_south + - map: [ "enum.EdgeLayer.East" ] + state: rock_east + - map: [ "enum.EdgeLayer.North" ] + state: rock_north + - map: [ "enum.EdgeLayer.West" ] + state: rock_west + - state: rock_quartz - type: entity id: WallRockSilver @@ -727,21 +757,28 @@ description: An ore vein rich with silver. suffix: Silver components: - - type: OreVein - oreChance: 1.0 - currentOre: OreSilver - - type: Sprite - layers: - - state: rock - - map: [ "enum.EdgeLayer.South" ] - state: rock_south - - map: [ "enum.EdgeLayer.East" ] - state: rock_east - - map: [ "enum.EdgeLayer.North" ] - state: rock_north - - map: [ "enum.EdgeLayer.West" ] - state: rock_west - - state: rock_silver + - type: EntityRemap + mask: + AsteroidRock: AsteroidRockSilver + WallRockBasalt: WallRockBasaltSilver + WallRockChromite: WallRockChromiteSilver + WallRockSand: WallRockSandSilver + WallRockSnow: WallRockSnowSilver + - type: OreVein + oreChance: 1.0 + currentOre: OreSilver + - type: Sprite + layers: + - state: rock + - map: [ "enum.EdgeLayer.South" ] + state: rock_south + - map: [ "enum.EdgeLayer.East" ] + state: rock_east + - map: [ "enum.EdgeLayer.North" ] + state: rock_north + - map: [ "enum.EdgeLayer.West" ] + state: rock_west + - state: rock_silver # Yes I know it drops steel but we may get smelting at some point - type: entity @@ -750,6 +787,13 @@ description: An ore vein rich with iron. suffix: Iron components: + - type: EntityRemap + mask: + AsteroidRock: AsteroidRockTin + WallRockBasalt: WallRockBasaltTin + WallRockChromite: WallRockChromiteTin + WallRockSand: WallRockSandTin + WallRockSnow: WallRockSnowTin - type: OreVein oreChance: 1.0 currentOre: OreSteel @@ -772,21 +816,28 @@ description: An ore vein rich with uranium. suffix: Uranium components: - - type: OreVein - oreChance: 1.0 - currentOre: OreUranium - - type: Sprite - layers: - - state: rock - - map: [ "enum.EdgeLayer.South" ] - state: rock_south - - map: [ "enum.EdgeLayer.East" ] - state: rock_east - - map: [ "enum.EdgeLayer.North" ] - state: rock_north - - map: [ "enum.EdgeLayer.West" ] - state: rock_west - - state: rock_uranium + - type: EntityRemap + mask: + AsteroidRock: AsteroidRockUranium + WallRockBasalt: WallRockBasaltUranium + WallRockChromite: WallRockChromiteUranium + WallRockSand: WallRockSandUranium + WallRockSnow: WallRockSnowUranium + - type: OreVein + oreChance: 1.0 + currentOre: OreUranium + - type: Sprite + layers: + - state: rock + - map: [ "enum.EdgeLayer.South" ] + state: rock_south + - map: [ "enum.EdgeLayer.East" ] + state: rock_east + - map: [ "enum.EdgeLayer.North" ] + state: rock_north + - map: [ "enum.EdgeLayer.West" ] + state: rock_west + - state: rock_uranium - type: entity @@ -795,21 +846,28 @@ description: An ore vein rich with bananium. suffix: Bananium components: - - type: OreVein - oreChance: 1.0 - currentOre: OreBananium - - type: Sprite - layers: - - state: rock - - map: [ "enum.EdgeLayer.South" ] - state: rock_south - - map: [ "enum.EdgeLayer.East" ] - state: rock_east - - map: [ "enum.EdgeLayer.North" ] - state: rock_north - - map: [ "enum.EdgeLayer.West" ] - state: rock_west - - state: rock_bananium + - type: EntityRemap + mask: + AsteroidRock: AsteroidRockBananium + WallRockBasalt: WallRockBasaltBananium + WallRockChromite: WallRockChromiteBananium + WallRockSand: WallRockSandBananium + WallRockSnow: WallRockSnowBananium + - type: OreVein + oreChance: 1.0 + currentOre: OreBananium + - type: Sprite + layers: + - state: rock + - map: [ "enum.EdgeLayer.South" ] + state: rock_south + - map: [ "enum.EdgeLayer.East" ] + state: rock_east + - map: [ "enum.EdgeLayer.North" ] + state: rock_north + - map: [ "enum.EdgeLayer.West" ] + state: rock_west + - state: rock_bananium - type: entity id: WallRockArtifactFragment @@ -817,21 +875,28 @@ description: A rock wall. What's that sticking out of it? suffix: Artifact Fragment components: - - type: OreVein - oreChance: 1.0 - currentOre: OreArtifactFragment - - type: Sprite - layers: - - state: rock - - map: [ "enum.EdgeLayer.South" ] - state: rock_south - - map: [ "enum.EdgeLayer.East" ] - state: rock_east - - map: [ "enum.EdgeLayer.North" ] - state: rock_north - - map: [ "enum.EdgeLayer.West" ] - state: rock_west - - state: rock_artifact_fragment + - type: EntityRemap + mask: + AsteroidRock: AsteroidRockArtifactFragment + WallRockBasalt: WallRockBasaltArtifactFragment + WallRockChromite: WallRockChromiteArtifactFragment + WallRockSand: WallRockSandArtifactFragment + WallRockSnow: WallRockSnowArtifactFragment + - type: OreVein + oreChance: 1.0 + currentOre: OreArtifactFragment + - type: Sprite + layers: + - state: rock + - map: [ "enum.EdgeLayer.South" ] + state: rock_south + - map: [ "enum.EdgeLayer.East" ] + state: rock_east + - map: [ "enum.EdgeLayer.North" ] + state: rock_north + - map: [ "enum.EdgeLayer.West" ] + state: rock_west + - state: rock_artifact_fragment - type: entity id: WallRockSalt @@ -839,21 +904,28 @@ description: An ore vein rich with salt. suffix: Salt components: - - type: OreVein - oreChance: 1.0 - currentOre: OreSalt - - type: Sprite - layers: - - state: rock - - map: [ "enum.EdgeLayer.South" ] - state: rock_south - - map: [ "enum.EdgeLayer.East" ] - state: rock_east - - map: [ "enum.EdgeLayer.North" ] - state: rock_north - - map: [ "enum.EdgeLayer.West" ] - state: rock_west - - state: rock_salt + - type: EntityRemap + mask: + AsteroidRock: AsteroidRockSalt + WallRockBasalt: WallRockBasaltSalt + WallRockChromite: WallRockChromiteSalt + WallRockSand: WallRockSandSalt + WallRockSnow: WallRockSnowSalt + - type: OreVein + oreChance: 1.0 + currentOre: OreSalt + - type: Sprite + layers: + - state: rock + - map: [ "enum.EdgeLayer.South" ] + state: rock_south + - map: [ "enum.EdgeLayer.East" ] + state: rock_east + - map: [ "enum.EdgeLayer.North" ] + state: rock_north + - map: [ "enum.EdgeLayer.West" ] + state: rock_west + - state: rock_salt # Basalt variants - type: entity diff --git a/Resources/Prototypes/Procedural/Magnet/asteroid.yml b/Resources/Prototypes/Procedural/Magnet/asteroid.yml index a21b709afad..c20b80af55b 100644 --- a/Resources/Prototypes/Procedural/Magnet/asteroid.yml +++ b/Resources/Prototypes/Procedural/Magnet/asteroid.yml @@ -15,7 +15,8 @@ - type: dungeonConfig id: BlobAsteroid # Floor generation - generator: !type:NoiseDunGen + layers: + - !type:NoiseDunGen tileCap: 1500 capStd: 32 iterations: 3 @@ -28,22 +29,22 @@ fractalType: FBm octaves: 2 lacunarity: 2 - # Everything else - postGeneration: - # Generate biome - - !type:BiomePostGen - biomeTemplate: Asteroid - # Generate ore veins - - !type:MarkerLayerPostGen - markerTemplate: AsteroidOre + # Generate biome + - !type:BiomeDunGen + biomeTemplate: Asteroid + + # Generate ore veins + - !type:BiomeMarkerLayerDunGen + markerTemplate: AsteroidOre # Multiple smaller asteroids # This is a pain so we generate fewer tiles - type: dungeonConfig id: ClusterAsteroid # Floor generation - generator: !type:NoiseDunGen + layers: + - !type:NoiseDunGen tileCap: 1000 capStd: 32 layers: @@ -55,21 +56,21 @@ fractalType: FBm octaves: 2 lacunarity: 2 - # Everything else - postGeneration: - # Generate biome - - !type:BiomePostGen - biomeTemplate: Asteroid - # Generate ore veins - - !type:MarkerLayerPostGen - markerTemplate: AsteroidOre + # Generate biome + - !type:BiomeDunGen + biomeTemplate: Asteroid + + # Generate ore veins + - !type:BiomeMarkerLayerDunGen + markerTemplate: AsteroidOre # Long and spindly, less smooth than blob - type: dungeonConfig id: SpindlyAsteroid # Floor generation - generator: !type:NoiseDunGen + layers: + - !type:NoiseDunGen tileCap: 1500 capStd: 32 layers: @@ -82,20 +83,21 @@ octaves: 3 lacunarity: 2 cellularDistanceFunction: Euclidean - postGeneration: - # Generate biome - - !type:BiomePostGen - biomeTemplate: Asteroid - # Generate ore veins - - !type:MarkerLayerPostGen - markerTemplate: AsteroidOre + # Generate biome + - !type:BiomeDunGen + biomeTemplate: Asteroid + + # Generate ore veins + - !type:BiomeMarkerLayerDunGen + markerTemplate: AsteroidOre # Lots of holes in it - type: dungeonConfig id: SwissCheeseAsteroid # Floor generation - generator: !type:NoiseDunGen + layers: + - !type:NoiseDunGen tileCap: 1500 capStd: 32 layers: @@ -107,12 +109,11 @@ fractalType: FBm octaves: 2 lacunarity: 2 - # Everything else - postGeneration: - # Generate biome - - !type:BiomePostGen - biomeTemplate: Asteroid - # Generate ore veins - - !type:MarkerLayerPostGen - markerTemplate: AsteroidOre + # Generate biome + - !type:BiomeDunGen + biomeTemplate: Asteroid + + # Generate ore veins + - !type:BiomeMarkerLayerDunGen + markerTemplate: AsteroidOre diff --git a/Resources/Prototypes/Procedural/dungeon_configs.yml b/Resources/Prototypes/Procedural/dungeon_configs.yml index 3614e4e787f..b55d5a9e697 100644 --- a/Resources/Prototypes/Procedural/dungeon_configs.yml +++ b/Resources/Prototypes/Procedural/dungeon_configs.yml @@ -1,361 +1,284 @@ +# Base configs - type: dungeonConfig - id: Experiment - generator: !type:PrefabDunGen - roomWhitelist: - - SalvageExperiment + id: PlanetBase + layers: + - !type:PrefabDunGen presets: - - Bucket - - Wow - - SpaceShip - - Tall - postGeneration: - - !type:CorridorPostGen - width: 3 + - Bucket + - Wow + - SpaceShip + - Tall - - !type:DungeonEntrancePostGen - count: 2 + - !type:CorridorDunGen + width: 3 - - !type:RoomEntrancePostGen - entities: - - CableApcExtension - - AirlockGlass + - !type:DungeonEntranceDunGen + count: 2 - - !type:EntranceFlankPostGen - entities: - - Grille - - Window + - !type:RoomEntranceDunGen - - !type:ExternalWindowPostGen - entities: - - Grille - - Window + - !type:EntranceFlankDunGen - - !type:WallMountPostGen - spawns: - # Posters - - id: RandomPosterLegit - orGroup: content - - id: ExtinguisherCabinetFilled - prob: 0.2 - orGroup: content - - id: RandomPainting - prob: 0.05 - orGroup: content - - id: IntercomCommon - prob: 0.1 - orGroup: content + - !type:ExternalWindowDunGen - - !type:BoundaryWallPostGen - tile: FloorSteel - wall: WallSolid - cornerWall: WallReinforced + - !type:WallMountDunGen - - !type:JunctionPostGen - width: 1 + - !type:BoundaryWallDunGen - - !type:JunctionPostGen + - !type:JunctionDunGen + width: 1 - - !type:AutoCablingPostGen + - !type:JunctionDunGen - - !type:CornerClutterPostGen - contents: - - id: PottedPlantRandom - amount: 1 + - !type:AutoCablingDunGen - - !type:CorridorDecalSkirtingPostGen - color: "#D381C996" - cardinalDecals: - South: BrickTileWhiteLineS - East: BrickTileWhiteLineE - North: BrickTileWhiteLineN - West: BrickTileWhiteLineW - cornerDecals: - SouthEast: BrickTileWhiteCornerSe - SouthWest: BrickTileWhiteCornerSw - NorthEast: BrickTileWhiteCornerNe - NorthWest: BrickTileWhiteCornerNw - pocketDecals: - SouthWest: BrickTileWhiteInnerSw - SouthEast: BrickTileWhiteInnerSe - NorthWest: BrickTileWhiteInnerNw - NorthEast: BrickTileWhiteInnerNe + - !type:CornerClutterDunGen + - !type:CorridorDecalSkirtingDunGen + cardinalDecals: + South: BrickTileWhiteLineS + East: BrickTileWhiteLineE + North: BrickTileWhiteLineN + West: BrickTileWhiteLineW + cornerDecals: + SouthEast: BrickTileWhiteCornerSe + SouthWest: BrickTileWhiteCornerSw + NorthEast: BrickTileWhiteCornerNe + NorthWest: BrickTileWhiteCornerNw + pocketDecals: + SouthWest: BrickTileWhiteInnerSw + SouthEast: BrickTileWhiteInnerSe + NorthWest: BrickTileWhiteInnerNw + NorthEast: BrickTileWhiteInnerNe +# Setups - type: dungeonConfig - id: LavaBrig - generator: !type:PrefabDunGen - roomWhitelist: - - LavaBrig - presets: - - Bucket - - Wow - - SpaceShip - - Tall - postGeneration: - - !type:CorridorPostGen - width: 3 - - - !type:DungeonEntrancePostGen - count: 2 - - - !type:RoomEntrancePostGen - entities: - - CableApcExtension - - AirlockSecurityGlassLocked - - - !type:EntranceFlankPostGen - entities: - - Grille - - Window - - - !type:ExternalWindowPostGen - entities: - - Grille - - Window - - - !type:WallMountPostGen - spawns: - # Posters - - id: RandomPosterLegit - orGroup: content - - id: ExtinguisherCabinetFilled - prob: 0.2 - orGroup: content - - id: RandomPainting - prob: 0.05 - orGroup: content - - id: IntercomCommon - prob: 0.1 - orGroup: content - - - !type:BoundaryWallPostGen - tile: FloorSteel - wall: WallSolid - cornerWall: WallReinforced - - - !type:JunctionPostGen - width: 1 - - - !type:JunctionPostGen - - - !type:AutoCablingPostGen - - - !type:CornerClutterPostGen - contents: - - id: PottedPlantRandom - amount: 1 - - - !type:CorridorDecalSkirtingPostGen - color: "#DE3A3A96" - cardinalDecals: - South: BrickTileWhiteLineS - East: BrickTileWhiteLineE - North: BrickTileWhiteLineN - West: BrickTileWhiteLineW - cornerDecals: - SouthEast: BrickTileWhiteCornerSe - SouthWest: BrickTileWhiteCornerSw - NorthEast: BrickTileWhiteCornerNe - NorthWest: BrickTileWhiteCornerNw - pocketDecals: - SouthWest: BrickTileWhiteInnerSw - SouthEast: BrickTileWhiteInnerSe - NorthWest: BrickTileWhiteInnerNw - NorthEast: BrickTileWhiteInnerNe + id: Experiment + data: + colors: + Decals: "#D381C996" + entities: + Cabling: CableApcExtension + CornerWalls: WallReinforced + Walls: WallSolid + spawnGroups: + CornerClutter: BaseClutter + Entrance: BaseAirlock + EntranceFlank: BaseWindow + Junction: BaseAirlock + WallMounts: ScienceLabsWalls + Window: BaseWindow + tiles: + FallbackTile: FloorSteel + whitelists: + Rooms: + tags: + - SalvageExperiment + layers: + - !type:PrototypeDunGen + proto: PlanetBase - type: dungeonConfig - id: Mineshaft - generator: !type:PrefabDunGen - tile: FloorCaveDrought - roomWhitelist: - - Mineshaft + id: Haunted + data: + entities: + Walls: WallRock + tiles: + FallbackTile: FloorCaveDrought + whitelists: + Rooms: + tags: + - Mineshaft + layers: + - !type:PrefabDunGen presets: - - Bucket - - Wow - - SpaceShip - - Tall - postGeneration: - - - !type:CorridorPostGen - tile: FloorCaveDrought - width: 3 - - - !type:DungeonEntrancePostGen - count: 5 - tile: FloorCaveDrought - entities: - - RandomWoodenWall - - - !type:RoomEntrancePostGen - tile: FloorCaveDrought - entities: - - RandomWoodenWall - - - !type:EntranceFlankPostGen - tile: FloorCaveDrought - entities: - - RandomWoodenWall - - - !type:ExternalWindowPostGen - tile: FloorCaveDrought - entities: - - RandomWoodenWall - - - !type:WallMountPostGen - tile: FloorCaveDrought - spawns: - # Ore - - id: WallRockSalt - prob: 0.6 - orGroup: content - - id: WallRockCoal - prob: 0.6 - orGroup: content - - id: WallRockTin - prob: 0.4 - orGroup: content - - id: WallMining - prob: 0.8 - orGroup: content - - - !type:BoundaryWallPostGen - tile: FloorCaveDrought - wall: WallRock - cornerWall: WallRock + - Bucket + - Wow + - SpaceShip + - Tall - - !type:AutoCablingPostGen - entity: Catwalk + - !type:WormCorridorDunGen + width: 3 - - !type:JunctionPostGen - tile: FloorCaveDrought - width: 3 - entities: - - RandomWoodenSupport + - !type:CorridorClutterDunGen + contents: + - id: FloraStalagmite1 + - id: FloraStalagmite2 + - id: FloraStalagmite3 + - id: FloraStalagmite4 + - id: FloraStalagmite5 + - id: FloraStalagmite6 - - !type:CornerClutterPostGen - contents: - - id: RandomStalagmiteOrCrystal - amount: 1 + - !type:BoundaryWallDunGen - type: dungeonConfig - id: SnowyLabs - generator: !type:PrefabDunGen - roomWhitelist: - - SnowyLabs - presets: - - Bucket - - Wow - - SpaceShip - - Tall - postGeneration: - - !type:CorridorPostGen - width: 3 - - - !type:DungeonEntrancePostGen - count: 2 - - - !type:RoomEntrancePostGen - entities: - - CableApcExtension - - AirlockFreezerHydroponicsLocked - - - !type:EntranceFlankPostGen - entities: - - Grille - - Window - - - !type:ExternalWindowPostGen - entities: - - Grille - - Window - - - !type:WallMountPostGen - spawns: - # Posters - - id: RandomPosterLegit - orGroup: content - - id: ExtinguisherCabinetFilled - prob: 0.2 - orGroup: content - - id: RandomPainting - prob: 0.05 - orGroup: content - - id: IntercomScience - prob: 0.1 - orGroup: content - - - !type:BoundaryWallPostGen - tile: FloorSteel - wall: WallSilver - cornerWall: WallSilver - - - !type:JunctionPostGen - width: 1 - entities: - - AirlockGlass - - - !type:JunctionPostGen - entities: - - AirlockGlass - - - !type:AutoCablingPostGen - - - !type:CornerClutterPostGen - contents: - - id: PottedPlantRandom - amount: 1 - - - !type:CorridorDecalSkirtingPostGen - color: "#4cc7aa96" - cardinalDecals: - South: BrickTileWhiteLineS - East: BrickTileWhiteLineE - North: BrickTileWhiteLineN - West: BrickTileWhiteLineW - cornerDecals: - SouthEast: BrickTileWhiteCornerSe - SouthWest: BrickTileWhiteCornerSw - NorthEast: BrickTileWhiteCornerNe - NorthWest: BrickTileWhiteCornerNw - pocketDecals: - SouthWest: BrickTileWhiteInnerSw - SouthEast: BrickTileWhiteInnerSe - NorthWest: BrickTileWhiteInnerNw - NorthEast: BrickTileWhiteInnerNe - -# todo: Add a biome dungeon generator -# Add corridor first gens that place rooms on top -# Add a worm corridor gen (place subsequent corridors somewhere randomly along the path) -# Place room entrances on ends of corridors touching a tile -# Remove all room tiles from corridors -# Fix paths up and try to reconnect all corridor tiles -# Add a postgen step to spread rooms out, though it shouldn't spread into corridor exteriors + id: LavaBrig + data: + colors: + Decals: "#DE3A3A96" + entities: + Cabling: CableApcExtension + CornerWalls: WallReinforced + Walls: WallSolid + spawnGroups: + CornerClutter: BaseClutter + Entrance: LavaBrigEntrance + EntranceFlank: BaseWindow + Junction: BaseAirlock + WallMounts: ScienceLabsWalls + Window: BaseWindow + whitelists: + Rooms: + tags: + - LavaBrig + layers: + - !type:PrototypeDunGen + proto: PlanetBase - type: dungeonConfig - id: Haunted - generator: !type:PrefabDunGen - tile: FloorCaveDrought - roomWhitelist: - - Mineshaft - presets: - - Bucket - - Wow - - SpaceShip - - Tall - postGeneration: - - !type:WormCorridorPostGen - width: 3 - tile: FloorCaveDrought - - - !type:CorridorClutterPostGen - contents: - - id: FloraStalagmite1 - - id: FloraStalagmite2 - - id: FloraStalagmite3 - - id: FloraStalagmite4 - - id: FloraStalagmite5 - - id: FloraStalagmite6 + id: Mineshaft + data: + entities: + Cabling: Catwalk + spawnGroups: + CornerClutter: MineshaftClutter + Entrance: BaseWoodWall + EntranceFlank: BaseWoodWall + Junction: BaseWoodSupport + Window: BaseWoodWall + tiles: + FallbackTile: FloorCaveDrought + whitelists: + Rooms: + tags: + - Mineshaft + layers: + - !type:PrototypeDunGen + proto: PlanetBase - - !type:BoundaryWallPostGen - tile: FloorCaveDrought - wall: WallRock +- type: dungeonConfig + id: SnowyLabs + data: + colors: + Decals: "#4cc7aa96" + entities: + Cabling: CableApcExtension + CornerWalls: WallSilver + Walls: WallSilver + spawnGroups: + CornerClutter: BaseClutter + Entrance: SnowyLabsEntrance + EntranceFlank: BaseWindow + Junction: BaseAirlock + WallMounts: SnowyLabsWalls + Window: BaseWindow + tiles: + FallbackTile: FloorSteel + whitelists: + Rooms: + tags: + - SnowyLabs + layers: + - !type:PrototypeDunGen + proto: PlanetBase + +# Spawn groups +# Basic +- type: entitySpawnEntry + id: BaseClutter + entries: + - id: PottedPlantRandom + amount: 1 + +- type: entitySpawnEntry + id: BaseAirlock + entries: + - id: CableApcExtension + - id: AirlockGlass + +- type: entitySpawnEntry + id: BaseWindow + entries: + - id: Grille + - id: Window + +# Lava brig +- type: entitySpawnEntry + id: LavaBrigEntrance + entries: + - id: CableApcExtension + - id: AirlockSecurityGlassLocked + +# Mineshaft +- type: entitySpawnEntry + id: BaseWoodWall + entries: + - id: RandomWoodenWall + +- type: entitySpawnEntry + id: BaseWoodSupport + entries: + - id: RandomWoodenSupport + +- type: entitySpawnEntry + id: MineshaftClutter + entries: + - id: RandomStalagmiteOrCrystal + amount: 1 + +- type: entitySpawnEntry + id: MineshaftWalls + entries: + # Ore + - id: WallRockSalt + prob: 0.6 + orGroup: content + - id: WallRockCoal + prob: 0.6 + orGroup: content + - id: WallRockTin + prob: 0.4 + orGroup: content + - id: WallMining + prob: 0.8 + orGroup: content + +# Science lab +- type: entitySpawnEntry + id: ScienceLabsWalls + entries: + # Posters + - id: RandomPosterLegit + orGroup: content + - id: ExtinguisherCabinetFilled + prob: 0.2 + orGroup: content + - id: RandomPainting + prob: 0.05 + orGroup: content + - id: IntercomCommon + prob: 0.1 + orGroup: content + +# Snowy labs +- type: entitySpawnEntry + id: SnowyLabsEntrance + entries: + - id: CableApcExtension + - id: AirlockFreezerHydroponicsLocked + +- type: entitySpawnEntry + id: SnowyLabsWalls + entries: + # Posters + - id: RandomPosterLegit + orGroup: content + - id: ExtinguisherCabinetFilled + prob: 0.2 + orGroup: content + - id: RandomPainting + prob: 0.05 + orGroup: content + - id: IntercomScience + prob: 0.1 + orGroup: content diff --git a/Resources/Prototypes/Procedural/vgroid.yml b/Resources/Prototypes/Procedural/vgroid.yml new file mode 100644 index 00000000000..49e956e73f5 --- /dev/null +++ b/Resources/Prototypes/Procedural/vgroid.yml @@ -0,0 +1,191 @@ +# Okay so my general thought is this: +# 1. Generate the large mass +# 2. Generate smaller masses offset +# 3. Generate N normal dungeons around the larger mass, preferably near the border +# 4. Generate large paths / small paths around the place +# 5. Spawn ores + fill the rest and the normal stuff + +# If you want mobs they needed to be added at specific steps due to how dungeons work at the moment. + +- type: dungeonConfig + id: VGRoid + layers: + - !type:PrototypeDunGen + proto: VGRoidBlob + - !type:PrototypeDunGen + proto: VGRoidExterior + - !type:PrototypeDunGen + proto: VGRoidSmaller + - !type:PrototypeDunGen + proto: VGRoidSmallPaths + # Fill + - !type:PrototypeDunGen + proto: VGRoidFill + # Ores + - !type:OreDunGen + replacement: IronRock + entity: IronRockIron + count: 50 + minGroupSize: 20 + maxGroupSize: 30 + - !type:OreDunGen + replacement: IronRock + entity: IronRockCoal + count: 50 + minGroupSize: 20 + maxGroupSize: 30 + - !type:OreDunGen + replacement: IronRock + entity: IronRockQuartz + count: 50 + minGroupSize: 20 + maxGroupSize: 30 + - !type:OreDunGen + replacement: IronRock + entity: IronRockSalt + count: 50 + minGroupSize: 20 + maxGroupSize: 30 + - !type:OreDunGen + replacement: IronRock + entity: IronRockGold + count: 50 + minGroupSize: 10 + maxGroupSize: 20 + - !type:OreDunGen + replacement: IronRock + entity: IronRockSilver + count: 50 + minGroupSize: 10 + maxGroupSize: 20 + - !type:OreDunGen + replacement: IronRock + entity: IronRockPlasma + count: 50 + minGroupSize: 10 + maxGroupSize: 20 + - !type:OreDunGen + replacement: IronRock + entity: IronRockUranium + count: 50 + minGroupSize: 10 + maxGroupSize: 20 + - !type:OreDunGen + replacement: IronRock + entity: IronRockBananium + count: 50 + minGroupSize: 10 + maxGroupSize: 20 + - !type:OreDunGen + replacement: IronRock + entity: IronRockArtifactFragment + count: 50 + minGroupSize: 2 + maxGroupSize: 4 + +# Configs +- type: dungeonConfig + id: VGRoidBlob + layers: + - !type:NoiseDistanceDunGen + size: 272, 272 + distanceConfig: !type:DunGenEuclideanSquaredDistance + blendWeight: 0.80 + layers: + - tile: FloorAsteroidSand + threshold: 0.50 + noise: + frequency: 0.010 + noiseType: OpenSimplex2 + fractalType: FBm + octaves: 5 + lacunarity: 2 + gain: 0.5 + +- type: dungeonConfig + id: VGRoidSmaller + minOffset: 40 + maxOffset: 60 + layers: + - !type:NoiseDistanceDunGen + size: 150, 150 + distanceConfig: !type:DunGenEuclideanSquaredDistance + layers: + - tile: FloorAsteroidSand + threshold: 0.50 + noise: + frequency: 0.080 + noiseType: OpenSimplex2 + fractalType: FBm + octaves: 5 + lacunarity: 1.5 + gain: 0.5 + +- type: dungeonConfig + id: VGRoidExterior + reserveTiles: true + data: + tiles: + FallbackTile: PlatingAsteroid + WidenTile: FloorAsteroidSand + layers: + - !type:PrototypeDunGen + proto: VGRoidExteriorDungeons + - !type:SplineDungeonConnectorDunGen + +- type: dungeonConfig + id: VGRoidExteriorDungeons + reserveTiles: true + minCount: 2 + maxCount: 3 + layers: + - !type:ExteriorDunGen + proto: Experiment + - !type:MobsDunGen + minCount: 5 + maxCount: 8 + groups: + - id: MobXeno + amount: 1 + +#- type: dungeonConfig +# id: VGRoidInteriorDungeons +# minCount: 3 +# maxCount: 5 +# # Just randomly spawn these in bounds, doesn't really matter if they go out. + +- type: dungeonConfig + id: VGRoidSmallPaths + reserveTiles: true + layers: + - !type:ReplaceTileDunGen + layers: + - tile: FloorAsteroidSand + threshold: 0.75 + noise: + frequency: 0.040 + noiseType: OpenSimplex2 + fractalType: Ridged + lacunarity: 1.5 + octaves: 2 + gain: 2.0 + # Mobs + # If you want exterior dungeon mobs add them under the prototype. + - !type:MobsDunGen + minCount: 20 + maxCount: 30 + groups: + - id: MobXeno + amount: 1 + +#- type: dungeonConfig +# id: VGRoidOres + +# Fill with rocks. +- type: dungeonConfig + id: VGRoidFill + data: + entities: + Fill: IronRock + layers: + - !type:FillGridDunGen From 6e99dc2401ce6b11053d8762ab898b91eefb2b85 Mon Sep 17 00:00:00 2001 From: Ed <96445749+TheShuEd@users.noreply.github.com> Date: Wed, 3 Jul 2024 18:14:39 +0300 Subject: [PATCH 039/765] New anomaly behaviour: Invisibility (#29120) * invisible anomaly * good luck --- Resources/Locale/en-US/anomaly/anomaly.ftl | 1 + Resources/Prototypes/Anomaly/behaviours.yml | 33 +++++++++++++++++++-- 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/Resources/Locale/en-US/anomaly/anomaly.ftl b/Resources/Locale/en-US/anomaly/anomaly.ftl index da5882fa62f..c8d099777d4 100644 --- a/Resources/Locale/en-US/anomaly/anomaly.ftl +++ b/Resources/Locale/en-US/anomaly/anomaly.ftl @@ -89,6 +89,7 @@ anomaly-behavior-rapid = The frequency of the pulsation is much higher, but its anomaly-behavior-reflect = A protective coating was detected. anomaly-behavior-nonsensivity = A weak reaction to particles was detected. anomaly-behavior-sensivity = Amplified reaction to particles was detected. +anomaly-behavior-invisibility = Light wave distortion has been detected. anomaly-behavior-secret = Interference detected. Some data cannot be read anomaly-behavior-inconstancy = [color=crimson]Impermanence has been detected. Particle types can change over time.[/color] anomaly-behavior-fast = [color=crimson]The pulsation frequency is strongly increased.[/color] diff --git a/Resources/Prototypes/Anomaly/behaviours.yml b/Resources/Prototypes/Anomaly/behaviours.yml index dea1ddb69c3..924a4a75004 100644 --- a/Resources/Prototypes/Anomaly/behaviours.yml +++ b/Resources/Prototypes/Anomaly/behaviours.yml @@ -20,10 +20,12 @@ InconstancyParticle: 0.5 FullUnknown: 0.5 Jumping: 0.3 + Invisibility: 0.5 #Complex FastUnknown: 0.2 JumpingUnknown: 0.1 InconstancyParticleUnknown: 0.1 + InvisibilityJumping: 0.1 # Easy x0.5 point production @@ -153,6 +155,17 @@ randomStartSecretMin: 4 randomStartSecretMax: 6 +- type: anomalyBehavior + id: Invisibility + earnPointModifier: 1.6 + description: anomaly-behavior-invisibility + components: + - type: Stealth + maxVisibility: 1.2 + - type: StealthOnMove + passiveVisibilityRate: -0.37 + movementVisibilityRate: 0.20 + # Complex Effects - type: anomalyBehavior @@ -170,7 +183,6 @@ randomStartSecretMin: 3 randomStartSecretMax: 5 - - type: anomalyBehavior id: FastUnknown earnPointModifier: 1.9 @@ -191,4 +203,21 @@ prob: 0.5 - type: SecretDataAnomaly randomStartSecretMin: 3 - randomStartSecretMax: 5 \ No newline at end of file + randomStartSecretMax: 5 + +- type: anomalyBehavior + id: InvisibilityJumping + earnPointModifier: 1.95 + description: anomaly-behavior-invisibility + components: + - type: ChaoticJump + jumpMinInterval: 15 + jumpMaxInterval: 25 + rangeMin: 1 + rangeMax: 1 + effect: PuddleSparkle + - type: Stealth + maxVisibility: 1.2 + - type: StealthOnMove + passiveVisibilityRate: -0.37 + movementVisibilityRate: 0.20 \ No newline at end of file From 09307a54950ba59781f62c64b4784c023c34dc76 Mon Sep 17 00:00:00 2001 From: PJBot Date: Wed, 3 Jul 2024 15:15:47 +0000 Subject: [PATCH 040/765] Automatic changelog update --- Resources/Changelog/Changelog.yml | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index e1a72faa15e..f19099f899a 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,12 +1,4 @@ Entries: -- author: MACMAN2003 - changes: - - message: Nuclear operatives now only need 20 players to be readied up again instead - of 35. - type: Tweak - id: 6364 - time: '2024-04-17T03:19:30.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/27036 - author: Bellwether changes: - message: The nun hood now appears in the Chaplain's loadout. @@ -3826,3 +3818,10 @@ id: 6863 time: '2024-07-03T05:27:33.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/28117 +- author: TheShuEd + changes: + - message: anomalies have the ability to gain invisibility behavior + type: Add + id: 6864 + time: '2024-07-03T15:14:39.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/29120 From 653a8371ad6e2fbe334113a5be07fd47635225bc Mon Sep 17 00:00:00 2001 From: Alex Pavlenko Date: Wed, 3 Jul 2024 18:37:40 +0300 Subject: [PATCH 041/765] feat: allow developers to customize vscode settings, closes #29285 (#29294) --- .vscode/settings.json | 4 ---- 1 file changed, 4 deletions(-) delete mode 100644 .vscode/settings.json diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index 0e0d3ae890c..00000000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "omnisharp.analyzeOpenDocumentsOnly": true, - "dotnet.defaultSolution": "SpaceStation14.sln" -} From 7e0a4d4db52bb837dfbe21b291fe802049621c90 Mon Sep 17 00:00:00 2001 From: ArkiveDev <95712736+ArkiveDev@users.noreply.github.com> Date: Wed, 3 Jul 2024 12:59:29 -0400 Subject: [PATCH 042/765] Allow construction of rotated railings (#29687) * Remove southRotation from railing structures * Curly Braces --- .../Construction/Graphs/structures/railing.yml | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/Resources/Prototypes/Recipes/Construction/Graphs/structures/railing.yml b/Resources/Prototypes/Recipes/Construction/Graphs/structures/railing.yml index f050c65c42c..1772bddea0b 100644 --- a/Resources/Prototypes/Recipes/Construction/Graphs/structures/railing.yml +++ b/Resources/Prototypes/Recipes/Construction/Graphs/structures/railing.yml @@ -6,32 +6,28 @@ edges: - to: railing completed: - - !type:SnapToGrid - southRotation: true + - !type:SnapToGrid { } steps: - material: MetalRod amount: 1 doAfter: 2 - to: railingCorner completed: - - !type:SnapToGrid - southRotation: true + - !type:SnapToGrid { } steps: - material: MetalRod amount: 2 doAfter: 2.5 - to: railingCornerSmall completed: - - !type:SnapToGrid - southRotation: true + - !type:SnapToGrid { } steps: - material: MetalRod amount: 1 doAfter: 2 - to: railingRound completed: - - !type:SnapToGrid - southRotation: true + - !type:SnapToGrid { } steps: - material: MetalRod amount: 2 From b704661998f978fbdd63ca9185b15cd925ba42cc Mon Sep 17 00:00:00 2001 From: PJBot Date: Wed, 3 Jul 2024 17:00:36 +0000 Subject: [PATCH 043/765] Automatic changelog update --- Resources/Changelog/Changelog.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index f19099f899a..51396e8a184 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,11 +1,4 @@ Entries: -- author: Bellwether - changes: - - message: The nun hood now appears in the Chaplain's loadout. - type: Tweak - id: 6365 - time: '2024-04-17T03:36:44.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/27025 - author: iNV3RT3D & metalgearsloth changes: - message: Added a jukebox. @@ -3825,3 +3818,10 @@ id: 6864 time: '2024-07-03T15:14:39.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/29120 +- author: ArkiveDev + changes: + - message: Railings can now be constructed in all 4 orientations. + type: Fix + id: 6865 + time: '2024-07-03T16:59:29.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/29687 From 3460bd49d0bc8fc0f58bbf69997277e241ecf2fb Mon Sep 17 00:00:00 2001 From: Interrobang01 <113810873+Interrobang01@users.noreply.github.com> Date: Wed, 3 Jul 2024 17:43:42 -0700 Subject: [PATCH 044/765] improved wrench description (#29700) Lefty latchy, righty removey --- Resources/Prototypes/Entities/Objects/Tools/tools.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Resources/Prototypes/Entities/Objects/Tools/tools.yml b/Resources/Prototypes/Entities/Objects/Tools/tools.yml index 433f269a7ab..b5ab18b2386 100644 --- a/Resources/Prototypes/Entities/Objects/Tools/tools.yml +++ b/Resources/Prototypes/Entities/Objects/Tools/tools.yml @@ -92,7 +92,7 @@ name: wrench parent: BaseItem id: Wrench - description: 'A common tool for assembly and disassembly. Remember: righty tighty, lefty loosey.' + description: 'A common tool for assembly and disassembly. Remember: lefty latchy, righty removey.' components: - type: EmitSoundOnLand sound: From 6dd602ef71d464b9ac86f35b644b6878b16e5246 Mon Sep 17 00:00:00 2001 From: Nemanja <98561806+EmoGarbage404@users.noreply.github.com> Date: Wed, 3 Jul 2024 21:13:49 -0400 Subject: [PATCH 045/765] add apc power draw to stat value command (#29701) add apc stat value --- .../UserInterface/StatValuesCommand.cs | 46 ++++++++++++++++++- .../en-US/commands/stat-values-command.ftl | 5 ++ 2 files changed, 50 insertions(+), 1 deletion(-) diff --git a/Content.Server/UserInterface/StatValuesCommand.cs b/Content.Server/UserInterface/StatValuesCommand.cs index f0c4f531d01..cb599f7b09f 100644 --- a/Content.Server/UserInterface/StatValuesCommand.cs +++ b/Content.Server/UserInterface/StatValuesCommand.cs @@ -4,6 +4,7 @@ using Content.Server.Cargo.Systems; using Content.Server.EUI; using Content.Server.Item; +using Content.Server.Power.Components; using Content.Shared.Administration; using Content.Shared.Item; using Content.Shared.Materials; @@ -56,6 +57,9 @@ public void Execute(IConsoleShell shell, string argStr, string[] args) case "itemsize": message = GetItem(); break; + case "drawrate": + message = GetDrawRateMessage(); + break; default: shell.WriteError(Loc.GetString("stat-values-invalid", ("arg", args[0]))); return; @@ -70,7 +74,7 @@ public CompletionResult GetCompletion(IConsoleShell shell, string[] args) { if (args.Length == 1) { - return CompletionResult.FromOptions(new[] { "cargosell", "lathesell", "melee" }); + return CompletionResult.FromOptions(new[] { "cargosell", "lathesell", "melee", "itemsize", "drawrate" }); } return CompletionResult.Empty; @@ -250,4 +254,44 @@ private StatValuesEuiMessage GetLatheMessage() return state; } + + private StatValuesEuiMessage GetDrawRateMessage() + { + var values = new List(); + var powerName = _factory.GetComponentName(typeof(ApcPowerReceiverComponent)); + + foreach (var proto in _proto.EnumeratePrototypes()) + { + if (proto.Abstract || + !proto.Components.TryGetValue(powerName, + out var powerConsumer)) + { + continue; + } + + var comp = (ApcPowerReceiverComponent) powerConsumer.Component; + + if (comp.Load == 0) + continue; + + values.Add(new[] + { + proto.ID, + comp.Load.ToString(CultureInfo.InvariantCulture), + }); + } + + var state = new StatValuesEuiMessage + { + Title = Loc.GetString("stat-drawrate-values"), + Headers = new List + { + Loc.GetString("stat-drawrate-id"), + Loc.GetString("stat-drawrate-rate"), + }, + Values = values, + }; + + return state; + } } diff --git a/Resources/Locale/en-US/commands/stat-values-command.ftl b/Resources/Locale/en-US/commands/stat-values-command.ftl index 99c6bd194e3..67a211adabe 100644 --- a/Resources/Locale/en-US/commands/stat-values-command.ftl +++ b/Resources/Locale/en-US/commands/stat-values-command.ftl @@ -18,3 +18,8 @@ stat-lathe-sell = Sell price stat-item-values = Item sizes stat-item-id = ID stat-item-price = Size + +# Draw Rate +stat-drawrate-values = APC draw rate +stat-drawrate-id = ID +stat-drawrate-rate = Draw Rate (W) From 500590142af7372ba13a76b5b164524b8038a68d Mon Sep 17 00:00:00 2001 From: Rinary <72972221+Rinary1@users.noreply.github.com> Date: Thu, 4 Jul 2024 04:25:25 +0300 Subject: [PATCH 046/765] Dynamic Radial Menus (#29678) * fix * Clean Some Code * Some Commentaries * Update Content.Client/UserInterface/Controls/RadialContainer.cs * Update Content.Client/UserInterface/Controls/RadialContainer.cs --------- Co-authored-by: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com> --- Content.Client/UserInterface/Controls/RadialContainer.cs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/Content.Client/UserInterface/Controls/RadialContainer.cs b/Content.Client/UserInterface/Controls/RadialContainer.cs index be263d12772..be9b8817a06 100644 --- a/Content.Client/UserInterface/Controls/RadialContainer.cs +++ b/Content.Client/UserInterface/Controls/RadialContainer.cs @@ -67,11 +67,18 @@ public RadialContainer() { } - + protected override void Draw(DrawingHandleScreen handle) { + + const float baseRadius = 100f; + const float radiusIncrement = 5f; + var children = ReserveSpaceForHiddenChildren ? Children : Children.Where(x => x.Visible); var childCount = children.Count(); + + // Add padding from the center at higher child counts so they don't overlap. + Radius = baseRadius + (childCount * radiusIncrement); // Determine the size of the arc, accounting for clockwise and anti-clockwise arrangements var arc = AngularRange.Y - AngularRange.X; From 1010a16777a3fdee9cc0c8f0eb449ffa9512d9ab Mon Sep 17 00:00:00 2001 From: PJBot Date: Thu, 4 Jul 2024 01:26:31 +0000 Subject: [PATCH 047/765] Automatic changelog update --- Resources/Changelog/Changelog.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 51396e8a184..074bfc3492b 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,11 +1,4 @@ Entries: -- author: iNV3RT3D & metalgearsloth - changes: - - message: Added a jukebox. - type: Add - id: 6366 - time: '2024-04-17T09:27:01.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/26736 - author: Vermidia changes: - message: Pirate Accent and Mobster accent will respect capitalization better now @@ -3825,3 +3818,10 @@ id: 6865 time: '2024-07-03T16:59:29.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/29687 +- author: Rinary + changes: + - message: Fixed radial menus overlapping where there's many icons. + type: Fix + id: 6866 + time: '2024-07-04T01:25:25.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/29678 From 1e2160bbf53ff19e41c400c585d64dd9565c7cd3 Mon Sep 17 00:00:00 2001 From: Plykiya <58439124+Plykiya@users.noreply.github.com> Date: Wed, 3 Jul 2024 18:29:07 -0700 Subject: [PATCH 048/765] Fixes objects changing physics behavior after being pulled (#29694) * Fixes pull rotation logic * cleaner condition * even less code * I CHANGED MY MIND * first one * second one --------- Co-authored-by: plykiya --- Content.Shared/Movement/Pulling/Systems/PullingSystem.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Content.Shared/Movement/Pulling/Systems/PullingSystem.cs b/Content.Shared/Movement/Pulling/Systems/PullingSystem.cs index edc8ad51617..f563440af04 100644 --- a/Content.Shared/Movement/Pulling/Systems/PullingSystem.cs +++ b/Content.Shared/Movement/Pulling/Systems/PullingSystem.cs @@ -310,7 +310,7 @@ public bool IsPulling(EntityUid puller, PullerComponent? component = null) private void OnReleasePulledObject(ICommonSession? session) { - if (session?.AttachedEntity is not {Valid: true} player) + if (session?.AttachedEntity is not { Valid: true } player) { return; } @@ -447,6 +447,9 @@ public bool TryStartPull(EntityUid pullerUid, EntityUid pullableUid, pullerComp.Pulling = pullableUid; pullableComp.Puller = pullerUid; + // store the pulled entity's physics FixedRotation setting in case we change it + pullableComp.PrevFixedRotation = pullablePhysics.FixedRotation; + // joint state handling will manage its own state if (!_timing.ApplyingState) { @@ -465,8 +468,6 @@ public bool TryStartPull(EntityUid pullerUid, EntityUid pullableUid, _physics.SetFixedRotation(pullableUid, pullableComp.FixedRotationOnPull, body: pullablePhysics); } - pullableComp.PrevFixedRotation = pullablePhysics.FixedRotation; - // Messaging var message = new PullStartedMessage(pullerUid, pullableUid); _modifierSystem.RefreshMovementSpeedModifiers(pullerUid); From 7022e0429438ae8739b9cbe285bf48a0b22baf27 Mon Sep 17 00:00:00 2001 From: PJBot Date: Thu, 4 Jul 2024 01:30:13 +0000 Subject: [PATCH 049/765] Automatic changelog update --- Resources/Changelog/Changelog.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 074bfc3492b..fa2e53f8b63 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,11 +1,4 @@ Entries: -- author: Vermidia - changes: - - message: Pirate Accent and Mobster accent will respect capitalization better now - type: Fix - id: 6367 - time: '2024-04-17T10:04:24.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/26644 - author: metalgearsloth changes: - message: Fix lobby character preview not updating upon changing characters. @@ -3825,3 +3818,10 @@ id: 6866 time: '2024-07-04T01:25:25.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/29678 +- author: Plykiya + changes: + - message: An object's physics properly returns to normal after being pulled. + type: Fix + id: 6867 + time: '2024-07-04T01:29:07.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/29694 From ac3c8dc05f2f8fef0bc2f4d87a05513c0dad0e47 Mon Sep 17 00:00:00 2001 From: Plykiya <58439124+Plykiya@users.noreply.github.com> Date: Wed, 3 Jul 2024 18:51:46 -0700 Subject: [PATCH 050/765] Makes portable flashers destructable (#29564) Makes portable flashers destructible Co-authored-by: plykiya --- Resources/Prototypes/Entities/Objects/Weapons/security.yml | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/Resources/Prototypes/Entities/Objects/Weapons/security.yml b/Resources/Prototypes/Entities/Objects/Weapons/security.yml index ceb81376752..d86f1dd0e9a 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/security.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/security.yml @@ -178,7 +178,7 @@ - type: entity name: portable flasher - parent: BaseStructure + parent: BaseMachine id: PortableFlasher description: An ultrabright flashbulb with a proximity trigger, useful for making an area security-only. components: @@ -194,14 +194,11 @@ !type:PhysShapeCircle radius: 2 repeating: true - - type: Anchorable - type: Sprite sprite: Objects/Weapons/pflash.rsi layers: - state: "off" map: ["enum.ProximityTriggerVisualLayers.Base"] - - type: InteractionOutline - - type: Physics - type: Fixtures fixtures: fix1: From 223b4494f9e4363b7948d9d1fa5c5f267a047245 Mon Sep 17 00:00:00 2001 From: PJBot Date: Thu, 4 Jul 2024 01:52:52 +0000 Subject: [PATCH 051/765] Automatic changelog update --- Resources/Changelog/Changelog.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index fa2e53f8b63..4089a09eaf2 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,11 +1,4 @@ Entries: -- author: metalgearsloth - changes: - - message: Fix lobby character preview not updating upon changing characters. - type: Fix - id: 6368 - time: '2024-04-17T10:06:10.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/27043 - author: Beck Thompson changes: - message: You now must equip gloved weapons (E.g boxing gloves) to use them. @@ -3825,3 +3818,10 @@ id: 6867 time: '2024-07-04T01:29:07.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/29694 +- author: Plykiya + changes: + - message: You can now destroy portable flashers. + type: Fix + id: 6868 + time: '2024-07-04T01:51:46.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/29564 From 7baaf31f23d80c1ff7b3c69b7a28bd4279a3907e Mon Sep 17 00:00:00 2001 From: Errant <35878406+Errant-4@users.noreply.github.com> Date: Thu, 4 Jul 2024 04:01:03 +0200 Subject: [PATCH 052/765] Starting gear for vox crewmembers (#29685) * tank harness * weh * Suit Storage Whitelist * Revert "Suit Storage Whitelist" This reverts commit b1f503573c2936642a2d7627c4852153ec71ce79. * suit storage filter * vox spawn gear * weh --- .../en-US/preferences/loadout-groups.ftl | 12 + .../DeltaV/Loadouts/loadout_groups.yml | 10 +- .../Entities/Clothing/OuterClothing/vests.yml | 12 + .../Entities/Clothing/base_clothing.yml | 9 + .../Entities/Objects/Tools/gas_tanks.yml | 3 + .../Loadouts/Miscellaneous/survival.yml | 258 ++++++++++++++++++ .../Prototypes/Loadouts/loadout_groups.yml | 107 +++++++- .../Prototypes/Loadouts/role_loadouts.yml | 113 ++++++++ Resources/Prototypes/tags.yml | 3 + .../equipped-OUTERCLOTHING-vox.png | Bin 0 -> 661 bytes .../equipped-OUTERCLOTHING.png | Bin 0 -> 800 bytes .../Vests/tankharness.rsi/icon.png | Bin 0 -> 307 bytes .../Vests/tankharness.rsi/inhand-left.png | Bin 0 -> 265 bytes .../Vests/tankharness.rsi/inhand-right.png | Bin 0 -> 289 bytes .../Vests/tankharness.rsi/meta.json | 30 ++ 15 files changed, 542 insertions(+), 15 deletions(-) create mode 100644 Resources/Prototypes/Loadouts/Miscellaneous/survival.yml create mode 100644 Resources/Textures/Clothing/OuterClothing/Vests/tankharness.rsi/equipped-OUTERCLOTHING-vox.png create mode 100644 Resources/Textures/Clothing/OuterClothing/Vests/tankharness.rsi/equipped-OUTERCLOTHING.png create mode 100644 Resources/Textures/Clothing/OuterClothing/Vests/tankharness.rsi/icon.png create mode 100644 Resources/Textures/Clothing/OuterClothing/Vests/tankharness.rsi/inhand-left.png create mode 100644 Resources/Textures/Clothing/OuterClothing/Vests/tankharness.rsi/inhand-right.png create mode 100644 Resources/Textures/Clothing/OuterClothing/Vests/tankharness.rsi/meta.json diff --git a/Resources/Locale/en-US/preferences/loadout-groups.ftl b/Resources/Locale/en-US/preferences/loadout-groups.ftl index 444577f2f00..d82533f2ae2 100644 --- a/Resources/Locale/en-US/preferences/loadout-groups.ftl +++ b/Resources/Locale/en-US/preferences/loadout-groups.ftl @@ -1,9 +1,21 @@ +# Errors +loadout-group-species-restriction = This item is not available for your current species. + # Miscellaneous loadout-group-trinkets = Trinkets loadout-group-glasses = Glasses loadout-group-backpack = Backpack loadout-group-instruments = Instruments +loadout-group-survival-basic = Survival Box +loadout-group-survival-extended = Extended Survival Box +loadout-group-survival-clown = Clown Survival Box +loadout-group-survival-medical = Medical Survival Box +loadout-group-survival-security = Security Survival Box +loadout-group-survival-syndicate = Github is forcing me to write text that is literally twice-impossible for the player to ever see, send help +loadout-group-breath-tool = Species-dependent breath tools +loadout-group-tank-harness = Species-specific survival equipment + # Command loadout-group-captain-head = Captain head loadout-group-captain-jumpsuit = Captain jumpsuit diff --git a/Resources/Prototypes/DeltaV/Loadouts/loadout_groups.yml b/Resources/Prototypes/DeltaV/Loadouts/loadout_groups.yml index ec6b03ca4ee..7d037793b12 100644 --- a/Resources/Prototypes/DeltaV/Loadouts/loadout_groups.yml +++ b/Resources/Prototypes/DeltaV/Loadouts/loadout_groups.yml @@ -102,7 +102,15 @@ - BrigMedicBackpack - BrigMedicSatchel - BrigMedicDuffel - + +## Security Cadet +- type: loadoutGroup + id: SecurityCadetHead + name: loadout-group-security-cadet-head + minLimit: 0 + loadouts: + - MimeHead + # Justice ## Chief Justice - type: loadoutGroup diff --git a/Resources/Prototypes/Entities/Clothing/OuterClothing/vests.yml b/Resources/Prototypes/Entities/Clothing/OuterClothing/vests.yml index 74b6ec74fb5..1fd46e8e763 100644 --- a/Resources/Prototypes/Entities/Clothing/OuterClothing/vests.yml +++ b/Resources/Prototypes/Entities/Clothing/OuterClothing/vests.yml @@ -78,3 +78,15 @@ sprite: Clothing/OuterClothing/Vests/vest.rsi - type: Clothing sprite: Clothing/OuterClothing/Vests/vest.rsi + +#Tank Harness +- type: entity + parent: [ClothingOuterBase, AllowSuitStorageClothingGasTanks] + id: ClothingOuterVestTank + name: tank harness + description: A simple harness that can hold a gas tank. + components: + - type: Sprite + sprite: Clothing/OuterClothing/Vests/tankharness.rsi + - type: Clothing + sprite: Clothing/OuterClothing/Vests/tankharness.rsi diff --git a/Resources/Prototypes/Entities/Clothing/base_clothing.yml b/Resources/Prototypes/Entities/Clothing/base_clothing.yml index 55bc2fd3e6a..a96ca2d23c8 100644 --- a/Resources/Prototypes/Entities/Clothing/base_clothing.yml +++ b/Resources/Prototypes/Entities/Clothing/base_clothing.yml @@ -25,6 +25,15 @@ components: - type: AllowSuitStorage +- type: entity + abstract: true + id: AllowSuitStorageClothingGasTanks + components: + - type: AllowSuitStorage + whitelist: + tags: + - GasTank + # for clothing that has a single item slot to insert and alt click out. # inheritors add a whitelisted slot named item - type: entity diff --git a/Resources/Prototypes/Entities/Objects/Tools/gas_tanks.yml b/Resources/Prototypes/Entities/Objects/Tools/gas_tanks.yml index 53423e84a4f..b825647ac13 100644 --- a/Resources/Prototypes/Entities/Objects/Tools/gas_tanks.yml +++ b/Resources/Prototypes/Entities/Objects/Tools/gas_tanks.yml @@ -9,6 +9,9 @@ - type: Item size: Normal sprite: Objects/Tanks/generic.rsi + - type: Tag + tags: + - GasTank - type: Clothing quickEquip: false sprite: Objects/Tanks/generic.rsi diff --git a/Resources/Prototypes/Loadouts/Miscellaneous/survival.yml b/Resources/Prototypes/Loadouts/Miscellaneous/survival.yml new file mode 100644 index 00000000000..6122752c91e --- /dev/null +++ b/Resources/Prototypes/Loadouts/Miscellaneous/survival.yml @@ -0,0 +1,258 @@ +# Species +- type: loadoutEffectGroup + id: NitrogenBreather + effects: + - !type:SpeciesLoadoutEffect + species: + - SlimePerson + - Vox + +- type: loadoutEffectGroup + id: OxygenBreather + effects: + - !type:SpeciesLoadoutEffect + species: + - Arachnid + - Diona + - Dwarf + - Human + - Moth + - Reptilian + - Harpy # DeltaV + - Vulpkanin # DeltaV + - Felenid # DeltaV + - Oni # DeltaV + +- type: loadoutEffectGroup + id: EffectSpeciesVox + effects: + - !type:SpeciesLoadoutEffect + species: + - Vox + +# Basic +- type: loadout + id: EmergencyOxygen + equipment: EmergencyOxygen + effects: + - !type:GroupLoadoutEffect + proto: OxygenBreather + +- type: startingGear + id: EmergencyOxygen + storage: + back: + - BoxSurvival + +- type: loadout + id: EmergencyNitrogen + equipment: EmergencyNitrogen + effects: + - !type:GroupLoadoutEffect + proto: NitrogenBreather + +- type: startingGear + id: EmergencyNitrogen + storage: + back: + - BoxSurvivalNitrogen + +# Clown +- type: loadout + id: EmergencyOxygenClown + equipment: EmergencyOxygenClown + effects: + - !type:GroupLoadoutEffect + proto: OxygenBreather + +- type: startingGear + id: EmergencyOxygenClown + storage: + back: + - BoxHug + +- type: loadout + id: EmergencyNitrogenClown + equipment: EmergencyNitrogenClown + effects: + - !type:GroupLoadoutEffect + proto: NitrogenBreather + +- type: startingGear + id: EmergencyNitrogenClown + storage: + back: + - BoxHugNitrogen + +# Engineering / Extended +- type: loadout + id: EmergencyOxygenExtended + equipment: EmergencyOxygenExtended + effects: + - !type:GroupLoadoutEffect + proto: OxygenBreather + +- type: startingGear + id: EmergencyOxygenExtended + storage: + back: + - BoxSurvivalEngineering + +- type: loadout + id: EmergencyNitrogenExtended + equipment: EmergencyNitrogenExtended + effects: + - !type:GroupLoadoutEffect + proto: NitrogenBreather + +- type: startingGear + id: EmergencyNitrogenExtended + storage: + back: + - BoxSurvivalEngineeringNitrogen + +# Medical +- type: loadout + id: EmergencyOxygenMedical + equipment: EmergencyOxygenMedical + effects: + - !type:GroupLoadoutEffect + proto: OxygenBreather + +- type: startingGear + id: EmergencyOxygenMedical + storage: + back: + - BoxSurvivalMedical + +- type: loadout + id: EmergencyNitrogenMedical + equipment: EmergencyNitrogenMedical + effects: + - !type:GroupLoadoutEffect + proto: NitrogenBreather + +- type: startingGear + id: EmergencyNitrogenMedical + storage: + back: + - BoxSurvivalMedicalNitrogen + +# Security +- type: loadout + id: EmergencyOxygenSecurity + equipment: EmergencyOxygenSecurity + effects: + - !type:GroupLoadoutEffect + proto: OxygenBreather + +- type: startingGear + id: EmergencyOxygenSecurity + storage: + back: + - BoxSurvivalSecurity + +- type: loadout + id: EmergencyNitrogenSecurity + equipment: EmergencyNitrogenSecurity + effects: + - !type:GroupLoadoutEffect + proto: NitrogenBreather + +- type: startingGear + id: EmergencyNitrogenSecurity + storage: + back: + - BoxSurvivalSecurityNitrogen + +# Syndicate +- type: loadout + id: EmergencyOxygenSyndicate + equipment: EmergencyOxygenSyndicate + effects: + - !type:GroupLoadoutEffect + proto: OxygenBreather + +- type: startingGear + id: EmergencyOxygenSyndicate + storage: + back: + - BoxSurvivalSyndicate + +- type: loadout + id: EmergencyNitrogenSyndicate + equipment: EmergencyNitrogenSyndicate + effects: + - !type:GroupLoadoutEffect + proto: NitrogenBreather + +- type: startingGear + id: EmergencyNitrogenSyndicate + storage: + back: + - BoxSurvivalSyndicateNitrogen + +# Pre-equipped species gear + +# Full Tank Equipped +- type: loadout + id: LoadoutSpeciesEVANitrogen + equipment: GearEVANitrogen + effects: + - !type:GroupLoadoutEffect + proto: EffectSpeciesVox + +- type: startingGear + id: GearEVANitrogen + equipment: + suitstorage: NitrogenTankFilled + +# Tank Harness +- type: loadout + id: LoadoutTankHarness + equipment: GearTankHarness + effects: + - !type:GroupLoadoutEffect + proto: EffectSpeciesVox + +- type: startingGear + id: GearTankHarness + equipment: + outerClothing: ClothingOuterVestTank + +# Breaths Tool On Face +- type: loadout + id: LoadoutSpeciesBreathTool + equipment: GearSpeciesBreathTool + effects: + - !type:GroupLoadoutEffect + proto: EffectSpeciesVox + +- type: startingGear + id: GearSpeciesBreathTool + equipment: + mask: ClothingMaskBreath + +- type: loadout + id: LoadoutSpeciesBreathToolMedical + equipment: GearSpeciesBreathToolMedical + effects: + - !type:GroupLoadoutEffect + proto: EffectSpeciesVox + +- type: startingGear + id: GearSpeciesBreathToolMedical + equipment: + mask: ClothingMaskBreathMedical + +- type: loadout + id: LoadoutSpeciesBreathToolSecurity + equipment: GearSpeciesBreathToolSecurity + effects: + - !type:GroupLoadoutEffect + proto: EffectSpeciesVox + +- type: startingGear + id: GearSpeciesBreathToolSecurity + equipment: + mask: ClothingMaskGasSecurity diff --git a/Resources/Prototypes/Loadouts/loadout_groups.yml b/Resources/Prototypes/Loadouts/loadout_groups.yml index dea95fc4716..8b260150e30 100644 --- a/Resources/Prototypes/Loadouts/loadout_groups.yml +++ b/Resources/Prototypes/Loadouts/loadout_groups.yml @@ -36,15 +36,23 @@ - GlassesJamjar - GlassesJensen -#- type: loadoutGroup -# id: Survival -# name: loadout-group-survival-basic -# minLimit: 1 -# maxLimit: 1 -# hidden: true -# loadouts: -# - EmergencyNitrogen -# - EmergencyOxygen +- type: loadoutGroup + id: GroupTankHarness + name: loadout-group-tank-harness + minLimit: 1 + hidden: true + loadouts: + - LoadoutTankHarness + +- type: loadoutGroup + id: Survival + name: loadout-group-survival-basic + minLimit: 3 + hidden: true + loadouts: + - EmergencyNitrogen + - EmergencyOxygen + - LoadoutSpeciesEVANitrogen # Command - type: loadoutGroup @@ -519,6 +527,16 @@ - ClownShoes - JesterShoes +- type: loadoutGroup + id: SurvivalClown + name: loadout-group-survival-clown + minLimit: 2 + hidden: true + loadouts: + - EmergencyNitrogenClown + - EmergencyOxygenClown + - LoadoutSpeciesEVANitrogen + - type: loadoutGroup id: MimeHead name: loadout-group-mime-head @@ -912,6 +930,16 @@ - WhiteShoes - EngineeringWinterBoots +- type: loadoutGroup + id: SurvivalExtended + name: loadout-group-survival-extended + minLimit: 2 + hidden: true + loadouts: + - EmergencyNitrogenExtended + - EmergencyOxygenExtended + - LoadoutSpeciesEVANitrogen + # Science - type: loadoutGroup id: ResearchDirectorHead @@ -1231,12 +1259,15 @@ - RedJumpsuit - RedJumpskirt -- type: loadoutGroup # DeltaV - id: SecurityCadetHead - name: loadout-group-security-cadet-head - minLimit: 0 +- type: loadoutGroup + id: SurvivalSecurity + name: loadout-group-survival-security + minLimit: 2 + hidden: true loadouts: - - MimeHead # DeltaV - Red Beret + - EmergencyNitrogenSecurity + - EmergencyOxygenSecurity + - LoadoutSpeciesEVANitrogen # Medical - type: loadoutGroup @@ -1471,6 +1502,16 @@ - MedicalWinterBoots - ParamedicWinterBoots # DeltaV +- type: loadoutGroup + id: SurvivalMedical + name: loadout-group-survival-medical + minLimit: 2 + hidden: true + loadouts: + - EmergencyNitrogenMedical + - EmergencyOxygenMedical + - LoadoutSpeciesEVANitrogen + # Wildcards - type: loadoutGroup id: ReporterJumpsuit @@ -1494,3 +1535,41 @@ - BlueBoxingGloves - GreenBoxingGloves - YellowBoxingGloves + +# Other +- type: loadoutGroup + id: SurvivalSyndicate + name: loadout-group-survival-syndicate + minLimit: 2 + hidden: true + loadouts: + - EmergencyNitrogenSyndicate + - EmergencyOxygenSyndicate + - LoadoutSpeciesEVANitrogen + +- type: loadoutGroup + id: GroupSpeciesBreathTool + name: loadout-group-breath-tool + minLimit: 1 + maxLimit: 1 + hidden: true + loadouts: + - LoadoutSpeciesBreathTool + +- type: loadoutGroup + id: GroupSpeciesBreathToolMedical + name: loadout-group-breath-tool + minLimit: 1 + maxLimit: 1 + hidden: true + loadouts: + - LoadoutSpeciesBreathToolMedical + +- type: loadoutGroup + id: GroupSpeciesBreathToolSecurity + name: loadout-group-breath-tool + minLimit: 1 + maxLimit: 1 + hidden: true + loadouts: + - LoadoutSpeciesBreathToolSecurity diff --git a/Resources/Prototypes/Loadouts/role_loadouts.yml b/Resources/Prototypes/Loadouts/role_loadouts.yml index cac84ac8e3c..718f598fd2b 100644 --- a/Resources/Prototypes/Loadouts/role_loadouts.yml +++ b/Resources/Prototypes/Loadouts/role_loadouts.yml @@ -10,10 +10,12 @@ - CaptainGloves # DeltaV - CaptainShoes # DeltaV - Trinkets + - GroupSpeciesBreathTool - type: roleLoadout id: JobHeadOfPersonnel groups: + - GroupTankHarness - HoPHead - HoPNeck - HoPJumpsuit @@ -23,12 +25,14 @@ - HoPShoes # DeltaV - Glasses - Trinkets + - GroupSpeciesBreathTool # Civilian - type: roleLoadout id: JobPassenger groups: - Scarfs # DeltaV + - GroupTankHarness - PassengerJumpsuit - CommonBackpack - PassengerFace @@ -38,10 +42,12 @@ - PassengerShoes - Glasses - Trinkets + - GroupSpeciesBreathTool - type: roleLoadout id: JobBartender groups: + - GroupTankHarness - BartenderHead - BartenderGlasses # DeltaV - BartenderNeck # DeltaV @@ -51,6 +57,7 @@ - BartenderPDADelta # DeltaV #- Glasses - Trinkets + - GroupSpeciesBreathTool - type: roleLoadout id: JobServiceWorker @@ -58,13 +65,16 @@ - ServiceWorkerHead # DeltaV - Scarfs # DeltaV - ServiceWorkerJumpsuit # DeltaV, was BartenderJumpsuit + - GroupTankHarness - CommonBackpack - Glasses - Trinkets + - GroupSpeciesBreathTool - type: roleLoadout id: JobChef groups: + - GroupTankHarness - ChefHead - ChefMask - ChefJumpsuit @@ -73,28 +83,34 @@ - ChefPDADelta # DeltaV - Glasses - Trinkets + - GroupSpeciesBreathTool - type: roleLoadout id: JobLibrarian groups: - LibrarianNeck # DeltaV + - GroupTankHarness - LibrarianJumpsuit - CommonBackpack - Glasses - Trinkets + - GroupSpeciesBreathTool - type: roleLoadout id: JobLawyer groups: + - GroupTankHarness - LawyerNeck - LawyerJumpsuit - LawyerBackpack - Glasses - Trinkets + - GroupSpeciesBreathTool - type: roleLoadout id: JobChaplain groups: + - GroupTankHarness - ChaplainHead - ChaplainMask - ChaplainNeck @@ -103,10 +119,12 @@ - ChaplainOuterClothing - Glasses - Trinkets + - GroupSpeciesBreathTool - type: roleLoadout id: JobJanitor groups: + - GroupTankHarness - JanitorHead - JanitorNeck # DeltaV - JanitorJumpsuit @@ -116,10 +134,12 @@ - Glasses - Trinkets - JanitorPlunger + - GroupSpeciesBreathTool - type: roleLoadout id: JobBotanist groups: + - GroupTankHarness - BotanistHead - BotanistNeck # DeltaV - BotanistJumpsuit @@ -127,10 +147,12 @@ - BotanistOuterClothing - Glasses - Trinkets + - GroupSpeciesBreathTool - type: roleLoadout id: JobClown groups: + - GroupTankHarness - ClownHead - Scarfs # DeltaV - ClownJumpsuit @@ -144,6 +166,7 @@ - type: roleLoadout id: JobMime groups: + - GroupTankHarness - MimeHead - MimeMask - MimeNeck # DeltaV @@ -156,6 +179,7 @@ - type: roleLoadout id: JobMusician groups: + - GroupTankHarness - MusicianJumpsuit - MusicianNeck - MusicianBackpack @@ -163,11 +187,13 @@ - Glasses - Trinkets - Instruments + - GroupSpeciesBreathTool # Cargo - type: roleLoadout id: JobQuartermaster groups: + - GroupTankHarness - QuartermasterHead - QuartermasterNeck - QuartermasterJumpsuit @@ -176,10 +202,12 @@ - QuartermasterShoes - Glasses - Trinkets + - GroupSpeciesBreathTool - type: roleLoadout id: JobCargoTechnician groups: + - GroupTankHarness - CargoTechnicianHead - CargoTechnicianNeck # DeltaV - CargoTechnicianJumpsuit @@ -189,22 +217,26 @@ - CargoTechnicianShoes - Glasses - Trinkets + - GroupSpeciesBreathTool - type: roleLoadout id: JobSalvageSpecialist groups: - SalvageSpecialistNeck # DeltaV + - GroupTankHarness - SalvageSpecialistBackpack - SalvageSpecialistOuterClothing - SalvagePDADelta # DeltaV - SalvageSpecialistShoes - Glasses - Trinkets + - GroupSpeciesBreathTool # Engineering - type: roleLoadout id: JobChiefEngineer groups: + - GroupTankHarness - ChiefEngineerHead - ChiefEngineerJumpsuit - ChiefEngineerBackpack @@ -212,17 +244,21 @@ - ChiefEngineerOuterClothing - ChiefEngineerShoes - Trinkets + - GroupSpeciesBreathTool - type: roleLoadout id: JobTechnicalAssistant groups: + - GroupTankHarness - TechnicalAssistantJumpsuit - StationEngineerBackpack - Trinkets + - GroupSpeciesBreathTool - type: roleLoadout id: JobStationEngineer groups: + - GroupTankHarness - StationEngineerHead - StationEngineerNeck # DeltaV - StationEngineerJumpsuit @@ -231,23 +267,27 @@ - StationEngineerShoes - StationEngineerID - Trinkets + - GroupSpeciesBreathTool - type: roleLoadout id: JobAtmosphericTechnician groups: - StationEngineerHead # DeltaV - Safety First! - AtmosphericTechnicianNeck # DeltaV + - GroupTankHarness - AtmosphericTechnicianJumpsuit - AtmosphericTechnicianBackpack - AtmosphericTechnicianOuterClothing - AtmosPDADelta # DeltaV - AtmosphericTechnicianShoes - Trinkets + - GroupSpeciesBreathTool # Science - type: roleLoadout id: JobResearchDirector groups: + - GroupTankHarness - ResearchDirectorHead - ResearchDirectorNeck - ResearchDirectorJumpsuit @@ -257,10 +297,12 @@ - ResearchDirectorShoes - Glasses - Trinkets + - GroupSpeciesBreathTool - type: roleLoadout id: JobScientist groups: + - GroupTankHarness - ScientistHead - ScientistNeck - ScientistJumpsuit @@ -271,14 +313,17 @@ - ScientistPDA - Glasses - Trinkets + - GroupSpeciesBreathTool - type: roleLoadout id: JobResearchAssistant groups: + - GroupTankHarness - ResearchAssistantJumpsuit - ScientistBackpack - Glasses - Trinkets + - GroupSpeciesBreathTool # Security - type: roleLoadout @@ -293,6 +338,7 @@ #- SecurityShoes - HeadOfSecurityShoes # DeltaV - Trinkets + - GroupSpeciesBreathToolSecurity - type: roleLoadout id: JobWarden @@ -305,6 +351,7 @@ - WardenOuterClothing - SecurityShoes - Trinkets + - GroupSpeciesBreathToolSecurity - type: roleLoadout id: JobSecurityOfficer @@ -318,10 +365,12 @@ - SecurityPDA - SecurityBelt - Trinkets + - GroupSpeciesBreathToolSecurity - type: roleLoadout id: JobDetective groups: + - GroupTankHarness - DetectiveHead - DetectiveNeck - DetectiveJumpsuit @@ -329,6 +378,7 @@ - DetectiveOuterClothing - SecurityShoes - Trinkets + - GroupSpeciesBreathToolSecurity - type: roleLoadout id: JobSecurityCadet @@ -338,11 +388,13 @@ - SecurityCadetJumpsuit - SecurityBackpack - Trinkets + - GroupSpeciesBreathToolSecurity # Medical - type: roleLoadout id: JobChiefMedicalOfficer groups: + - GroupTankHarness - ChiefMedicalOfficerHead - MedicalMask - ChiefMedicalOfficerJumpsuit @@ -353,10 +405,12 @@ - ChiefMedicalOfficerShoes - Glasses - Trinkets + - GroupSpeciesBreathToolMedical - type: roleLoadout id: JobMedicalDoctor groups: + - GroupTankHarness - MedicalDoctorHead - MedicalDoctorNeck # DeltaV - MedicalMask @@ -368,19 +422,23 @@ - MedicalDoctorPDA - Glasses - Trinkets + - GroupSpeciesBreathToolMedical - type: roleLoadout id: JobMedicalIntern groups: + - GroupTankHarness - MedicalInternJumpsuit - MedicalBackpack - MedicalInternPDADelta # DeltaV - Glasses - Trinkets + - GroupSpeciesBreathToolMedical - type: roleLoadout id: JobChemist groups: + - GroupTankHarness - MedicalMask - ChemistNeck # DeltaV - ChemistJumpsuit @@ -391,10 +449,12 @@ # - MedicalShoes - ChemistShoes # DeltaV - Trinkets + - GroupSpeciesBreathToolMedical - type: roleLoadout id: JobParamedic groups: + - GroupTankHarness - ParamedicHead - MedicalMask - MedicalDoctorNeck # DeltaV @@ -405,35 +465,88 @@ - ParamedicShoes - Glasses - Trinkets + - GroupSpeciesBreathToolMedical # Wildcards - type: roleLoadout id: JobZookeeper groups: + - GroupTankHarness - CommonBackpack - Glasses - Trinkets + - GroupSpeciesBreathTool - type: roleLoadout id: JobReporter groups: + - GroupTankHarness - ReporterJumpsuit - CommonBackpack - Glasses - Trinkets + - GroupSpeciesBreathTool - type: roleLoadout id: JobPsychologist groups: + - GroupTankHarness - MedicalBackpack - Glasses - Trinkets + - GroupSpeciesBreathTool - type: roleLoadout id: JobBoxer groups: + - GroupTankHarness - BoxerJumpsuit - BoxerGloves - CommonBackpack - Glasses - Trinkets + - GroupSpeciesBreathTool + +# These loadouts are used for non-crew spawns, like off-station antags and event mobs +# They will be used without player configuration, thus they will only ever apply what is forced by MinLimit + +- type: roleLoadout + id: RoleSurvivalStandard + groups: + - Survival + - GroupSpeciesBreathTool + - GroupTankHarness + +- type: roleLoadout + id: RoleSurvivalClown + groups: + - SurvivalClown + - GroupTankHarness + +- type: roleLoadout + id: RoleSurvivalExtended + groups: + - SurvivalExtended + - GroupSpeciesBreathTool + - GroupTankHarness + +- type: roleLoadout + id: RoleSurvivalMedical + groups: + - SurvivalMedical + - GroupSpeciesBreathToolMedical + - GroupTankHarness + +- type: roleLoadout + id: RoleSurvivalSecurity + groups: + - SurvivalSecurity + - GroupSpeciesBreathToolSecurity + - GroupTankHarness + +- type: roleLoadout + id: RoleSurvivalSyndicate + groups: + - SurvivalSyndicate + - GroupSpeciesBreathTool + - GroupTankHarness diff --git a/Resources/Prototypes/tags.yml b/Resources/Prototypes/tags.yml index f6acfab913e..f11653417b6 100644 --- a/Resources/Prototypes/tags.yml +++ b/Resources/Prototypes/tags.yml @@ -623,6 +623,9 @@ - type: Tag id: GasScrubber +- type: Tag + id: GasTank + - type: Tag id: GasVent diff --git a/Resources/Textures/Clothing/OuterClothing/Vests/tankharness.rsi/equipped-OUTERCLOTHING-vox.png b/Resources/Textures/Clothing/OuterClothing/Vests/tankharness.rsi/equipped-OUTERCLOTHING-vox.png new file mode 100644 index 0000000000000000000000000000000000000000..712a04c614c73d17caba2e57a5a37243c076d601 GIT binary patch literal 661 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=oCO|{#S9F5he4R}c>anM1_mZ~ zPZ!6KinzBkee(_(2(->!;hGc}5abu&kaW6Dx*$vMP}3&;MIxt~ScO*34|UJv5b&Sl zurz%om)X4e-+SLKh|)9@QeZ?vjYcfL^7B0}?(u${TC?lSOdmB*JF#C9=L zI^glglVOI#?XljC1@`K5A3(W!%y2Obs# z9Di)s%JA_;a*f$+OV;T==koTyEt|dTz>XyhkDLSM@8Se%dF6e?Be&#^{qlWpy}2In zEV!Gez4uM;3yZD|QX6D_>P@6p{;bivT6&o;^qANYZT<2WGYf0pS4mjqGU^)KeE&W3 zsC}6BWRoMwG4&#UC3dd-Q+}v;HS3Rbbvu{jm`g6+;tHP*mOORcr{a0Jjm4t@Cz4Wa zsJAySm5pdKOsC=eqsS&y-UkYfjDaezf-dEyX93&xa)#NT~c+ zt@L45?zR2vQ{O)|Ivm9RCH8O9#t)A^3voDj_^E&1`r0&NqW|*M8?~<*E}9r|SNp*7 ziYGCg4eRzu@wLBNdf71N%jRpZey`f~UH4VC{WRY*={Czn1za!QWK5rKvueHl^s51x z^X~q3y}efBxYxl`^GK9+=J;JYD@<);T3K0RU1rCO7~9 literal 0 HcmV?d00001 diff --git a/Resources/Textures/Clothing/OuterClothing/Vests/tankharness.rsi/equipped-OUTERCLOTHING.png b/Resources/Textures/Clothing/OuterClothing/Vests/tankharness.rsi/equipped-OUTERCLOTHING.png new file mode 100644 index 0000000000000000000000000000000000000000..51708c386a685b7888d7b399a57ccb90911d637c GIT binary patch literal 800 zcmV+*1K<3KP)pH(n&-?RCr$Pn!RosK@i86God30Vj0&4MU*HhB1I|E&_#Ze6nPRC zR*Jkvlp=nCl&+Bl)WLEN2y|dBJFCoTy&Q0}=d%s|uY`_WX6NI#vwOgeQfMFm0w4ea zAOHd&00PgGKtURINGy+_jC7{w%e=2Lt|$=9-AxmeYc_b5F~?P7)G?};b>&Cf%@fg zx$vS?$`t?wNudAS+^pE4ar#_(HxL7uPNyc=`FyVGM@MRSeXXcZv{;S}Yc89n=6+x7!uzl%&kI72fu_#1>>h00ck)1V8`; zKw$3)tbA*``tdyu`t_&Nod;mYL&3N)iGL05JP{{=XAfZC78LP-00@8p2!H?xfB*=j zB_RF_oBp?_S^zSTR40&keLzxRS?UACzXiAuf*fHG?)$X#edX-OV0Q4nkH=E`K?W!T z_{D_^c0aW;PeC_$H|X3U*nTqrHtN<5c*eMK8ryJf``Qve8?+4t2M6X1S>E2Rl&ttV zlxAL*J@4ulp8>W49k}W0C$r+iG)3x--+Zy}l%db{d_*h;3{?awZ`}^zJqd$B*D_yYRuoKg<^wi|V zYndCCH8;tmSSnvQ-s9BNv_OE-m0dYRCR?)ce5lS6tCpB z&v~AU4DxC}*Dg>N8+^(2{fv@^juSTL&ntc1Xmonhn{Vqf_Z6u_tO1eFH_Psi=JWp_ zb^rTO{_V2+q`4Gd>{@r!a`|6|P|>TO&e^|ZXJ80;$GCHcX~l|F9x5O`p00i_>zopr E0Ozi1fB*mh literal 0 HcmV?d00001 diff --git a/Resources/Textures/Clothing/OuterClothing/Vests/tankharness.rsi/inhand-right.png b/Resources/Textures/Clothing/OuterClothing/Vests/tankharness.rsi/inhand-right.png new file mode 100644 index 0000000000000000000000000000000000000000..56e13c98e6323484999554f404ac082a4a2e279c GIT binary patch literal 289 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=FFaiwLn`LHy=mCjY#`A3kn!l0 zg*QCDn29@l616Z*ziDE}$kci0XwFv82@Pw^{5Gxmw|=9+`U)xEbU~nQ5IFF!^8MAw z)%U9Jo_d;XKWA%I^}CD5UzV5`N9@YE9rk`yV=IEt{G9_L`V}UPH$T1D@*_5>3CU`(8HrZRYxMnHt0*kX`>b zJYW7f|91Xy`v+^T?pjxF-ObP0l+XkK!YO<) literal 0 HcmV?d00001 diff --git a/Resources/Textures/Clothing/OuterClothing/Vests/tankharness.rsi/meta.json b/Resources/Textures/Clothing/OuterClothing/Vests/tankharness.rsi/meta.json new file mode 100644 index 00000000000..80cd5e0bd88 --- /dev/null +++ b/Resources/Textures/Clothing/OuterClothing/Vests/tankharness.rsi/meta.json @@ -0,0 +1,30 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Modified from tgstation vest sprite at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e by Errant for Space Station 14", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "icon" + }, + { + "name": "equipped-OUTERCLOTHING", + "directions": 4 + }, + { + "name": "equipped-OUTERCLOTHING-vox", + "directions": 4 + }, + { + "name": "inhand-left", + "directions": 4 + }, + { + "name": "inhand-right", + "directions": 4 + } + ] +} From 350754879e385b2cdd9f50b79a99f0237b400d77 Mon Sep 17 00:00:00 2001 From: Nemanja <98561806+EmoGarbage404@users.noreply.github.com> Date: Wed, 3 Jul 2024 22:29:26 -0400 Subject: [PATCH 053/765] Make all nukies humans (#29693) --- .../GameTicking/Rules/AntagLoadProfileRuleSystem.cs | 12 ++++++++++-- .../Components/AntagLoadProfileRuleCOmponent.cs | 12 +++++++++++- Resources/Prototypes/GameRules/roundstart.yml | 1 + 3 files changed, 22 insertions(+), 3 deletions(-) diff --git a/Content.Server/GameTicking/Rules/AntagLoadProfileRuleSystem.cs b/Content.Server/GameTicking/Rules/AntagLoadProfileRuleSystem.cs index fd3fb6cd655..b93904c685f 100644 --- a/Content.Server/GameTicking/Rules/AntagLoadProfileRuleSystem.cs +++ b/Content.Server/GameTicking/Rules/AntagLoadProfileRuleSystem.cs @@ -30,10 +30,18 @@ private void OnSelectEntity(Entity ent, ref Antag var profile = args.Session != null ? _prefs.GetPreferences(args.Session.UserId).SelectedCharacter as HumanoidCharacterProfile : HumanoidCharacterProfile.RandomWithSpecies(); - if (profile?.Species is not {} speciesId || !_proto.TryIndex(speciesId, out var species)) + + SpeciesPrototype? species; + if (ent.Comp.SpeciesOverride != null) + { + species = _proto.Index(ent.Comp.SpeciesOverride.Value); + } + else if (profile?.Species is not { } speciesId || !_proto.TryIndex(speciesId, out species)) + { species = _proto.Index(SharedHumanoidAppearanceSystem.DefaultSpecies); + } args.Entity = Spawn(species.Prototype); - _humanoid.LoadProfile(args.Entity.Value, profile); + _humanoid.LoadProfile(args.Entity.Value, profile?.WithSpecies(species.ID)); } } diff --git a/Content.Server/GameTicking/Rules/Components/AntagLoadProfileRuleCOmponent.cs b/Content.Server/GameTicking/Rules/Components/AntagLoadProfileRuleCOmponent.cs index 5e58fd14fc0..0816902ad43 100644 --- a/Content.Server/GameTicking/Rules/Components/AntagLoadProfileRuleCOmponent.cs +++ b/Content.Server/GameTicking/Rules/Components/AntagLoadProfileRuleCOmponent.cs @@ -1,7 +1,17 @@ +using Content.Shared.Humanoid.Prototypes; +using Robust.Shared.Prototypes; + namespace Content.Server.GameTicking.Rules.Components; /// /// Makes this rules antags spawn a humanoid, either from the player's profile or a random one. /// [RegisterComponent] -public sealed partial class AntagLoadProfileRuleComponent : Component; +public sealed partial class AntagLoadProfileRuleComponent : Component +{ + /// + /// If specified, the profile loaded will be made into this species. + /// + [DataField] + public ProtoId? SpeciesOverride; +} diff --git a/Resources/Prototypes/GameRules/roundstart.yml b/Resources/Prototypes/GameRules/roundstart.yml index 082d6a977bf..fa8899bfc34 100644 --- a/Resources/Prototypes/GameRules/roundstart.yml +++ b/Resources/Prototypes/GameRules/roundstart.yml @@ -87,6 +87,7 @@ - type: RuleGrids - type: AntagSelection - type: AntagLoadProfileRule + speciesOverride: Human - type: entity noSpawn: true From a600e17558bc04bf5da1d735186972ae5fe73c8e Mon Sep 17 00:00:00 2001 From: PJBot Date: Thu, 4 Jul 2024 02:30:32 +0000 Subject: [PATCH 054/765] Automatic changelog update --- Resources/Changelog/Changelog.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 4089a09eaf2..4a0b1b1a53f 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,11 +1,4 @@ Entries: -- author: Beck Thompson - changes: - - message: You now must equip gloved weapons (E.g boxing gloves) to use them. - type: Fix - id: 6369 - time: '2024-04-17T10:10:04.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/26762 - author: slarticodefast changes: - message: The gas analyzer now tells you the volume of scanned objects. Tanks inside @@ -3825,3 +3818,10 @@ id: 6868 time: '2024-07-04T01:51:46.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/29564 +- author: EmoGarbage404 + changes: + - message: All nuclear operatives are now humans. + type: Tweak + id: 6869 + time: '2024-07-04T02:29:26.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/29693 From 1de9dfcea8d2b5c5d86daa8d6661f4d7911b92b1 Mon Sep 17 00:00:00 2001 From: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com> Date: Thu, 4 Jul 2024 17:11:01 +1000 Subject: [PATCH 055/765] Make vox roundstart (#29704) * Make vox roundstart I believe all the issues are fixed. * Click detection bandaid --- Content.Client/Clickable/ClickableComponent.cs | 7 +++++-- Resources/Prototypes/Species/vox.yml | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/Content.Client/Clickable/ClickableComponent.cs b/Content.Client/Clickable/ClickableComponent.cs index 6f75df46830..987473ca46c 100644 --- a/Content.Client/Clickable/ClickableComponent.cs +++ b/Content.Client/Clickable/ClickableComponent.cs @@ -48,7 +48,7 @@ public bool CheckClick(SpriteComponent sprite, TransformComponent transform, Ent Angle cardinalSnapping = sprite.SnapCardinals ? relativeRotation.GetCardinalDir().ToAngle() : Angle.Zero; // First we get `localPos`, the clicked location in the sprite-coordinate frame. - var entityXform = Matrix3Helpers.CreateInverseTransform(transform.WorldPosition, sprite.NoRotation ? -eye.Rotation : spriteRot - cardinalSnapping); + var entityXform = Matrix3Helpers.CreateInverseTransform(spritePos, sprite.NoRotation ? -eye.Rotation : spriteRot - cardinalSnapping); var localPos = Vector2.Transform(Vector2.Transform(worldPos, entityXform), invSpriteMatrix); // Check explicitly defined click-able bounds @@ -58,8 +58,11 @@ public bool CheckClick(SpriteComponent sprite, TransformComponent transform, Ent // Next check each individual sprite layer using automatically computed click maps. foreach (var spriteLayer in sprite.AllLayers) { - if (!spriteLayer.Visible || spriteLayer is not Layer layer) + // TODO: Move this to a system and also use SpriteSystem.IsVisible instead. + if (!spriteLayer.Visible || spriteLayer is not Layer layer || layer.CopyToShaderParameters != null) + { continue; + } // Check the layer's texture, if it has one if (layer.Texture != null) diff --git a/Resources/Prototypes/Species/vox.yml b/Resources/Prototypes/Species/vox.yml index e3fdb2bf08f..7419f3f277e 100644 --- a/Resources/Prototypes/Species/vox.yml +++ b/Resources/Prototypes/Species/vox.yml @@ -1,7 +1,7 @@ - type: species id: Vox name: species-name-vox - roundStart: false # sad + roundStart: true prototype: MobVox sprites: MobVoxSprites markingLimits: MobVoxMarkingLimits From 080e57066d00a93d73f2dcdd18b075004863537b Mon Sep 17 00:00:00 2001 From: PJBot Date: Thu, 4 Jul 2024 07:12:08 +0000 Subject: [PATCH 056/765] Automatic changelog update --- Resources/Changelog/Changelog.yml | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 4a0b1b1a53f..06c545ef630 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,15 +1,4 @@ Entries: -- author: slarticodefast - changes: - - message: The gas analyzer now tells you the volume of scanned objects. Tanks inside - canisters now show up as well. - type: Add - - message: The gas analyzer now shows the amount of moles inside the scanned pipe - element instead of the whole pipe network. - type: Tweak - id: 6370 - time: '2024-04-17T17:42:24.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/25720 - author: deltanedas changes: - message: The Chameleon Projector has been added to the uplink for 7 TC, it lets @@ -3825,3 +3814,10 @@ id: 6869 time: '2024-07-04T02:29:26.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/29693 +- author: metalgearsloth + changes: + - message: Made vox roundstart. + type: Tweak + id: 6870 + time: '2024-07-04T07:11:02.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/29704 From 6c48ba02dd0e1cbaeb89755ee710888f0a32153a Mon Sep 17 00:00:00 2001 From: JIPDawg <51352440+JIPDawg@users.noreply.github.com> Date: Thu, 4 Jul 2024 02:17:47 -0500 Subject: [PATCH 057/765] Added Health Analyzer to basic treatment module. (#29696) Removed dropped, added Health Analyzer to Basic Treatment Module Co-authored-by: JIP --- .../Entities/Objects/Specific/Robotics/borg_modules.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Resources/Prototypes/Entities/Objects/Specific/Robotics/borg_modules.yml b/Resources/Prototypes/Entities/Objects/Specific/Robotics/borg_modules.yml index c7951cd945c..29d8e8f42ba 100644 --- a/Resources/Prototypes/Entities/Objects/Specific/Robotics/borg_modules.yml +++ b/Resources/Prototypes/Entities/Objects/Specific/Robotics/borg_modules.yml @@ -345,12 +345,12 @@ - state: icon-treatment - type: ItemBorgModule items: + - HandheldHealthAnalyzerUnpowered - Brutepack10Lingering - Ointment10Lingering - Gauze10Lingering - Bloodpack10Lingering - Syringe - - Dropper - type: entity id: BorgModuleDefibrillator From f5504bee05aa26952de502ca56b9e77887bea03c Mon Sep 17 00:00:00 2001 From: PJBot Date: Thu, 4 Jul 2024 07:18:53 +0000 Subject: [PATCH 058/765] Automatic changelog update --- Resources/Changelog/Changelog.yml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 06c545ef630..e41c5f4389d 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,12 +1,4 @@ Entries: -- author: deltanedas - changes: - - message: The Chameleon Projector has been added to the uplink for 7 TC, it lets - you disguise as anything (within reason). - type: Add - id: 6371 - time: '2024-04-17T21:48:35.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/26691 - author: ShadowCommander changes: - message: Fixed PDA and ID card name, job, and access not getting set on some jobs. @@ -3821,3 +3813,11 @@ id: 6870 time: '2024-07-04T07:11:02.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/29704 +- author: JIPDawg + changes: + - message: Changed the basic treatment module to include a Health Analyzer and removed + the dropper. + type: Tweak + id: 6871 + time: '2024-07-04T07:17:47.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/29696 From 6b488b1c315927173414958edb8284de31ff8bc2 Mon Sep 17 00:00:00 2001 From: Pieter-Jan Briers Date: Thu, 4 Jul 2024 10:02:43 +0200 Subject: [PATCH 059/765] Fix animation looping bugs. (#29457) Summary of the problem is in the corresponding engine commit: https://github.com/space-wizards/RobustToolbox/commit/a4ea5a462092c93cca941b073d080e284d73c2a6 This commit requires engine master right now. I think #29144 is probably the most severe one, but I touched Jittering and RotatingLight too since they seemed sus too. Fixes #29144 Co-authored-by: metalgearsloth --- Content.Client/Jittering/JitteringSystem.cs | 3 +++ Content.Client/Light/EntitySystems/LightBehaviorSystem.cs | 3 +++ Content.Client/Light/EntitySystems/RotatingLightSystem.cs | 3 +++ 3 files changed, 9 insertions(+) diff --git a/Content.Client/Jittering/JitteringSystem.cs b/Content.Client/Jittering/JitteringSystem.cs index 185bd490d3b..0c11a139635 100644 --- a/Content.Client/Jittering/JitteringSystem.cs +++ b/Content.Client/Jittering/JitteringSystem.cs @@ -48,6 +48,9 @@ private void OnAnimationCompleted(EntityUid uid, JitteringComponent jittering, A if(args.Key != _jitterAnimationKey) return; + if (!args.Finished) + return; + if (TryComp(uid, out AnimationPlayerComponent? animationPlayer) && TryComp(uid, out SpriteComponent? sprite)) _animationPlayer.Play(uid, animationPlayer, GetAnimation(jittering, sprite), _jitterAnimationKey); diff --git a/Content.Client/Light/EntitySystems/LightBehaviorSystem.cs b/Content.Client/Light/EntitySystems/LightBehaviorSystem.cs index 11f69165cf6..ca19d8522c5 100644 --- a/Content.Client/Light/EntitySystems/LightBehaviorSystem.cs +++ b/Content.Client/Light/EntitySystems/LightBehaviorSystem.cs @@ -19,6 +19,9 @@ public override void Initialize() private void OnBehaviorAnimationCompleted(EntityUid uid, LightBehaviourComponent component, AnimationCompletedEvent args) { + if (!args.Finished) + return; + var container = component.Animations.FirstOrDefault(x => x.FullKey == args.Key); if (container == null) diff --git a/Content.Client/Light/EntitySystems/RotatingLightSystem.cs b/Content.Client/Light/EntitySystems/RotatingLightSystem.cs index 842c13dedfe..5c2c4e4c875 100644 --- a/Content.Client/Light/EntitySystems/RotatingLightSystem.cs +++ b/Content.Client/Light/EntitySystems/RotatingLightSystem.cs @@ -69,6 +69,9 @@ private void OnAfterAutoHandleState(EntityUid uid, RotatingLightComponent comp, private void OnAnimationComplete(EntityUid uid, RotatingLightComponent comp, AnimationCompletedEvent args) { + if (!args.Finished) + return; + PlayAnimation(uid, comp); } From dc2b3e4598a04a1b3579ba5bd488e06b44e2d9d0 Mon Sep 17 00:00:00 2001 From: PJBot Date: Thu, 4 Jul 2024 08:03:49 +0000 Subject: [PATCH 060/765] Automatic changelog update --- Resources/Changelog/Changelog.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index e41c5f4389d..8d5076c356a 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,11 +1,4 @@ Entries: -- author: ShadowCommander - changes: - - message: Fixed PDA and ID card name, job, and access not getting set on some jobs. - type: Fix - id: 6372 - time: '2024-04-17T22:16:25.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/27062 - author: Krunk changes: - message: Head of Security and Warden now have armored and unarmored variants of @@ -3821,3 +3814,10 @@ id: 6871 time: '2024-07-04T07:17:47.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/29696 +- author: PJB3005 + changes: + - message: Fixed flashlights and similar permanently getting stuck blinking. + type: Fix + id: 6872 + time: '2024-07-04T08:02:43.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/29457 From 28d461306edcb12e13cffcccd7c5acc156b379a1 Mon Sep 17 00:00:00 2001 From: Ed <96445749+TheShuEd@users.noreply.github.com> Date: Thu, 4 Jul 2024 15:55:00 +0300 Subject: [PATCH 061/765] Fix Vox clothing in character creation menu (#29709) Update vox.yml --- Resources/Prototypes/Entities/Mobs/Species/vox.yml | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/Resources/Prototypes/Entities/Mobs/Species/vox.yml b/Resources/Prototypes/Entities/Mobs/Species/vox.yml index ec8035563b7..4d5239e50c5 100644 --- a/Resources/Prototypes/Entities/Mobs/Species/vox.yml +++ b/Resources/Prototypes/Entities/Mobs/Species/vox.yml @@ -112,4 +112,16 @@ species: Vox - type: Body prototype: Vox + - type: Inventory + speciesId: vox + displacements: + jumpsuit: + layer: + sprite: Mobs/Species/Vox/displacement.rsi + state: jumpsuit + copyToShaderParameters: + # Value required, provide a dummy. Gets overridden when applied. + layerKey: dummy + parameterTexture: displacementMap + parameterUV: displacementUV From 47ec6bd3a2f7763f09b568b902433157581989de Mon Sep 17 00:00:00 2001 From: jmcb Date: Thu, 4 Jul 2024 19:30:33 +0100 Subject: [PATCH 062/765] Fix typo in pineapple pizza description (#29714) --- .../Prototypes/Entities/Objects/Consumable/Food/Baked/pizza.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Resources/Prototypes/Entities/Objects/Consumable/Food/Baked/pizza.yml b/Resources/Prototypes/Entities/Objects/Consumable/Food/Baked/pizza.yml index 3004dc4cb2b..f822fb7c2da 100644 --- a/Resources/Prototypes/Entities/Objects/Consumable/Food/Baked/pizza.yml +++ b/Resources/Prototypes/Entities/Objects/Consumable/Food/Baked/pizza.yml @@ -401,7 +401,7 @@ name: Hawaiian pizza parent: FoodPizzaBase id: FoodPizzaPineapple - description: Makes people burst into tears. Tears of joy or sadness depends on the persons fondness for pineapple. + description: Makes people burst into tears. Tears of joy or sadness depends on the person's fondness for pineapple. components: - type: FlavorProfile flavors: From 1f3cf5c68fb763c42993265f1046dd0e7de7bff5 Mon Sep 17 00:00:00 2001 From: nikthechampiongr <32041239+nikthechampiongr@users.noreply.github.com> Date: Thu, 4 Jul 2024 19:02:53 +0000 Subject: [PATCH 063/765] Move checking code for BlacklistedRange to the right place in sqlite (#29389) --- Content.Server/Database/ServerDbSqlite.cs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/Content.Server/Database/ServerDbSqlite.cs b/Content.Server/Database/ServerDbSqlite.cs index ce6f97a1171..204d9fca4fb 100644 --- a/Content.Server/Database/ServerDbSqlite.cs +++ b/Content.Server/Database/ServerDbSqlite.cs @@ -131,6 +131,10 @@ private static async Task> GetAllBans( if (exemptFlags is { } exempt) { + // Any flag to bypass BlacklistedRange bans. + if (exempt != ServerBanExemptFlags.None) + exempt |= ServerBanExemptFlags.BlacklistedRange; + query = query.Where(b => (b.ExemptFlags & exempt) == 0); } @@ -144,15 +148,12 @@ private static bool BanMatches(ServerBan ban, ServerBanExemptFlags? exemptFlags, bool newPlayer) { - // Any flag to bypass BlacklistedRange bans. - var exemptFromBlacklistedRange = exemptFlags != null && exemptFlags.Value != ServerBanExemptFlags.None; - if (!exemptFlags.GetValueOrDefault(ServerBanExemptFlags.None).HasFlag(ServerBanExemptFlags.IP) && address != null && ban.Address is not null && address.IsInSubnet(ban.Address.ToTuple().Value) && (!ban.ExemptFlags.HasFlag(ServerBanExemptFlags.BlacklistedRange) || - newPlayer && !exemptFromBlacklistedRange)) + newPlayer)) { return true; } From 4e03110cff014559bb44fb7f7b7515b68fb6ccff Mon Sep 17 00:00:00 2001 From: Jezithyr Date: Fri, 5 Jul 2024 00:59:16 -0700 Subject: [PATCH 064/765] Re-enabling nukie species(except vox), added antag species blacklisting * Revert "Make all Nukies humans (#29693)" This reverts commit 3e3e050aafb93daa1eb017ee06b5e2a15fb3d315. * Implemented species blacklist * Re-enabled all species as Nukies except for Vox because loadouts don't support breathing alternative gases yet. --- .../GameTicking/Rules/AntagLoadProfileRuleSystem.cs | 12 +++++++----- .../Components/AntagLoadProfileRuleCOmponent.cs | 8 +++++++- Resources/Prototypes/GameRules/roundstart.yml | 5 +++++ 3 files changed, 19 insertions(+), 6 deletions(-) diff --git a/Content.Server/GameTicking/Rules/AntagLoadProfileRuleSystem.cs b/Content.Server/GameTicking/Rules/AntagLoadProfileRuleSystem.cs index b93904c685f..3527e2a11c2 100644 --- a/Content.Server/GameTicking/Rules/AntagLoadProfileRuleSystem.cs +++ b/Content.Server/GameTicking/Rules/AntagLoadProfileRuleSystem.cs @@ -31,14 +31,16 @@ private void OnSelectEntity(Entity ent, ref Antag ? _prefs.GetPreferences(args.Session.UserId).SelectedCharacter as HumanoidCharacterProfile : HumanoidCharacterProfile.RandomWithSpecies(); - SpeciesPrototype? species; - if (ent.Comp.SpeciesOverride != null) + + if (profile?.Species is not { } speciesId || !_proto.TryIndex(speciesId, out var species)) { - species = _proto.Index(ent.Comp.SpeciesOverride.Value); + species = _proto.Index(SharedHumanoidAppearanceSystem.DefaultSpecies); } - else if (profile?.Species is not { } speciesId || !_proto.TryIndex(speciesId, out species)) + + if (ent.Comp.SpeciesOverride != null + && (ent.Comp.SpeciesOverrideBlacklist?.Contains(new ProtoId(species.ID)) ?? false)) { - species = _proto.Index(SharedHumanoidAppearanceSystem.DefaultSpecies); + species = _proto.Index(ent.Comp.SpeciesOverride.Value); } args.Entity = Spawn(species.Prototype); diff --git a/Content.Server/GameTicking/Rules/Components/AntagLoadProfileRuleCOmponent.cs b/Content.Server/GameTicking/Rules/Components/AntagLoadProfileRuleCOmponent.cs index 0816902ad43..3a4cb5fc75e 100644 --- a/Content.Server/GameTicking/Rules/Components/AntagLoadProfileRuleCOmponent.cs +++ b/Content.Server/GameTicking/Rules/Components/AntagLoadProfileRuleCOmponent.cs @@ -10,8 +10,14 @@ namespace Content.Server.GameTicking.Rules.Components; public sealed partial class AntagLoadProfileRuleComponent : Component { /// - /// If specified, the profile loaded will be made into this species. + /// If specified, the profile loaded will be made into this species if the chosen species matches the blacklist. /// [DataField] public ProtoId? SpeciesOverride; + + /// + /// List of species that trigger the override + /// + [DataField] + public HashSet>? SpeciesOverrideBlacklist; } diff --git a/Resources/Prototypes/GameRules/roundstart.yml b/Resources/Prototypes/GameRules/roundstart.yml index fa8899bfc34..a32ff528402 100644 --- a/Resources/Prototypes/GameRules/roundstart.yml +++ b/Resources/Prototypes/GameRules/roundstart.yml @@ -88,6 +88,11 @@ - type: AntagSelection - type: AntagLoadProfileRule speciesOverride: Human + speciesOverrideBlacklist: + #Species that do not work with nukies should be included in this list. + #Once the issues are fixed the species should be removed from this list to be enabled. + #Balance concerns are not a valid reason to disable a species, except for high-impact Nukie-specific exploits. + - Vox - type: entity noSpawn: true From e3427f4a677a8f9f1a1c9fbe19d9a2c2079c7c17 Mon Sep 17 00:00:00 2001 From: PJBot Date: Fri, 5 Jul 2024 08:00:24 +0000 Subject: [PATCH 065/765] Automatic changelog update --- Resources/Changelog/Changelog.yml | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 8d5076c356a..4d0bb277f8e 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,15 +1,4 @@ Entries: -- author: Krunk - changes: - - message: Head of Security and Warden now have armored and unarmored variants of - their winter coats and the unarmored variants are available in the uniform printer. - type: Tweak - - message: Head of Security's and Warden's winter coats now provide resistances - equal to their non-winter counterparts. - type: Tweak - id: 6373 - time: '2024-04-18T00:08:06.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/24865 - author: icekot8 changes: - message: "\u0421argo request console now reports when a request is approved" @@ -3821,3 +3810,11 @@ id: 6872 time: '2024-07-04T08:02:43.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/29457 +- author: Jezithyr + changes: + - message: All species except for Vox can now be played as Nukies. (Vox will be + enabled when load out code supports them) + type: Tweak + id: 6873 + time: '2024-07-05T07:59:16.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/29707 From a008a646e9287f41bf0bc8402b58fcb96740c096 Mon Sep 17 00:00:00 2001 From: lzk <124214523+lzk228@users.noreply.github.com> Date: Fri, 5 Jul 2024 15:01:39 +0200 Subject: [PATCH 066/765] Add summary comments for ElectrifiedComponent fields (#29733) add summaries for ElectrifiedComponent --- .../Components/ElectrifiedComponent.cs | 32 ++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/Content.Server/Electrocution/Components/ElectrifiedComponent.cs b/Content.Server/Electrocution/Components/ElectrifiedComponent.cs index 4ef07a0cca8..5755e98091b 100644 --- a/Content.Server/Electrocution/Components/ElectrifiedComponent.cs +++ b/Content.Server/Electrocution/Components/ElectrifiedComponent.cs @@ -11,33 +11,63 @@ public sealed partial class ElectrifiedComponent : Component [DataField("enabled")] public bool Enabled = true; + /// + /// Should player get damage on collide + /// [DataField("onBump")] public bool OnBump = true; + /// + /// Should player get damage on attack + /// [DataField("onAttacked")] public bool OnAttacked = true; + /// + /// When true - disables power if a window is present in the same tile + /// [DataField("noWindowInTile")] public bool NoWindowInTile = false; + /// + /// Should player get damage on interact with empty hand + /// [DataField("onHandInteract")] public bool OnHandInteract = true; + /// + /// Should player get damage on interact while holding an object in their hand + /// [DataField("onInteractUsing")] public bool OnInteractUsing = true; + /// + /// Indicates if the entity requires power to function + /// [DataField("requirePower")] public bool RequirePower = true; + /// + /// Indicates if the entity uses APC power + /// [DataField("usesApcPower")] public bool UsesApcPower = false; + /// + /// Identifier for the high voltage node. + /// [DataField("highVoltageNode")] public string? HighVoltageNode; + /// + /// Identifier for the medium voltage node. + /// [DataField("mediumVoltageNode")] public string? MediumVoltageNode; + /// + /// Identifier for the low voltage node. + /// [DataField("lowVoltageNode")] public string? LowVoltageNode; @@ -69,7 +99,7 @@ public sealed partial class ElectrifiedComponent : Component public float ShockDamage = 7.5f; /// - /// Shock time, in seconds. + /// Shock time, in seconds. /// [DataField("shockTime")] public float ShockTime = 8f; From 5232a19afdef36b3ef31b0e34ad25f53e192e16f Mon Sep 17 00:00:00 2001 From: DrSmugleaf <10968691+DrSmugleaf@users.noreply.github.com> Date: Fri, 5 Jul 2024 07:25:23 -0700 Subject: [PATCH 067/765] Fix showing the inventory button on entities without any inventory slots (#29728) --- .../UserInterface/Systems/Inventory/InventoryUIController.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Content.Client/UserInterface/Systems/Inventory/InventoryUIController.cs b/Content.Client/UserInterface/Systems/Inventory/InventoryUIController.cs index fb747799170..5d7a775104c 100644 --- a/Content.Client/UserInterface/Systems/Inventory/InventoryUIController.cs +++ b/Content.Client/UserInterface/Systems/Inventory/InventoryUIController.cs @@ -132,6 +132,9 @@ private void UpdateInventoryHotbar(InventorySlotsComponent? clientInv) if (clientInv == null) { _inventoryHotbar?.ClearButtons(); + if (_inventoryButton != null) + _inventoryButton.Visible = false; + return; } @@ -409,6 +412,8 @@ private void UnloadSlots() { slotGroup.ClearButtons(); } + + UpdateInventoryHotbar(null); } private void SpriteUpdated(SlotSpriteUpdate update) From 5e00fa69a0926c2552b8515cb091167cab883cf8 Mon Sep 17 00:00:00 2001 From: AndreyCamper Date: Sat, 6 Jul 2024 00:37:29 +0300 Subject: [PATCH 068/765] Fire Axe resprite 45 degrees v3 (#28866) Rotating Fire Axe 45 deg --- .../Weapons/Melee/fireaxeflaming.rsi/icon.png | Bin 334 -> 331 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/Resources/Textures/Objects/Weapons/Melee/fireaxeflaming.rsi/icon.png b/Resources/Textures/Objects/Weapons/Melee/fireaxeflaming.rsi/icon.png index 58e2f14942656a01fa6681f72aa4b1902b538631..ef62ecf5f49264955cbfe263c2fb69eb24687721 100644 GIT binary patch delta 315 zcmX@dbed^`WIZzj1B1(wu46!ou{g-xiDBJ2nU_EgOS+@4BLl<6e(pbstU$g>fKP~P zm4MZM#VAcp%|(kARaRF1|NlQKDk?NI^hCe<#~Z;<_SpgzGFLrM22wmFL4LtN1u(!M zbpPBrpg3oNM`SSr1K&XqX53LfG5al0bcUykV~B3n3R3)nl8P%NLbFk|AUu<0dg3;yLO;*=8yE*wy3hZVT z9E|<(K#l2w3yV+7f-Z@U3g+Vy1#gQu&X%Q~loCIF*B Be$M~^ delta 318 zcmV-E0m1&u0?q=E8Gi-<0047(dh`GQ00DDSM?wIu&K&6g009U|L_t(oh3%8E3W7i! z#y`b1u%#gyTzv!a363Ub1KZl&!sc3g1mVC3XzK~WRS=|bXov=vg7&VZ%)u);P?!5n zC;tz>?>_zqNF53WW$4&&FEIKPnn;=s1puKXwJMoSzzLV}Nl30017>;^%xY9+hWqfHX~o z%)`YKm*lr*QVGEgkY$-762S8RYvL^!l7hbj?`340`#~tgKP>-P{#QLujat!qXux&d z)}NzB2*C{d+BaboMIeMQ&+}So0sufMWjrXQtv8^2Levdgy}3jpkx1UW0Copq4=@Y+ QlmGw#07*qoM6N<$g0?Y>%>V!Z From 00d29fcf72d4d543f48165966498d872bd349208 Mon Sep 17 00:00:00 2001 From: end <72604018+laok233@users.noreply.github.com> Date: Fri, 5 Jul 2024 23:52:27 +0200 Subject: [PATCH 069/765] nuke biochem (#29751) Nuke biomchem again --- .../ServerInfo/Guidebook/Science/Science.xml | 15 +++++++-------- .../ServerInfo/Guidebook/Science/Technologies.xml | 3 --- 2 files changed, 7 insertions(+), 11 deletions(-) diff --git a/Resources/ServerInfo/Guidebook/Science/Science.xml b/Resources/ServerInfo/Guidebook/Science/Science.xml index 0e28557dd93..5c6271e5eb6 100644 --- a/Resources/ServerInfo/Guidebook/Science/Science.xml +++ b/Resources/ServerInfo/Guidebook/Science/Science.xml @@ -15,14 +15,13 @@ Each technology costs [color=#a4885c]Research Points[/color] and unlocks recipes Information about the different technologies can be viewed [textlink="on the technology guidebook page" link="Technologies"]. ## Disciplines -Technologies are spread over 5 different Disciplines: - - - - - - - +Technologies are spread over 4 different Disciplines: + + + + + + Use your nearest R&D console to take note of which kind of research is locked behind each Discipline tree. diff --git a/Resources/ServerInfo/Guidebook/Science/Technologies.xml b/Resources/ServerInfo/Guidebook/Science/Technologies.xml index 7f0feaca420..ef89c80269a 100644 --- a/Resources/ServerInfo/Guidebook/Science/Technologies.xml +++ b/Resources/ServerInfo/Guidebook/Science/Technologies.xml @@ -8,9 +8,6 @@ The different technologies and their respective discipline are listed below. ## Industrial -## Biochemical - - ## Arsenal From d512cd08a39d38b48bc29d2b17611500fb892cd0 Mon Sep 17 00:00:00 2001 From: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com> Date: Sat, 6 Jul 2024 13:51:55 +1000 Subject: [PATCH 070/765] Shuttle map button tweaks (#29757) - Avoids adding pending objects we can never show so the list should fill much faster. --- Content.Client/Shuttles/UI/MapScreen.xaml.cs | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/Content.Client/Shuttles/UI/MapScreen.xaml.cs b/Content.Client/Shuttles/UI/MapScreen.xaml.cs index 10800b8c5f7..489dbc8c90c 100644 --- a/Content.Client/Shuttles/UI/MapScreen.xaml.cs +++ b/Content.Client/Shuttles/UI/MapScreen.xaml.cs @@ -261,7 +261,7 @@ private void RebuildMapObjects() ourMap = shuttleXform.MapID; } - while (mapComps.MoveNext(out var mapComp, out var mapXform, out var mapMetadata)) + while (mapComps.MoveNext(out var mapUid, out var mapComp, out var mapXform, out var mapMetadata)) { if (_console != null && !_shuttles.CanFTLTo(_shuttleEntity.Value, mapComp.MapId, _console.Value)) { @@ -327,8 +327,10 @@ private void RebuildMapObjects() { AddMapObject(mapComp.MapId, gridObj); } - else if (!_shuttles.IsBeaconMap(_mapManager.GetMapEntityId(mapComp.MapId)) && (iffComp == null || - (iffComp.Flags & IFFFlags.Hide) == 0x0)) + // If we can show it then add it to pending. + else if (!_shuttles.IsBeaconMap(mapUid) && (iffComp == null || + (iffComp.Flags & IFFFlags.Hide) == 0x0) && + !gridObj.HideButton) { _pendingMapObjects.Add((mapComp.MapId, gridObj)); } @@ -336,11 +338,17 @@ private void RebuildMapObjects() foreach (var (beacon, _) in _shuttles.GetExclusions(mapComp.MapId, _exclusions)) { + if (beacon.HideButton) + continue; + _pendingMapObjects.Add((mapComp.MapId, beacon)); } foreach (var (beacon, _) in _shuttles.GetBeacons(mapComp.MapId, _beacons)) { + if (beacon.HideButton) + continue; + _pendingMapObjects.Add((mapComp.MapId, beacon)); } @@ -425,9 +433,6 @@ private void AddMapObject(MapId mapId, IMapObject mapObj) var existing = _mapObjects.GetOrNew(mapId); existing.Add(mapObj); - if (mapObj.HideButton) - return; - var gridContents = _mapHeadings[mapId]; var gridButton = new Button() From fcf70dc790bb9dc4ac5060052c460b22122ae967 Mon Sep 17 00:00:00 2001 From: PJBot Date: Sat, 6 Jul 2024 03:53:02 +0000 Subject: [PATCH 071/765] Automatic changelog update --- Resources/Changelog/Changelog.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 4d0bb277f8e..d57e1cde11b 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,11 +1,4 @@ Entries: -- author: icekot8 - changes: - - message: "\u0421argo request console now reports when a request is approved" - type: Add - id: 6374 - time: '2024-04-18T00:32:22.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/27038 - author: Bellwether changes: - message: Midround zombie outbreaks are less common and spread more slowly. @@ -3818,3 +3811,10 @@ id: 6873 time: '2024-07-05T07:59:16.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/29707 +- author: metalgearsloth + changes: + - message: Shuttle map buttons will show up faster. + type: Tweak + id: 6874 + time: '2024-07-06T03:51:55.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/29757 From 9f37f7c14a12245f829b971bf20ede22cecfc306 Mon Sep 17 00:00:00 2001 From: themias <89101928+themias@users.noreply.github.com> Date: Fri, 5 Jul 2024 23:55:58 -0400 Subject: [PATCH 072/765] Don't allow toggling internals while asleep (#29753) --- Content.Server/Body/Systems/InternalsSystem.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Content.Server/Body/Systems/InternalsSystem.cs b/Content.Server/Body/Systems/InternalsSystem.cs index 922d48f13ed..d6ece39d590 100644 --- a/Content.Server/Body/Systems/InternalsSystem.cs +++ b/Content.Server/Body/Systems/InternalsSystem.cs @@ -100,7 +100,7 @@ public void ToggleInternals( // Toggle off if they're on if (AreInternalsWorking(internals)) { - if (force || user == uid) + if (force) { DisconnectTank(internals); return; From 506458e501554ef08680a80c3e0eccffe07eb007 Mon Sep 17 00:00:00 2001 From: Killerqu00 <47712032+Killerqu00@users.noreply.github.com> Date: Sat, 6 Jul 2024 06:01:51 +0200 Subject: [PATCH 073/765] You no longer get deleted when cuffed and buckled (#29718) fix --- Content.Shared/Buckle/SharedBuckleSystem.Strap.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Content.Shared/Buckle/SharedBuckleSystem.Strap.cs b/Content.Shared/Buckle/SharedBuckleSystem.Strap.cs index eb23aa973b4..bfb0cd9cd6f 100644 --- a/Content.Shared/Buckle/SharedBuckleSystem.Strap.cs +++ b/Content.Shared/Buckle/SharedBuckleSystem.Strap.cs @@ -57,7 +57,7 @@ private void StrapRemoveAll(EntityUid uid, StrapComponent strapComp) { foreach (var entity in strapComp.BuckledEntities.ToArray()) { - TryUnbuckle(entity, entity, true); + Unbuckle(entity, entity); } } From e74d314afb1ba231f14424fa1b623991f0b6e182 Mon Sep 17 00:00:00 2001 From: MFMessage <22904993+MFMessage@users.noreply.github.com> Date: Fri, 5 Jul 2024 23:04:59 -0500 Subject: [PATCH 074/765] Fixes a minor typo for the base gingerbread body part (#29717) "Fixes a minor typo in the gingerbread bodypart prototype" --- Resources/Prototypes/Body/Parts/gingerbread.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Resources/Prototypes/Body/Parts/gingerbread.yml b/Resources/Prototypes/Body/Parts/gingerbread.yml index 661835ab843..f95e66145be 100644 --- a/Resources/Prototypes/Body/Parts/gingerbread.yml +++ b/Resources/Prototypes/Body/Parts/gingerbread.yml @@ -1,7 +1,7 @@ - type: entity id: PartGingerbread parent: [BaseItem, BasePart] - name: "gingerbead body part" + name: "gingerbread body part" abstract: true components: - type: Extractable From a3bd9ad2314b8a681e27c1cc0f70e47141ecd584 Mon Sep 17 00:00:00 2001 From: Errant <35878406+Errant-4@users.noreply.github.com> Date: Sat, 6 Jul 2024 06:17:32 +0200 Subject: [PATCH 075/765] Phoronman 1984 (#29747) No more. --- .../Textures/Mobs/Species/lungs_phoronman.png | Bin 233 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 Resources/Textures/Mobs/Species/lungs_phoronman.png diff --git a/Resources/Textures/Mobs/Species/lungs_phoronman.png b/Resources/Textures/Mobs/Species/lungs_phoronman.png deleted file mode 100644 index 1c6d2dc11a8c8d12b1bc8cd3ffe9c0ba180c2896..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 233 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnF3?v&v(vJfvxd5LK*8>L*e17=l^{KZ<5>D;* zICQ4$;-gJZFSTEvW;|z=^+vxBe=Y)5GL{7S1v5B2yO9RuRC>BNhGMavWE-LEPKf4Vddn=#9_PU;Xy{8 zV+%PLr(FnQXM27jV26Y8i36Goj} Date: Sat, 6 Jul 2024 17:34:30 +0000 Subject: [PATCH 076/765] Automatic changelog update --- Resources/Changelog/Changelog.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index d57e1cde11b..a2f77f3b5ae 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,11 +1,4 @@ Entries: -- author: Bellwether - changes: - - message: Midround zombie outbreaks are less common and spread more slowly. - type: Tweak - id: 6375 - time: '2024-04-18T01:06:33.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/27060 - author: Flareguy changes: - message: Updated Remote Signaller sprites. @@ -3818,3 +3811,10 @@ id: 6874 time: '2024-07-06T03:51:55.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/29757 +- author: JIPDawg + changes: + - message: Added Late join CryoSleepers to Origin. + type: Tweak + id: 6875 + time: '2024-07-06T17:33:20.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/29761 From 14f9c515e92b98a3f75a80417d1d72aad1dc19f4 Mon Sep 17 00:00:00 2001 From: themias <89101928+themias@users.noreply.github.com> Date: Sat, 6 Jul 2024 23:49:55 -0400 Subject: [PATCH 077/765] Fix wielding while pulling (#29781) --- Content.Shared/Inventory/VirtualItem/SharedVirtualItemSystem.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Content.Shared/Inventory/VirtualItem/SharedVirtualItemSystem.cs b/Content.Shared/Inventory/VirtualItem/SharedVirtualItemSystem.cs index b31cc755763..4a5894d8958 100644 --- a/Content.Shared/Inventory/VirtualItem/SharedVirtualItemSystem.cs +++ b/Content.Shared/Inventory/VirtualItem/SharedVirtualItemSystem.cs @@ -99,7 +99,7 @@ public bool TrySpawnVirtualItemInHand(EntityUid blockingEnt, EntityUid user, [No if (hand.HeldEntity is not { } held) continue; - if (held == blockingEnt || HasComp(held)) + if (held == blockingEnt) continue; if (!_handsSystem.TryDrop(user, hand)) From 06f67a73e6937401cf7159e53608a0f31c7c7223 Mon Sep 17 00:00:00 2001 From: beck-thompson <107373427+beck-thompson@users.noreply.github.com> Date: Sat, 6 Jul 2024 20:52:18 -0700 Subject: [PATCH 078/765] Spilling reagents on mutliple entities at once fix (#29763) * Fixed! * That could have been bad this is why I'm glad I check the diff xD --- .../Fluids/EntitySystems/PuddleSystem.Spillable.cs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/Content.Server/Fluids/EntitySystems/PuddleSystem.Spillable.cs b/Content.Server/Fluids/EntitySystems/PuddleSystem.Spillable.cs index 8cdae84a936..e722108e147 100644 --- a/Content.Server/Fluids/EntitySystems/PuddleSystem.Spillable.cs +++ b/Content.Server/Fluids/EntitySystems/PuddleSystem.Spillable.cs @@ -70,13 +70,18 @@ private void SplashOnMeleeHit(Entity entity, ref MeleeHitEve return; args.Handled = true; + + // First update the hit count so anything that is not reactive wont count towards the total! + foreach (var hit in args.HitEntities) + { + if (!HasComp(hit)) + hitCount -= 1; + } + foreach (var hit in args.HitEntities) { if (!HasComp(hit)) - { - hitCount -= 1; // so we don't undershoot solution calculation for actual reactive entities continue; - } var splitSolution = _solutionContainerSystem.SplitSolution(soln.Value, totalSplit / hitCount); From 1289e466f93e92a718f3bce46bb37fd00afe7ecc Mon Sep 17 00:00:00 2001 From: PJBot Date: Sun, 7 Jul 2024 03:53:24 +0000 Subject: [PATCH 079/765] Automatic changelog update --- Resources/Changelog/Changelog.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index a2f77f3b5ae..87dfa869fb7 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,11 +1,4 @@ Entries: -- author: Flareguy - changes: - - message: Updated Remote Signaller sprites. - type: Tweak - id: 6376 - time: '2024-04-18T01:16:48.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/27073 - author: Dutch-VanDerLinde changes: - message: Grey security jumpsuits are now available in the security officer loadout. @@ -3818,3 +3811,10 @@ id: 6875 time: '2024-07-06T17:33:20.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/29761 +- author: Beck Thompson + changes: + - message: Splashing reagents on players will now apply the correct amounts. + type: Fix + id: 6876 + time: '2024-07-07T03:52:18.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/29763 From 0338b847aea213e914e4ea3219506f52b90f7efd Mon Sep 17 00:00:00 2001 From: Tayrtahn Date: Sun, 7 Jul 2024 02:20:53 -0400 Subject: [PATCH 080/765] Improve buckling's interactions with standing state (#29741) --- .../Buckle/SharedBuckleSystem.Buckle.cs | 9 +++------ Content.Shared/Standing/StandingStateSystem.cs | 16 +++++++++++----- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/Content.Shared/Buckle/SharedBuckleSystem.Buckle.cs b/Content.Shared/Buckle/SharedBuckleSystem.Buckle.cs index 0ce8c992682..0fbfd51d698 100644 --- a/Content.Shared/Buckle/SharedBuckleSystem.Buckle.cs +++ b/Content.Shared/Buckle/SharedBuckleSystem.Buckle.cs @@ -196,7 +196,6 @@ protected void SetBuckledTo(Entity buckle, Entity buckle, Entity strap SetBuckledTo(buckle, strap!); Appearance.SetData(strap, StrapVisuals.State, true); Appearance.SetData(buckle, BuckleVisuals.Buckled, true); - Appearance.SetData(buckle, RotationVisuals.RotationState, RotationState.Horizontal); _rotationVisuals.SetHorizontalAngle(buckle.Owner, strap.Comp.Rotation); @@ -363,10 +361,10 @@ private void Buckle(Entity buckle, Entity strap switch (strap.Comp.Position) { case StrapPosition.Stand: - _standing.Stand(buckle); + _standing.Stand(buckle, force: true); break; case StrapPosition.Down: - _standing.Down(buckle, false, false); + _standing.Down(buckle, false, false, force: true); break; } @@ -458,10 +456,9 @@ private void Unbuckle(Entity buckle, Entity str _rotationVisuals.ResetHorizontalAngle(buckle.Owner); Appearance.SetData(strap, StrapVisuals.State, strap.Comp.BuckledEntities.Count != 0); Appearance.SetData(buckle, BuckleVisuals.Buckled, false); - Appearance.SetData(buckle, RotationVisuals.RotationState, RotationState.Vertical); if (HasComp(buckle) || _mobState.IsIncapacitated(buckle)) - _standing.Down(buckle); + _standing.Down(buckle, playSound: false); else _standing.Stand(buckle); diff --git a/Content.Shared/Standing/StandingStateSystem.cs b/Content.Shared/Standing/StandingStateSystem.cs index ed586e970dc..8d9be9ab776 100644 --- a/Content.Shared/Standing/StandingStateSystem.cs +++ b/Content.Shared/Standing/StandingStateSystem.cs @@ -25,7 +25,10 @@ public bool IsDown(EntityUid uid, StandingStateComponent? standingState = null) return !standingState.Standing; } - public bool Down(EntityUid uid, bool playSound = true, bool dropHeldItems = true, + public bool Down(EntityUid uid, + bool playSound = true, + bool dropHeldItems = true, + bool force = false, StandingStateComponent? standingState = null, AppearanceComponent? appearance = null, HandsComponent? hands = null) @@ -49,11 +52,14 @@ public bool Down(EntityUid uid, bool playSound = true, bool dropHeldItems = true RaiseLocalEvent(uid, new DropHandItemsEvent(), false); } - var msg = new DownAttemptEvent(); - RaiseLocalEvent(uid, msg, false); + if (!force) + { + var msg = new DownAttemptEvent(); + RaiseLocalEvent(uid, msg, false); - if (msg.Cancelled) - return false; + if (msg.Cancelled) + return false; + } standingState.Standing = false; Dirty(uid, standingState); From 5a8cff81106c14dd6982d20835104fea2144e579 Mon Sep 17 00:00:00 2001 From: PJBot Date: Sun, 7 Jul 2024 06:21:59 +0000 Subject: [PATCH 081/765] Automatic changelog update --- Resources/Changelog/Changelog.yml | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 87dfa869fb7..ef044e72013 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,11 +1,4 @@ Entries: -- author: Dutch-VanDerLinde - changes: - - message: Grey security jumpsuits are now available in the security officer loadout. - type: Tweak - id: 6377 - time: '2024-04-18T01:22:09.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/27023 - author: Tayrtahn changes: - message: Sodas and other fizzy drinks can be shaken with the verbs menu to build @@ -3818,3 +3811,11 @@ id: 6876 time: '2024-07-07T03:52:18.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/29763 +- author: Tayrtahn + changes: + - message: Dead bodies will no longer remain standing after being unbuckled from + chairs. + type: Fix + id: 6877 + time: '2024-07-07T06:20:53.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/29741 From 4aa3703242e5fc7991dac5022168ca6687674338 Mon Sep 17 00:00:00 2001 From: lzk <124214523+lzk228@users.noreply.github.com> Date: Sun, 7 Jul 2024 15:05:09 +0200 Subject: [PATCH 082/765] Add supplybot moving states (#29795) * Add supplybot moving states * forgor --- .../Prototypes/Entities/Mobs/NPCs/silicon.yml | 7 ++++++ .../Mobs/Silicon/Bots/supplybot.rsi/meta.json | 22 ++++++++++++++++++ .../Bots/supplybot.rsi/supplybot-moving.png | Bin 0 -> 2970 bytes .../Silicon/Bots/supplybot.rsi/supplybot.png | Bin 2970 -> 2718 bytes 4 files changed, 29 insertions(+) create mode 100644 Resources/Textures/Mobs/Silicon/Bots/supplybot.rsi/supplybot-moving.png diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/silicon.yml b/Resources/Prototypes/Entities/Mobs/NPCs/silicon.yml index 8530401a1df..47378837ef1 100644 --- a/Resources/Prototypes/Entities/Mobs/NPCs/silicon.yml +++ b/Resources/Prototypes/Entities/Mobs/NPCs/silicon.yml @@ -335,6 +335,13 @@ sprite: Mobs/Silicon/Bots/supplybot.rsi layers: - state: supplybot + - type: SpriteMovement + movementLayers: + movement: + state: supplybot-moving + noMovementLayers: + movement: + state: supplybot - type: GhostRole makeSentient: true name: ghost-role-information-supplybot-name diff --git a/Resources/Textures/Mobs/Silicon/Bots/supplybot.rsi/meta.json b/Resources/Textures/Mobs/Silicon/Bots/supplybot.rsi/meta.json index 6bb3e77cfeb..f459a7caa63 100644 --- a/Resources/Textures/Mobs/Silicon/Bots/supplybot.rsi/meta.json +++ b/Resources/Textures/Mobs/Silicon/Bots/supplybot.rsi/meta.json @@ -10,6 +10,28 @@ { "name": "supplybot", "directions": 4, + "delays": [ + [ + 0.3, + 0.1 + ], + [ + 0.3, + 0.1 + ], + [ + 0.3, + 0.1 + ], + [ + 0.3, + 0.1 + ] + ] + }, + { + "name": "supplybot-moving", + "directions": 4, "delays": [ [ 0.1, diff --git a/Resources/Textures/Mobs/Silicon/Bots/supplybot.rsi/supplybot-moving.png b/Resources/Textures/Mobs/Silicon/Bots/supplybot.rsi/supplybot-moving.png new file mode 100644 index 0000000000000000000000000000000000000000..cac976240bd3619027dfebb0597e3529251b5612 GIT binary patch literal 2970 zcmYjTc{tST7ypiRt|d!j&zeYRk|c`ASSzv%8H5tDm2CzS*|J?t2*XHMLYm@gvNXfB zPIj_2Vj48|j3qOfrr&hCfBgP<-}5~0Ip;m^`#hiXIiHLxwwA&IvH}1A2wPjh95@#B zYk~PVdxx=49{>pYSi?-6VleBa@i*mY@;$^YrXNj}{Cb;u#CfgLrBz_k{dq-Yw%Mwm zpoh$Ixu!;n_MZXkv)=c_z;an{g0&!9Jzh8a%CGwfaZM{;hu*vY!rH=RrC+Br%6G&q zHm}Yw5ANqt0Ij#%S{GR#G+f?5*56f6+mAQJAop5m+pGo4p>2%qoF$L}Q^~VZ75~>% zj+tD{v|?>l2bo~uK2f{`xJS_G3$An1YsWQ-GfX>THI}$6Okqzwo(5mb7PfnoPn_7+ ze+T+=;?1Q{pxWtuFc00ey-K0&OT_c_R#uOT7*O`Hzs;V+1xP>hGA=7q>{y#oiBddp z7NB$+;N0eGO#H_K4Ajs?TtIpt2%GB<0Q@<#&WmD1B+I7Grc+Hf{c->WjZ^UjP{T$b zVAFFrZU5)22Hf|~-hBY}Imkz1(TbieC(T`baPAgiMO3t;|IOn;+8*@_<@%{pd?Uls zodfMXOUMK$;C=EmkFuVSvR)QxYPg>6P-KBtC+Hyu3{2+v__QXo2IMr`BL*JOm~}z` zQu{>!@^u}SF+mR$zZn^L8a3s|$EDal1(W4cv_Dtao$r~l@kcSe>rP@Pz5r*SX@rPt z0h>fRyl${INIWEKYX)WS9uyH8KxKq#!?%wCy*XyfJEQOJcVf~@FXuD9i&W)ZQd0&` z|8unkoB~7@~7R$~&CzZ2d}_1}dJeC@Q-+`)i(*C`0dA4^>{b=o>vqulp<& zFA?@Rc{i-(6N8a&xkbo@$Erq~24pfS7lUjsNvDb-evWbtF2Xj$AmiiXF}G+6o20<7 zjooH)bsAPV-{uJo!#^?tIgqdiI$3nd9<4<6=$Nd7beyOluUiZmhyY4Dx;UBry689F z>~OB1$WU7aTvFOo&ZEuM?U1XC8vX1SVz0CWO+|-iX0k389tRC8+?db{?wMzB z_Yd9BjNPP|E)l&6e!ii#gW|J$&eZ9F?q*IBsBa z6q2L_ro<|6+zr{w?{WK`7fx#ACWHfAp9R4KoNreQ(HvX3qt-vBgq;aq;$2!^&Kp9r`L00V zwL*t~S#v)1kMlPR5 zHEx8cvscWGPy>~5xy-fYb>EjyUd56nyXZT}s9+XVf8z{5Y1j@?0aDJ(11g6_7HO|Z zSw7K1^t$;~!(`bR3CgX~Enn`33fn4FlKIT{pb0FS>82*{S6UCC+NZJOrrI>^CBFF`?wn>bf zyyGM1tba>^V}5jUTLzy@j)|~OxUZ6;>A0W?5rfbmkxVn>DzjLa^07!#CqXB9U{!O$ z(o!=s$Hk@5TKUWO{da%C)FpK=qLhUX8|l?}Sm34i<6*v%!Uwye z?{WOZirl1m-IPN4Tl@Xu^ou={*Ayv3Uqj5wI~tEA#(ix&M2L^@GiS$8ONR9SHg3Zu zcuongFJJli2qyxGn@s#hhFP=do%*@(`dyG}exD+C2p<=ZLbA~h6G;>N-qIF$p@tuH zCbD*tKgMCZY8T|>SH%j92PCF765SQcJMTixWfljq|3}WM;(^Y`@RPF}$ht;8t!=&n za*$n+@N-(|Rqj{GlU{Z~dWjMIWX}RU;B3q~7G}H)oGzp)Y-dM$y(WAXEN*wCTTaEF zSvw)Sw;x>s1D@Y?ru4Pc6A@$I$A8|Oom3<2BD?gHQd7skA2f`6pkf~IINzddi1#pfijvZQ+ODiNvz)Uw@5aE(&AkiMqujEJY1v{AL}2 zGVbsmzzQl?SbI2hvV8Sqn9tWO#Z=KbcR~f|&iC3Adg%7GHI;7Pi=V8nNl>QUn2B%c zZ#@^;Gff5Qp+-cm-eOVgr@eYGknJ(?nLVew`KAd%?$%zVEMT^-H=XgWzPP`%p!$8* z#!Qsw+`CoYJRj+$dDBu4UOj8iJ`Hyd7eq#Bt?amdw%OCd zU=B(p;1AqLyqf#uo}Iup)pQ#q-_w^24nfYBZ( zrqx&T{X+&^fxt2q?Fr`uJ}xWkURpY8DI2``6eylp-XTjEfiBz zh;Kp{sEK5X*qvz$$K2vQ!saAAtE##@A4Gb|ltL<^Xt9Ul10kjCV_h|l^Yil$)}LK2 zfp{!48H~5B+7{=A`kQ@rv5o@+jo6 zv0JTIR4u2gNb^@?!rWRo;O*XA3UTYt%AjB%#uA_qwLjlU=%7K1!p*PxZr*X%f|06q+KtBr~>(gS!0HeVj(D4HZ?O3|BJ_rH2V!KcPrY*|}$ z!8jDI)gY(1Sk{wmR@#aq&EDl;3OWSh3~=o1ZqiXO7YB3mPtj!Sj z?UCvdO=a82^Kl!e=Q=h*BA<-GQyhCf)qgb>1uw-d3{Wo;5Jm*~ZCo!7RUBbNVo?dk4MF{&0?2?|S7)Sa8y-aoEfyoNCsZ%wd)o@>o4=uE>mU86lH1o0|=H_V!9< zd2i9{R+1VSK^#F~1DrsJ{~ciTJ!%N+r~5-BKkH15=}dGMM{@(#=C-hx7rc}H2Z;~W AhX4Qo literal 0 HcmV?d00001 diff --git a/Resources/Textures/Mobs/Silicon/Bots/supplybot.rsi/supplybot.png b/Resources/Textures/Mobs/Silicon/Bots/supplybot.rsi/supplybot.png index cac976240bd3619027dfebb0597e3529251b5612..9a4895603b1cf1c2eb12d58a865531c200f1107d 100644 GIT binary patch literal 2718 zcmV;P3Ssq$P)c9KKK%u?0jvAVKESr3OUVJX(vh?rSy!d?JzB8V9?l$PeZ%~mmb1_fY2Cb{e zj4(a`lUCk@j1ztY?hJB@cUq><>#NeRs=XzP}{Z589z@? z=0w|7_V+w|mURV?1n9z7UIpYj%;hfqEt6U*5IX*~hZbmYagnlF^NP^e*hp<{ZFJ~2 zn`kb%P93e6`iiw&$_&tjuUrB{dt0gZ>J8M<*=%iS)UEf=h|Yie_)cpD;4_Zl9E!aT ze85-Oq6=S1Kw{eaCv016{LgKV=pdsHJU_?|%N{4+wvRyz@dY zVI*(+-dW1$^Pz&EE_~lcp%EBabOa@pTvZO(w;tO{tIH|+`;$u|2B3gA#D=h)mmoUu zJqZ{X7$_jJ%Yta1NF>Bp)jHqUeJw4|ou$=Plce6>UU7A>`2I`KVY!0_;} zXnadci`e74y%-~7{B`Ku){;{Wn;;*4Bm~v1Bz~wFV61D_2paLC5XB6L0-rqtxZoIB z*anSa*clKNK6?gm*RSlD*E;6G;x;svZ`X9WqTc{`Y`~ZAEH}$bq58?<{9ny*Ks|iEIa8py z#dUiBMKeDD2@t}z!D$CkB$HYbwxtvu_<;!$TdrIe3Q;Kqx5P`8#bkm+)cDF6aOBt$ zVN(@*$NV}O3yAV12xywCl-uQ1r(L z@?4ho?rfx{mL`F>mRY0mGg%tkZrn;YVumb8tU@3>`QaM<@E238JIb=IE_`JS=7rO)G-y;NEqjtW224B$%CaehFYA3#)&#$Qfdxl}6QgL_$y?P3OE z24V(c24V(c24V($8K~75zBs>}Sr>bboqd$$ zy9NB#Dc3L8j)U(hjX~UeX*6Zk|Hgq1gMi|ubL~)5K3dNSR9wGYJ3oBK62RKR=%dKQ z0+}R%SXLkFi+Hn1H?Kt?386ejdl9Qf$Y?~t<;EOnaRh_vvil1GV zp&~=zL_v+f{6mgW#hU;;zW*u?Cd=~_-H$g zj1nEXDLCaO$Zw_b9R%FGubJizr` zaQ$-aIQSw4K#Bd_EngQyzGdr1`sn364eV}p>~S3WzubcC;7iV$-#>DZj(y*F7m4u< z@~5x=VgY#e##Iwv5P+wKy=j6My@8$vGbb&y77w$kgwBMHIl2zbM4$Xy77ya05p7P`R>BiEOY3`t#$?goY@zdp8-n z@jY{dOfA3N(KfCo&$aWt6l%n`VgQs`X!pXa|BFztgL}tii$`GI%-!TKEMh_XgQaJ%rbL;feXBKH>WJGj&Y-}trM?fdOoh_Y+`?tB1yj(|Id0J#N-A;>k5c?VFRRT6nM@LBf*?3%wj9{{5&kGXRQa1I24 zg!^uv7HK!7lqm5dT>`SR$PK_!c=gx~T9*I^zvwD}I1pu$)PIAZGFPVB_@&Iy|LHpa Y0pR2nZ#wygegFUf07*qoM6N<$f_Dx)r~m)} literal 2970 zcmYjTc{tST7ypiRt|d!j&zeYRk|c`ASSzv%8H5tDm2CzS*|J?t2*XHMLYm@gvNXfB zPIj_2Vj48|j3qOfrr&hCfBgP<-}5~0Ip;m^`#hiXIiHLxwwA&IvH}1A2wPjh95@#B zYk~PVdxx=49{>pYSi?-6VleBa@i*mY@;$^YrXNj}{Cb;u#CfgLrBz_k{dq-Yw%Mwm zpoh$Ixu!;n_MZXkv)=c_z;an{g0&!9Jzh8a%CGwfaZM{;hu*vY!rH=RrC+Br%6G&q zHm}Yw5ANqt0Ij#%S{GR#G+f?5*56f6+mAQJAop5m+pGo4p>2%qoF$L}Q^~VZ75~>% zj+tD{v|?>l2bo~uK2f{`xJS_G3$An1YsWQ-GfX>THI}$6Okqzwo(5mb7PfnoPn_7+ ze+T+=;?1Q{pxWtuFc00ey-K0&OT_c_R#uOT7*O`Hzs;V+1xP>hGA=7q>{y#oiBddp z7NB$+;N0eGO#H_K4Ajs?TtIpt2%GB<0Q@<#&WmD1B+I7Grc+Hf{c->WjZ^UjP{T$b zVAFFrZU5)22Hf|~-hBY}Imkz1(TbieC(T`baPAgiMO3t;|IOn;+8*@_<@%{pd?Uls zodfMXOUMK$;C=EmkFuVSvR)QxYPg>6P-KBtC+Hyu3{2+v__QXo2IMr`BL*JOm~}z` zQu{>!@^u}SF+mR$zZn^L8a3s|$EDal1(W4cv_Dtao$r~l@kcSe>rP@Pz5r*SX@rPt z0h>fRyl${INIWEKYX)WS9uyH8KxKq#!?%wCy*XyfJEQOJcVf~@FXuD9i&W)ZQd0&` z|8unkoB~7@~7R$~&CzZ2d}_1}dJeC@Q-+`)i(*C`0dA4^>{b=o>vqulp<& zFA?@Rc{i-(6N8a&xkbo@$Erq~24pfS7lUjsNvDb-evWbtF2Xj$AmiiXF}G+6o20<7 zjooH)bsAPV-{uJo!#^?tIgqdiI$3nd9<4<6=$Nd7beyOluUiZmhyY4Dx;UBry689F z>~OB1$WU7aTvFOo&ZEuM?U1XC8vX1SVz0CWO+|-iX0k389tRC8+?db{?wMzB z_Yd9BjNPP|E)l&6e!ii#gW|J$&eZ9F?q*IBsBa z6q2L_ro<|6+zr{w?{WK`7fx#ACWHfAp9R4KoNreQ(HvX3qt-vBgq;aq;$2!^&Kp9r`L00V zwL*t~S#v)1kMlPR5 zHEx8cvscWGPy>~5xy-fYb>EjyUd56nyXZT}s9+XVf8z{5Y1j@?0aDJ(11g6_7HO|Z zSw7K1^t$;~!(`bR3CgX~Enn`33fn4FlKIT{pb0FS>82*{S6UCC+NZJOrrI>^CBFF`?wn>bf zyyGM1tba>^V}5jUTLzy@j)|~OxUZ6;>A0W?5rfbmkxVn>DzjLa^07!#CqXB9U{!O$ z(o!=s$Hk@5TKUWO{da%C)FpK=qLhUX8|l?}Sm34i<6*v%!Uwye z?{WOZirl1m-IPN4Tl@Xu^ou={*Ayv3Uqj5wI~tEA#(ix&M2L^@GiS$8ONR9SHg3Zu zcuongFJJli2qyxGn@s#hhFP=do%*@(`dyG}exD+C2p<=ZLbA~h6G;>N-qIF$p@tuH zCbD*tKgMCZY8T|>SH%j92PCF765SQcJMTixWfljq|3}WM;(^Y`@RPF}$ht;8t!=&n za*$n+@N-(|Rqj{GlU{Z~dWjMIWX}RU;B3q~7G}H)oGzp)Y-dM$y(WAXEN*wCTTaEF zSvw)Sw;x>s1D@Y?ru4Pc6A@$I$A8|Oom3<2BD?gHQd7skA2f`6pkf~IINzddi1#pfijvZQ+ODiNvz)Uw@5aE(&AkiMqujEJY1v{AL}2 zGVbsmzzQl?SbI2hvV8Sqn9tWO#Z=KbcR~f|&iC3Adg%7GHI;7Pi=V8nNl>QUn2B%c zZ#@^;Gff5Qp+-cm-eOVgr@eYGknJ(?nLVew`KAd%?$%zVEMT^-H=XgWzPP`%p!$8* z#!Qsw+`CoYJRj+$dDBu4UOj8iJ`Hyd7eq#Bt?amdw%OCd zU=B(p;1AqLyqf#uo}Iup)pQ#q-_w^24nfYBZ( zrqx&T{X+&^fxt2q?Fr`uJ}xWkURpY8DI2``6eylp-XTjEfiBz zh;Kp{sEK5X*qvz$$K2vQ!saAAtE##@A4Gb|ltL<^Xt9Ul10kjCV_h|l^Yil$)}LK2 zfp{!48H~5B+7{=A`kQ@rv5o@+jo6 zv0JTIR4u2gNb^@?!rWRo;O*XA3UTYt%AjB%#uA_qwLjlU=%7K1!p*PxZr*X%f|06q+KtBr~>(gS!0HeVj(D4HZ?O3|BJ_rH2V!KcPrY*|}$ z!8jDI)gY(1Sk{wmR@#aq&EDl;3OWSh3~=o1ZqiXO7YB3mPtj!Sj z?UCvdO=a82^Kl!e=Q=h*BA<-GQyhCf)qgb>1uw-d3{Wo;5Jm*~ZCo!7RUBbNVo?dk4MF{&0?2?|S7)Sa8y-aoEfyoNCsZ%wd)o@>o4=uE>mU86lH1o0|=H_V!9< zd2i9{R+1VSK^#F~1DrsJ{~ciTJ!%N+r~5-BKkH15=}dGMM{@(#=C-hx7rc}H2Z;~W AhX4Qo From 64447f812d25bc5ee5c5ca3a628971363f12b949 Mon Sep 17 00:00:00 2001 From: Simon <63975668+Simyon264@users.noreply.github.com> Date: Sun, 7 Jul 2024 15:06:24 +0200 Subject: [PATCH 083/765] Raise ratking migration minimum players to 30 from 15 (#29737) --- Resources/Prototypes/GameRules/events.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Resources/Prototypes/GameRules/events.yml b/Resources/Prototypes/GameRules/events.yml index ed9f7b71c77..74d0dfb80c6 100644 --- a/Resources/Prototypes/GameRules/events.yml +++ b/Resources/Prototypes/GameRules/events.yml @@ -204,7 +204,7 @@ path: /Audio/Announcements/attention.ogg startDelay: 10 earliestStart: 20 #DeltaV - was 30 - minimumPlayers: 25 #DeltaV - was 35 + minimumPlayers: 25 #DeltaV - was 30 weight: 5 duration: 50 - type: VentCrittersRule From 42b2f4e2e643005650a704a73a92b49f6d2bb3f2 Mon Sep 17 00:00:00 2001 From: PJBot Date: Sun, 7 Jul 2024 13:07:30 +0000 Subject: [PATCH 084/765] Automatic changelog update --- Resources/Changelog/Changelog.yml | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index ef044e72013..f5387d8fdb7 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,12 +1,4 @@ Entries: -- author: Tayrtahn - changes: - - message: Sodas and other fizzy drinks can be shaken with the verbs menu to build - up fizziness so they spray when opened. - type: Add - id: 6378 - time: '2024-04-18T01:49:58.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/25574 - author: metalgearsloth changes: - message: Fix lobby UI not resetting for character changes. @@ -3819,3 +3811,10 @@ id: 6877 time: '2024-07-07T06:20:53.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/29741 +- author: Simyon + changes: + - message: Ratkings now require at least 30 players in order to spawn. + type: Tweak + id: 6878 + time: '2024-07-07T13:06:24.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/29737 From 8295d4331909191d9f03430d66b6fc9cc7bb3348 Mon Sep 17 00:00:00 2001 From: Nemanja <98561806+EmoGarbage404@users.noreply.github.com> Date: Sun, 7 Jul 2024 10:19:10 -0400 Subject: [PATCH 085/765] Intercom buffs and fixes (#29580) * Intercom buffs and fixes * remove unused bui state * mild sec intercom buff * reinforce sec intercoms --- .../Radio/EntitySystems/RadioDeviceSystem.cs | 23 +++ .../Radio/Ui/IntercomBoundUserInterface.cs | 15 +- Content.Client/Radio/Ui/IntercomMenu.xaml.cs | 37 +++- .../Radio/EntitySystems/RadioDeviceSystem.cs | 84 ++++---- .../Radio/EntitySystems/RadioSystem.cs | 9 +- .../Radio/Components/IntercomComponent.cs | 21 +- .../Components/TelecomExemptComponent.cs | 9 + .../EntitySystems/EncryptionKeySystem.cs | 14 +- Content.Shared/Radio/SharedIntercom.cs | 20 +- Content.Shared/Wires/SharedWiresSystem.cs | 6 + .../en-US/radio/components/intercom.ftl | 3 +- Resources/Migrations/migration.yml | 3 + .../Entities/Objects/Devices/radio.yml | 3 +- .../Structures/Wallmounts/intercom.yml | 186 +++++++++++++----- .../Graphs/utilities/intercom.yml | 41 +++- .../Recipes/Construction/utilities.yml | 2 +- .../Wallmounts/intercom.rsi/base.png | Bin 1438 -> 729 bytes .../Wallmounts/intercom.rsi/broadcasting.png | Bin 171 -> 137 bytes .../Wallmounts/intercom.rsi/build.png | Bin 1369 -> 656 bytes .../Wallmounts/intercom.rsi/panel.png | Bin 656 -> 316 bytes .../Wallmounts/intercom.rsi/speaker.png | Bin 157 -> 134 bytes .../Wallmounts/intercom.rsi/unshaded.png | Bin 328 -> 217 bytes 22 files changed, 339 insertions(+), 137 deletions(-) create mode 100644 Content.Client/Radio/EntitySystems/RadioDeviceSystem.cs create mode 100644 Content.Shared/Radio/Components/TelecomExemptComponent.cs diff --git a/Content.Client/Radio/EntitySystems/RadioDeviceSystem.cs b/Content.Client/Radio/EntitySystems/RadioDeviceSystem.cs new file mode 100644 index 00000000000..29d6c635ebc --- /dev/null +++ b/Content.Client/Radio/EntitySystems/RadioDeviceSystem.cs @@ -0,0 +1,23 @@ +using Content.Client.Radio.Ui; +using Content.Shared.Radio; +using Content.Shared.Radio.Components; +using Robust.Client.GameObjects; + +namespace Content.Client.Radio.EntitySystems; + +public sealed class RadioDeviceSystem : EntitySystem +{ + [Dependency] private readonly UserInterfaceSystem _ui = default!; + + /// + public override void Initialize() + { + SubscribeLocalEvent(OnAfterHandleState); + } + + private void OnAfterHandleState(Entity ent, ref AfterAutoHandleStateEvent args) + { + if (_ui.TryGetOpenUi(ent.Owner, IntercomUiKey.Key, out var bui)) + bui.Update(ent); + } +} diff --git a/Content.Client/Radio/Ui/IntercomBoundUserInterface.cs b/Content.Client/Radio/Ui/IntercomBoundUserInterface.cs index abbb1d58ec4..7b3e39aa084 100644 --- a/Content.Client/Radio/Ui/IntercomBoundUserInterface.cs +++ b/Content.Client/Radio/Ui/IntercomBoundUserInterface.cs @@ -1,6 +1,6 @@ using Content.Shared.Radio; +using Content.Shared.Radio.Components; using JetBrains.Annotations; -using Robust.Client.GameObjects; namespace Content.Client.Radio.Ui; @@ -19,7 +19,9 @@ protected override void Open() { base.Open(); - _menu = new(); + var comp = EntMan.GetComponent(Owner); + + _menu = new((Owner, comp)); _menu.OnMicPressed += enabled => { @@ -46,13 +48,8 @@ protected override void Dispose(bool disposing) _menu?.Close(); } - protected override void UpdateState(BoundUserInterfaceState state) + public void Update(Entity ent) { - base.UpdateState(state); - - if (state is not IntercomBoundUIState msg) - return; - - _menu?.Update(msg); + _menu?.Update(ent); } } diff --git a/Content.Client/Radio/Ui/IntercomMenu.xaml.cs b/Content.Client/Radio/Ui/IntercomMenu.xaml.cs index 8b4b38753c1..2e08913051c 100644 --- a/Content.Client/Radio/Ui/IntercomMenu.xaml.cs +++ b/Content.Client/Radio/Ui/IntercomMenu.xaml.cs @@ -1,8 +1,9 @@ using Content.Client.UserInterface.Controls; -using Content.Shared.Radio; +using Content.Shared.Radio.Components; using Robust.Client.AutoGenerated; using Robust.Client.UserInterface.XAML; using Robust.Shared.Prototypes; +using Robust.Shared.Utility; namespace Content.Client.Radio.Ui; @@ -17,38 +18,54 @@ public sealed partial class IntercomMenu : FancyWindow private readonly List _channels = new(); - public IntercomMenu() + public IntercomMenu(Entity entity) { RobustXamlLoader.Load(this); IoCManager.InjectDependencies(this); MicButton.OnPressed += args => OnMicPressed?.Invoke(args.Button.Pressed); SpeakerButton.OnPressed += args => OnSpeakerPressed?.Invoke(args.Button.Pressed); + + Update(entity); } - public void Update(IntercomBoundUIState state) + public void Update(Entity entity) { - MicButton.Pressed = state.MicEnabled; - SpeakerButton.Pressed = state.SpeakerEnabled; + MicButton.Pressed = entity.Comp.MicrophoneEnabled; + SpeakerButton.Pressed = entity.Comp.SpeakerEnabled; + + MicButton.Disabled = entity.Comp.SupportedChannels.Count == 0; + SpeakerButton.Disabled = entity.Comp.SupportedChannels.Count == 0; + ChannelOptions.Disabled = entity.Comp.SupportedChannels.Count == 0; ChannelOptions.Clear(); _channels.Clear(); - for (var i = 0; i < state.AvailableChannels.Count; i++) + for (var i = 0; i < entity.Comp.SupportedChannels.Count; i++) { - var channel = state.AvailableChannels[i]; - if (!_prototype.TryIndex(channel, out var prototype)) + var channel = entity.Comp.SupportedChannels[i]; + if (!_prototype.TryIndex(channel, out var prototype)) continue; _channels.Add(channel); ChannelOptions.AddItem(Loc.GetString(prototype.Name), i); - if (channel == state.SelectedChannel) + if (channel == entity.Comp.CurrentChannel) ChannelOptions.Select(i); } + + if (entity.Comp.SupportedChannels.Count == 0) + { + ChannelOptions.AddItem(Loc.GetString("intercom-options-none"), 0); + ChannelOptions.Select(0); + } + ChannelOptions.OnItemSelected += args => { + if (!_channels.TryGetValue(args.Id, out var proto)) + return; + ChannelOptions.SelectId(args.Id); - OnChannelSelected?.Invoke(_channels[args.Id]); + OnChannelSelected?.Invoke(proto); }; } } diff --git a/Content.Server/Radio/EntitySystems/RadioDeviceSystem.cs b/Content.Server/Radio/EntitySystems/RadioDeviceSystem.cs index 8484fb23363..1258e0b8c7e 100644 --- a/Content.Server/Radio/EntitySystems/RadioDeviceSystem.cs +++ b/Content.Server/Radio/EntitySystems/RadioDeviceSystem.cs @@ -1,3 +1,4 @@ +using System.Linq; using Content.Server.Chat.Systems; using Content.Server.Interaction; using Content.Server.Popups; @@ -6,13 +7,10 @@ using Content.Server.Radio.Components; using Content.Server.Speech; using Content.Server.Speech.Components; -using Content.Shared.UserInterface; -using Content.Shared.Chat; using Content.Shared.Examine; using Content.Shared.Interaction; using Content.Shared.Radio; using Content.Shared.Radio.Components; -using Robust.Server.GameObjects; using Robust.Shared.Prototypes; namespace Content.Server.Radio.EntitySystems; @@ -28,7 +26,6 @@ public sealed class RadioDeviceSystem : EntitySystem [Dependency] private readonly RadioSystem _radio = default!; [Dependency] private readonly InteractionSystem _interaction = default!; [Dependency] private readonly SharedAppearanceSystem _appearance = default!; - [Dependency] private readonly UserInterfaceSystem _ui = default!; // Used to prevent a shitter from using a bunch of radios to spam chat. private HashSet<(string, EntityUid)> _recentlySent = new(); @@ -47,7 +44,7 @@ public override void Initialize() SubscribeLocalEvent(OnActivateSpeaker); SubscribeLocalEvent(OnReceiveRadio); - SubscribeLocalEvent(OnBeforeIntercomUiOpen); + SubscribeLocalEvent(OnIntercomEncryptionChannelsChanged); SubscribeLocalEvent(OnToggleIntercomMic); SubscribeLocalEvent(OnToggleIntercomSpeaker); SubscribeLocalEvent(OnSelectIntercomChannel); @@ -150,18 +147,18 @@ public void ToggleRadioSpeaker(EntityUid uid, EntityUid user, bool quiet = false SetSpeakerEnabled(uid, user, !component.Enabled, quiet, component); } - public void SetSpeakerEnabled(EntityUid uid, EntityUid user, bool enabled, bool quiet = false, RadioSpeakerComponent? component = null) + public void SetSpeakerEnabled(EntityUid uid, EntityUid? user, bool enabled, bool quiet = false, RadioSpeakerComponent? component = null) { if (!Resolve(uid, ref component)) return; component.Enabled = enabled; - if (!quiet) + if (!quiet && user != null) { var state = Loc.GetString(component.Enabled ? "handheld-radio-component-on-state" : "handheld-radio-component-off-state"); var message = Loc.GetString("handheld-radio-component-on-use", ("radioState", state)); - _popup.PopupEntity(message, user, user); + _popup.PopupEntity(message, user.Value, user.Value); } _appearance.SetData(uid, RadioDeviceVisuals.Speaker, component.Enabled); @@ -213,61 +210,74 @@ private void OnReceiveRadio(EntityUid uid, RadioSpeakerComponent component, ref var nameEv = new TransformSpeakerNameEvent(args.MessageSource, Name(args.MessageSource)); RaiseLocalEvent(args.MessageSource, nameEv); - var name = Loc.GetString("speech-name-relay", ("speaker", Name(uid)), + var name = Loc.GetString("speech-name-relay", + ("speaker", Name(uid)), ("originalName", nameEv.Name)); // log to chat so people can identity the speaker/source, but avoid clogging ghost chat if there are many radios _chat.TrySendInGameICMessage(uid, args.Message, InGameICChatType.Whisper, ChatTransmitRange.GhostRangeLimit, nameOverride: name, checkRadioPrefix: false); } - private void OnBeforeIntercomUiOpen(EntityUid uid, IntercomComponent component, BeforeActivatableUIOpenEvent args) + private void OnIntercomEncryptionChannelsChanged(Entity ent, ref EncryptionChannelsChangedEvent args) { - UpdateIntercomUi(uid, component); + ent.Comp.SupportedChannels = args.Component.Channels.Select(p => new ProtoId(p)).ToList(); + + var channel = args.Component.DefaultChannel; + if (ent.Comp.CurrentChannel != null && ent.Comp.SupportedChannels.Contains(ent.Comp.CurrentChannel.Value)) + channel = ent.Comp.CurrentChannel; + + SetIntercomChannel(ent, channel); } - private void OnToggleIntercomMic(EntityUid uid, IntercomComponent component, ToggleIntercomMicMessage args) + private void OnToggleIntercomMic(Entity ent, ref ToggleIntercomMicMessage args) { - if (component.RequiresPower && !this.IsPowered(uid, EntityManager)) + if (ent.Comp.RequiresPower && !this.IsPowered(ent, EntityManager)) return; - SetMicrophoneEnabled(uid, args.Actor, args.Enabled, true); - UpdateIntercomUi(uid, component); + SetMicrophoneEnabled(ent, args.Actor, args.Enabled, true); + ent.Comp.MicrophoneEnabled = args.Enabled; + Dirty(ent); } - private void OnToggleIntercomSpeaker(EntityUid uid, IntercomComponent component, ToggleIntercomSpeakerMessage args) + private void OnToggleIntercomSpeaker(Entity ent, ref ToggleIntercomSpeakerMessage args) { - if (component.RequiresPower && !this.IsPowered(uid, EntityManager)) + if (ent.Comp.RequiresPower && !this.IsPowered(ent, EntityManager)) return; - SetSpeakerEnabled(uid, args.Actor, args.Enabled, true); - UpdateIntercomUi(uid, component); + SetSpeakerEnabled(ent, args.Actor, args.Enabled, true); + ent.Comp.SpeakerEnabled = args.Enabled; + Dirty(ent); } - private void OnSelectIntercomChannel(EntityUid uid, IntercomComponent component, SelectIntercomChannelMessage args) + private void OnSelectIntercomChannel(Entity ent, ref SelectIntercomChannelMessage args) { - if (component.RequiresPower && !this.IsPowered(uid, EntityManager)) + if (ent.Comp.RequiresPower && !this.IsPowered(ent, EntityManager)) return; - if (!_protoMan.TryIndex(args.Channel, out _) || !component.SupportedChannels.Contains(args.Channel)) + if (!_protoMan.HasIndex(args.Channel) || !ent.Comp.SupportedChannels.Contains(args.Channel)) return; - if (TryComp(uid, out var mic)) - mic.BroadcastChannel = args.Channel; - if (TryComp(uid, out var speaker)) - speaker.Channels = new(){ args.Channel }; - UpdateIntercomUi(uid, component); + SetIntercomChannel(ent, args.Channel); } - private void UpdateIntercomUi(EntityUid uid, IntercomComponent component) + private void SetIntercomChannel(Entity ent, ProtoId? channel) { - var micComp = CompOrNull(uid); - var speakerComp = CompOrNull(uid); - - var micEnabled = micComp?.Enabled ?? false; - var speakerEnabled = speakerComp?.Enabled ?? false; - var availableChannels = component.SupportedChannels; - var selectedChannel = micComp?.BroadcastChannel ?? SharedChatSystem.CommonChannel; - var state = new IntercomBoundUIState(micEnabled, speakerEnabled, availableChannels, selectedChannel); - _ui.SetUiState(uid, IntercomUiKey.Key, state); + ent.Comp.CurrentChannel = channel; + + if (channel == null) + { + SetSpeakerEnabled(ent, null, false); + SetMicrophoneEnabled(ent, null, false); + ent.Comp.MicrophoneEnabled = false; + ent.Comp.SpeakerEnabled = false; + Dirty(ent); + return; + } + + if (TryComp(ent, out var mic)) + mic.BroadcastChannel = channel; + if (TryComp(ent, out var speaker)) + speaker.Channels = new(){ channel }; + Dirty(ent); } } diff --git a/Content.Server/Radio/EntitySystems/RadioSystem.cs b/Content.Server/Radio/EntitySystems/RadioSystem.cs index 100fb7201f7..283b5972817 100644 --- a/Content.Server/Radio/EntitySystems/RadioSystem.cs +++ b/Content.Server/Radio/EntitySystems/RadioSystem.cs @@ -33,11 +33,15 @@ public sealed class RadioSystem : EntitySystem // set used to prevent radio feedback loops. private readonly HashSet _messages = new(); + private EntityQuery _exemptQuery; + public override void Initialize() { base.Initialize(); SubscribeLocalEvent(OnIntrinsicReceive); SubscribeLocalEvent(OnIntrinsicSpeak); + + _exemptQuery = GetEntityQuery(); } private void OnIntrinsicSpeak(EntityUid uid, IntrinsicRadioTransmitterComponent component, EntitySpokeEvent args) @@ -125,9 +129,8 @@ public void SendRadioMessage(EntityUid messageSource, string message, RadioChann var sourceMapId = Transform(radioSource).MapID; var hasActiveServer = HasActiveServer(sourceMapId, channel.ID); - var hasMicro = HasComp(radioSource); + var sourceServerExempt = _exemptQuery.HasComp(radioSource); - var speakerQuery = GetEntityQuery(); var radioQuery = EntityQueryEnumerator(); while (canSend && radioQuery.MoveNext(out var receiver, out var radio, out var transform)) { @@ -142,7 +145,7 @@ public void SendRadioMessage(EntityUid messageSource, string message, RadioChann continue; // don't need telecom server for long range channels or handheld radios and intercoms - var needServer = !channel.LongRange && (!hasMicro || !speakerQuery.HasComponent(receiver)); + var needServer = !channel.LongRange && !sourceServerExempt; if (needServer && !hasActiveServer) continue; diff --git a/Content.Shared/Radio/Components/IntercomComponent.cs b/Content.Shared/Radio/Components/IntercomComponent.cs index be2734ff168..8d7b87597b1 100644 --- a/Content.Shared/Radio/Components/IntercomComponent.cs +++ b/Content.Shared/Radio/Components/IntercomComponent.cs @@ -1,23 +1,32 @@ using Robust.Shared.GameStates; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.List; +using Robust.Shared.Prototypes; namespace Content.Shared.Radio.Components; /// /// Handles intercom ui and is authoritative on the channels an intercom can access. /// -[RegisterComponent, NetworkedComponent] +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState(true)] public sealed partial class IntercomComponent : Component { /// - /// Does this intercom require popwer to function + /// Does this intercom require power to function /// - [DataField("requiresPower"), ViewVariables(VVAccess.ReadWrite)] + [DataField] public bool RequiresPower = true; + [DataField, AutoNetworkedField] + public bool SpeakerEnabled; + + [DataField, AutoNetworkedField] + public bool MicrophoneEnabled; + + [DataField, AutoNetworkedField] + public ProtoId? CurrentChannel; + /// /// The list of radio channel prototypes this intercom can choose between. /// - [DataField("supportedChannels", customTypeSerializer: typeof(PrototypeIdListSerializer))] - public List SupportedChannels = new(); + [DataField, AutoNetworkedField] + public List> SupportedChannels = new(); } diff --git a/Content.Shared/Radio/Components/TelecomExemptComponent.cs b/Content.Shared/Radio/Components/TelecomExemptComponent.cs new file mode 100644 index 00000000000..7af5c1c78ca --- /dev/null +++ b/Content.Shared/Radio/Components/TelecomExemptComponent.cs @@ -0,0 +1,9 @@ +using Robust.Shared.GameStates; + +namespace Content.Shared.Radio.Components; + +/// +/// This is used for a radio that doesn't need a telecom server in order to broadcast. +/// +[RegisterComponent, NetworkedComponent] +public sealed partial class TelecomExemptComponent : Component; diff --git a/Content.Shared/Radio/EntitySystems/EncryptionKeySystem.cs b/Content.Shared/Radio/EntitySystems/EncryptionKeySystem.cs index ea07b5f8a5c..cfa553661a3 100644 --- a/Content.Shared/Radio/EntitySystems/EncryptionKeySystem.cs +++ b/Content.Shared/Radio/EntitySystems/EncryptionKeySystem.cs @@ -31,6 +31,7 @@ public sealed partial class EncryptionKeySystem : EntitySystem [Dependency] private readonly SharedContainerSystem _container = default!; [Dependency] private readonly SharedAudioSystem _audio = default!; [Dependency] private readonly SharedHandsSystem _hands = default!; + [Dependency] private readonly SharedWiresSystem _wires = default!; public override void Initialize() { @@ -150,7 +151,7 @@ private void TryRemoveKey(EntityUid uid, EncryptionKeyHolderComponent component, return; } - if (TryComp(uid, out var panel) && !panel.Open) + if (!_wires.IsPanelOpen(uid)) { _popup.PopupClient(Loc.GetString("encryption-keys-panel-locked"), uid, args.User); return; @@ -184,8 +185,15 @@ private void OnHolderExamined(EntityUid uid, EncryptionKeyHolderComponent compon if (component.Channels.Count > 0) { - args.PushMarkup(Loc.GetString("examine-encryption-channels-prefix")); - AddChannelsExamine(component.Channels, component.DefaultChannel, args, _protoManager, "examine-encryption-channel"); + using (args.PushGroup(nameof(EncryptionKeyComponent))) + { + args.PushMarkup(Loc.GetString("examine-encryption-channels-prefix")); + AddChannelsExamine(component.Channels, + component.DefaultChannel, + args, + _protoManager, + "examine-encryption-channel"); + } } } diff --git a/Content.Shared/Radio/SharedIntercom.cs b/Content.Shared/Radio/SharedIntercom.cs index 410843312fd..f697add8b90 100644 --- a/Content.Shared/Radio/SharedIntercom.cs +++ b/Content.Shared/Radio/SharedIntercom.cs @@ -1,4 +1,5 @@ -using Robust.Shared.Serialization; +using Robust.Shared.Prototypes; +using Robust.Shared.Serialization; namespace Content.Shared.Radio; @@ -8,23 +9,6 @@ public enum IntercomUiKey Key, } -[Serializable, NetSerializable] -public sealed class IntercomBoundUIState : BoundUserInterfaceState -{ - public bool MicEnabled; - public bool SpeakerEnabled; - public List AvailableChannels; - public string SelectedChannel; - - public IntercomBoundUIState(bool micEnabled, bool speakerEnabled, List availableChannels, string selectedChannel) - { - MicEnabled = micEnabled; - SpeakerEnabled = speakerEnabled; - AvailableChannels = availableChannels; - SelectedChannel = selectedChannel; - } -} - [Serializable, NetSerializable] public sealed class ToggleIntercomMicMessage : BoundUserInterfaceMessage { diff --git a/Content.Shared/Wires/SharedWiresSystem.cs b/Content.Shared/Wires/SharedWiresSystem.cs index d84766a5fc6..7032293eaf6 100644 --- a/Content.Shared/Wires/SharedWiresSystem.cs +++ b/Content.Shared/Wires/SharedWiresSystem.cs @@ -20,6 +20,7 @@ public override void Initialize() { base.Initialize(); + SubscribeLocalEvent(OnStartup); SubscribeLocalEvent(OnPanelDoAfter); SubscribeLocalEvent(OnInteractUsing); SubscribeLocalEvent(OnExamine); @@ -28,6 +29,11 @@ public override void Initialize() SubscribeLocalEvent(OnActivatableUIPanelChanged); } + private void OnStartup(Entity ent, ref ComponentStartup args) + { + UpdateAppearance(ent, ent); + } + private void OnPanelDoAfter(EntityUid uid, WiresPanelComponent panel, WirePanelDoAfterEvent args) { if (args.Cancelled) diff --git a/Resources/Locale/en-US/radio/components/intercom.ftl b/Resources/Locale/en-US/radio/components/intercom.ftl index e56e3cd0f73..63303999c21 100644 --- a/Resources/Locale/en-US/radio/components/intercom.ftl +++ b/Resources/Locale/en-US/radio/components/intercom.ftl @@ -1,5 +1,6 @@ intercom-menu-title = Intercom intercom-channel-label = Channel: intercom-button-text-mic = Mic. -intercom-button-text-speaker = Speak +intercom-button-text-speaker = Spkr. +intercom-options-none = No channels intercom-flavor-text-left = Keep lines free of chatter diff --git a/Resources/Migrations/migration.yml b/Resources/Migrations/migration.yml index fd14a6ab762..c7ce3215a89 100644 --- a/Resources/Migrations/migration.yml +++ b/Resources/Migrations/migration.yml @@ -342,3 +342,6 @@ FloorTileItemReinforced: PartRodMetal1 #2024-06-25 BookChefGaming: BookHowToCookForFortySpaceman + +#2024-06-29 +IntercomAssesmbly: IntercomAssembly diff --git a/Resources/Prototypes/Entities/Objects/Devices/radio.yml b/Resources/Prototypes/Entities/Objects/Devices/radio.yml index 43f84fe404e..77b6cac2d37 100644 --- a/Resources/Prototypes/Entities/Objects/Devices/radio.yml +++ b/Resources/Prototypes/Entities/Objects/Devices/radio.yml @@ -4,6 +4,7 @@ parent: BaseItem id: RadioHandheld components: + - type: TelecomExempt - type: RadioMicrophone broadcastChannel: Handheld - type: RadioSpeaker @@ -39,4 +40,4 @@ sprite: Objects/Devices/securityhandy.rsi - type: Item sprite: Objects/Devices/securityhandy.rsi - heldPrefix: walkietalkie \ No newline at end of file + heldPrefix: walkietalkie diff --git a/Resources/Prototypes/Entities/Structures/Wallmounts/intercom.yml b/Resources/Prototypes/Entities/Structures/Wallmounts/intercom.yml index e31152a5b6e..52c71914210 100644 --- a/Resources/Prototypes/Entities/Structures/Wallmounts/intercom.yml +++ b/Resources/Prototypes/Entities/Structures/Wallmounts/intercom.yml @@ -1,5 +1,5 @@ - type: entity - id: Intercom + id: BaseIntercom name: intercom description: An intercom. For when the station just needs to know something. abstract: true @@ -9,6 +9,10 @@ - type: Electrified enabled: false usesApcPower: true + - type: TelecomExempt + - type: EncryptionKeyHolder + keySlots: 3 + keysExtractionMethod: Prying - type: RadioMicrophone powerRequired: true unobstructedRequired: true @@ -24,12 +28,14 @@ - type: InteractionOutline - type: Appearance - type: WiresVisuals + - type: WiresPanelSecurity - type: ContainerFill containers: board: [ IntercomElectronics ] - type: ContainerContainer containers: board: !type:Container + key_slots: !type:Container - type: Sprite noRot: false drawdepth: SmallObjects @@ -49,7 +55,6 @@ visible: false - state: panel map: ["enum.WiresVisualLayers.MaintenancePanel"] - shader: unshaded visible: false - type: Transform noRot: false @@ -61,6 +66,7 @@ - type: ActivatableUIRequiresPower - type: ActivatableUI key: enum.IntercomUiKey.Key + singleUser: true - type: UserInterface interfaces: enum.IntercomUiKey.Key: @@ -116,7 +122,7 @@ - Wallmount - type: entity - id: IntercomAssesmbly + id: IntercomAssembly name: intercom assembly description: An intercom. It doesn't seem very helpful right now. components: @@ -126,7 +132,18 @@ - type: Sprite drawdepth: SmallObjects sprite: Structures/Wallmounts/intercom.rsi - state: build + layers: + - state: build + - state: panel + visible: false + map: [ "wires" ] + - type: Appearance + - type: GenericVisualizer + visuals: + enum.ConstructionVisuals.Layer: + wires: + 0: { visible: false } + 1: { visible: true } - type: Construction graph: Intercom node: assembly @@ -137,97 +154,176 @@ snap: - Wallmount +# this weird inheritance BS exists for construction shitcode +- type: entity + id: IntercomConstructed + parent: BaseIntercom + suffix: Empty, Panel Open + components: + - type: Sprite + layers: + - state: base + - state: unshaded + map: ["enum.PowerDeviceVisualLayers.Powered"] + shader: unshaded + - state: broadcasting + map: ["enum.RadioDeviceVisualLayers.Broadcasting"] + shader: unshaded + visible: false + - state: speaker + map: ["enum.RadioDeviceVisualLayers.Speaker"] + shader: unshaded + visible: false + - state: panel + map: ["enum.WiresVisualLayers.MaintenancePanel"] + visible: true + - type: WiresPanel + open: true + +- type: entity + id: Intercom + parent: IntercomConstructed + suffix: "" + components: + - type: Sprite + layers: + - state: base + - state: unshaded + map: ["enum.PowerDeviceVisualLayers.Powered"] + shader: unshaded + - state: broadcasting + map: ["enum.RadioDeviceVisualLayers.Broadcasting"] + shader: unshaded + visible: false + - state: speaker + map: ["enum.RadioDeviceVisualLayers.Speaker"] + shader: unshaded + visible: false + - state: panel + map: ["enum.WiresVisualLayers.MaintenancePanel"] + - type: WiresPanel + open: false + - type: entity id: IntercomCommon parent: Intercom suffix: Common components: - - type: Intercom - supportedChannels: - - Common + - type: ContainerFill + containers: + board: + - IntercomElectronics + key_slots: + - EncryptionKeyCommon - type: entity id: IntercomCommand parent: Intercom suffix: Command components: - - type: Intercom - supportedChannels: - - Common - - Command + - type: ContainerFill + containers: + board: + - IntercomElectronics + key_slots: + - EncryptionKeyCommon + - EncryptionKeyCommand - type: entity id: IntercomEngineering parent: Intercom suffix: Engineering components: - - type: Intercom - supportedChannels: - - Common - - Engineering + - type: ContainerFill + containers: + board: + - IntercomElectronics + key_slots: + - EncryptionKeyCommon + - EncryptionKeyEngineering - type: entity id: IntercomMedical parent: Intercom suffix: Medical components: - - type: Intercom - supportedChannels: - - Common - - Medical + - type: ContainerFill + containers: + board: + - IntercomElectronics + key_slots: + - EncryptionKeyCommon + - EncryptionKeyMedical - type: entity id: IntercomScience parent: Intercom suffix: Epistemics # DeltaV - Epistemics Department replacing Science components: - - type: Intercom - supportedChannels: - - Common - - Science + - type: ContainerFill + containers: + board: + - IntercomElectronics + key_slots: + - EncryptionKeyCommon + - EncryptionKeyScience - type: entity id: IntercomSecurity parent: Intercom suffix: Security + description: An intercom. It's been reinforced with metal from security helmets, making it a bitch-and-a-half to open. components: - - type: Intercom - supportedChannels: - - Common - - Security + - type: WiresPanel + openDelay: 5 + - type: WiresPanelSecurity + examine: wires-panel-component-on-examine-security-level2 + wiresAccessible: false + - type: Construction + node: intercomReinforced + - type: ContainerFill + containers: + board: + - IntercomElectronics + key_slots: + - EncryptionKeyCommon + - EncryptionKeySecurity - type: entity id: IntercomService parent: Intercom suffix: Service components: - - type: Intercom - supportedChannels: - - Common - - Service + - type: ContainerFill + containers: + board: + - IntercomElectronics + key_slots: + - EncryptionKeyCommon + - EncryptionKeyService - type: entity id: IntercomSupply parent: Intercom suffix: Supply components: - - type: Intercom - supportedChannels: - - Common - - Supply + - type: ContainerFill + containers: + board: + - IntercomElectronics + key_slots: + - EncryptionKeyCommon + - EncryptionKeyCargo - type: entity id: IntercomAll parent: Intercom suffix: All components: - - type: Intercom - supportedChannels: - - Common - - Command - - Engineering - - Medical - - Science - - Security - - Service - - Supply + - type: ContainerFill + containers: + board: + - IntercomElectronics + key_slots: + - EncryptionKeyCommon + - EncryptionKeyStationMaster diff --git a/Resources/Prototypes/Recipes/Construction/Graphs/utilities/intercom.yml b/Resources/Prototypes/Recipes/Construction/Graphs/utilities/intercom.yml index 2247860f892..ba29d72539a 100644 --- a/Resources/Prototypes/Recipes/Construction/Graphs/utilities/intercom.yml +++ b/Resources/Prototypes/Recipes/Construction/Graphs/utilities/intercom.yml @@ -11,13 +11,17 @@ doAfter: 2.0 - node: assembly - entity: IntercomAssesmbly + entity: IntercomAssembly edges: - to: wired steps: - material: Cable amount: 2 doAfter: 1 + completed: + - !type:VisualizerDataInt + key: "enum.ConstructionVisuals.Layer" + data: 1 - to: start completed: - !type:GivePrototype @@ -29,7 +33,7 @@ doAfter: 2 - node: wired - entity: IntercomAssesmbly + entity: IntercomAssembly edges: - to: electronics steps: @@ -45,6 +49,9 @@ - !type:GivePrototype prototype: CableApcStack1 amount: 2 + - !type:VisualizerDataInt + key: "enum.ConstructionVisuals.Layer" + data: 0 steps: - tool: Cutting doAfter: 1 @@ -57,7 +64,11 @@ doAfter: 2 - node: intercom - entity: IntercomCommon #TODO: make this work with encryption keys + entity: IntercomConstructed + doNotReplaceInheritingEntities: true + actions: + - !type:SetWiresPanelSecurity + wiresAccessible: true edges: - to: wired conditions: @@ -72,3 +83,27 @@ steps: - tool: Prying doAfter: 1 + - to: intercomReinforced + conditions: + - !type:WirePanel + steps: + - material: Steel + amount: 1 + - tool: Welding + doAfter: 1 + + - node: intercomReinforced + actions: + - !type:SetWiresPanelSecurity + examine: wires-panel-component-on-examine-security-level2 + wiresAccessible: false + edges: + - to: intercom + conditions: + - !type:WirePanel + completed: + - !type:GivePrototype + prototype: SheetSteel1 + steps: + - tool: Welding + doAfter: 5 diff --git a/Resources/Prototypes/Recipes/Construction/utilities.yml b/Resources/Prototypes/Recipes/Construction/utilities.yml index 19f2fee1837..82c16de7b6a 100644 --- a/Resources/Prototypes/Recipes/Construction/utilities.yml +++ b/Resources/Prototypes/Recipes/Construction/utilities.yml @@ -790,7 +790,7 @@ # INTERCOM - type: construction name: intercom - id: IntercomAssesmbly + id: IntercomAssembly graph: Intercom startNode: start targetNode: intercom diff --git a/Resources/Textures/Structures/Wallmounts/intercom.rsi/base.png b/Resources/Textures/Structures/Wallmounts/intercom.rsi/base.png index 787af3f53876b0ceabe9599acf922b1e4f2748f6..a85cbfbecc6aa5f549067703687291f9ea7634a6 100644 GIT binary patch delta 693 zcmbQoeUo*9K|RxCPZ!6KiaBp*1$GMsiX8v%%Cq`wK(3P)^CrjFW~X}=?pCPfe7SJF z!2|ZF4_m8VDgNSeQ`~Xt*@m{S0n;8%X>psP_bq|nd-Ae-Z#PxHpE=`mwd9`ib>;6K z-m(0CzMi42)8zRId54zN$jg`ixv#z|wC>}fO!a_PAiv_wfv->Md1ox^{2L{@_#?}9 zqD*m4km|_r5_($biT3EX3g8TOCRrXlU2R$dik^8oX3A= z+I^IK{M&BQ$&>=thP_3WFY;yU<<8x;|6RR4rY-rl`Z>W@JTqedyyw{wt??kksPX!W z!$7;59+FmIa&mFzO2&jS z?dRM7;M3G>?c-}+{m)t;9RC@78mwF5L z70eSnVqBj;H{SERrX|OwyQGTwu%o;_f8Xo+kN0YAYClOZOxRmI=NC}${=DlG;^N(t zUaQ@!|DiHR`AW2cobj_;ReR-vR$e(}c>0(7dL}nD+JRT`07pFdJPz?u1J__-#@ntNFCz20Fq*J0IA-= zTC&10OQ~KYO`31(oMAYMmA0Qg*Xq(9#1ls<>Aed9Uc1aYDXT5^T|o6`#1PQ)jPi TO!EgO0tN<8S3j3^P619 delta 1407 zcmV-_1%Ue51)d9#Fn;0U}0flVPWyVrO&9NR4Ne+21}iOAb%Q-_Vx7{e&)jY)TkpE z43-A2*cfrT@pwGET3exTQe?vK*Y8o%sha0x?^w-yFj4eHW2gW?AABa0;qL4l%gf9B zzOuroYZw6UxUc3JB^d``SKVVV6k;b9I|s45hp7TQ9uL`URzCtPhC)1l@eJ>{k3cY3 z_qlX3&SEIUR(~YYeTlowCuW`5Y!;`}sUHEB!ePCCI~uLHzr4K^4l^}5*-cr`1=AT& zK6o($?$6C}S}c-I#_^8(YLt*p#u;(Ck-cM=Vg{Hh;MLj+cW39wX0yD@DEjq&n+@4J zrrUct)jz>b_%~J}Qw0=GiYzZL>+K`$!1Skfq#aN=DSx&pW-VeRDo0gSTrQX4Gxhq- zRw7dc3|z5s%XhZy$?_PAQoHm4X!(8S=jSW>6Y*Hb3UN5>*k8XvIXvX*gIOLue!|B3 zDw`Wy0L*{Cz_Xv80x&%@b=F_lD6pa1D6{l|O5_nRuf;jp9p^&4;ZPMIE9@-xPkjR-Y z!-ft@AQ0%v^edbc+1}o6%Ml6$0yXx3q#bZg8ZvywsNYD2o_2);fk3I;^MuCU=T0of zz!e*AkBrml)IC@u1sIyZKSFox!ggyPa9S+#K7aep(EA*5y6LxloUvl?*=$z#V2v>S z2lN6{lanlk!;HFy^}&~WpxekjZ59jhq=hyG@18eu8&r=g4F-ywAQf{R#H80(xO3 zvVX9!u&}VOu&}VOu=r1MDYr=GO81Wf}X-TY8D5eXBA!%i-jr*Kl#V*nxwBw_)L z((|SY2nK_t3BRAI$w{^%5&Z~ffd?VPMbrTte-`7G{R=iXBNc-e8Et@6s(vCz&{RxN zWO~ap!vME@e(bN`v?+e)yxlw1&#U8rB7Y>-h^AtKqpo3|zj(%|YnanwQ4c=@D2InI zB())a=S&Yw>*peQTRsC`t*tbCN7F%35t2?P;}tQus}E+$W=~P8EhfZrcoVGtw&3Ff$|vqHED>A^;I_3S55PU=ZQ$t3Qmi~3Uh6S zjuIo1{d$cM7l}xn)k~il(esHBGv>cv;P_Yr&P)}~W@^0(mTFp>0oCzyiGQX|K;+*>obGcIrd6hArqJ^H9lfI|6WCSv`0kr| zcGbNKCrAi!5vZ!l%$vsIXDGc;6y*i{)-UECP%Z&B>-k-vSDM7**LP84aE zSCyDyx_=j?a-wWr3|>@TRR<;7Er)BBZU$;h1@6^|kcEYXg@r|T_#2w_qxa3rkskm6 N002ovPDHLkV1mjqvT*#WAE}&fA;bybKCFE(g_aIH=VLv@TfG{$A0W w>8Gz-GcYh@eLMyvfnt~ZjtMEUF)-{%WY)?T;I-A0Ee45uy85}Sb4q9e05)kJdjJ3c delta 129 zcmeBVT+KMauqxHl#WAE}&f8lXc^ec&SOSugvRw~5m~8Vq5~O#~Y@3(`i_7AD<_DhM zI{jaf0SMv+z4KP)t+m#;y7uU#-_0N)1_rAhiy9y0E}N%!`j=}1`SoAF@o#!(YO(%w eha3aL_T3CUlKe&%h9?hz6nnb*xvXK;#J3tWrH3!@SFrl?xRqbOu9vkP_sQLgZ zwAQO;(7+8KJ!e}%q?Qib{xbOG>TrUj6(t5T22^4X6 zdyDyE0ibvlD5Y?!&d}+c|7iu(S^%Zg)+Pu5%^)b+>;M#Qf<|gBzrF$&-#wdUfH^z-o03U9Q8>0X|+!!~;6Pgb<#*NkBDBKt~;s$Lh zQ@Alf5ClOG1VP}z+PF}LB^*JFl^3A=bj{aiahq8GD@+-da0D?<>@a0mLLJ075r8r* zp$=l4d}JX)8J187G1dZ5h9w+9jI{uiVF^bNV=Vw>Si%v+SPMWImT&|y)&fw5B^*Ia z<)g66u!JLssT^WZh9y3N7zswIc0d`HNDw0kf*=T_d;^<`CUbQETe1KE002ovPDHLk FV1jWY7&`y} delta 1338 zcmV-A1;zT11=$LaFn%!$pwi^K0z=5%!~rQ*MYg#01_eXnWKrxv$gzXmgSA_)>)mx7 zlPvB2E;GAh&CEW(H-FxH5D^g(5fSmfWz4Ig-EO04TKl*In17}@Ha6xt%&GI4SA(W$ zZ7CijlgXg#I#N6afDnT3mzM`FMfE&6_vd4<0;lN>x?cKRkZiRupC6QdQMZ z3&2x1RaI^4x{hU8D2jq*SyU<&gb);##?hX}SqrEe>kVXCW@~FJv^L;r0)Xq|6-5DH zaZz{L{p#j!!+-TItPG_A0EsJ*d)8!Al054`=rzDs08%_gVc{~CWwBS?rP(?nm($qT zC=S&5;-XHuYz{4elh}!T1pW*N=h)eK)AzSR)VOu)maF~M_BPGdk>3!3q<5QIqj9RFVSYkX__r)N+U1!MEM@1GFb?Fl*pu(#cXW|Q(YiNoK# z>(JSDv)Qcc{8B6yhg$^0z~Z8g@u7%x<~sMvCgxHLX{RjqByHCT z+<$a`yk%LW(`hD^slYx0U1CpGS9!Fu(g}Be==j`h-`n}wSuPzj@Npc>-G)=|^#fL` zRnqBnU>|`3c(k&@lhsv>^#+AAIt$IFt9>iL>-sUtzQ5qq_o}=9&;Voed0-y{YruE1 z%$H@8@-@lTeptv4G4(O&|>1zJGJq z^_+Xw?k!yh0F3>xP)1=!3My>&2G=YnAIfSS= z&)p_4at*Le0Ngo&c52K?W1j=^`2wQe5kj{K45|UXw->*lqNvyS=G*T8`02+rUBz-)EY2KM~&}Px#_DMuRRCt{2+OZOXFbsg<=;^2qjx0Ql z@BapLaq`rIJb(_aa$Z`}9QOYf1_~FrmTMA30002crcHDJ7Jc8pevL^fnVxBzA5IKa zmGfl~Rh1znQB_I9=a^%4FJNgbf&6gl(`hU^|IIEpm~LOk^AFmy6389 zfQMDh0G&p;?dLc47000000DwPGT*39M6xXOiFH#fqY?gR8Vwx|CvII&l7V&MC)M&&M|0LzvEUD3m oY5p5fJOezNB^xwi0040H2AB(}cg~IGwEzGB07*qoM6N<$f(<}`Bme*a delta 632 zcmV-;0*C#)0+0oeBYy%{NklBjE6vzK^Tgi*28w$-(*@ohRaW*gM61hvi zKqik`0$Q{OLczNhL%%@3gOd){U?gN=MYeH3I=$cY^ai1K zdjETO?+zdcf*|&1U>JgeFEO>M56I2~z!(#k!=V@$hGN9%Y{lX!q-A{CWeAb3A9yt`?Zj=ZaJkI6m%fWe4|*HJ?-&003GC zXkLeys%oYUpzs;6*T-$E?V<-y5Cl<*N$Mph-C9|K{}_hQIxAn6z0b@0z#?nkZ*+i^-Ef#!9Hf6WFw&f#&6=-S?M%~K_B@@rWZMy?BBb@?g${RdN3Eo24& zK)YWDuyHy~8o6%#odd%Vo3cTgDv*|d$2n}r!Pkq6-6fEuOjRH$0o!rn%sproDC#08 zs|w^Do=CHtJ!lmuE1Rl791K;E~hzhr(peRbtwc(8&sGll0< T#mz~RK*~H_{an^LB{Ts5O_nYE diff --git a/Resources/Textures/Structures/Wallmounts/intercom.rsi/unshaded.png b/Resources/Textures/Structures/Wallmounts/intercom.rsi/unshaded.png index 7b0bb630722bb12089a4a1d54ca9eeeaa7d1b32a..a8fda54fc9332fe037dae35c49093bc5c4650995 100644 GIT binary patch delta 177 zcmX@Xbdzy{K|RA{PZ!6KiaBp@IdUCV5MVg4cKw_EpE~Q*o(R8Pna^?C*>m9+v81)7 zY&I_(Lm~=dl^I@KHqoz)yBy|ru!%5L0xcm4M5|1_2Kme%zA z-@4G5fuUhq+rBQjsl8jbSxZmpJ^DbA0R$Yb)N20w8UA9{QLRZ)#qz&=*QIS-GTZ6Q d1+a96k delta 289 zcmV++0p9-E0muT7Fn<98Nkl}OyzoZF}khCwnw&_Cz0002prA4W+F-=R0Qf>EXH1*&`RYmVy z3_{TN#q0UEhC>lPcMNq?624npsppbgj?veF+byiNfC000000084ji}I`EXQ#FQ2J!L~Ha14JRfw?NpCNr*7@7UD7XwPN zywg|eRAuO$v?%qoS<8O8kU>+mU5)wYIiUU5+Tf|`!Yc670JxwIfOZJLq~?It;V2>^ n+p21=z0-9S02%-Q06cXAB#Z2r?C8JM00000NkvXXu0mjf+scRB From 6baccfc565bb8d5e9f8a3226819d8a37293acf02 Mon Sep 17 00:00:00 2001 From: PJBot Date: Sun, 7 Jul 2024 14:20:16 +0000 Subject: [PATCH 086/765] Automatic changelog update --- Resources/Changelog/Changelog.yml | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index f5387d8fdb7..70c1904899b 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,11 +1,4 @@ Entries: -- author: metalgearsloth - changes: - - message: Fix lobby UI not resetting for character changes. - type: Fix - id: 6379 - time: '2024-04-18T03:01:12.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/27075 - author: TokenStyle changes: - message: Benzene is no longer required for the Insuzine recipe. @@ -3818,3 +3811,13 @@ id: 6878 time: '2024-07-07T13:06:24.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/29737 +- author: EmoGarbage404 + changes: + - message: Intercoms now use encryption keys to determine what channels they can + broadcast on. + type: Tweak + - message: Intercoms and handheld radios no longer rely on telecom servers. + type: Fix + id: 6879 + time: '2024-07-07T14:19:10.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/29580 From 7d74de8f5a9587fa2e6049c6068a9447ca2bdaec Mon Sep 17 00:00:00 2001 From: Verm <32827189+Vermidia@users.noreply.github.com> Date: Sun, 7 Jul 2024 09:21:53 -0500 Subject: [PATCH 087/765] Bartending+: Shaking and Stirring (#29243) * Shaking and Stirring * Remove shake message * Switch if order a bit * Add doafter supprot for reactionmixer * Fix nullability * Timespan zero * Forgot to remove loc string * Reorganize usings * Remove unneeded usings, fix b52 needing to be shaken --- .../EntitySystems/ReactionMixerSystem.cs | 57 +++++++++++++++---- .../Reaction/ReactionMixerComponent.cs | 21 +++++++ .../chemistry/components/mixing-component.ftl | 3 + .../Prototypes/Chemistry/mixing_types.yml | 14 +++++ .../Consumable/Drinks/drinks_special.yml | 6 +- .../Entities/Objects/Misc/utensils.yml | 15 +++++ .../Prototypes/Recipes/Reactions/drinks.yml | 54 ++++++++++++++++++ 7 files changed, 159 insertions(+), 11 deletions(-) diff --git a/Content.Server/Chemistry/EntitySystems/ReactionMixerSystem.cs b/Content.Server/Chemistry/EntitySystems/ReactionMixerSystem.cs index d5f7655f884..a81f38a21d4 100644 --- a/Content.Server/Chemistry/EntitySystems/ReactionMixerSystem.cs +++ b/Content.Server/Chemistry/EntitySystems/ReactionMixerSystem.cs @@ -1,6 +1,9 @@ +using Content.Shared.Chemistry.Components; using Content.Shared.Chemistry.Reaction; +using Content.Shared.DoAfter; using Content.Shared.IdentityManagement; using Content.Shared.Interaction; +using Content.Shared.Nutrition.EntitySystems; using Content.Server.Chemistry.Containers.EntitySystems; using Content.Server.Popups; @@ -10,34 +13,68 @@ public sealed partial class ReactionMixerSystem : EntitySystem { [Dependency] private readonly PopupSystem _popup = default!; [Dependency] private readonly SolutionContainerSystem _solutionContainers = default!; + [Dependency] private readonly SharedDoAfterSystem _doAfterSystem = default!; public override void Initialize() { base.Initialize(); SubscribeLocalEvent(OnAfterInteract); + SubscribeLocalEvent(OnShake); + SubscribeLocalEvent(OnDoAfter); } private void OnAfterInteract(Entity entity, ref AfterInteractEvent args) { - if (!args.Target.HasValue || !args.CanReach) + if (!args.Target.HasValue || !args.CanReach || !entity.Comp.MixOnInteract) return; - var mixAttemptEvent = new MixingAttemptEvent(entity); - RaiseLocalEvent(entity, ref mixAttemptEvent); - if (mixAttemptEvent.Cancelled) - { + if (!MixAttempt(entity, args.Target.Value, out var solution)) return; - } - if (!_solutionContainers.TryGetMixableSolution(args.Target.Value, out var solution, out _)) + var doAfterArgs = new DoAfterArgs(EntityManager, args.User, entity.Comp.TimeToMix, new ReactionMixDoAfterEvent(), entity, args.Target.Value, entity); + + _doAfterSystem.TryStartDoAfter(doAfterArgs); + } + + private void OnDoAfter(Entity entity, ref ReactionMixDoAfterEvent args) + { + //Do again to get the solution again + if (!MixAttempt(entity, args.Target!.Value, out var solution)) return; - _popup.PopupEntity(Loc.GetString(entity.Comp.MixMessage, ("mixed", Identity.Entity(args.Target.Value, EntityManager)), ("mixer", Identity.Entity(entity.Owner, EntityManager))), args.User, args.User); + _popup.PopupEntity(Loc.GetString(entity.Comp.MixMessage, ("mixed", Identity.Entity(args.Target!.Value, EntityManager)), ("mixer", Identity.Entity(entity.Owner, EntityManager))), args.User, args.User); + + _solutionContainers.UpdateChemicals(solution!.Value, true, entity.Comp); + + var afterMixingEvent = new AfterMixingEvent(entity, args.Target!.Value); + RaiseLocalEvent(entity, afterMixingEvent); + } + + private void OnShake(Entity entity, ref ShakeEvent args) + { + if (!MixAttempt(entity, entity, out var solution)) + return; - _solutionContainers.UpdateChemicals(solution.Value, true, entity.Comp); + _solutionContainers.UpdateChemicals(solution!.Value, true, entity.Comp); - var afterMixingEvent = new AfterMixingEvent(entity, args.Target.Value); + var afterMixingEvent = new AfterMixingEvent(entity, entity); RaiseLocalEvent(entity, afterMixingEvent); } + + private bool MixAttempt(EntityUid ent, EntityUid target, out Entity? solution) + { + solution = null; + var mixAttemptEvent = new MixingAttemptEvent(ent); + RaiseLocalEvent(ent, ref mixAttemptEvent); + if (mixAttemptEvent.Cancelled) + { + return false; + } + + if (!_solutionContainers.TryGetMixableSolution(target, out solution, out _)) + return false; + + return true; + } } diff --git a/Content.Shared/Chemistry/Reaction/ReactionMixerComponent.cs b/Content.Shared/Chemistry/Reaction/ReactionMixerComponent.cs index 118f2240610..8edfa44ce85 100644 --- a/Content.Shared/Chemistry/Reaction/ReactionMixerComponent.cs +++ b/Content.Shared/Chemistry/Reaction/ReactionMixerComponent.cs @@ -1,5 +1,7 @@ using Content.Shared.Chemistry.Components; +using Content.Shared.DoAfter; using Robust.Shared.Prototypes; +using Robust.Shared.Serialization; namespace Content.Shared.Chemistry.Reaction; @@ -19,9 +21,28 @@ public sealed partial class ReactionMixerComponent : Component [ViewVariables] [DataField] public LocId MixMessage = "default-mixing-success"; + + /// + /// Defines if interacting is enough to mix with this component + /// + [ViewVariables] + [DataField] + public bool MixOnInteract = true; + + /// + /// How long it takes to mix with this + /// + [ViewVariables] + [DataField] + public TimeSpan TimeToMix = TimeSpan.Zero; } [ByRefEvent] public record struct MixingAttemptEvent(EntityUid Mixed, bool Cancelled = false); public readonly record struct AfterMixingEvent(EntityUid Mixed, EntityUid Mixer); + +[Serializable, NetSerializable] +public sealed partial class ReactionMixDoAfterEvent : SimpleDoAfterEvent +{ +} diff --git a/Resources/Locale/en-US/chemistry/components/mixing-component.ftl b/Resources/Locale/en-US/chemistry/components/mixing-component.ftl index a486ed8ede3..c434246fab7 100644 --- a/Resources/Locale/en-US/chemistry/components/mixing-component.ftl +++ b/Resources/Locale/en-US/chemistry/components/mixing-component.ftl @@ -6,9 +6,12 @@ mixing-verb-default-condense = condense mixing-verb-centrifuge = centrifugation mixing-verb-electrolysis = electrolyze mixing-verb-holy = bless +mixing-verb-stir = stir +mixing-verb-shake = shake ## Entity default-mixing-success = You mix the {$mixed} with the {$mixer} bible-mixing-success = You bless the {$mixed} with the {$mixer} +spoon-mixing-success = You stir the {$mixed} with the {$mixer} diff --git a/Resources/Prototypes/Chemistry/mixing_types.yml b/Resources/Prototypes/Chemistry/mixing_types.yml index 20d58e70abd..fd732564108 100644 --- a/Resources/Prototypes/Chemistry/mixing_types.yml +++ b/Resources/Prototypes/Chemistry/mixing_types.yml @@ -51,3 +51,17 @@ icon: sprite: Objects/Specific/Chapel/bible.rsi state: icon + +- type: mixingCategory + id: Shake + verbText: mixing-verb-shake + icon: + sprite: Objects/Consumable/Drinks/shaker.rsi + state: icon + +- type: mixingCategory + id: Stir + verbText: mixing-verb-stir + icon: + sprite: Objects/Misc/utensils.rsi + state: spoon diff --git a/Resources/Prototypes/Entities/Objects/Consumable/Drinks/drinks_special.yml b/Resources/Prototypes/Entities/Objects/Consumable/Drinks/drinks_special.yml index d2c1249740e..604ae28fb30 100644 --- a/Resources/Prototypes/Entities/Objects/Consumable/Drinks/drinks_special.yml +++ b/Resources/Prototypes/Entities/Objects/Consumable/Drinks/drinks_special.yml @@ -11,7 +11,7 @@ - type: MixableSolution solution: drink - type: Drink - - type: Shakeable # Doesn't do anything, but I mean... + - type: Shakeable - type: FitsInDispenser solution: drink - type: DrawableSolution @@ -34,6 +34,10 @@ - type: PhysicalComposition materialComposition: Steel: 50 + - type: ReactionMixer + mixOnInteract: false + reactionTypes: + - Shake - type: entity parent: DrinkGlassBase diff --git a/Resources/Prototypes/Entities/Objects/Misc/utensils.yml b/Resources/Prototypes/Entities/Objects/Misc/utensils.yml index 86667f094fd..e735b2dcddc 100644 --- a/Resources/Prototypes/Entities/Objects/Misc/utensils.yml +++ b/Resources/Prototypes/Entities/Objects/Misc/utensils.yml @@ -87,6 +87,11 @@ Blunt: 1 - type: Shovel speedModifier: 0.1 # you can try + - type: ReactionMixer + mixMessage: "spoon-mixing-success" + timeToMix: 0.5 + reactionTypes: + - Stir - type: entity parent: UtensilBasePlastic @@ -103,6 +108,11 @@ - Spoon - type: Shovel speedModifier: 0.1 # you can try + - type: ReactionMixer + mixMessage: "spoon-mixing-success" + timeToMix: 0.5 + reactionTypes: + - Stir - type: entity parent: UtensilBasePlastic @@ -137,6 +147,11 @@ - type: Utensil types: - Spoon + - type: ReactionMixer + mixMessage: "spoon-mixing-success" + timeToMix: 0.5 + reactionTypes: + - Stir - type: MeleeWeapon wideAnimationRotation: 180 attackRate: 2 diff --git a/Resources/Prototypes/Recipes/Reactions/drinks.yml b/Resources/Prototypes/Recipes/Reactions/drinks.yml index 2a14c0ecd29..96cc5b6aaa4 100644 --- a/Resources/Prototypes/Recipes/Reactions/drinks.yml +++ b/Resources/Prototypes/Recipes/Reactions/drinks.yml @@ -10,6 +10,8 @@ - type: reaction id: AlliesCocktail + requiredMixerCategories: + - Shake reactants: Martini: amount: 2 @@ -20,6 +22,8 @@ - type: reaction id: Amasec + requiredMixerCategories: + - Shake reactants: Wine: amount: 2 @@ -32,6 +36,8 @@ - type: reaction id: Andalusia + requiredMixerCategories: + - Stir reactants: Rum: amount: 1 @@ -98,6 +104,8 @@ - type: reaction id: BlueHawaiian + requiredMixerCategories: + - Shake reactants: CoconutRum: amount: 2 @@ -126,6 +134,8 @@ - type: reaction id: BahamaMama + requiredMixerCategories: + - Shake reactants: Ice: amount: 1 @@ -168,6 +178,8 @@ - type: reaction id: BeepskySmash + requiredMixerCategories: + - Shake reactants: Iron: amount: 1 @@ -190,6 +202,8 @@ - type: reaction id: BloodyMary + requiredMixerCategories: + - Stir reactants: JuiceLime: amount: 1 @@ -280,6 +294,8 @@ - type: reaction id: DemonsBlood + requiredMixerCategories: + - Stir reactants: Rum: amount: 1 @@ -294,6 +310,8 @@ - type: reaction id: DevilsKiss + requiredMixerCategories: + - Stir reactants: Rum: amount: 1 @@ -306,6 +324,8 @@ - type: reaction id: DoctorsDelight + requiredMixerCategories: + - Stir reactants: Cream: amount: 2 @@ -322,6 +342,8 @@ - type: reaction id: DriestMartini + requiredMixerCategories: + - Shake reactants: Gin: amount: 1 @@ -332,6 +354,8 @@ - type: reaction id: ErikaSurprise + requiredMixerCategories: + - Shake reactants: Ale: amount: 2 @@ -373,6 +397,8 @@ - type: reaction id: GargleBlaster + requiredMixerCategories: + - Shake reactants: Cognac: amount: 1 @@ -411,6 +437,8 @@ - type: reaction id: Gildlager + requiredMixerCategories: + - Shake reactants: Gold: amount: 1 @@ -548,6 +576,8 @@ - type: reaction id: IrishCoffee + requiredMixerCategories: + - Stir reactants: Coffee: amount: 1 @@ -568,6 +598,8 @@ - type: reaction id: KiraSpecial + requiredMixerCategories: + - Stir reactants: JuiceLime: amount: 1 @@ -580,6 +612,8 @@ - type: reaction id: Lemonade + requiredMixerCategories: + - Stir reactants: JuiceLemon: amount: 1 @@ -592,6 +626,8 @@ - type: reaction id: LemonLime + requiredMixerCategories: + - Stir reactants: JuiceLemon: amount: 1 @@ -604,6 +640,8 @@ - type: reaction id: LongIslandIcedTea + requiredMixerCategories: + - Stir reactants: CubaLibre: amount: 3 @@ -618,6 +656,8 @@ - type: reaction id: Manhattan + requiredMixerCategories: + - Shake reactants: Whiskey: amount: 2 @@ -658,6 +698,8 @@ - type: reaction id: Martini + requiredMixerCategories: + - Shake reactants: Gin: amount: 2 @@ -679,6 +721,8 @@ - type: reaction id: Mojito + requiredMixerCategories: + - Shake reactants: JuiceLime: amount: 1 @@ -726,6 +770,8 @@ - type: reaction id: Patron + requiredMixerCategories: + - Shake reactants: Tequila: amount: 10 @@ -736,6 +782,8 @@ - type: reaction id: Painkiller + requiredMixerCategories: + - Shake reactants: JuicePineapple: amount: 3 @@ -838,6 +886,8 @@ - type: reaction id: ScrewdriverCocktail + requiredMixerCategories: + - Shake reactants: JuiceOrange: amount: 2 @@ -955,6 +1005,8 @@ - type: reaction id: ToxinsSpecial + requiredMixerCategories: + - Shake reactants: Rum: amount: 2 @@ -967,6 +1019,8 @@ - type: reaction id: VodkaMartini + requiredMixerCategories: + - Shake reactants: Vermouth: amount: 1 From 91ae1ece5b343b3f0053c15dcb53b230d36f14d3 Mon Sep 17 00:00:00 2001 From: NotSoDamn <75203942+NotSoDana@users.noreply.github.com> Date: Sun, 7 Jul 2024 16:22:38 +0200 Subject: [PATCH 088/765] Slicing food with Swords (#29005) * added utensil component * BaseSword added --- .../Entities/Objects/Weapons/Melee/sword.yml | 53 ++++++++----------- 1 file changed, 22 insertions(+), 31 deletions(-) diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Melee/sword.yml b/Resources/Prototypes/Entities/Objects/Weapons/Melee/sword.yml index 5ffe16d3b53..0d710b0d3cc 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Melee/sword.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Melee/sword.yml @@ -1,15 +1,28 @@ - type: entity - name: captain's sabre parent: BaseItem + id: BaseSword + abstract: true + components: + - type: Sharp + - type: MeleeWeapon + wideAnimationRotation: -135 + - type: Sprite + state: icon + - type: Item + size: Normal + - type: Utensil + types: + - Knife + +- type: entity + name: captain's sabre + parent: BaseSword id: CaptainSabre description: A ceremonial weapon belonging to the captain of the station. components: - - type: Sharp - type: Sprite sprite: Objects/Weapons/Melee/captain_sabre.rsi - state: icon - type: MeleeWeapon - wideAnimationRotation: -135 attackRate: 1.5 damage: types: @@ -21,7 +34,6 @@ reflectProb: .1 spread: 90 - type: Item - size: Normal sprite: Objects/Weapons/Melee/captain_sabre.rsi - type: Tag tags: @@ -30,26 +42,22 @@ - type: entity name: katana - parent: BaseItem + parent: BaseSword id: Katana description: Ancient craftwork made with not so ancient plasteel. components: - - type: Sharp - type: Tag tags: - Katana - type: Sprite sprite: DeltaV/Objects/Weapons/Melee/katana.rsi #DeltaV - state: icon - type: MeleeWeapon - wideAnimationRotation: -135 damage: types: Slash: 15 soundHit: path: /Audio/Weapons/bladeslice.ogg - type: Item - size: Normal sprite: DeltaV/Objects/Weapons/Melee/katana.rsi #DeltaV - type: DisarmMalus @@ -61,14 +69,12 @@ components: - type: Sprite sprite: Objects/Weapons/Melee/energykatana.rsi - state: icon - type: MeleeWeapon wideAnimationRotation: -60 damage: types: Slash: 30 - type: Item - size: Normal sprite: Objects/Weapons/Melee/energykatana.rsi - type: EnergyKatana - type: DashAbility @@ -86,41 +92,34 @@ - type: entity name: machete - parent: BaseItem + parent: BaseSword id: Machete description: A large, vicious looking blade. components: - - type: Sharp - type: Tag tags: - Machete - type: Sprite sprite: Objects/Weapons/Melee/machete.rsi - state: icon - type: MeleeWeapon - wideAnimationRotation: -135 damage: types: Slash: 15 soundHit: path: /Audio/Weapons/bladeslice.ogg - type: Item - size: Normal sprite: Objects/Weapons/Melee/machete.rsi - type: DisarmMalus - type: entity name: claymore - parent: BaseItem + parent: BaseSword id: Claymore description: An ancient war blade. components: - - type: Sharp - type: Sprite sprite: Objects/Weapons/Melee/claymore.rsi - state: icon - type: MeleeWeapon - wideAnimationRotation: -135 attackRate: 0.75 damage: types: @@ -128,7 +127,6 @@ soundHit: path: /Audio/Weapons/bladeslice.ogg - type: Item - size: Normal - type: Clothing sprite: Objects/Weapons/Melee/claymore.rsi slots: @@ -137,41 +135,34 @@ - type: entity name: cutlass - parent: BaseItem + parent: BaseSword id: Cutlass description: A wickedly curved blade, often seen in the hands of space pirates. components: - - type: Sharp - type: Tag tags: - Machete - type: Sprite sprite: Objects/Weapons/Melee/cutlass.rsi - state: icon - type: MeleeWeapon - wideAnimationRotation: -135 damage: types: Slash: 16 soundHit: path: /Audio/Weapons/bladeslice.ogg - type: Item - size: Normal sprite: Objects/Weapons/Melee/cutlass.rsi - type: DisarmMalus - type: entity name: The Throngler - parent: BaseItem + parent: BaseSword id: Throngler description: Why would you make this? components: - - type: Sharp - type: Sprite sprite: Objects/Weapons/Melee/Throngler2.rsi - state: icon - type: MeleeWeapon - wideAnimationRotation: -135 attackRate: 10 damage: types: From 7090f6885f9425b4f782665bb19e6e24fb449ef0 Mon Sep 17 00:00:00 2001 From: Brandon Hu <103440971+Brandon-Huu@users.noreply.github.com> Date: Sun, 7 Jul 2024 14:23:03 +0000 Subject: [PATCH 089/765] fix(hardsuits): Give the carp suit and hardsuit a suit storage slot (#29322) * fix(hardsuits): Give the carp hardsuit suit storage * Both carpsuits have suit slots --- Resources/Prototypes/Entities/Clothing/OuterClothing/suits.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/Resources/Prototypes/Entities/Clothing/OuterClothing/suits.yml b/Resources/Prototypes/Entities/Clothing/OuterClothing/suits.yml index 79c116b3cad..2053ced0f63 100644 --- a/Resources/Prototypes/Entities/Clothing/OuterClothing/suits.yml +++ b/Resources/Prototypes/Entities/Clothing/OuterClothing/suits.yml @@ -246,6 +246,7 @@ name: carp suit description: A special suit that makes you look just like a space carp, if your eyesight is bad. components: + - type: AllowSuitStorage - type: Sprite sprite: Clothing/OuterClothing/Suits/carpsuit.rsi - type: Item From 45087d534d3f0cddeb716837922abd3fd6ad4716 Mon Sep 17 00:00:00 2001 From: PJBot Date: Sun, 7 Jul 2024 14:23:44 +0000 Subject: [PATCH 090/765] Automatic changelog update --- Resources/Changelog/Changelog.yml | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 70c1904899b..8b060381ade 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,18 +1,4 @@ Entries: -- author: TokenStyle - changes: - - message: Benzene is no longer required for the Insuzine recipe. - type: Tweak - id: 6380 - time: '2024-04-18T03:03:39.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/26829 -- author: Golinth - changes: - - message: The Nukie Agent now comes with a medihud built into their visor! - type: Add - id: 6381 - time: '2024-04-18T03:04:14.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/26218 - author: Krunk changes: - message: Cyborgs no longer see criminal status icons. @@ -3821,3 +3807,18 @@ id: 6879 time: '2024-07-07T14:19:10.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/29580 +- author: Vermidia + changes: + - message: Some drink reactions now require shaking with the shaker or stirring + with a spoon + type: Add + id: 6880 + time: '2024-07-07T14:21:53.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/29243 +- author: Dezzzix + changes: + - message: Now you can slice food with swords + type: Add + id: 6881 + time: '2024-07-07T14:22:38.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/29005 From 96e1be9a0a2474f76b5453e8234a31054617f1ee Mon Sep 17 00:00:00 2001 From: Nemanja <98561806+EmoGarbage404@users.noreply.github.com> Date: Sun, 7 Jul 2024 10:26:58 -0400 Subject: [PATCH 091/765] metal foam grenades (#29428) * metal foam grenades * wow okay * meh * bruh * test * push --- .../Effects/AreaReactionEffect.cs | 10 ++-- .../EntitySystems/SmokeOnTriggerSystem.cs | 7 ++- Content.Server/Spreader/SpreaderSystem.cs | 17 ++++++- .../Spreader/EdgeSpreaderPrototype.cs | 6 +++ .../Tiles/ReplaceFloorOnSpawnComponent.cs | 36 +++++++++++++ .../Tiles/ReplaceFloorOnSpawnSystem.cs | 48 ++++++++++++++++++ Resources/Locale/en-US/tiles/tiles.ftl | 3 +- .../Catalog/Cargo/cargo_engineering.yml | 10 ++++ .../Catalog/Fills/Crates/engineering.yml | 11 ++++ .../Entities/Effects/chemistry_effects.yml | 11 +++- .../Objects/Weapons/Throwable/grenades.yml | 15 ++++++ Resources/Prototypes/Tiles/floors.yml | 15 ++++++ Resources/Prototypes/edge_spreaders.yml | 5 ++ .../Grenades/metalfoam.rsi/equipped-BELT.png | Bin 0 -> 240 bytes .../Weapons/Grenades/metalfoam.rsi/icon.png | Bin 0 -> 335 bytes .../Weapons/Grenades/metalfoam.rsi/meta.json | 27 ++++++++++ .../Weapons/Grenades/metalfoam.rsi/primed.png | Bin 0 -> 454 bytes Resources/Textures/Tiles/attributions.yml | 10 ++-- Resources/Textures/Tiles/foammetal.png | Bin 0 -> 2491 bytes 19 files changed, 218 insertions(+), 13 deletions(-) create mode 100644 Content.Shared/Tiles/ReplaceFloorOnSpawnComponent.cs create mode 100644 Content.Shared/Tiles/ReplaceFloorOnSpawnSystem.cs create mode 100644 Resources/Textures/Objects/Weapons/Grenades/metalfoam.rsi/equipped-BELT.png create mode 100644 Resources/Textures/Objects/Weapons/Grenades/metalfoam.rsi/icon.png create mode 100644 Resources/Textures/Objects/Weapons/Grenades/metalfoam.rsi/meta.json create mode 100644 Resources/Textures/Objects/Weapons/Grenades/metalfoam.rsi/primed.png create mode 100644 Resources/Textures/Tiles/foammetal.png diff --git a/Content.Server/EntityEffects/Effects/AreaReactionEffect.cs b/Content.Server/EntityEffects/Effects/AreaReactionEffect.cs index 481f1fc27c5..858da2b3605 100644 --- a/Content.Server/EntityEffects/Effects/AreaReactionEffect.cs +++ b/Content.Server/EntityEffects/Effects/AreaReactionEffect.cs @@ -1,4 +1,5 @@ using Content.Server.Fluids.EntitySystems; +using Content.Server.Spreader; using Content.Shared.Audio; using Content.Shared.Coordinates.Helpers; using Content.Shared.Database; @@ -64,16 +65,19 @@ public override void Effect(EntityEffectBaseArgs args) var transform = reagentArgs.EntityManager.GetComponent(reagentArgs.TargetEntity); var mapManager = IoCManager.Resolve(); var mapSys = reagentArgs.EntityManager.System(); - var sys = reagentArgs.EntityManager.System(); + var spreaderSys = args.EntityManager.System(); + var sys = args.EntityManager.System(); var mapCoords = sys.GetMapCoordinates(reagentArgs.TargetEntity, xform: transform); if (!mapManager.TryFindGridAt(mapCoords, out var gridUid, out var grid) || - !mapSys.TryGetTileRef(gridUid, grid, transform.Coordinates, out var tileRef) || - tileRef.Tile.IsSpace()) + !mapSys.TryGetTileRef(gridUid, grid, transform.Coordinates, out var tileRef)) { return; } + if (spreaderSys.RequiresFloorToSpread(_prototypeId) && tileRef.Tile.IsSpace()) + return; + var coords = mapSys.MapToGrid(gridUid, mapCoords); var ent = reagentArgs.EntityManager.SpawnEntity(_prototypeId, coords.SnapToGrid()); diff --git a/Content.Server/Explosion/EntitySystems/SmokeOnTriggerSystem.cs b/Content.Server/Explosion/EntitySystems/SmokeOnTriggerSystem.cs index f958373ac74..3d3c5d85630 100644 --- a/Content.Server/Explosion/EntitySystems/SmokeOnTriggerSystem.cs +++ b/Content.Server/Explosion/EntitySystems/SmokeOnTriggerSystem.cs @@ -1,6 +1,7 @@ using Content.Shared.Explosion.Components; using Content.Shared.Explosion.EntitySystems; using Content.Server.Fluids.EntitySystems; +using Content.Server.Spreader; using Content.Shared.Chemistry.Components; using Content.Shared.Coordinates.Helpers; using Content.Shared.Maps; @@ -17,6 +18,7 @@ public sealed class SmokeOnTriggerSystem : SharedSmokeOnTriggerSystem [Dependency] private readonly IMapManager _mapMan = default!; [Dependency] private readonly SmokeSystem _smoke = default!; [Dependency] private readonly TransformSystem _transform = default!; + [Dependency] private readonly SpreaderSystem _spreader = default!; public override void Initialize() { @@ -31,11 +33,14 @@ private void OnTrigger(EntityUid uid, SmokeOnTriggerComponent comp, TriggerEvent var mapCoords = _transform.GetMapCoordinates(uid, xform); if (!_mapMan.TryFindGridAt(mapCoords, out _, out var grid) || !grid.TryGetTileRef(xform.Coordinates, out var tileRef) || - tileRef.Tile.IsSpace()) + tileRef.Tile.IsEmpty) { return; } + if (_spreader.RequiresFloorToSpread(comp.SmokePrototype.ToString()) && tileRef.Tile.IsSpace()) + return; + var coords = grid.MapToGrid(mapCoords); var ent = Spawn(comp.SmokePrototype, coords.SnapToGrid()); if (!TryComp(ent, out var smoke)) diff --git a/Content.Server/Spreader/SpreaderSystem.cs b/Content.Server/Spreader/SpreaderSystem.cs index 7de8a43d354..50f5d81183b 100644 --- a/Content.Server/Spreader/SpreaderSystem.cs +++ b/Content.Server/Spreader/SpreaderSystem.cs @@ -2,6 +2,7 @@ using Content.Server.Atmos.EntitySystems; using Content.Server.Shuttles.Components; using Content.Shared.Atmos; +using Content.Shared.Maps; using Content.Shared.Spreader; using Content.Shared.Tag; using Robust.Shared.Collections; @@ -175,11 +176,12 @@ private void Spread(EntityUid uid, TransformComponent xform, ProtoId public void GetNeighbors(EntityUid uid, TransformComponent comp, ProtoId prototype, out ValueList<(MapGridComponent, TileRef)> freeTiles, out ValueList occupiedTiles, out ValueList neighbors) { - // TODO remove occupiedTiles -- its currently unused and just slows this method down. - DebugTools.Assert(_prototype.HasIndex(prototype)); freeTiles = []; occupiedTiles = []; neighbors = []; + // TODO remove occupiedTiles -- its currently unused and just slows this method down. + if (!_prototype.TryIndex(prototype, out var spreaderPrototype)) + return; if (!TryComp(comp.GridUid, out var grid)) return; @@ -244,6 +246,9 @@ public void GetNeighbors(EntityUid uid, TransformComponent comp, ProtoId spreader) + { + if (!_prototype.Index(spreader).TryGetComponent(out var spreaderComp, EntityManager.ComponentFactory)) + return false; + + return _prototype.Index(spreaderComp.Id).PreventSpreadOnSpaced; + } } diff --git a/Content.Shared/Spreader/EdgeSpreaderPrototype.cs b/Content.Shared/Spreader/EdgeSpreaderPrototype.cs index fee8f93a6d3..33665d82b5d 100644 --- a/Content.Shared/Spreader/EdgeSpreaderPrototype.cs +++ b/Content.Shared/Spreader/EdgeSpreaderPrototype.cs @@ -10,4 +10,10 @@ public sealed partial class EdgeSpreaderPrototype : IPrototype { [IdDataField] public string ID { get; } = string.Empty; [DataField(required:true)] public int UpdatesPerSecond; + + /// + /// If true, this spreader can't spread onto spaced tiles like lattice. + /// + [DataField] + public bool PreventSpreadOnSpaced = true; } diff --git a/Content.Shared/Tiles/ReplaceFloorOnSpawnComponent.cs b/Content.Shared/Tiles/ReplaceFloorOnSpawnComponent.cs new file mode 100644 index 00000000000..1b87082defa --- /dev/null +++ b/Content.Shared/Tiles/ReplaceFloorOnSpawnComponent.cs @@ -0,0 +1,36 @@ +using Content.Shared.Maps; +using Robust.Shared.GameStates; +using Robust.Shared.Prototypes; + +namespace Content.Shared.Tiles; + +/// +/// Replaces floor tiles around this entity when it spawns +/// +[RegisterComponent, NetworkedComponent, Access(typeof(ReplaceFloorOnSpawnSystem))] +public sealed partial class ReplaceFloorOnSpawnComponent : Component +{ + /// + /// The floor tiles that will be replaced. If null, will replace all. + /// + [DataField] + public List>? ReplaceableTiles = new(); + + /// + /// The tiles that it will replace. Randomly picked from the list. + /// + [DataField] + public List> ReplacementTiles = new(); + + /// + /// Whether or not there has to be a tile in the location to be replaced. + /// + [DataField] + public bool ReplaceSpace = true; + + /// + /// List of offsets from the base tile, used to determine which tiles will be replaced. + /// + [DataField] + public List Offsets = new() { Vector2i.Up, Vector2i.Down, Vector2i.Left, Vector2i.Right, Vector2i.Zero }; +} diff --git a/Content.Shared/Tiles/ReplaceFloorOnSpawnSystem.cs b/Content.Shared/Tiles/ReplaceFloorOnSpawnSystem.cs new file mode 100644 index 00000000000..818991f823d --- /dev/null +++ b/Content.Shared/Tiles/ReplaceFloorOnSpawnSystem.cs @@ -0,0 +1,48 @@ +using Robust.Shared.Map; +using Robust.Shared.Map.Components; +using Robust.Shared.Prototypes; +using Robust.Shared.Random; + +namespace Content.Shared.Tiles; + +public sealed class ReplaceFloorOnSpawnSystem : EntitySystem +{ + [Dependency] private readonly ITileDefinitionManager _tile = default!; + [Dependency] private readonly IPrototypeManager _prototype = default!; + [Dependency] private readonly IRobustRandom _random = default!; + [Dependency] private readonly SharedMapSystem _map = default!; + + /// + public override void Initialize() + { + SubscribeLocalEvent(OnMapInit); + } + + private void OnMapInit(Entity ent, ref MapInitEvent args) + { + var xform = Transform(ent); + if (xform.GridUid is not { } grid || !TryComp(grid, out var gridComp)) + return; + + if (ent.Comp.ReplaceableTiles != null && ent.Comp.ReplaceableTiles.Count == 0) + return; + + var tileIndices = _map.LocalToTile(grid, gridComp, xform.Coordinates); + + foreach (var offset in ent.Comp.Offsets) + { + var actualIndices = tileIndices + offset; + + if (!_map.TryGetTileRef(grid, gridComp, actualIndices, out var tile)) + continue; + + if (ent.Comp.ReplaceableTiles != null && + !tile.Tile.IsEmpty && + !ent.Comp.ReplaceableTiles.Contains(_tile[tile.Tile.TypeId].ID)) + continue; + + var tileToSet = _random.Pick(ent.Comp.ReplacementTiles); + _map.SetTile(grid, gridComp, tile.GridIndices, new Tile(_prototype.Index(tileToSet).TileId)); + } + } +} diff --git a/Resources/Locale/en-US/tiles/tiles.ftl b/Resources/Locale/en-US/tiles/tiles.ftl index e5b6810fcab..35cea19f786 100644 --- a/Resources/Locale/en-US/tiles/tiles.ftl +++ b/Resources/Locale/en-US/tiles/tiles.ftl @@ -87,6 +87,7 @@ tiles-gold-tile = gold tile tiles-silver-tile = silver tile tiles-glass-floor = glass floor tiles-reinforced-glass-floor = reinforced glass floor +tiles-metal-foam = metal foam floor tiles-green-circuit-floor = green circuit floor tiles-blue-circuit-floor = blue circuit floor tiles-snow = snow @@ -126,4 +127,4 @@ tiles-mowed-astro-grass = mowed astro-grass tiles-jungle-astro-grass = jungle astro-grass tiles-astro-ice = astro-ice tiles-astro-snow = astro-snow -tiles-wood-large = large wood \ No newline at end of file +tiles-wood-large = large wood diff --git a/Resources/Prototypes/Catalog/Cargo/cargo_engineering.yml b/Resources/Prototypes/Catalog/Cargo/cargo_engineering.yml index 7ca6af84518..d4e2b4c60dc 100644 --- a/Resources/Prototypes/Catalog/Cargo/cargo_engineering.yml +++ b/Resources/Prototypes/Catalog/Cargo/cargo_engineering.yml @@ -28,6 +28,16 @@ category: cargoproduct-category-name-engineering group: market +- type: cargoProduct + id: EngineeringFoamGrenade + icon: + sprite: Objects/Weapons/Grenades/metalfoam.rsi + state: icon + product: CrateEngineeringFoamGrenade + cost: 2500 + category: cargoproduct-category-name-engineering + group: market + - type: cargoProduct id: EngineeringCableBulk icon: diff --git a/Resources/Prototypes/Catalog/Fills/Crates/engineering.yml b/Resources/Prototypes/Catalog/Fills/Crates/engineering.yml index 26a8910c735..62d07b0beda 100644 --- a/Resources/Prototypes/Catalog/Fills/Crates/engineering.yml +++ b/Resources/Prototypes/Catalog/Fills/Crates/engineering.yml @@ -76,6 +76,17 @@ - id: CableHVStack amount: 3 +- type: entity + id: CrateEngineeringFoamGrenade + parent: CrateEngineeringSecure + name: sealant grenade crate + description: 5 metal foam sealant grenades. + components: + - type: StorageFill + contents: + - id: MetalFoamGrenade + amount: 5 + - type: entity id: CrateEngineeringCableBulk parent: CrateElectrical diff --git a/Resources/Prototypes/Entities/Effects/chemistry_effects.yml b/Resources/Prototypes/Entities/Effects/chemistry_effects.yml index 096e88bcb6f..ee300e9aeaf 100644 --- a/Resources/Prototypes/Entities/Effects/chemistry_effects.yml +++ b/Resources/Prototypes/Entities/Effects/chemistry_effects.yml @@ -101,6 +101,8 @@ state: m_foam-north - map: [ "enum.EdgeLayer.West" ] state: m_foam-west + - type: EdgeSpreader + id: MetalFoam - type: FoamVisuals animationTime: 0.6 animationState: m_foam-dissolve @@ -135,7 +137,7 @@ - type: RCDDeconstructable cost: 2 delay: 2 - fx: EffectRCDDeconstruct2 + fx: EffectRCDDeconstruct2 - type: Clickable - type: InteractionOutline - type: Sprite @@ -159,6 +161,13 @@ - type: Transform anchored: true - type: Airtight + - type: ReplaceFloorOnSpawn + replaceableTiles: + - Plating + - Lattice + - TrainLattice + replacementTiles: + - FloorMetalFoam - type: Damageable damageContainer: Inorganic damageModifierSet: Metallic diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Throwable/grenades.yml b/Resources/Prototypes/Entities/Objects/Weapons/Throwable/grenades.yml index b1d260c3276..eb382c01e5f 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Throwable/grenades.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Throwable/grenades.yml @@ -422,6 +422,21 @@ - ReagentId: TearGas Quantity: 50 +- type: entity + parent: SmokeGrenade + id: MetalFoamGrenade + name: metal foam grenade + description: An emergency tool used for patching up holes. Almost as good as real walls. + components: + - type: Sprite + sprite: Objects/Weapons/Grenades/metalfoam.rsi + - type: SmokeOnTrigger + duration: 10 + spreadAmount: 13 + smokePrototype: AluminiumMetalFoam + - type: StaticPrice + price: 350 + # Non-explosive "dummy" grenades to use as a distraction. - type: entity diff --git a/Resources/Prototypes/Tiles/floors.yml b/Resources/Prototypes/Tiles/floors.yml index 1fc6de09358..49b61a361da 100644 --- a/Resources/Prototypes/Tiles/floors.yml +++ b/Resources/Prototypes/Tiles/floors.yml @@ -1391,6 +1391,21 @@ itemDrop: SheetRGlass1 heatCapacity: 10000 +- type: tile + id: FloorMetalFoam + name: tiles-metal-foam + sprite: /Textures/Tiles/foammetal.png + variants: 1 + placementVariants: + - 1.0 + baseTurf: Plating + isSubfloor: false + deconstructTools: [ Prying ] + footstepSounds: + collection: FootstepHull + itemDrop: SheetSteel1 + heatCapacity: 10000 + # Circuits - type: tile id: FloorGreenCircuit diff --git a/Resources/Prototypes/edge_spreaders.yml b/Resources/Prototypes/edge_spreaders.yml index 061932c706d..c93cc02ba97 100644 --- a/Resources/Prototypes/edge_spreaders.yml +++ b/Resources/Prototypes/edge_spreaders.yml @@ -9,3 +9,8 @@ - type: edgeSpreader id: Smoke updatesPerSecond: 8 + +- type: edgeSpreader + id: MetalFoam + updatesPerSecond: 16 + preventSpreadOnSpaced: false diff --git a/Resources/Textures/Objects/Weapons/Grenades/metalfoam.rsi/equipped-BELT.png b/Resources/Textures/Objects/Weapons/Grenades/metalfoam.rsi/equipped-BELT.png new file mode 100644 index 0000000000000000000000000000000000000000..d3cf1cf4c9329b5e0ba25716b5eee1c78ee13068 GIT binary patch literal 240 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=jKx9jP7LeL$-D%KdAc};RLpsM z%aH3(fB?${*PL9|)pHIVvvbvQoFb#ScKSyxGodw2Q+s=R7qp*vmi%BZ^O*x%b_)Wv zGALgu{W~}MxRUmY*SqpVLob?~O;Pr_IMM7t`rgjB4@Gt-&lZhbk~~v%OZ?o&WwpmY z|2x&Ca|tNDG=K5?-x6(#N^+4Kk6MFFVqj?aKl!8fgfcmO-Php>+n7`SaxIyA-23z| i(HUR1^V5~j%8-*tbW(7bvhNV%u0pUXO@geCxb0bm#a literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Weapons/Grenades/metalfoam.rsi/icon.png b/Resources/Textures/Objects/Weapons/Grenades/metalfoam.rsi/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..a13dedfc2052c67c1346cc71dc821facda8e1cd4 GIT binary patch literal 335 zcmV-V0kHmwP)Px$2}wjjR9J=WmN9F>KorM+X)7^fE3`|<;v}7fF6~#4toAeHqt&T2^b>T~>A+Ir z5Rz&IQCuV?Q735$UG7C1g!@gm{O|qmy?gf#3`o&=USWc^Rn*?F^Jo4}eli5*vUsvGPc0XCMqik|e3mK==NEUgwsZ%PXd< zCF9YMx0h$J0qqj3vTwGQMd38b7IW-87Y7#^u=AX3F~=zi?AA43v(HKfwA;{i-9PWZ zzqO(7`$ugs*XZ%51b4s$Kwg5{XMwh;JPnmn hl}2*y{{e%+um|$mboU?%v_Jp=002ovPDHLkV1h5Fli2_O literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Weapons/Grenades/metalfoam.rsi/meta.json b/Resources/Textures/Objects/Weapons/Grenades/metalfoam.rsi/meta.json new file mode 100644 index 00000000000..139eebb04da --- /dev/null +++ b/Resources/Textures/Objects/Weapons/Grenades/metalfoam.rsi/meta.json @@ -0,0 +1,27 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Created by EmoGarbage404", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "icon" + }, + { + "name": "primed", + "delays": [ + [ + 0.2, + 0.1 + ] + ] + }, + { + "name": "equipped-BELT", + "directions": 4 + } + ] +} diff --git a/Resources/Textures/Objects/Weapons/Grenades/metalfoam.rsi/primed.png b/Resources/Textures/Objects/Weapons/Grenades/metalfoam.rsi/primed.png new file mode 100644 index 0000000000000000000000000000000000000000..dafc378c3bca93b686e1ae223ae5c700132750d1 GIT binary patch literal 454 zcmV;%0XhDOP)Px$fJsC_RA_NHP!xxMt=8C41zkcNoWw~GK}XlpwLZgLeFFO$f)Ai{5Q|UX zDs{S`*mMYqrb4hNSfYu?$v+f9&dqIt=6+L_lkaeHPEKwBgTY`h7z{2}RNxgQNevi@z1uY^XqSt`v zxl0tZQu$ex``&uvWbqUx;b)J)So;A0q?9UdC3O4CI+FU!usfjB>A>^6N#v4?pIw0U zt!>m-*RV78ws;lwRj&M^M;o5q{=y(d% zW&$ZI$_eD{H{Su=fHP)AbM_^~qh7chf$Aj-bK}s8d wnPx;bxA})R7i;>*4dLJ$6Wy6Jbsy3S$7}PJ=3$h<26E(5A7>3pI_4DW7CTV(iJnp-0x816`1_p7G9;c&2U7gNm z7^92tE~ewjdbOI4Ce|3?i6l<*B6rAPLJ%eZ$@B;%QS|ib(@#G6x$wk6Re&8jJ~^fg z80W@X3N(si!C9Uc>QHjdk+s*$B?DGf)nak-^3{t`n%>;pdY-h-CTVJ|1qyB7BZ8f? zd0Ez~ev|Dm#uQ<~g%G|p#u#g*l-teL_vCDLyf`^wjC(>%C(}4iFu@dHyW0^$b+3LdCua<9HYbF1Rm!;9NBgcIbA!2F51y`N?7dgfv~pIM1@8X;h_Z_~7wl zz{FWg2_cmBMpH@=LMNxEwW{yUj*6nRgKqoI4}!LByS5#V$4%QJgaqe|vFT(&0HQc5 zvuu;)G7JdDAAIl=PtaXn5Ik6?2O&HuB|@la8w?bLx7luX+3xnuMm4JId!WD>>${e7 zMhHO&hf%~hQ%c=C`yRqr)oL;xdmhKuR&{lCby*$`d6tnczxvW*r&N8YO3v6Q9aD#^ zaxb_z8c$5GogSL1x>>K9rs;b<7~6F{rBwPdP7*)xn^r|ZfUNBY6Q(1~xI^e-wff~R z|IHu_$hnJ`FI8RNtX7NDJG0pgA;bV?vuT#)&N__HfnXuMw(C4kTIY6ohA_$Y#W+np z;ay!^)^#nUf9Kv^%BXe7Ij7pzA%rj{#+Z923m{YqQB{X*U%bh8##)3>-|H}nDy0k| zhyunWO%euxDGB2+2>dsjH-zB3_wL@gbH|r{zTF1Givu4BO{5P1C-WINxMxigu1?$zO=^7C)1{Bi9^O1O6mOg`276qquJ4+s(fFD zVKAB=DOKm$4lu?br5}ad^Q4r!?babgFz)qG?hllbw(HV3F3Yl|)RSJ{_sF5;a@jTw zW1PehqEHljgi)U7jI-Ttm*+*kFBq_@s)2L9%?syHu`l-f{V)s&Awmg4*g1<3qJ-qz zZQu82XWx7J8`Y-<+h7kY& zMd*j`JxG%zPLi@Lx7#h};2dhZ&N_2!+UrXIyy3T4$|YUODSL=>Y{UMAI~8(DTJf-*(IEYrqKmo^P!c!t;ZW zbLJ4jglOFpN+ftv`p#OV)cMn=fANwu!JmEr&C*y3lYnldtMqzYwbAu6@ zj3;@KPbU+t`yh${VHAZ?6va^#Ypth~Y1elM6NJ$uO&J%vEX%W<@B6y%DW!}tKM0~E zmeLD-N%7I`?JaOt6nPi~z1GGIjZ%laAean&4?t;_?+#Vv2pT16btthzG6;O%-)(o& z_a~#2VCwQAJe`}fl+wC7oZY`))ioOoA(-s814h80*P3u4 z7K>8`kcLUuc0mwQ0AMUiV&Qq5b7L$39fpB3COruNopVQv#hcAWa&LZg6!2!TJf;-F$@K9@AE{Q6+3_qK zjmqjkDe1dbcfIs|LP$IwwbmI5gbP1T2tcFitCugkw#~NNM%8`aE2RLyISUBC{_cVj z9LM3wd`>B4o~OF*?%5g5i~XPe)n9-6Ki_c186j=k_FZ3=hj=_DoC9O&Xk?AqZa0Ub zNTaB0JH{Bn*df>VU3n-$@WtZPW1_4MeiW`>uZkj%Mx+1!;`1aO!JzeOwXW-$=NV&6 z)e1Q@o{aZdRvz|?#ho(Ghd~qT2*TDmLTMZ)M@LiXdFz{Xu`e0po85MGz0C3*_oZrE z-}j>+u*1-|4NyvSRY}ha!pK@9gs{%;>l&G%%8M)2B0?C@KctUP0D!h_*6X$J2U=^O zRCk?f+c-^x;H#@;GD@7Y6gh(NY%&3iF+r&B`nGKeAr>Krki(c!$^i($jPoE2D23f_ zE4XMHb+TAwS+1G}0Q$ZMrOxi%YuaYlYhMTsplY?gUTWQIt-)GLD1G$!!>3Pv-|OBO zb0|wf2xp*bMS)u9q?FQ=n2_t`wL^HhTxzWe#)ML9O?4>uc_yXI_j`hnb@ms3_xGF4 z78pC!HDH7(C2zm|_Txv7&cFVe5PEWQ^5Vsd#p$UhB|<0;qkVm-t6Fejoh6i%d2Woo zd*}46Ke~UtTwPsW9v`0^>S{Wh-`=d>edpamsdPU7@~ht_NrHd+vyZ>|`kZs_`?9L) zKVa~~2M^Q9 Date: Sun, 7 Jul 2024 10:27:52 -0400 Subject: [PATCH 092/765] The real AME nerf (#29587) * The real AME nerf * oh the real change * Update AmeNodeGroup.cs --- Content.Server/Ame/AmeNodeGroup.cs | 27 +++++++------------ .../Ame/EntitySystems/AmeControllerSystem.cs | 20 ++++++++++---- .../Components/AmeFuelContainerComponent.cs | 4 +-- 3 files changed, 26 insertions(+), 25 deletions(-) diff --git a/Content.Server/Ame/AmeNodeGroup.cs b/Content.Server/Ame/AmeNodeGroup.cs index 9acc1034ddf..bb482f7726b 100644 --- a/Content.Server/Ame/AmeNodeGroup.cs +++ b/Content.Server/Ame/AmeNodeGroup.cs @@ -134,22 +134,11 @@ public float InjectFuel(int fuel, out bool overloading) // The AME is being overloaded. // Note about these maths: I would assume the general idea here is to make larger engines less safe to overload. // In other words, yes, those are supposed to be CoreCount, not safeFuelLimit. - var instability = 0; var overloadVsSizeResult = fuel - CoreCount; - // fuel > safeFuelLimit: Slow damage. Can safely run at this level for burst periods if the engine is small and someone is keeping an eye on it. - if (_random.Prob(0.5f)) - instability = 1; - // overloadVsSizeResult > 5: - if (overloadVsSizeResult > 5) - instability = 3; - // overloadVsSizeResult > 10: This will explode in at most 20 injections. - if (overloadVsSizeResult > 10) - instability = 5; - - // Apply calculated instability - if (instability == 0) - return powerOutput; + var instability = overloadVsSizeResult / CoreCount; + var fuzz = _random.Next(-1, 2); // -1 to 1 + instability += fuzz; // fuzz the values a tiny bit. overloading = true; var integrityCheck = 100; @@ -179,10 +168,12 @@ public float InjectFuel(int fuel, out bool overloading) /// public float CalculatePower(int fuel, int cores) { - // Fuel is squared so more fuel vastly increases power and efficiency - // We divide by the number of cores so a larger AME is less efficient at the same fuel settings - // this results in all AMEs having the same efficiency at the same fuel-per-core setting - return 20000f * fuel * fuel / cores; // Delt V - Revert upstream buff for normal AME operation + // Balanced around a single core AME with injection level 2 producing 120KW. + // Overclocking yields diminishing returns until it evens out at around 360KW. + + // The adjustment for cores make it so that a 1 core AME at 2 injections is better than a 2 core AME at 2 injections. + // However, for the relative amounts for each (1 core at 2 and 2 core at 4), more cores has more output. + return 200000f * MathF.Log10(fuel * fuel) * MathF.Pow(0.75f, cores - 1); } public int GetTotalStability() diff --git a/Content.Server/Ame/EntitySystems/AmeControllerSystem.cs b/Content.Server/Ame/EntitySystems/AmeControllerSystem.cs index e6abe98b95c..eda91582739 100644 --- a/Content.Server/Ame/EntitySystems/AmeControllerSystem.cs +++ b/Content.Server/Ame/EntitySystems/AmeControllerSystem.cs @@ -274,9 +274,9 @@ public void SetInjectionAmount(EntityUid uid, int value, EntityUid? user = null, At the time of editing, players regularly "overclock" the AME and those cases require no admin attention. // Admin alert - var safeLimit = 0; + var safeLimit = int.MaxValue; if (TryGetAMENodeGroup(uid, out var group)) - safeLimit = group.CoreCount * 2; + safeLimit = group.CoreCount * 4; if (oldValue <= safeLimit && value > safeLimit) { @@ -291,10 +291,20 @@ public void SetInjectionAmount(EntityUid uid, int value, EntityUid? user = null, */ } - public void AdjustInjectionAmount(EntityUid uid, int delta, int min = 0, int max = int.MaxValue, EntityUid? user = null, AmeControllerComponent? controller = null) + public void AdjustInjectionAmount(EntityUid uid, int delta, EntityUid? user = null, AmeControllerComponent? controller = null) { - if (Resolve(uid, ref controller)) - SetInjectionAmount(uid, MathHelper.Clamp(controller.InjectionAmount + delta, min, max), user, controller); + if (!Resolve(uid, ref controller)) + return; + + var max = GetMaxInjectionAmount((uid, controller)); + SetInjectionAmount(uid, MathHelper.Clamp(controller.InjectionAmount + delta, 0, max), user, controller); + } + + public int GetMaxInjectionAmount(Entity ent) + { + if (!TryGetAMENodeGroup(ent, out var group)) + return 0; + return group.CoreCount * 8; } private void UpdateDisplay(EntityUid uid, int stability, AmeControllerComponent? controller = null, AppearanceComponent? appearance = null) diff --git a/Content.Shared/Ame/Components/AmeFuelContainerComponent.cs b/Content.Shared/Ame/Components/AmeFuelContainerComponent.cs index 757a3a515b6..455414597e5 100644 --- a/Content.Shared/Ame/Components/AmeFuelContainerComponent.cs +++ b/Content.Shared/Ame/Components/AmeFuelContainerComponent.cs @@ -9,11 +9,11 @@ public sealed partial class AmeFuelContainerComponent : Component /// The amount of fuel in the container. /// [DataField, ViewVariables(VVAccess.ReadWrite), AutoNetworkedField] - public int FuelAmount = 1000; + public int FuelAmount = 500; /// /// The maximum fuel capacity of the container. /// [DataField, ViewVariables(VVAccess.ReadWrite), AutoNetworkedField] - public int FuelCapacity = 1000; + public int FuelCapacity = 500; } From e6fb874d617d71d7b6463400640e95aa35edff2e Mon Sep 17 00:00:00 2001 From: Plykiya <58439124+Plykiya@users.noreply.github.com> Date: Sun, 7 Jul 2024 07:28:13 -0700 Subject: [PATCH 093/765] Removes max damage threshold on healing for hyperzine (#29712) * Removes max damage threshold for hyperzine * the description... --------- Co-authored-by: plykiya --- Resources/Locale/en-US/reagents/meta/narcotics.ftl | 2 +- Resources/Prototypes/Reagents/narcotics.yml | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/Resources/Locale/en-US/reagents/meta/narcotics.ftl b/Resources/Locale/en-US/reagents/meta/narcotics.ftl index b48eb03b7df..600ceffce65 100644 --- a/Resources/Locale/en-US/reagents/meta/narcotics.ftl +++ b/Resources/Locale/en-US/reagents/meta/narcotics.ftl @@ -5,7 +5,7 @@ reagent-name-ephedrine = ephedrine reagent-desc-ephedrine = A caffeinated adrenaline stimulator chemical that makes you faster and harder to knock down. Also helps combat narcolepsy at dosages over thirty, at the cost of severe nerval stress. reagent-name-stimulants = hyperzine -reagent-desc-stimulants = A chemical cocktail developed by Donk Co. that allows agents to recover from stuns faster, move more quickly, and grants a small heal while close to critical condition. Due to the complex nature of the chemical, it is much harder for the body to purge naturally. +reagent-desc-stimulants = A chemical cocktail developed by Donk Co. that allows agents to recover from stuns faster, move more quickly, and grants a small heal when you're more dead than alive. Due to the complex nature of the chemical, it is much harder for the body to purge naturally. reagent-name-experimental-stimulants = experimental stimulants reagent-desc-experimental-stimulants = A prototype version of hyperzine. Usage grants virtual immunity to stun weaponry, rapid tissue regeneration, extreme running speed by reducing lactic acid buildup, and a general feeling of euphoria. Side effects may include extreme levels of anticoagulation, tunnel vision, extreme toxin buildup in the bloodstream, and rapid liver death. Do not give to animals. diff --git a/Resources/Prototypes/Reagents/narcotics.yml b/Resources/Prototypes/Reagents/narcotics.yml index e20fb5dd57e..e6a59e5d275 100644 --- a/Resources/Prototypes/Reagents/narcotics.yml +++ b/Resources/Prototypes/Reagents/narcotics.yml @@ -161,8 +161,7 @@ - !type:HealthChange conditions: - !type:TotalDamage - min: 70 - max: 120 # you've got a chance to get out of crit + min: 70 # only heals when you're more dead than alive damage: # heals at the same rate as tricordrazine, doesn't heal poison because if you OD'd I'm not giving you a safety net groups: Burn: -1 From 90a7568e8db2f0666b0906e019852da39f7a8a83 Mon Sep 17 00:00:00 2001 From: PJBot Date: Sun, 7 Jul 2024 14:29:18 +0000 Subject: [PATCH 094/765] Automatic changelog update --- Resources/Changelog/Changelog.yml | 34 ++++++++++++++++++------------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 8b060381ade..c1f6f5632a9 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,18 +1,4 @@ Entries: -- author: Krunk - changes: - - message: Cyborgs no longer see criminal status icons. - type: Remove - id: 6382 - time: '2024-04-18T03:20:44.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/26207 -- author: ArZarLordOfMango - changes: - - message: Added autolathe recipe for beverage jug. - type: Add - id: 6383 - time: '2024-04-18T03:24:15.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/25681 - author: superjj18 changes: - message: Emergency lighting now changes based on station alert level! @@ -3822,3 +3808,23 @@ id: 6881 time: '2024-07-07T14:22:38.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/29005 +- author: EmoGarbage404 + changes: + - message: Changed AME power output. Lower injection amounts now produce more power + but further injections have diminishing returns. + type: Tweak + - message: Increased damage per injection overclocked AMEs. + type: Tweak + - message: Halved fuel per AME jar. + type: Tweak + id: 6882 + time: '2024-07-07T14:27:52.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/29587 +- author: Plykiya + changes: + - message: Hyperzine's effective healing range has been changed from 70 to 120, + to anything above 70 total damage. + type: Tweak + id: 6883 + time: '2024-07-07T14:28:13.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/29712 From 37af3861da7414db37c1f707a1c4a6e15f8ea684 Mon Sep 17 00:00:00 2001 From: Tayrtahn Date: Sun, 7 Jul 2024 23:33:17 -0400 Subject: [PATCH 095/765] Silence ringtones on admin PDAs (#29801) * Silence ringtones on invisible PDAs * Revert "Silence ringtones on invisible PDAs" This reverts commit afc1041f31eebe82e83630a856a8856b877a9826. * Literally just this * Add an admin announcement for news article publishing --- Content.Server/MassMedia/Systems/NewsSystem.cs | 8 ++++++++ Resources/Locale/en-US/mass-media/news-ui.ftl | 1 + Resources/Prototypes/Entities/Objects/Devices/pda.yml | 1 + 3 files changed, 10 insertions(+) diff --git a/Content.Server/MassMedia/Systems/NewsSystem.cs b/Content.Server/MassMedia/Systems/NewsSystem.cs index 0fb5d423949..9f917d6dbfa 100644 --- a/Content.Server/MassMedia/Systems/NewsSystem.cs +++ b/Content.Server/MassMedia/Systems/NewsSystem.cs @@ -20,6 +20,7 @@ using Content.Shared.Popups; using Content.Shared.StationRecords; using Robust.Shared.Audio.Systems; +using Content.Server.Chat.Managers; namespace Content.Server.MassMedia.Systems; @@ -35,6 +36,7 @@ public sealed class NewsSystem : SharedNewsSystem [Dependency] private readonly GameTicker _ticker = default!; [Dependency] private readonly AccessReaderSystem _accessReader = default!; [Dependency] private readonly IdCardSystem _idCardSystem = default!; + [Dependency] private readonly IChatManager _chatManager = default!; public override void Initialize() { @@ -161,6 +163,12 @@ private void OnWriteUiPublishMessage(Entity ent, ref NewsWr $"{ToPrettyString(msg.Actor):actor} created news article {article.Title} by {article.Author}: {article.Content}" ); + _chatManager.SendAdminAnnouncement(Loc.GetString("news-publish-admin-announcement", + ("actor", msg.Actor), + ("title", article.Title), + ("author", article.Author ?? Loc.GetString("news-read-ui-no-author")) + )); + articles.Add(article); var args = new NewsArticlePublishedEvent(article); diff --git a/Resources/Locale/en-US/mass-media/news-ui.ftl b/Resources/Locale/en-US/mass-media/news-ui.ftl index 9f62fe75c0c..1553a24b4af 100644 --- a/Resources/Locale/en-US/mass-media/news-ui.ftl +++ b/Resources/Locale/en-US/mass-media/news-ui.ftl @@ -34,3 +34,4 @@ news-write-ui-richtext-tooltip = News articles support rich text {"[bullet/]bullet[/color]"} news-pda-notification-header = New news article +news-publish-admin-announcement = {$actor} published news article {$title} by {$author}" diff --git a/Resources/Prototypes/Entities/Objects/Devices/pda.yml b/Resources/Prototypes/Entities/Objects/Devices/pda.yml index cbaf8ab40cb..7f74cd995a5 100644 --- a/Resources/Prototypes/Entities/Objects/Devices/pda.yml +++ b/Resources/Prototypes/Entities/Objects/Devices/pda.yml @@ -737,6 +737,7 @@ scanDelay: 0 - type: CartridgeLoader uiKey: enum.PdaUiKey.Key + notificationsEnabled: false preinstalled: - CrewManifestCartridge - NotekeeperCartridge From c35dc1a3c9848ebafa2339ab979089a4ab7b8579 Mon Sep 17 00:00:00 2001 From: PJBot Date: Mon, 8 Jul 2024 03:34:24 +0000 Subject: [PATCH 096/765] Automatic changelog update --- Resources/Changelog/Changelog.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index c1f6f5632a9..335776e58f0 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,11 +1,4 @@ Entries: -- author: superjj18 - changes: - - message: Emergency lighting now changes based on station alert level! - type: Tweak - id: 6384 - time: '2024-04-18T10:50:08.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/26932 - author: Dutch-VanDerLinde changes: - message: Chemists now start with chemical analysis goggles. @@ -3828,3 +3821,10 @@ id: 6883 time: '2024-07-07T14:28:13.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/29712 +- author: Tayrtahn + changes: + - message: Fixed admin ghosts briefly becoming visible when a news article is published. + type: Fix + id: 6884 + time: '2024-07-08T03:33:17.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/29801 From 23a374f7ac633e2897fb3976db9a54f642120ec4 Mon Sep 17 00:00:00 2001 From: JIPDawg <51352440+JIPDawg@users.noreply.github.com> Date: Mon, 8 Jul 2024 03:30:41 -0500 Subject: [PATCH 097/765] Fixed the guide book entry for Diona's blood type (#29805) Fixed the entry for Diona's blood type Co-authored-by: JIP --- Resources/ServerInfo/Guidebook/Mobs/Diona.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Resources/ServerInfo/Guidebook/Mobs/Diona.xml b/Resources/ServerInfo/Guidebook/Mobs/Diona.xml index 575fae561ad..eedf23b14f2 100644 --- a/Resources/ServerInfo/Guidebook/Mobs/Diona.xml +++ b/Resources/ServerInfo/Guidebook/Mobs/Diona.xml @@ -7,7 +7,7 @@ They can't wear shoes, but are not slowed by Kudzu. They get hungry and thirsty slower. - Their "blood" is normal water and can't be metabolised from Iron. + Their "blood" is tree sap and can't be metabolised from Iron. Being plants, Weed Killer poisons them, while Robust Harvest heals them (but not without risk when overused!) They take [color=#1e90ff]30% less Blunt damage and 20% less Slash damage[/color]; From f84b23cd3837c8b2dcd75395835b429a890edf7d Mon Sep 17 00:00:00 2001 From: slarticodefast <161409025+slarticodefast@users.noreply.github.com> Date: Mon, 8 Jul 2024 11:03:53 +0200 Subject: [PATCH 098/765] Improve throwing precision (#29726) * improve throwing precision * remove debugging logs * minor fixes * f * Update Content.Shared/Throwing/LandAtCursorComponent.cs --------- Co-authored-by: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com> --- .../Throwing/ThrownItemVisualizerSystem.cs | 1 - Content.Server/Hands/Systems/HandsSystem.cs | 8 +- Content.Server/Lube/LubedSystem.cs | 2 +- .../EntitySystems/ContainmentFieldSystem.cs | 2 +- .../Hands/Components/HandsComponent.cs | 6 +- Content.Shared/Throwing/BeforeThrowEvent.cs | 6 +- .../Throwing/LandAtCursorComponent.cs | 12 +++ Content.Shared/Throwing/ThrowingSystem.cs | 80 +++++++++++++------ Content.Shared/Throwing/ThrownItemSystem.cs | 2 +- .../Prototypes/Entities/Objects/Fun/darts.yml | 1 + .../Prototypes/Entities/Objects/Misc/pen.yml | 1 + .../Objects/Specific/Janitorial/janitor.yml | 1 + .../Guns/Ammunition/Projectiles/toy.yml | 1 + .../Entities/Objects/Weapons/Melee/knife.yml | 3 + .../Entities/Objects/Weapons/Melee/spear.yml | 1 + .../Objects/Weapons/Throwable/bola.yml | 2 +- .../Objects/Weapons/Throwable/clusterbang.yml | 2 + .../Weapons/Throwable/throwing_stars.yml | 1 + 18 files changed, 93 insertions(+), 39 deletions(-) create mode 100644 Content.Shared/Throwing/LandAtCursorComponent.cs diff --git a/Content.Client/Throwing/ThrownItemVisualizerSystem.cs b/Content.Client/Throwing/ThrownItemVisualizerSystem.cs index b25b4fbb7de..28a07ae94a7 100644 --- a/Content.Client/Throwing/ThrownItemVisualizerSystem.cs +++ b/Content.Client/Throwing/ThrownItemVisualizerSystem.cs @@ -59,7 +59,6 @@ private void OnShutdown(EntityUid uid, ThrownItemComponent component, ComponentS if (length <= TimeSpan.Zero) return null; - length += TimeSpan.FromSeconds(ThrowingSystem.FlyTime); var scale = ent.Comp2.Scale; var lenFloat = (float) length.TotalSeconds; diff --git a/Content.Server/Hands/Systems/HandsSystem.cs b/Content.Server/Hands/Systems/HandsSystem.cs index feae130ce8e..e2bb991318f 100644 --- a/Content.Server/Hands/Systems/HandsSystem.cs +++ b/Content.Server/Hands/Systems/HandsSystem.cs @@ -207,13 +207,13 @@ hands.ActiveHandEntity is not { } throwEnt || var length = direction.Length(); var distance = Math.Clamp(length, minDistance, hands.ThrowRange); - direction *= distance/length; + direction *= distance / length; - var throwStrength = hands.ThrowForceMultiplier; + var throwSpeed = hands.BaseThrowspeed; // Let other systems change the thrown entity (useful for virtual items) // or the throw strength. - var ev = new BeforeThrowEvent(throwEnt, direction, throwStrength, player); + var ev = new BeforeThrowEvent(throwEnt, direction, throwSpeed, player); RaiseLocalEvent(player, ref ev); if (ev.Cancelled) @@ -223,7 +223,7 @@ hands.ActiveHandEntity is not { } throwEnt || if (IsHolding(player, throwEnt, out _, hands) && !TryDrop(player, throwEnt, handsComp: hands)) return false; - _throwingSystem.TryThrow(ev.ItemUid, ev.Direction, ev.ThrowStrength, ev.PlayerUid); + _throwingSystem.TryThrow(ev.ItemUid, ev.Direction, ev.ThrowSpeed, ev.PlayerUid, compensateFriction: !HasComp(ev.ItemUid)); return true; } diff --git a/Content.Server/Lube/LubedSystem.cs b/Content.Server/Lube/LubedSystem.cs index c2d15c8a284..3c536dcceb2 100644 --- a/Content.Server/Lube/LubedSystem.cs +++ b/Content.Server/Lube/LubedSystem.cs @@ -43,7 +43,7 @@ private void OnHandPickUp(EntityUid uid, LubedComponent component, ContainerGett var user = args.Container.Owner; _transform.SetCoordinates(uid, Transform(user).Coordinates); _transform.AttachToGridOrMap(uid); - _throwing.TryThrow(uid, _random.NextVector2(), strength: component.SlipStrength); + _throwing.TryThrow(uid, _random.NextVector2(), baseThrowSpeed: component.SlipStrength); _popup.PopupEntity(Loc.GetString("lube-slip", ("target", Identity.Entity(uid, EntityManager))), user, user, PopupType.MediumCaution); } diff --git a/Content.Server/Singularity/EntitySystems/ContainmentFieldSystem.cs b/Content.Server/Singularity/EntitySystems/ContainmentFieldSystem.cs index 3944e94c20d..0af49545190 100644 --- a/Content.Server/Singularity/EntitySystems/ContainmentFieldSystem.cs +++ b/Content.Server/Singularity/EntitySystems/ContainmentFieldSystem.cs @@ -37,7 +37,7 @@ private void HandleFieldCollide(EntityUid uid, ContainmentFieldComponent compone var fieldDir = Transform(uid).WorldPosition; var playerDir = Transform(otherBody).WorldPosition; - _throwing.TryThrow(otherBody, playerDir-fieldDir, strength: component.ThrowForce); + _throwing.TryThrow(otherBody, playerDir-fieldDir, baseThrowSpeed: component.ThrowForce); } } diff --git a/Content.Shared/Hands/Components/HandsComponent.cs b/Content.Shared/Hands/Components/HandsComponent.cs index 919d55f294a..84a389a39c5 100644 --- a/Content.Shared/Hands/Components/HandsComponent.cs +++ b/Content.Shared/Hands/Components/HandsComponent.cs @@ -38,11 +38,11 @@ public sealed partial class HandsComponent : Component public bool DisableExplosionRecursion = false; /// - /// The amount of throw impulse per distance the player is from the throw target. + /// Modifies the speed at which items are thrown. /// - [DataField("throwForceMultiplier")] + [DataField] [ViewVariables(VVAccess.ReadWrite)] - public float ThrowForceMultiplier { get; set; } = 10f; //should be tuned so that a thrown item lands about under the player's cursor + public float BaseThrowspeed { get; set; } = 10f; /// /// Distance after which longer throw targets stop increasing throw impulse. diff --git a/Content.Shared/Throwing/BeforeThrowEvent.cs b/Content.Shared/Throwing/BeforeThrowEvent.cs index 36e7dd758b8..d2bf2f38b8e 100644 --- a/Content.Shared/Throwing/BeforeThrowEvent.cs +++ b/Content.Shared/Throwing/BeforeThrowEvent.cs @@ -5,17 +5,17 @@ namespace Content.Shared.Throwing; [ByRefEvent] public struct BeforeThrowEvent { - public BeforeThrowEvent(EntityUid itemUid, Vector2 direction, float throwStrength, EntityUid playerUid) + public BeforeThrowEvent(EntityUid itemUid, Vector2 direction, float throwSpeed, EntityUid playerUid) { ItemUid = itemUid; Direction = direction; - ThrowStrength = throwStrength; + ThrowSpeed = throwSpeed; PlayerUid = playerUid; } public EntityUid ItemUid { get; set; } public Vector2 Direction { get; } - public float ThrowStrength { get; set;} + public float ThrowSpeed { get; set;} public EntityUid PlayerUid { get; } public bool Cancelled = false; diff --git a/Content.Shared/Throwing/LandAtCursorComponent.cs b/Content.Shared/Throwing/LandAtCursorComponent.cs new file mode 100644 index 00000000000..f8e99e2fc87 --- /dev/null +++ b/Content.Shared/Throwing/LandAtCursorComponent.cs @@ -0,0 +1,12 @@ +using Robust.Shared.GameStates; + +namespace Content.Shared.Throwing +{ + /// + /// Makes an item land at the cursor when thrown and slide a little further. + /// Without it the item lands slightly in front and stops moving at the cursor. + /// Use this for throwing weapons that should pierce the opponent, for example spears. + /// + [RegisterComponent, NetworkedComponent] + public sealed partial class LandAtCursorComponent : Component { } +} diff --git a/Content.Shared/Throwing/ThrowingSystem.cs b/Content.Shared/Throwing/ThrowingSystem.cs index 7d94ada924d..56bbf4c2bf3 100644 --- a/Content.Shared/Throwing/ThrowingSystem.cs +++ b/Content.Shared/Throwing/ThrowingSystem.cs @@ -1,13 +1,12 @@ using System.Numerics; using Content.Shared.Administration.Logs; using Content.Shared.Camera; +using Content.Shared.CCVar; using Content.Shared.Database; +using Content.Shared.Friction; using Content.Shared.Gravity; -using Content.Shared.Hands.Components; -using Content.Shared.Hands.EntitySystems; -using Content.Shared.Interaction; using Content.Shared.Projectiles; -using Content.Shared.Tag; +using Robust.Shared.Configuration; using Robust.Shared.Map; using Robust.Shared.Physics; using Robust.Shared.Physics.Components; @@ -31,7 +30,10 @@ public sealed class ThrowingSystem : EntitySystem /// The minimum amount of time an entity needs to be thrown before the timer can be run. /// Anything below this threshold never enters the air. /// - public const float FlyTime = 0.15f; + public const float MinFlyTime = 0.15f; + public const float FlyTimePercentage = 0.8f; + + private float _frictionModifier; [Dependency] private readonly IGameTiming _gameTiming = default!; [Dependency] private readonly SharedGravitySystem _gravity = default!; @@ -40,13 +42,23 @@ public sealed class ThrowingSystem : EntitySystem [Dependency] private readonly ThrownItemSystem _thrownSystem = default!; [Dependency] private readonly SharedCameraRecoilSystem _recoil = default!; [Dependency] private readonly ISharedAdminLogManager _adminLogger = default!; + [Dependency] private readonly IConfigurationManager _configManager = default!; + + public override void Initialize() + { + base.Initialize(); + + Subs.CVar(_configManager, CCVars.TileFrictionModifier, value => _frictionModifier = value, true); + } public void TryThrow( EntityUid uid, EntityCoordinates coordinates, - float strength = 1.0f, + float baseThrowSpeed = 10.0f, EntityUid? user = null, float pushbackRatio = PushbackDefault, + float? friction = null, + bool compensateFriction = false, bool recoil = true, bool animated = true, bool playSound = true, @@ -58,7 +70,7 @@ public void TryThrow( if (mapPos.MapId != thrownPos.MapId) return; - TryThrow(uid, mapPos.Position - thrownPos.Position, strength, user, pushbackRatio, recoil: recoil, animated: animated, playSound: playSound, doSpin: doSpin); + TryThrow(uid, mapPos.Position - thrownPos.Position, baseThrowSpeed, user, pushbackRatio, friction, compensateFriction: compensateFriction, recoil: recoil, animated: animated, playSound: playSound, doSpin: doSpin); } /// @@ -66,14 +78,18 @@ public void TryThrow( /// /// The entity being thrown. /// A vector pointing from the entity to its destination. - /// How much the direction vector should be multiplied for velocity. + /// Throw velocity. Gets modified if compensateFriction is true. /// The ratio of impulse applied to the thrower - defaults to 10 because otherwise it's not enough to properly recover from getting spaced + /// friction value used for the distance calculation. If set to null this defaults to the standard tile values + /// True will adjust the throw so the item stops at the target coordinates. False means it will land at the target and keep sliding. /// Whether spin will be applied to the thrown entity. public void TryThrow(EntityUid uid, Vector2 direction, - float strength = 1.0f, + float baseThrowSpeed = 10.0f, EntityUid? user = null, float pushbackRatio = PushbackDefault, + float? friction = null, + bool compensateFriction = false, bool recoil = true, bool animated = true, bool playSound = true, @@ -91,9 +107,10 @@ public void TryThrow(EntityUid uid, physics, Transform(uid), projectileQuery, - strength, + baseThrowSpeed, user, - pushbackRatio, recoil: recoil, animated: animated, playSound: playSound, doSpin: doSpin); + pushbackRatio, + friction, compensateFriction: compensateFriction, recoil: recoil, animated: animated, playSound: playSound, doSpin: doSpin); } /// @@ -101,23 +118,27 @@ public void TryThrow(EntityUid uid, /// /// The entity being thrown. /// A vector pointing from the entity to its destination. - /// How much the direction vector should be multiplied for velocity. + /// Throw velocity. Gets modified if compensateFriction is true. /// The ratio of impulse applied to the thrower - defaults to 10 because otherwise it's not enough to properly recover from getting spaced + /// friction value used for the distance calculation. If set to null this defaults to the standard tile values + /// True will adjust the throw so the item stops at the target coordinates. False means it will land at the target and keep sliding. /// Whether spin will be applied to the thrown entity. public void TryThrow(EntityUid uid, Vector2 direction, PhysicsComponent physics, TransformComponent transform, EntityQuery projectileQuery, - float strength = 1.0f, + float baseThrowSpeed = 10.0f, EntityUid? user = null, float pushbackRatio = PushbackDefault, + float? friction = null, + bool compensateFriction = false, bool recoil = true, bool animated = true, bool playSound = true, bool doSpin = true) { - if (strength <= 0 || direction == Vector2Helpers.Infinity || direction == Vector2Helpers.NaN || direction == Vector2.Zero) + if (baseThrowSpeed <= 0 || direction == Vector2Helpers.Infinity || direction == Vector2Helpers.NaN || direction == Vector2.Zero || friction < 0) return; if ((physics.BodyType & (BodyType.Dynamic | BodyType.KinematicController)) == 0x0) @@ -136,16 +157,22 @@ public void TryThrow(EntityUid uid, Animate = animated, }; - // Estimate time to arrival so we can apply OnGround status and slow it much faster. - var time = direction.Length() / strength; + // if not given, get the default friction value for distance calculation + var tileFriction = friction ?? _frictionModifier * TileFrictionController.DefaultFriction; + + if (tileFriction == 0f) + compensateFriction = false; // cannot calculate this if there is no friction + + // Set the time the item is supposed to be in the air so we can apply OnGround status. + // This is a free parameter, but we should set it to something reasonable. + var flyTime = direction.Length() / baseThrowSpeed; + if (compensateFriction) + flyTime *= FlyTimePercentage; + + if (flyTime < MinFlyTime) + flyTime = 0f; comp.ThrownTime = _gameTiming.CurTime; - // TODO: This is a bandaid, don't do this. - // if you want to force landtime have the caller handle it or add a new method. - // did we launch this with something stronger than our hands? - if (TryComp(comp.Thrower, out var hands) && strength > hands.ThrowForceMultiplier) - comp.LandTime = comp.ThrownTime + TimeSpan.FromSeconds(time); - else - comp.LandTime = time < FlyTime ? default : comp.ThrownTime + TimeSpan.FromSeconds(time - FlyTime); + comp.LandTime = comp.ThrownTime + TimeSpan.FromSeconds(flyTime); comp.PlayLandSound = playSound; AddComp(uid, comp, true); @@ -173,7 +200,12 @@ public void TryThrow(EntityUid uid, if (user != null) _adminLogger.Add(LogType.Throw, LogImpact.Low, $"{ToPrettyString(user.Value):user} threw {ToPrettyString(uid):entity}"); - var impulseVector = direction.Normalized() * strength * physics.Mass; + // if compensateFriction==true compensate for the distance the item will slide over the floor after landing by reducing the throw speed accordingly. + // else let the item land on the cursor and from where it slides a little further. + // This is an exact formula we get from exponentially decaying velocity after landing. + // If someone changes how tile friction works at some point, this will have to be adjusted. + var throwSpeed = compensateFriction ? direction.Length() / (flyTime + 1 / tileFriction) : baseThrowSpeed; + var impulseVector = direction.Normalized() * throwSpeed * physics.Mass; _physics.ApplyLinearImpulse(uid, impulseVector, body: physics); if (comp.LandTime == null || comp.LandTime <= TimeSpan.Zero) diff --git a/Content.Shared/Throwing/ThrownItemSystem.cs b/Content.Shared/Throwing/ThrownItemSystem.cs index ef28db26727..6b6f321e127 100644 --- a/Content.Shared/Throwing/ThrownItemSystem.cs +++ b/Content.Shared/Throwing/ThrownItemSystem.cs @@ -156,7 +156,7 @@ public override void Update(float frameTime) LandComponent(uid, thrown, physics, thrown.PlayLandSound); } - var stopThrowTime = (thrown.LandTime ?? thrown.ThrownTime) + TimeSpan.FromSeconds(ThrowingSystem.FlyTime); + var stopThrowTime = thrown.LandTime ?? thrown.ThrownTime; if (stopThrowTime <= _gameTiming.CurTime) { StopThrow(uid, thrown); diff --git a/Resources/Prototypes/Entities/Objects/Fun/darts.yml b/Resources/Prototypes/Entities/Objects/Fun/darts.yml index c0b5eb33999..dd25d503ce2 100644 --- a/Resources/Prototypes/Entities/Objects/Fun/darts.yml +++ b/Resources/Prototypes/Entities/Objects/Fun/darts.yml @@ -10,6 +10,7 @@ offset: 0.0,0.0 - type: ThrowingAngle angle: 315 + - type: LandAtCursor - type: Fixtures fixtures: fix1: diff --git a/Resources/Prototypes/Entities/Objects/Misc/pen.yml b/Resources/Prototypes/Entities/Objects/Misc/pen.yml index 635df230a4a..187672ec4dd 100644 --- a/Resources/Prototypes/Entities/Objects/Misc/pen.yml +++ b/Resources/Prototypes/Entities/Objects/Misc/pen.yml @@ -29,6 +29,7 @@ removalTime: 0.0 - type: ThrowingAngle angle: 315 + - type: LandAtCursor - type: DamageOtherOnHit damage: types: diff --git a/Resources/Prototypes/Entities/Objects/Specific/Janitorial/janitor.yml b/Resources/Prototypes/Entities/Objects/Specific/Janitorial/janitor.yml index f4cc09430a2..2a6f314904a 100644 --- a/Resources/Prototypes/Entities/Objects/Specific/Janitorial/janitor.yml +++ b/Resources/Prototypes/Entities/Objects/Specific/Janitorial/janitor.yml @@ -238,6 +238,7 @@ embedOnThrow: True - type: ThrowingAngle angle: 0 + - type: LandAtCursor - type: Ammo muzzleFlash: null - type: Projectile diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Projectiles/toy.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Projectiles/toy.yml index 9b6c288e378..14595bd34a2 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Projectiles/toy.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Projectiles/toy.yml @@ -31,3 +31,4 @@ removalTime: .2 - type: ThrowingAngle angle: 180 + - type: LandAtCursor diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Melee/knife.yml b/Resources/Prototypes/Entities/Objects/Weapons/Melee/knife.yml index afe4644517c..f862a0f10aa 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Melee/knife.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Melee/knife.yml @@ -92,6 +92,7 @@ Slash: 12 - type: EmbeddableProjectile sound: /Audio/Weapons/star_hit.ogg + - type: LandAtCursor - type: DamageOtherOnHit damage: types: @@ -150,6 +151,7 @@ damage: types: Slash: 10 + - type: LandAtCursor - type: Sprite sprite: Clothing/Head/Hats/greyflatcap.rsi - type: Clothing @@ -274,6 +276,7 @@ Slash: 5 - type: EmbeddableProjectile sound: /Audio/Weapons/star_hit.ogg + - type: LandAtCursor - type: DamageOtherOnHit ignoreResistances: true damage: diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Melee/spear.yml b/Resources/Prototypes/Entities/Objects/Weapons/Melee/spear.yml index 0def916ddc7..ea2e73ac151 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Melee/spear.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Melee/spear.yml @@ -8,6 +8,7 @@ offset: 0.15,0.15 - type: ThrowingAngle angle: 225 + - type: LandAtCursor - type: Tag tags: - Spear diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Throwable/bola.yml b/Resources/Prototypes/Entities/Objects/Weapons/Throwable/bola.yml index ca3edf68c0d..fea9a8d5ea3 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Throwable/bola.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Throwable/bola.yml @@ -47,4 +47,4 @@ staminaDamage: 55 # Sudden weight increase sapping stamina canThrowTrigger: true canMoveBreakout: true - + - type: LandAtCursor diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Throwable/clusterbang.yml b/Resources/Prototypes/Entities/Objects/Weapons/Throwable/clusterbang.yml index 35174ba34d2..cc55aab237c 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Throwable/clusterbang.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Throwable/clusterbang.yml @@ -96,6 +96,7 @@ damage: types: Blunt: 10 + - type: LandAtCursor - type: Damageable damageContainer: Inorganic - type: EmitSoundOnTrigger @@ -224,6 +225,7 @@ damage: types: Blunt: 10 + - type: LandAtCursor - type: EmitSoundOnTrigger sound: path: "/Audio/Effects/flash_bang.ogg" diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Throwable/throwing_stars.yml b/Resources/Prototypes/Entities/Objects/Weapons/Throwable/throwing_stars.yml index c68feff0b5c..0dfc9a0312f 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Throwable/throwing_stars.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Throwable/throwing_stars.yml @@ -31,6 +31,7 @@ friction: 0.2 - type: EmbeddableProjectile sound: /Audio/Weapons/star_hit.ogg + - type: LandAtCursor - type: DamageOtherOnHit damage: types: From 6056436c6922d42783a764750b9609cca218f2c5 Mon Sep 17 00:00:00 2001 From: PJBot Date: Mon, 8 Jul 2024 09:04:59 +0000 Subject: [PATCH 099/765] Automatic changelog update --- Resources/Changelog/Changelog.yml | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 335776e58f0..d9c904f7902 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,11 +1,4 @@ Entries: -- author: Dutch-VanDerLinde - changes: - - message: Chemists now start with chemical analysis goggles. - type: Tweak - id: 6385 - time: '2024-04-18T10:52:33.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/27047 - author: TheShuEd changes: - message: botanist can now mutate blood tomatoes into killer tomatoes! they will @@ -3828,3 +3821,12 @@ id: 6884 time: '2024-07-08T03:33:17.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/29801 +- author: slarticodefast + changes: + - message: Improved throwing calculations. Thrown items now stop moving exactly + below your cursor. Throwing weapons will land at your cursor and then slide + until stopped by friction. + type: Tweak + id: 6885 + time: '2024-07-08T09:03:53.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/29726 From 07d20a188122499801a4d2c0fbde9d67b8ef40a6 Mon Sep 17 00:00:00 2001 From: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com> Date: Tue, 9 Jul 2024 04:05:01 +1000 Subject: [PATCH 100/765] Don't treat vgroid as station grid (#29811) Forgot I added this toggle. --- .../Prototypes/Entities/Stations/base.yml | 35 ++++++++----------- 1 file changed, 15 insertions(+), 20 deletions(-) diff --git a/Resources/Prototypes/Entities/Stations/base.yml b/Resources/Prototypes/Entities/Stations/base.yml index 40d5e3b6746..e6cb659500b 100644 --- a/Resources/Prototypes/Entities/Stations/base.yml +++ b/Resources/Prototypes/Entities/Stations/base.yml @@ -46,31 +46,13 @@ path: /Maps/Shuttles/cargo.yml - type: GridSpawn groups: - vgroid: !type:DungeonSpawnGroup - minimumDistance: 1000 - nameDataset: names_borer - addComponents: - - type: Gravity - enabled: true - inherent: true - protos: - - VGRoid - trade: !type:GridSpawnGroup - addComponents: - - type: ProtectedGrid - - type: TradeStation - paths: - - /Maps/Shuttles/trading_outpost.yml - mining: !type:GridSpawnGroup - paths: - - /Maps/Shuttles/mining.yml -# trade: +# trade: # DeltaV - trade station has its own map # addComponents: # - type: ProtectedGrid # - type: TradeStation # paths: # - /Maps/Shuttles/trading_outpost.yml -# mining: +# mining: # DeltaV - no salv ship # paths: # - /Maps/Shuttles/mining.yml # Spawn last @@ -81,13 +63,26 @@ maxCount: 2 stationGrid: false paths: + #- /Maps/Ruins/chunked_tcomms.yml # TODO - /Maps/Ruins/DeltaV/biodome_satellite.yml #Delta V - Move to DV folder - /Maps/Ruins/DeltaV/derelict.yml #Delta V - Move to DV folder - /Maps/Ruins/DeltaV/djstation.yml #Delta V - Move to DV folder + #- /Maps/Ruins/empty_flagship.yml # TODO - /Maps/Ruins/DeltaV/old_ai_sat.yml #Delta V - Move to DV folder - /Maps/Ruins/DeltaV/relaystation.yml #Delta V - Move to DV folder + #- /Maps/Ruins/syndicate_dropship.yml # TODO - /Maps/Ruins/DeltaV/whiteship_ancient.yml #Delta V - Move to DV folder - /Maps/Ruins/DeltaV/whiteship_bluespacejumper.yml #Delta V - Move to DV folder + vgroid: !type:DungeonSpawnGroup + minimumDistance: 1000 + nameDataset: names_borer + stationGrid: false + addComponents: + - type: Gravity + enabled: true + inherent: true + protos: + - VGRoid - type: entity id: BaseStationCentcomm From 3d0daf454c6bffb7a6e4be570f252435020fed26 Mon Sep 17 00:00:00 2001 From: Errant <35878406+Errant-4@users.noreply.github.com> Date: Tue, 9 Jul 2024 02:28:33 +0200 Subject: [PATCH 101/765] Vox guidebook entry (#29713) * vox guidebook entry * skreee * Removed incorrect diet reference --- Resources/Prototypes/Guidebook/species.yml | 6 ++++++ Resources/ServerInfo/Guidebook/Mobs/Species.xml | 1 + Resources/ServerInfo/Guidebook/Mobs/Vox.xml | 16 ++++++++++++++++ 3 files changed, 23 insertions(+) create mode 100644 Resources/ServerInfo/Guidebook/Mobs/Vox.xml diff --git a/Resources/Prototypes/Guidebook/species.yml b/Resources/Prototypes/Guidebook/species.yml index 8562feb3f41..6f120cc2325 100644 --- a/Resources/Prototypes/Guidebook/species.yml +++ b/Resources/Prototypes/Guidebook/species.yml @@ -10,6 +10,7 @@ - Moth - Reptilian - SlimePerson + - Vox # DeltaV additions - Vulpkanin - Harpy @@ -50,3 +51,8 @@ id: SlimePerson name: species-name-slime text: "/ServerInfo/Guidebook/Mobs/SlimePerson.xml" + +- type: guideEntry + id: Vox + name: species-name-vox + text: "/ServerInfo/Guidebook/Mobs/Vox.xml" diff --git a/Resources/ServerInfo/Guidebook/Mobs/Species.xml b/Resources/ServerInfo/Guidebook/Mobs/Species.xml index aa7b824250a..e6b489817fe 100644 --- a/Resources/ServerInfo/Guidebook/Mobs/Species.xml +++ b/Resources/ServerInfo/Guidebook/Mobs/Species.xml @@ -13,6 +13,7 @@ + # Delta-V specific species diff --git a/Resources/ServerInfo/Guidebook/Mobs/Vox.xml b/Resources/ServerInfo/Guidebook/Mobs/Vox.xml new file mode 100644 index 00000000000..173ba89b411 --- /dev/null +++ b/Resources/ServerInfo/Guidebook/Mobs/Vox.xml @@ -0,0 +1,16 @@ + + # Vox + + + + + + [color=#ffa500]Caution! This species has a severely limiting game mechanic and is not recommended for new players. [/color] + + They breathe nitrogen, and [color=#ffa500] oxygen is very toxic to them.[/color] + They need to be on internals at all times to avoid being poisoned by the station's oxygen. + Eating or drinking will require you to remove your breath mask, although injecting liquid food is an option. + + Their unarmed claw attacks deal Slash damage instead of Blunt. + + From 60bba797aa49c1f4232ffdb5d149e51fba1daae1 Mon Sep 17 00:00:00 2001 From: PJBot Date: Tue, 9 Jul 2024 00:29:39 +0000 Subject: [PATCH 102/765] Automatic changelog update --- Resources/Changelog/Changelog.yml | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index d9c904f7902..4f27c925c4e 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,12 +1,4 @@ Entries: -- author: TheShuEd - changes: - - message: botanist can now mutate blood tomatoes into killer tomatoes! they will - be personal pets, aggressively defending the owner from any social interactions. - type: Add - id: 6386 - time: '2024-04-18T11:21:56.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/26053 - author: TheShuEd changes: - message: Now winter around Europa is different every round @@ -3830,3 +3822,10 @@ id: 6885 time: '2024-07-08T09:03:53.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/29726 +- author: Errant + changes: + - message: Vox now have their entry in the guidebook. + type: Fix + id: 6886 + time: '2024-07-09T00:28:33.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/29713 From 64128ba1baa970eb53b1d3ceac7fd2d9eba17380 Mon Sep 17 00:00:00 2001 From: Whisper <121047731+QuietlyWhisper@users.noreply.github.com> Date: Tue, 9 Jul 2024 00:14:51 -0400 Subject: [PATCH 103/765] all toggle light actions have a 1 second use delay (#29833) --- Resources/Prototypes/Actions/types.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/Resources/Prototypes/Actions/types.yml b/Resources/Prototypes/Actions/types.yml index 4b3d75bf920..07d1a622ada 100644 --- a/Resources/Prototypes/Actions/types.yml +++ b/Resources/Prototypes/Actions/types.yml @@ -37,6 +37,7 @@ description: Turn the light on and off. components: - type: InstantAction + useDelay: 1 icon: { sprite: Objects/Tools/flashlight.rsi, state: flashlight } iconOn: { sprite: Objects/Tools/flashlight.rsi, state: flashlight-on } event: !type:ToggleActionEvent From 60e25fbdc85845492c16042d818d6bfd6e2801d9 Mon Sep 17 00:00:00 2001 From: PJBot Date: Tue, 9 Jul 2024 04:15:58 +0000 Subject: [PATCH 104/765] Automatic changelog update --- Resources/Changelog/Changelog.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 4f27c925c4e..ecf5fe58460 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,11 +1,4 @@ Entries: -- author: TheShuEd - changes: - - message: Now winter around Europa is different every round - type: Tweak - id: 6387 - time: '2024-04-18T11:27:54.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/26510 - author: Flareguy changes: - message: The Research Director's hardsuit is now 5x5 in the inventory instead @@ -3829,3 +3822,10 @@ id: 6886 time: '2024-07-09T00:28:33.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/29713 +- author: Whisper + changes: + - message: Light toggle actions now have a 1 second cooldown between uses. + type: Tweak + id: 6887 + time: '2024-07-09T04:14:51.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/29833 From 01b4922dc0119a972a062d3b67461a1e4be68758 Mon Sep 17 00:00:00 2001 From: Cojoke <83733158+Cojoke-dot@users.noreply.github.com> Date: Mon, 8 Jul 2024 23:23:08 -0500 Subject: [PATCH 105/765] Fix Shotgun Spam Loading (#29827) --- .../Weapons/Ranged/Systems/SharedGunSystem.Ballistic.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.Ballistic.cs b/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.Ballistic.cs index 9123661c8e9..503459cefd9 100644 --- a/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.Ballistic.cs +++ b/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.Ballistic.cs @@ -86,6 +86,9 @@ private void OnBallisticAfterInteract(EntityUid uid, BallisticAmmoProviderCompon private void OnBallisticAmmoFillDoAfter(EntityUid uid, BallisticAmmoProviderComponent component, AmmoFillDoAfterEvent args) { + if (args.Handled || args.Cancelled) + return; + if (Deleted(args.Target) || !TryComp(args.Target, out var target) || target.Whitelist == null) From 986cf27129444f5bcf6be54519d1c58a080ea7d9 Mon Sep 17 00:00:00 2001 From: PJBot Date: Tue, 9 Jul 2024 04:24:14 +0000 Subject: [PATCH 106/765] Automatic changelog update --- Resources/Changelog/Changelog.yml | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index ecf5fe58460..9709740f452 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,12 +1,4 @@ Entries: -- author: Flareguy - changes: - - message: The Research Director's hardsuit is now 5x5 in the inventory instead - of 2x2. You'll need a duffelbag to store it now. - type: Tweak - id: 6388 - time: '2024-04-18T18:05:45.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/27094 - author: Dutch-VanDerLinde changes: - message: Roboticist gear in now available in the scientist loadout. @@ -3829,3 +3821,10 @@ id: 6887 time: '2024-07-09T04:14:51.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/29833 +- author: Cojoke-dot + changes: + - message: Shotgun loading doafter now does something + type: Fix + id: 6888 + time: '2024-07-09T04:23:08.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/29827 From 70b269717c80505b37bf0ec9e051be07a7ee30ab Mon Sep 17 00:00:00 2001 From: lzk <124214523+lzk228@users.noreply.github.com> Date: Tue, 9 Jul 2024 10:41:47 +0200 Subject: [PATCH 107/765] Add popup for healing target (#29804) * Add popup for healing target * hop * huh * fix one * fix showing popup to all --- Content.Server/Medical/HealingSystem.cs | 8 ++++++++ .../Locale/en-US/medical/components/healing-component.ftl | 1 + 2 files changed, 9 insertions(+) diff --git a/Content.Server/Medical/HealingSystem.cs b/Content.Server/Medical/HealingSystem.cs index b89710cc5f2..ab31066cf8a 100644 --- a/Content.Server/Medical/HealingSystem.cs +++ b/Content.Server/Medical/HealingSystem.cs @@ -10,12 +10,14 @@ using Content.Shared.Database; using Content.Shared.DoAfter; using Content.Shared.FixedPoint; +using Content.Shared.IdentityManagement; using Content.Shared.Interaction; using Content.Shared.Interaction.Events; using Content.Shared.Medical; using Content.Shared.Mobs; using Content.Shared.Mobs.Components; using Content.Shared.Mobs.Systems; +using Content.Shared.Popups; using Content.Shared.Stacks; using Robust.Shared.Audio.Systems; using Robust.Shared.Random; @@ -188,6 +190,12 @@ targetDamage.DamageContainerID is not null && var isNotSelf = user != target; + if (isNotSelf) + { + var msg = Loc.GetString("medical-item-popup-target", ("user", Identity.Entity(user, EntityManager)), ("item", uid)); + _popupSystem.PopupEntity(msg, target, target, PopupType.Medium); + } + var delay = isNotSelf ? component.Delay : component.Delay * GetScaledHealingPenalty(user, component); diff --git a/Resources/Locale/en-US/medical/components/healing-component.ftl b/Resources/Locale/en-US/medical/components/healing-component.ftl index 5c2aaaabd9b..1deb39db091 100644 --- a/Resources/Locale/en-US/medical/components/healing-component.ftl +++ b/Resources/Locale/en-US/medical/components/healing-component.ftl @@ -1,3 +1,4 @@ medical-item-finished-using = You have finished healing with the {$item} medical-item-cant-use = There is no damage you can heal with the {$item} medical-item-stop-bleeding = They have stopped bleeding +medical-item-popup-target = {CAPITALIZE(THE($user))} is trying to heal you with the {$item}! From 2d0fc339ed181c602a9071d7a689dd8f46645674 Mon Sep 17 00:00:00 2001 From: lzk <124214523+lzk228@users.noreply.github.com> Date: Tue, 9 Jul 2024 10:42:35 +0200 Subject: [PATCH 108/765] Add popup for health analyzer target (#29803) * Add popup for health analyzer target * addition * fix showing popup to all --- Content.Server/Medical/HealthAnalyzerSystem.cs | 6 ++++++ .../en-US/medical/components/health-analyzer-component.ftl | 2 ++ 2 files changed, 8 insertions(+) diff --git a/Content.Server/Medical/HealthAnalyzerSystem.cs b/Content.Server/Medical/HealthAnalyzerSystem.cs index 7282ea197c9..c72cd2ddf6f 100644 --- a/Content.Server/Medical/HealthAnalyzerSystem.cs +++ b/Content.Server/Medical/HealthAnalyzerSystem.cs @@ -5,10 +5,12 @@ using Content.Server.Temperature.Components; using Content.Shared.Damage; using Content.Shared.DoAfter; +using Content.Shared.IdentityManagement; using Content.Shared.Interaction; using Content.Shared.Interaction.Events; using Content.Shared.MedicalScanner; using Content.Shared.Mobs.Components; +using Content.Shared.Popups; using Content.Shared.PowerCell; using Robust.Server.GameObjects; using Robust.Shared.Audio.Systems; @@ -27,6 +29,7 @@ public sealed class HealthAnalyzerSystem : EntitySystem [Dependency] private readonly SolutionContainerSystem _solutionContainerSystem = default!; [Dependency] private readonly UserInterfaceSystem _uiSystem = default!; [Dependency] private readonly TransformSystem _transformSystem = default!; + [Dependency] private readonly SharedPopupSystem _popupSystem = default!; public override void Initialize() { @@ -85,6 +88,9 @@ private void OnAfterInteract(Entity uid, ref AfterInter NeedHand = true, BreakOnMove = true }); + + var msg = Loc.GetString("health-analyzer-popup-scan-target", ("user", Identity.Entity(args.User, EntityManager))); + _popupSystem.PopupEntity(msg, args.Target.Value, args.Target.Value, PopupType.Medium); } private void OnDoAfter(Entity uid, ref HealthAnalyzerDoAfterEvent args) diff --git a/Resources/Locale/en-US/medical/components/health-analyzer-component.ftl b/Resources/Locale/en-US/medical/components/health-analyzer-component.ftl index 8460bcc27b0..121e50b923e 100644 --- a/Resources/Locale/en-US/medical/components/health-analyzer-component.ftl +++ b/Resources/Locale/en-US/medical/components/health-analyzer-component.ftl @@ -14,3 +14,5 @@ health-analyzer-window-scan-mode-active = ACTIVE health-analyzer-window-scan-mode-inactive = INACTIVE health-analyzer-window-malnutrition = Severely malnourished + +health-analyzer-popup-scan-target = {CAPITALIZE(THE($user))} is trying to scan you! From 1f0d608fcd8f2b2e978d107e0cd15254f2af3fe8 Mon Sep 17 00:00:00 2001 From: chavonadelal <156101927+chavonadelal@users.noreply.github.com> Date: Tue, 9 Jul 2024 16:36:33 +0300 Subject: [PATCH 109/765] localization and change of appearance of the phrase about the remaining time (#29844) --- .../Communications/UI/CommunicationsConsoleMenu.xaml.cs | 4 +++- .../en-US/communications/communications-console-component.ftl | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/Content.Client/Communications/UI/CommunicationsConsoleMenu.xaml.cs b/Content.Client/Communications/UI/CommunicationsConsoleMenu.xaml.cs index 4d8dd86a4dc..bbca06f5194 100644 --- a/Content.Client/Communications/UI/CommunicationsConsoleMenu.xaml.cs +++ b/Content.Client/Communications/UI/CommunicationsConsoleMenu.xaml.cs @@ -113,7 +113,9 @@ public void UpdateCountdown() } EmergencyShuttleButton.Text = Loc.GetString("comms-console-menu-recall-shuttle"); - CountdownLabel.SetMessage($"Time remaining\n{Owner.Countdown.ToString()}s"); + var infoText = Loc.GetString($"comms-console-menu-time-remaining", + ("time", Owner.Countdown.ToString())); + CountdownLabel.SetMessage(infoText); } public override void Close() diff --git a/Resources/Locale/en-US/communications/communications-console-component.ftl b/Resources/Locale/en-US/communications/communications-console-component.ftl index bead43df286..d3200914b3c 100644 --- a/Resources/Locale/en-US/communications/communications-console-component.ftl +++ b/Resources/Locale/en-US/communications/communications-console-component.ftl @@ -5,6 +5,7 @@ comms-console-menu-announcement-button = Announce comms-console-menu-broadcast-button = Broadcast comms-console-menu-call-shuttle = Call emergency shuttle comms-console-menu-recall-shuttle = Recall emergency shuttle +comms-console-menu-time-remaining = Time remaining: {$time} # Popup comms-console-permission-denied = Permission denied From dd3e88d44029c1bdb45ce53635c0d2a9f1dfb1ad Mon Sep 17 00:00:00 2001 From: chavonadelal <156101927+chavonadelal@users.noreply.github.com> Date: Tue, 9 Jul 2024 16:37:00 +0300 Subject: [PATCH 110/765] Action menu localization (#29839) --- .../UserInterface/Systems/Actions/Windows/ActionsWindow.xaml | 2 +- .../Systems/Actions/Windows/ActionsWindow.xaml.cs | 2 +- Resources/Locale/en-US/actions/ui/actionmenu.ftl | 5 +++++ 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/Content.Client/UserInterface/Systems/Actions/Windows/ActionsWindow.xaml b/Content.Client/UserInterface/Systems/Actions/Windows/ActionsWindow.xaml index 52346adba27..443b79242e7 100644 --- a/Content.Client/UserInterface/Systems/Actions/Windows/ActionsWindow.xaml +++ b/Content.Client/UserInterface/Systems/Actions/Windows/ActionsWindow.xaml @@ -3,7 +3,7 @@ xmlns:windows="clr-namespace:Content.Client.UserInterface.Systems.Actions.Windows" Name="ActionsList" HorizontalExpand="True" - Title="Actions" + Title="{Loc ui-actionmenu-title}" VerticalExpand="True" Resizable="True" MinHeight="300" diff --git a/Content.Client/UserInterface/Systems/Actions/Windows/ActionsWindow.xaml.cs b/Content.Client/UserInterface/Systems/Actions/Windows/ActionsWindow.xaml.cs index fbe1e71535d..f972a96eb74 100644 --- a/Content.Client/UserInterface/Systems/Actions/Windows/ActionsWindow.xaml.cs +++ b/Content.Client/UserInterface/Systems/Actions/Windows/ActionsWindow.xaml.cs @@ -26,7 +26,7 @@ public ActionsWindow() foreach (var filter in Enum.GetValues()) { - FilterButton.AddItem(filter.ToString(), filter); + FilterButton.AddItem(Loc.GetString($"ui-actionmenu-{filter.ToString().ToLower()}"), filter); } } diff --git a/Resources/Locale/en-US/actions/ui/actionmenu.ftl b/Resources/Locale/en-US/actions/ui/actionmenu.ftl index a6f0dee5342..47fdb43f699 100644 --- a/Resources/Locale/en-US/actions/ui/actionmenu.ftl +++ b/Resources/Locale/en-US/actions/ui/actionmenu.ftl @@ -9,3 +9,8 @@ ui-actionmenu-clear-button = Clear ui-actionsui-function-lock-action-slots = (Un)lock dragging and clearing action slots ui-actionsui-function-open-abilities-menu = Open action menu +ui-actionmenu-enabled = Enabled +ui-actionmenu-item = Item +ui-actionmenu-innate = Innate +ui-actionmenu-instant = Instant +ui-actionmenu-targeted = Targeted From db895a458445afd1eac0c48c375d45c90d929426 Mon Sep 17 00:00:00 2001 From: slarticodefast <161409025+slarticodefast@users.noreply.github.com> Date: Tue, 9 Jul 2024 15:39:47 +0200 Subject: [PATCH 111/765] fix passive vent sprite in construction menu (#29820) --- Resources/Prototypes/Recipes/Construction/utilities.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Resources/Prototypes/Recipes/Construction/utilities.yml b/Resources/Prototypes/Recipes/Construction/utilities.yml index 82c16de7b6a..930768b3ea7 100644 --- a/Resources/Prototypes/Recipes/Construction/utilities.yml +++ b/Resources/Prototypes/Recipes/Construction/utilities.yml @@ -489,12 +489,12 @@ canBuildInImpassable: false icon: sprite: Structures/Piping/Atmospherics/vent.rsi - state: vent_off + state: vent_passive layers: - sprite: Structures/Piping/Atmospherics/pipe.rsi state: pipeHalf - sprite: Structures/Piping/Atmospherics/vent.rsi - state: vent_off + state: vent_passive conditions: - !type:NoUnstackableInTile From b8e2382a5c4c22ecdefc765d6e4beac8122a9e2f Mon Sep 17 00:00:00 2001 From: PJBot Date: Tue, 9 Jul 2024 13:40:53 +0000 Subject: [PATCH 112/765] Automatic changelog update --- Resources/Changelog/Changelog.yml | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 9709740f452..d84d8423bf3 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,11 +1,4 @@ Entries: -- author: Dutch-VanDerLinde - changes: - - message: Roboticist gear in now available in the scientist loadout. - type: Tweak - id: 6389 - time: '2024-04-18T23:38:17.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/27045 - author: Whisper changes: - message: Raised the difficulty class of RD hardsuit objective, it will be less @@ -3828,3 +3821,11 @@ id: 6888 time: '2024-07-09T04:23:08.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/29827 +- author: slarticodefast + changes: + - message: The construction menu and building preview now show the correct passive + vent sprite. + type: Fix + id: 6889 + time: '2024-07-09T13:39:47.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/29820 From 944e3f49a9d0e15fb565d5d572219744031fc955 Mon Sep 17 00:00:00 2001 From: Cojoke <83733158+Cojoke-dot@users.noreply.github.com> Date: Tue, 9 Jul 2024 08:46:21 -0500 Subject: [PATCH 113/765] Let Pacifists Use Certain Guns(Foam Weapons) (#29835) Let Pacifists Use Certain Guns(foam) --- .../CombatMode/Pacification/PacificationSystem.cs | 3 +++ .../Pacification/PacifismAllowedGunComponent.cs | 11 +++++++++++ Resources/Prototypes/Entities/Objects/Fun/toys.yml | 1 + .../Entities/Objects/Weapons/Guns/Rifles/rifles.yml | 1 + 4 files changed, 16 insertions(+) create mode 100644 Content.Shared/CombatMode/Pacification/PacifismAllowedGunComponent.cs diff --git a/Content.Shared/CombatMode/Pacification/PacificationSystem.cs b/Content.Shared/CombatMode/Pacification/PacificationSystem.cs index 14507ce1f5c..6bc32c5b96c 100644 --- a/Content.Shared/CombatMode/Pacification/PacificationSystem.cs +++ b/Content.Shared/CombatMode/Pacification/PacificationSystem.cs @@ -62,6 +62,9 @@ private void ShowPopup(Entity user, EntityUid target, string private void OnShootAttempt(Entity ent, ref ShotAttemptedEvent args) { + if (HasComp(args.Used)) + return; + // Disallow firing guns in all cases. ShowPopup(ent, args.Used, "pacified-cannot-fire-gun"); args.Cancel(); diff --git a/Content.Shared/CombatMode/Pacification/PacifismAllowedGunComponent.cs b/Content.Shared/CombatMode/Pacification/PacifismAllowedGunComponent.cs new file mode 100644 index 00000000000..7decbeb3bc6 --- /dev/null +++ b/Content.Shared/CombatMode/Pacification/PacifismAllowedGunComponent.cs @@ -0,0 +1,11 @@ +using Robust.Shared.GameStates; + +namespace Content.Shared.CombatMode.Pacification; + +/// +/// Guns with this component can be fired by pacifists +/// +[RegisterComponent, NetworkedComponent] +public sealed partial class PacifismAllowedGunComponent : Component +{ +} diff --git a/Resources/Prototypes/Entities/Objects/Fun/toys.yml b/Resources/Prototypes/Entities/Objects/Fun/toys.yml index d12154ea29d..16c96b2a150 100644 --- a/Resources/Prototypes/Entities/Objects/Fun/toys.yml +++ b/Resources/Prototypes/Entities/Objects/Fun/toys.yml @@ -876,6 +876,7 @@ - type: Sprite - type: Item size: Normal + - type: PacifismAllowedGun - type: entity parent: FoamWeaponBase diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Rifles/rifles.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Rifles/rifles.yml index 46721c041ad..c0e5bf42ee2 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Rifles/rifles.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Rifles/rifles.yml @@ -241,3 +241,4 @@ soundEmpty: path: /Audio/Weapons/Guns/Empty/empty.ogg clumsyProof: true + - type: PacifismAllowedGun From 21510b14f91c027121790face5d93a19edcad384 Mon Sep 17 00:00:00 2001 From: PJBot Date: Tue, 9 Jul 2024 13:47:27 +0000 Subject: [PATCH 114/765] Automatic changelog update --- Resources/Changelog/Changelog.yml | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index d84d8423bf3..abd590c4715 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,12 +1,4 @@ Entries: -- author: Whisper - changes: - - message: Raised the difficulty class of RD hardsuit objective, it will be less - likely to get it with other hard objectives. - type: Tweak - id: 6390 - time: '2024-04-18T23:41:12.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/27103 - author: iztokbajcar changes: - message: Glass textures are now less transparent. @@ -3829,3 +3821,10 @@ id: 6889 time: '2024-07-09T13:39:47.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/29820 +- author: Cojoke-dot + changes: + - message: Pacifists can now use foam weaponry + type: Tweak + id: 6890 + time: '2024-07-09T13:46:21.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/29835 From 8661571bb593bd6c861009a3bcfb2e16d150e66d Mon Sep 17 00:00:00 2001 From: lzk <124214523+lzk228@users.noreply.github.com> Date: Tue, 9 Jul 2024 15:51:03 +0200 Subject: [PATCH 115/765] Fix lobby time typo (#29841) --- Resources/Locale/en-US/lobby/lobby-state.ftl | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/Resources/Locale/en-US/lobby/lobby-state.ftl b/Resources/Locale/en-US/lobby/lobby-state.ftl index 2e60b66bde1..0c4c401daa3 100644 --- a/Resources/Locale/en-US/lobby/lobby-state.ftl +++ b/Resources/Locale/en-US/lobby/lobby-state.ftl @@ -9,7 +9,14 @@ lobby-state-player-status-not-ready = Not Ready lobby-state-player-status-ready = Ready lobby-state-player-status-observer = Observer lobby-state-player-status-round-not-started = The round hasn't started yet -lobby-state-player-status-round-time = The round time is: {$hours} hours and {$minutes} minutes +lobby-state-player-status-round-time = + The round time is: {$hours} {$hours -> + [1]hour + *[other]hours + } and {$minutes} {$minutes -> + [1]minute + *[other]minutes + } lobby-state-song-text = Playing: [color=white]{$songTitle}[/color] by [color=white]{$songArtist}[/color] lobby-state-song-no-song-text = No lobby song playing. lobby-state-song-unknown-title = [color=dimgray]Unknown title[/color] From b2ec9a6551e206d11bbbf792cd182a2d36d892ab Mon Sep 17 00:00:00 2001 From: chavonadelal <156101927+chavonadelal@users.noreply.github.com> Date: Tue, 9 Jul 2024 17:57:36 +0300 Subject: [PATCH 116/765] Localization of the threat level in an emergency lamp (#29847) --- Content.Server/Light/EntitySystems/EmergencyLightSystem.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Content.Server/Light/EntitySystems/EmergencyLightSystem.cs b/Content.Server/Light/EntitySystems/EmergencyLightSystem.cs index f2c4c7dcc59..156088ea072 100644 --- a/Content.Server/Light/EntitySystems/EmergencyLightSystem.cs +++ b/Content.Server/Light/EntitySystems/EmergencyLightSystem.cs @@ -70,7 +70,7 @@ private void OnEmergencyExamine(EntityUid uid, EmergencyLightComponent component args.PushMarkup( Loc.GetString("emergency-light-component-on-examine-alert", ("color", color.ToHex()), - ("level", name))); + ("level", Loc.GetString($"alert-level-{name.ToString().ToLower()}")))); } } @@ -234,6 +234,6 @@ private void TurnOn(Entity entity, Color color) _pointLight.SetColor(entity.Owner, color); _appearance.SetData(entity.Owner, EmergencyLightVisuals.Color, color); _appearance.SetData(entity.Owner, EmergencyLightVisuals.On, true); - _ambient.SetAmbience(entity.Owner, true); + _ambient.SetAmbience(entity.Owner, true); } } From 70296211fa7be43c5d19707d291b274128a60280 Mon Sep 17 00:00:00 2001 From: chavonadelal <156101927+chavonadelal@users.noreply.github.com> Date: Tue, 9 Jul 2024 19:11:07 +0300 Subject: [PATCH 117/765] Nozzle Direction Localization (#29849) --- Content.Server/Shuttles/Systems/ThrusterSystem.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Content.Server/Shuttles/Systems/ThrusterSystem.cs b/Content.Server/Shuttles/Systems/ThrusterSystem.cs index e82235e44f5..fd149630814 100644 --- a/Content.Server/Shuttles/Systems/ThrusterSystem.cs +++ b/Content.Server/Shuttles/Systems/ThrusterSystem.cs @@ -18,6 +18,7 @@ using Robust.Shared.Physics.Systems; using Robust.Shared.Timing; using Robust.Shared.Utility; +using Content.Shared.Localizations; namespace Content.Server.Shuttles.Systems; @@ -67,8 +68,9 @@ private void OnThrusterExamine(EntityUid uid, ThrusterComponent component, Exami EntityManager.TryGetComponent(uid, out TransformComponent? xform) && xform.Anchored) { + var nozzleLocalization = ContentLocalizationManager.FormatDirection(xform.LocalRotation.Opposite().ToWorldVec().GetDir()).ToLower(); var nozzleDir = Loc.GetString("thruster-comp-nozzle-direction", - ("direction", xform.LocalRotation.Opposite().ToWorldVec().GetDir().ToString().ToLowerInvariant())); + ("direction", nozzleLocalization)); args.PushMarkup(nozzleDir); From 2337238cec48e77b3c32c13c85b292a9420d63bf Mon Sep 17 00:00:00 2001 From: Errant <35878406+Errant-4@users.noreply.github.com> Date: Tue, 9 Jul 2024 18:55:47 +0200 Subject: [PATCH 118/765] Aghosts can now /ghost (#29360) I will not be subjected to criminal abuse --- Content.Server/GameTicking/GameTicker.GamePreset.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Content.Server/GameTicking/GameTicker.GamePreset.cs b/Content.Server/GameTicking/GameTicker.GamePreset.cs index 6e297789528..5a2b375dd68 100644 --- a/Content.Server/GameTicking/GameTicker.GamePreset.cs +++ b/Content.Server/GameTicking/GameTicker.GamePreset.cs @@ -226,7 +226,7 @@ public bool OnGhostAttempt(EntityUid mindId, bool canReturnGlobal, bool viaComma return false; } - if (HasComp(playerEntity)) + if (TryComp(playerEntity, out var comp) && !comp.CanGhostInteract) return false; if (mind.VisitingEntity != default) From f68b5a8817894b7d7abdeabb70bdae3489d299eb Mon Sep 17 00:00:00 2001 From: Plykiya <58439124+Plykiya@users.noreply.github.com> Date: Tue, 9 Jul 2024 16:12:40 -0700 Subject: [PATCH 119/765] Stop eating food if you drop it (#29854) * Stop eating food if you drop it * woops, unused param * comments --------- Co-authored-by: plykiya --- Content.Server/Nutrition/EntitySystems/DrinkSystem.cs | 11 ++++++++--- Content.Server/Nutrition/EntitySystems/FoodSystem.cs | 9 ++++++--- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/Content.Server/Nutrition/EntitySystems/DrinkSystem.cs b/Content.Server/Nutrition/EntitySystems/DrinkSystem.cs index b8e334fb0da..d9122ff278c 100644 --- a/Content.Server/Nutrition/EntitySystems/DrinkSystem.cs +++ b/Content.Server/Nutrition/EntitySystems/DrinkSystem.cs @@ -17,6 +17,7 @@ using Content.Shared.DoAfter; using Content.Shared.EntityEffects; using Content.Shared.FixedPoint; +using Content.Shared.Hands.EntitySystems; using Content.Shared.IdentityManagement; using Content.Shared.Interaction; using Content.Shared.Interaction.Events; @@ -48,6 +49,7 @@ public sealed class DrinkSystem : SharedDrinkSystem [Dependency] private readonly SharedAppearanceSystem _appearance = default!; [Dependency] private readonly SharedAudioSystem _audio = default!; [Dependency] private readonly SharedDoAfterSystem _doAfter = default!; + [Dependency] private readonly SharedHandsSystem _hands = default!; [Dependency] private readonly SharedInteractionSystem _interaction = default!; [Dependency] private readonly SolutionContainerSystem _solutionContainer = default!; [Dependency] private readonly StomachSystem _stomach = default!; @@ -156,6 +158,9 @@ public void UpdateAppearance(EntityUid uid, DrinkComponent component) _appearance.SetData(uid, FoodVisuals.Visual, drainAvailable.Float(), appearance); } + /// + /// Tries to feed the drink item to the target entity + /// private bool TryDrink(EntityUid user, EntityUid target, DrinkComponent drink, EntityUid item) { if (!HasComp(target)) @@ -210,9 +215,9 @@ private bool TryDrink(EntityUid user, EntityUid target, DrinkComponent drink, En BreakOnDamage = true, MovementThreshold = 0.01f, DistanceThreshold = 1.0f, - // Mice and the like can eat without hands. - // TODO maybe set this based on some CanEatWithoutHands event or component? - NeedHand = forceDrink, + // do-after will stop if item is dropped when trying to feed someone else + // or if the item started out in the user's own hands + NeedHand = forceDrink || _hands.IsHolding(user, item), }; _doAfter.TryStartDoAfter(doAfterEventArgs); diff --git a/Content.Server/Nutrition/EntitySystems/FoodSystem.cs b/Content.Server/Nutrition/EntitySystems/FoodSystem.cs index 1862b4e19f1..fc9d228b056 100644 --- a/Content.Server/Nutrition/EntitySystems/FoodSystem.cs +++ b/Content.Server/Nutrition/EntitySystems/FoodSystem.cs @@ -99,6 +99,9 @@ private void OnFeedFood(Entity entity, ref AfterInteractEvent arg args.Handled = result.Handled; } + /// + /// Tries to feed the food item to the target entity + /// public (bool Success, bool Handled) TryFeed(EntityUid user, EntityUid target, EntityUid food, FoodComponent foodComp) { //Suppresses eating yourself and alive mobs @@ -189,9 +192,9 @@ private void OnFeedFood(Entity entity, ref AfterInteractEvent arg BreakOnDamage = true, MovementThreshold = 0.01f, DistanceThreshold = MaxFeedDistance, - // Mice and the like can eat without hands. - // TODO maybe set this based on some CanEatWithoutHands event or component? - NeedHand = forceFeed, + // do-after will stop if item is dropped when trying to feed someone else + // or if the item started out in the user's own hands + NeedHand = forceFeed || _hands.IsHolding(user, food), }; _doAfter.TryStartDoAfter(doAfterArgs); From 11d14c37a3e33cef9b43172c2d5fa58e6ed0cef9 Mon Sep 17 00:00:00 2001 From: PJBot Date: Tue, 9 Jul 2024 23:13:46 +0000 Subject: [PATCH 120/765] Automatic changelog update --- Resources/Changelog/Changelog.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index abd590c4715..7cc4cbdef1f 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,11 +1,4 @@ Entries: -- author: iztokbajcar - changes: - - message: Glass textures are now less transparent. - type: Tweak - id: 6391 - time: '2024-04-18T23:43:01.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/26948 - author: SlamBamActionman changes: - message: Snouts and noses no longer disappear with toggled masks. @@ -3828,3 +3821,10 @@ id: 6890 time: '2024-07-09T13:46:21.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/29835 +- author: Plykiya + changes: + - message: You can now drop food and drinks to stop consuming it. + type: Fix + id: 6891 + time: '2024-07-09T23:12:40.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/29854 From ec65a571c7ca3f608fb884fe670a65fbaa6a1511 Mon Sep 17 00:00:00 2001 From: lzk <124214523+lzk228@users.noreply.github.com> Date: Wed, 10 Jul 2024 01:24:38 +0200 Subject: [PATCH 121/765] Fix colornetwork desc and help (#29856) * Fix colornetwork description * suggested changes * forgor * done * ok now it IS done --- Content.Server/Sandbox/Commands/ColorNetworkCommand.cs | 10 ++++------ .../Locale/en-US/commands/colornetwork-command.ftl | 3 +++ 2 files changed, 7 insertions(+), 6 deletions(-) create mode 100644 Resources/Locale/en-US/commands/colornetwork-command.ftl diff --git a/Content.Server/Sandbox/Commands/ColorNetworkCommand.cs b/Content.Server/Sandbox/Commands/ColorNetworkCommand.cs index d5dca64eaac..1fc207058d8 100644 --- a/Content.Server/Sandbox/Commands/ColorNetworkCommand.cs +++ b/Content.Server/Sandbox/Commands/ColorNetworkCommand.cs @@ -9,21 +9,19 @@ namespace Content.Server.Sandbox.Commands { [AnyCommand] - public sealed class ColorNetworkCommand : IConsoleCommand + public sealed class ColorNetworkCommand : LocalizedCommands { [Dependency] private readonly IEntityManager _entManager = default!; - public string Command => "colornetwork"; - public string Description => Loc.GetString("color-network-command-description"); - public string Help => Loc.GetString("color-network-command-help-text", ("command",Command)); + public override string Command => "colornetwork"; - public void Execute(IConsoleShell shell, string argStr, string[] args) + public override void Execute(IConsoleShell shell, string argStr, string[] args) { var sandboxManager = _entManager.System(); var adminManager = IoCManager.Resolve(); if (shell.IsClient && (!sandboxManager.IsSandboxEnabled && !adminManager.HasAdminFlag(shell.Player!, AdminFlags.Mapping))) { - shell.WriteError("You are not currently able to use mapping commands."); + shell.WriteError(Loc.GetString("cmd-colornetwork-no-access")); } if (args.Length != 3) diff --git a/Resources/Locale/en-US/commands/colornetwork-command.ftl b/Resources/Locale/en-US/commands/colornetwork-command.ftl new file mode 100644 index 00000000000..3fd60bcb89f --- /dev/null +++ b/Resources/Locale/en-US/commands/colornetwork-command.ftl @@ -0,0 +1,3 @@ +cmd-colornetwork-desc = Paints the atmos devices in the specified color +cmd-colornetwork-help = colornetwork Pipe +cmd-colornetwork-no-access = You are not currently able to use mapping commands. From 29c4d64c0ce1f1ce9a0acd0f1cf1ffb9abc8dd58 Mon Sep 17 00:00:00 2001 From: Boaz1111 <149967078+Boaz1111@users.noreply.github.com> Date: Wed, 10 Jul 2024 01:28:10 +0200 Subject: [PATCH 122/765] made the guitars be able to be worn on suitstorage (#29048) * made the guitars be able to be worn on suitstorage * minor fix --- .../Fun/Instruments/instruments_string.yml | 4 ++++ .../bassguitar.rsi/equipped-SUITSTORAGE.png | Bin 0 -> 862 bytes .../Fun/Instruments/bassguitar.rsi/meta.json | 4 ++++ .../eguitar.rsi/equipped-SUITSTORAGE.png | Bin 0 -> 845 bytes .../Fun/Instruments/eguitar.rsi/meta.json | 4 ++++ .../guitar.rsi/equipped-SUITSTORAGE.png | Bin 0 -> 1515 bytes .../Objects/Fun/Instruments/guitar.rsi/meta.json | 4 ++++ .../rockguitar.rsi/equipped-SUITSTORAGE.png | Bin 0 -> 803 bytes .../Fun/Instruments/rockguitar.rsi/meta.json | 4 ++++ 9 files changed, 20 insertions(+) create mode 100644 Resources/Textures/Objects/Fun/Instruments/bassguitar.rsi/equipped-SUITSTORAGE.png create mode 100644 Resources/Textures/Objects/Fun/Instruments/eguitar.rsi/equipped-SUITSTORAGE.png create mode 100644 Resources/Textures/Objects/Fun/Instruments/guitar.rsi/equipped-SUITSTORAGE.png create mode 100644 Resources/Textures/Objects/Fun/Instruments/rockguitar.rsi/equipped-SUITSTORAGE.png diff --git a/Resources/Prototypes/Entities/Objects/Fun/Instruments/instruments_string.yml b/Resources/Prototypes/Entities/Objects/Fun/Instruments/instruments_string.yml index 7224efa9e02..6ceb5e23edc 100644 --- a/Resources/Prototypes/Entities/Objects/Fun/Instruments/instruments_string.yml +++ b/Resources/Prototypes/Entities/Objects/Fun/Instruments/instruments_string.yml @@ -21,6 +21,7 @@ quickEquip: false slots: - back + - suitStorage sprite: Objects/Fun/Instruments/eguitar.rsi - type: Tag tags: @@ -50,6 +51,7 @@ quickEquip: false slots: - back + - suitStorage sprite: Objects/Fun/Instruments/bassguitar.rsi - type: Tag tags: @@ -78,6 +80,7 @@ quickEquip: false slots: - back + - suitStorage sprite: Objects/Fun/Instruments/rockguitar.rsi - type: Tag tags: @@ -120,6 +123,7 @@ quickEquip: false slots: - back + - suitStorage sprite: Objects/Fun/Instruments/guitar.rsi - type: Wieldable - type: Damageable # Smash it! Does 20 damage a hit, but breaks after 1 hit. diff --git a/Resources/Textures/Objects/Fun/Instruments/bassguitar.rsi/equipped-SUITSTORAGE.png b/Resources/Textures/Objects/Fun/Instruments/bassguitar.rsi/equipped-SUITSTORAGE.png new file mode 100644 index 0000000000000000000000000000000000000000..72146d40e5a27251471ab50183fd21a0f611e125 GIT binary patch literal 862 zcmV-k1EKthP)R?X_mg)Z_$Q*M$%QQ6~(AfpF|hA}ua9NUMEvJe9Ev(uq%Yo*QPf$8ig zofqJLve8=iEGHD)qFEfTn8oo*)9!1n!yKlRGD@kYvmck+a<-EyrA)P24f|8FiH25b z`Uh5ObJpY95DjtK^@IINI2VQb{OmLUgpus~e#^C3FH}lt;s%S$x{l+d<^VFjG1MQw zzY~6c^xz&kF`P(sr@8^1b%Kn4{%j0O%c~t5PQ=~~4s<$}78hqvC~ zmsVgLXBu!!7UnF ziS9ySq*|@!gb<4;43QIT7G*PDn#9d{_tjtP=dGo& z#`2h}PCJo!Z3-mX;oIv|>%M*IfP?)C#BGVU+hZ3-ZQnVd-2#nkbFOVz7%iKi?pyCZ o&}R`4)csyBfngYiVXhPZ02e#ZDRbKY*8l(j07*qoM6N<$f=Fek;gOdstXE#BFB3PVsDh_5V z4X;B}$k3q(g27@Tf%Xj@I+fc&&TA51UY_wL(QrNpyyTwTd(XM&ocDO=01U%048t%C z0|3b7i>A?-<2Vh+x{c#FCTxFUdif}&j8e)32|JEsq?Gs8001DR3^YP6Uo@m!{a7De zD5Z=L0zwF67iQYM*N&21m_aI)f)E1rM(7LrLy#bGpS&QQj2rqil2J;To&6(JDwV)- z-vB%NNANrkp63C$X$04GV~IopK=+M6N^eY!VqdI(C!j<)KQ!R~_Wa!kyc&B_BWL^W(-L7%Wp|x7 zos64YzG!m!V$&zUsN5+Bq?2*eX{%SeJHs#x!!QiPFbu;m3}c%}HT7PF>T2~ypqgN} z3#7IPe4nSaHlF7pl}h34?CeI-p}sCyDwR6+UQkMDY_1pBAF#E(2LLrS_39IMT{lMM z@TSzptcgNwQ1CPLUgiy#`apFu0)|QI5>!Mxg1)5v+bH;IF4g%gMQ}ST!!QiPFoFC7 X?$d`GV%U4o00000NkvXXu0mjfG|h-o literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Fun/Instruments/eguitar.rsi/meta.json b/Resources/Textures/Objects/Fun/Instruments/eguitar.rsi/meta.json index 0891477f1b5..8723daef066 100644 --- a/Resources/Textures/Objects/Fun/Instruments/eguitar.rsi/meta.json +++ b/Resources/Textures/Objects/Fun/Instruments/eguitar.rsi/meta.json @@ -14,6 +14,10 @@ "name": "equipped-BACKPACK", "directions": 4 }, + { + "name": "equipped-SUITSTORAGE", + "directions": 4 + }, { "name": "inhand-left", "directions": 4 diff --git a/Resources/Textures/Objects/Fun/Instruments/guitar.rsi/equipped-SUITSTORAGE.png b/Resources/Textures/Objects/Fun/Instruments/guitar.rsi/equipped-SUITSTORAGE.png new file mode 100644 index 0000000000000000000000000000000000000000..71667f4e21cef619cd105ef332058d670f6adebd GIT binary patch literal 1515 zcmV~osik1& z3tj^F3E@v`mN65L$M|=B-r-X9c2xEH|K6XgXH~Z}aCHe!YKB=6mT8EsR}975!hKpk zy()Yt95!V@;VY$Q9DY`ubNF4cnM}-rTlEa)esJaoYk9LMJR%$_7OGln9`z+Yy|ged zbwKtY773z62$G@78U-qhN-ardfBVLozB$U`(d2DV!xTr3ym-T+R;8;hH7mLPIo>uoJ`0KJ=VcG=c4 zyKue*{SQXkOgANuYLLgPBfId*E(^kfqN^w>EHCn+3oDG07F$-! zoYU#%w$pi5Co(_w?3{N;7w-c@(D(eG|MPpF_dWBx2aq8NNCJ{T1_;!aLdk%vaLHWZ zimD(L?#V0XaoI?t38 zWo2a^jzl&Ns~eP3Un zu637=+ehbW6>B7lYmYym@mMpQy*ClF<{5xyg7;rSxPGM>0nZ*pVhIGsM-3NG0_;722Ai?dPuCrx;SgH3xe;|ZaQ6IZ zv^Q2FcToLrOAWm0A+BfEBQbi@Bin-OnFYXBoNeU;LOs*zYqlZadS*Qnr1f;E-h-wW3B==ZSk&kA z6v1F{&K{L(6GG<{4)t+4h32ijDi_TUd&Rw|@$|6g&w2d6ouKzzUPMRDl$(yz$g_wX zNsa9uhtjd5bVfn#s7zQwhR|#|$t!tg$bhv8Hk3I~l=rLcrwckJGZO;kn(b(gypm^5 zu#U#u?&ZI=`Z=0&KBi>lQj{cJc*S^Gv&5!6J5`mkrOfC8P7d-)p2bwJs*qrP#ln<= zW^9O@9ORWVVFZY^2L#sa!_ke-lt9fmJ?7*fujH8%tUVy{par8b_4SM_iP7N*id4^> zU;()CdXS?vZ^m@?1=(I$0Q~AnY&J!<`OPM_(yJsO2}lBxfFvLZNCN*4fuCb0go|%H R58(g+002ovPDHLkV1g2w*Hi!i literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Fun/Instruments/guitar.rsi/meta.json b/Resources/Textures/Objects/Fun/Instruments/guitar.rsi/meta.json index 68132823727..bcd517578fc 100644 --- a/Resources/Textures/Objects/Fun/Instruments/guitar.rsi/meta.json +++ b/Resources/Textures/Objects/Fun/Instruments/guitar.rsi/meta.json @@ -29,6 +29,10 @@ { "name": "equipped-BACKPACK", "directions": 4 + }, + { + "name": "equipped-SUITSTORAGE", + "directions": 4 } ] } diff --git a/Resources/Textures/Objects/Fun/Instruments/rockguitar.rsi/equipped-SUITSTORAGE.png b/Resources/Textures/Objects/Fun/Instruments/rockguitar.rsi/equipped-SUITSTORAGE.png new file mode 100644 index 0000000000000000000000000000000000000000..36cb11d801bfcf45f16274f89a34c7ed8b56d6ee GIT binary patch literal 803 zcmV+;1Kj+HP)Z-fv`&7ES&b;^C_uk070SJO12!bF8B9%s?5ggivI2w&c zu!((!`lZYH(g3%fx43WHb|8d+r(DY$ob!M&2G?~LHYWK50HyFCEz3g7vUX?X0k{|p zP&LiSdn*FGOs9C6P64c{2h3H@+Q41V>Ib%M2LK?10DxT71T|7ymW7Jr z;Lr6no+c9jt9h@YZTyeZ)8O0l^HNa+{s|%ZS}sF*$gM85-N^^*Io}lFE0V;IWF0G_--SBtU;_)!k34K zm1jny5ng*e0Kl)eHvsE74@9g2c_i%oXfy%<)M_-k&|Eyfb=bIbU zYBd0J5#;B`P6tnuNj?PFG~{*04T}H(-_OqhZ1(nnf~0_o>im7X4PbNUfdUF3xo@{I z_WiBL(Ow4gfSAqj*y%vbX0iY5)+N_PFpOLp<(tn!fWoCfmd+CdK@bE%5ClOG1aX{1 zZYuQa^&oEJL2ZoYp)a^Ci913q%UbEpd7fu5#=sZ@=RDYVr#S2R5(SXw1i}-$u4~A4 zxfCKxqxMOp0R7?6keiQH(_9=q38MedD5g21=hT7mN>Y1EfqY9pd5Q!-u zMQ92Ud&Wkx&nQSsKY2W+U$3Xyle#UgMuLt}`$A2>F!E)MeIIEeX!Ql82s%dTjF%-* zbKZT_E*-QRBmLp9Fl+ugkyxnSpe{`zFvdI;iuB@$EYPX^Duru~CZT(zPUXK6;OJR5 h`~ivpf*^?F<{gKAM`X|(z<2-v002ovPDHLkV1j}ba;g9T literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Fun/Instruments/rockguitar.rsi/meta.json b/Resources/Textures/Objects/Fun/Instruments/rockguitar.rsi/meta.json index 7fb73d450dc..96bd8a37e53 100644 --- a/Resources/Textures/Objects/Fun/Instruments/rockguitar.rsi/meta.json +++ b/Resources/Textures/Objects/Fun/Instruments/rockguitar.rsi/meta.json @@ -14,6 +14,10 @@ "name": "equipped-BACKPACK", "directions": 4 }, + { + "name": "equipped-SUITSTORAGE", + "directions": 4 + }, { "name": "inhand-left", "directions": 4 From 032b3f80cb11bbd6960a691121c7f3724a8629c3 Mon Sep 17 00:00:00 2001 From: PJBot Date: Tue, 9 Jul 2024 23:29:16 +0000 Subject: [PATCH 123/765] Automatic changelog update --- Resources/Changelog/Changelog.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 7cc4cbdef1f..f404d68589d 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,11 +1,4 @@ Entries: -- author: SlamBamActionman - changes: - - message: Snouts and noses no longer disappear with toggled masks. - type: Fix - id: 6392 - time: '2024-04-19T05:39:47.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/25716 - author: shampunj changes: - message: 'Now for crafting stunprod you need: igniter, cable cuffs, small power @@ -3828,3 +3821,10 @@ id: 6891 time: '2024-07-09T23:12:40.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/29854 +- author: Boaz1111 + changes: + - message: Guitars can now be worn in the suit storage slot + type: Add + id: 6892 + time: '2024-07-09T23:28:10.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/29048 From 9cbb019dcdbb7685cf582b9aa9c48fea82e2e3e2 Mon Sep 17 00:00:00 2001 From: Winkarst-cpu <74284083+Winkarst-cpu@users.noreply.github.com> Date: Wed, 10 Jul 2024 02:48:56 +0300 Subject: [PATCH 124/765] Fix borg's popup spam (#29861) Fix borg popup spam Co-authored-by: Winkarst-cpu --- Content.Shared/Lock/LockSystem.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Content.Shared/Lock/LockSystem.cs b/Content.Shared/Lock/LockSystem.cs index bf4af1cb9a4..22a90aa0a62 100644 --- a/Content.Shared/Lock/LockSystem.cs +++ b/Content.Shared/Lock/LockSystem.cs @@ -365,7 +365,7 @@ private void OnUIOpenAttempt(EntityUid uid, ActivatableUIRequiresLockComponent c { args.Cancel(); if (lockComp.Locked) - _sharedPopupSystem.PopupEntity(Loc.GetString("entity-storage-component-locked-message"), uid, args.User); + _sharedPopupSystem.PopupClient(Loc.GetString("entity-storage-component-locked-message"), uid, args.User); } } From d208b6ed03996fc5c01a43f423d8d68034d4c1c6 Mon Sep 17 00:00:00 2001 From: PJBot Date: Tue, 9 Jul 2024 23:50:02 +0000 Subject: [PATCH 125/765] Automatic changelog update --- Resources/Changelog/Changelog.yml | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index f404d68589d..4f38a9f753d 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,15 +1,4 @@ Entries: -- author: shampunj - changes: - - message: 'Now for crafting stunprod you need: igniter, cable cuffs, small power - cell, metal rod.' - type: Tweak - - message: Stunprod deals 35 stamina damage per hit and 5 shock damage. The battery - charge is enough for 3 hits. - type: Tweak - id: 6393 - time: '2024-04-19T05:50:10.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/25922 - author: EmoGarbage404 changes: - message: Halved passive fuel consumption of welding tools. @@ -3828,3 +3817,10 @@ id: 6892 time: '2024-07-09T23:28:10.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/29048 +- author: Winkarst-cpu + changes: + - message: Fixed popup spam when trying to open borg's UI while the borg is locked. + type: Fix + id: 6893 + time: '2024-07-09T23:48:56.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/29861 From 92cd28bb1138922c023f3fbdac793ab815107255 Mon Sep 17 00:00:00 2001 From: Ed <96445749+TheShuEd@users.noreply.github.com> Date: Wed, 10 Jul 2024 08:24:25 +0300 Subject: [PATCH 126/765] Steal Objective Condition now support stacks (#29843) * Update StealConditionSystem.cs * Update StealConditionSystem.cs --- .../Objectives/Systems/StealConditionSystem.cs | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/Content.Server/Objectives/Systems/StealConditionSystem.cs b/Content.Server/Objectives/Systems/StealConditionSystem.cs index 0fe6f0947c8..42a296ab925 100644 --- a/Content.Server/Objectives/Systems/StealConditionSystem.cs +++ b/Content.Server/Objectives/Systems/StealConditionSystem.cs @@ -10,6 +10,7 @@ using Content.Shared.Mobs.Systems; using Content.Shared.Mobs.Components; using Content.Shared.Movement.Pulling.Components; +using Content.Shared.Stacks; namespace Content.Server.Objectives.Systems; @@ -105,7 +106,7 @@ private float GetProgress(MindComponent mind, StealConditionComponent condition) if (pulledEntity != null) { // check if this is the item - if (CheckStealTarget(pulledEntity.Value, condition)) count++; + count += CheckStealTarget(pulledEntity.Value, condition); //we don't check the inventories of sentient entity if (!HasComp(pulledEntity)) @@ -126,7 +127,7 @@ private float GetProgress(MindComponent mind, StealConditionComponent condition) foreach (var entity in container.ContainedEntities) { // check if this is the item - if (CheckStealTarget(entity, condition)) count++; //To Do: add support for stackable items + count += CheckStealTarget(entity, condition); // if it is a container check its contents if (_containerQuery.TryGetComponent(entity, out var containerManager)) @@ -140,14 +141,14 @@ private float GetProgress(MindComponent mind, StealConditionComponent condition) return result; } - private bool CheckStealTarget(EntityUid entity, StealConditionComponent condition) + private int CheckStealTarget(EntityUid entity, StealConditionComponent condition) { // check if this is the target if (!TryComp(entity, out var target)) - return false; + return 0; if (target.StealGroup != condition.StealGroup) - return false; + return 0; // check if needed target alive if (condition.CheckAlive) @@ -155,9 +156,10 @@ private bool CheckStealTarget(EntityUid entity, StealConditionComponent conditio if (TryComp(entity, out var state)) { if (!_mobState.IsAlive(entity, state)) - return false; + return 0; } } - return true; + + return TryComp(entity, out var stack) ? stack.Count : 1; } } From 90d3155c0d8fe941fe982c3a2962605111d00341 Mon Sep 17 00:00:00 2001 From: Moomoobeef <62638182+Moomoobeef@users.noreply.github.com> Date: Wed, 10 Jul 2024 00:25:24 -0500 Subject: [PATCH 127/765] fixed missing characters in OwO accent (#29047) replaced two characters with ones that actually show up ingame --- Content.Server/Speech/EntitySystems/OwOAccentSystem.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Content.Server/Speech/EntitySystems/OwOAccentSystem.cs b/Content.Server/Speech/EntitySystems/OwOAccentSystem.cs index cac3debe819..2b3d5aa3d49 100644 --- a/Content.Server/Speech/EntitySystems/OwOAccentSystem.cs +++ b/Content.Server/Speech/EntitySystems/OwOAccentSystem.cs @@ -8,7 +8,7 @@ public sealed class OwOAccentSystem : EntitySystem [Dependency] private readonly IRobustRandom _random = default!; private static readonly IReadOnlyList Faces = new List{ - " (・`ω´・)", " ;;w;;", " owo", " UwU", " >w<", " ^w^" + " (•`ω´•)", " ;;w;;", " owo", " UwU", " >w<", " ^w^" }.AsReadOnly(); private static readonly IReadOnlyDictionary SpecialWords = new Dictionary() From 3048cdb8f2665484b62ef9457711c1567c75f895 Mon Sep 17 00:00:00 2001 From: Ivan <69372103+lokachop@users.noreply.github.com> Date: Wed, 10 Jul 2024 07:26:33 +0200 Subject: [PATCH 128/765] Add scarf to warm clothing bounty (#29779) * Add scarf to warm clothing bounty * Added ClothingScarfBase prototype and assigned to all of the scarves --- .../Prototypes/Catalog/Bounties/bounties.yml | 4 +++- .../Clothing/Neck/base_clothingneck.yml | 9 +++++++ .../Entities/Clothing/Neck/scarfs.yml | 24 +++++++++---------- Resources/Prototypes/tags.yml | 3 +++ 4 files changed, 27 insertions(+), 13 deletions(-) diff --git a/Resources/Prototypes/Catalog/Bounties/bounties.yml b/Resources/Prototypes/Catalog/Bounties/bounties.yml index 08bb2a14225..f656eb1962f 100644 --- a/Resources/Prototypes/Catalog/Bounties/bounties.yml +++ b/Resources/Prototypes/Catalog/Bounties/bounties.yml @@ -1,4 +1,4 @@ -- type: cargoBounty +- type: cargoBounty id: BountyArtifact reward: 2500 description: bounty-description-artifact @@ -500,6 +500,8 @@ whitelist: components: - TemperatureProtection + tags: + - Scarf - type: cargoBounty id: BountyBattery diff --git a/Resources/Prototypes/Entities/Clothing/Neck/base_clothingneck.yml b/Resources/Prototypes/Entities/Clothing/Neck/base_clothingneck.yml index 1bccb4c92a3..d2fffb81537 100644 --- a/Resources/Prototypes/Entities/Clothing/Neck/base_clothingneck.yml +++ b/Resources/Prototypes/Entities/Clothing/Neck/base_clothingneck.yml @@ -29,3 +29,12 @@ tags: - ClothMade - WhitelistChameleon + +- type: entity + abstract: true + parent: ClothingNeckBase + id: ClothingScarfBase + components: + - type: Tag + tags: + - Scarf diff --git a/Resources/Prototypes/Entities/Clothing/Neck/scarfs.yml b/Resources/Prototypes/Entities/Clothing/Neck/scarfs.yml index 33f582d30de..1f9d6b8b2c6 100644 --- a/Resources/Prototypes/Entities/Clothing/Neck/scarfs.yml +++ b/Resources/Prototypes/Entities/Clothing/Neck/scarfs.yml @@ -1,5 +1,5 @@ - type: entity - parent: ClothingNeckBase + parent: ClothingScarfBase id: ClothingNeckScarfStripedRed name: striped red scarf description: A stylish striped red scarf. The perfect winter accessory for those with a keen fashion sense, and those who just can't handle a cold breeze on their necks. @@ -10,7 +10,7 @@ sprite: Clothing/Neck/Scarfs/red.rsi - type: entity - parent: ClothingNeckBase + parent: ClothingScarfBase id: ClothingNeckScarfStripedBlue name: striped blue scarf description: A stylish striped blue scarf. The perfect winter accessory for those with a keen fashion sense, and those who just can't handle a cold breeze on their necks. @@ -21,7 +21,7 @@ sprite: Clothing/Neck/Scarfs/blue.rsi - type: entity - parent: ClothingNeckBase + parent: ClothingScarfBase id: ClothingNeckScarfStripedGreen name: striped green scarf description: A stylish striped green scarf. The perfect winter accessory for those with a keen fashion sense, and those who just can't handle a cold breeze on their necks. @@ -32,7 +32,7 @@ sprite: Clothing/Neck/Scarfs/green.rsi - type: entity - parent: ClothingNeckBase + parent: ClothingScarfBase id: ClothingNeckScarfStripedBlack name: striped black scarf description: A stylish striped black scarf. The perfect winter accessory for those with a keen fashion sense, and those who just can't handle a cold breeze on their necks. @@ -43,7 +43,7 @@ sprite: Clothing/Neck/Scarfs/black.rsi - type: entity - parent: ClothingNeckBase + parent: ClothingScarfBase id: ClothingNeckScarfStripedBrown name: striped brown scarf description: A stylish striped brown scarf. The perfect winter accessory for those with a keen fashion sense, and those who just can't handle a cold breeze on their necks. @@ -54,7 +54,7 @@ sprite: Clothing/Neck/Scarfs/brown.rsi - type: entity - parent: ClothingNeckBase + parent: ClothingScarfBase id: ClothingNeckScarfStripedLightBlue name: striped light blue scarf description: A stylish striped light blue scarf. The perfect winter accessory for those with a keen fashion sense, and those who just can't handle a cold breeze on their necks. @@ -65,7 +65,7 @@ sprite: Clothing/Neck/Scarfs/lightblue.rsi - type: entity - parent: ClothingNeckBase + parent: ClothingScarfBase id: ClothingNeckScarfStripedOrange name: striped orange scarf description: A stylish striped orange scarf. The perfect winter accessory for those with a keen fashion sense, and those who just can't handle a cold breeze on their necks. @@ -76,7 +76,7 @@ sprite: Clothing/Neck/Scarfs/orange.rsi - type: entity - parent: ClothingNeckBase + parent: ClothingScarfBase id: ClothingNeckScarfStripedPurple name: striped purple scarf description: A stylish striped purple scarf. The perfect winter accessory for those with a keen fashion sense, and those who just can't handle a cold breeze on their necks. @@ -87,7 +87,7 @@ sprite: Clothing/Neck/Scarfs/purple.rsi - type: entity - parent: ClothingNeckBase + parent: ClothingScarfBase id: ClothingNeckScarfStripedSyndieGreen name: striped syndicate green scarf description: A stylish striped syndicate green scarf. The perfect winter accessory for those with a keen fashion sense, and those who are in the mood to steal something. @@ -98,7 +98,7 @@ sprite: Clothing/Neck/Scarfs/syndiegreen.rsi - type: entity - parent: ClothingNeckBase + parent: ClothingScarfBase id: ClothingNeckScarfStripedSyndieRed name: striped syndicate red scarf description: A stylish striped syndicate red scarf. The perfect winter accessory for those with a keen fashion sense, and those who are in the mood to steal something. @@ -109,7 +109,7 @@ sprite: Clothing/Neck/Scarfs/syndiered.rsi - type: entity - parent: ClothingNeckBase + parent: ClothingScarfBase id: ClothingNeckScarfStripedCentcom name: striped CentCom scarf description: A stylish striped centcom colored scarf. The perfect winter accessory for those with a keen fashion sense, and those who need to do paperwork in the cold. @@ -120,7 +120,7 @@ sprite: Clothing/Neck/Scarfs/centcom.rsi - type: entity - parent: ClothingNeckBase + parent: ClothingScarfBase id: ClothingNeckScarfStripedZebra name: zebra scarf description: A striped scarf, a mandatory accessory for artists. diff --git a/Resources/Prototypes/tags.yml b/Resources/Prototypes/tags.yml index f11653417b6..7c85152ea33 100644 --- a/Resources/Prototypes/tags.yml +++ b/Resources/Prototypes/tags.yml @@ -1108,6 +1108,9 @@ - type: Tag id: SalvageExperiment +- type: Tag + id: Scarf + - type: Tag id: Screwdriver From d74b89275442ffd6e49d7e59649b9876e3a50af0 Mon Sep 17 00:00:00 2001 From: PJBot Date: Wed, 10 Jul 2024 05:27:40 +0000 Subject: [PATCH 129/765] Automatic changelog update --- Resources/Changelog/Changelog.yml | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 4f38a9f753d..4b10c79f6b4 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,13 +1,4 @@ Entries: -- author: EmoGarbage404 - changes: - - message: Halved passive fuel consumption of welding tools. - type: Tweak - - message: Completing an action with a welding tool now directly drains the fuel. - type: Tweak - id: 6394 - time: '2024-04-19T23:20:30.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/27030 - author: superjj18 changes: - message: Pneumatic cannon inventory reduced in size to 2x2, item blacklist removed @@ -3824,3 +3815,10 @@ id: 6893 time: '2024-07-09T23:48:56.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/29861 +- author: Lokachop + changes: + - message: Scarves now count as warm clothing for the warm clothing cargo bounty. + type: Tweak + id: 6894 + time: '2024-07-10T05:26:33.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/29779 From e63d2a2ac67329e873af92fee57e8bfe4d386725 Mon Sep 17 00:00:00 2001 From: dffdff2423 Date: Wed, 10 Jul 2024 00:28:36 -0500 Subject: [PATCH 130/765] Add an option to the admin fax menu to lock papers such that they can't be edited by cybersun pens (#28972) * Add option to adminfax for locking papers. * Replace dummy control with margin --- Content.Client/Fax/AdminUI/AdminFaxEui.cs | 2 +- Content.Client/Fax/AdminUI/AdminFaxWindow.xaml | 4 ++-- Content.Client/Fax/AdminUI/AdminFaxWindow.xaml.cs | 5 +++-- Content.Server/Fax/AdminUI/AdminFaxEui.cs | 4 +++- Content.Server/Fax/FaxConstants.cs | 1 + Content.Server/Fax/FaxSystem.cs | 9 +++++++-- Content.Server/Paper/PaperComponent.cs | 4 +++- Content.Server/Paper/PaperSystem.cs | 8 ++++++++ Content.Shared/Fax/AdminFaxEui.cs | 4 +++- Content.Shared/Fax/Components/FaxMachineComponent.cs | 6 +++++- Resources/Locale/en-US/fax/fax-admin.ftl | 2 ++ Resources/Locale/en-US/paper/paper-component.ftl | 2 ++ 12 files changed, 40 insertions(+), 11 deletions(-) diff --git a/Content.Client/Fax/AdminUI/AdminFaxEui.cs b/Content.Client/Fax/AdminUI/AdminFaxEui.cs index ace3f3eb7b3..452c54eb797 100644 --- a/Content.Client/Fax/AdminUI/AdminFaxEui.cs +++ b/Content.Client/Fax/AdminUI/AdminFaxEui.cs @@ -16,7 +16,7 @@ public AdminFaxEui() _window.OnClose += () => SendMessage(new AdminFaxEuiMsg.Close()); _window.OnFollowFax += entity => SendMessage(new AdminFaxEuiMsg.Follow(entity)); _window.OnMessageSend += args => SendMessage(new AdminFaxEuiMsg.Send(args.entity, args.title, - args.stampedBy, args.message, args.stampSprite, args.stampColor)); + args.stampedBy, args.message, args.stampSprite, args.stampColor, args.locked)); } public override void Opened() diff --git a/Content.Client/Fax/AdminUI/AdminFaxWindow.xaml b/Content.Client/Fax/AdminUI/AdminFaxWindow.xaml index d469a0e9d38..dc4092a3b53 100644 --- a/Content.Client/Fax/AdminUI/AdminFaxWindow.xaml +++ b/Content.Client/Fax/AdminUI/AdminFaxWindow.xaml @@ -23,7 +23,7 @@ [DataField("stampState")] public string? StampState { get; set; } + + [DataField] + public bool EditingDisabled = false; } diff --git a/Content.Server/Paper/PaperSystem.cs b/Content.Server/Paper/PaperSystem.cs index 61addc1b517..ae88c0becf1 100644 --- a/Content.Server/Paper/PaperSystem.cs +++ b/Content.Server/Paper/PaperSystem.cs @@ -102,6 +102,14 @@ private void OnInteractUsing(EntityUid uid, PaperComponent paperComp, InteractUs var editable = paperComp.StampedBy.Count == 0 || _tagSystem.HasTag(args.Used, "WriteIgnoreStamps"); if (_tagSystem.HasTag(args.Used, "Write") && editable && paperComp.CanEdit) { + if (paperComp.EditingDisabled) + { + var paperEditingDisabledMessage = Loc.GetString("paper-tamper-proof-modified-message"); + _popupSystem.PopupEntity(paperEditingDisabledMessage, uid, args.User); + + args.Handled = true; + return; + } var writeEvent = new PaperWriteEvent(uid, args.User); RaiseLocalEvent(args.Used, ref writeEvent); diff --git a/Content.Shared/Fax/AdminFaxEui.cs b/Content.Shared/Fax/AdminFaxEui.cs index 7b3e1fae8d3..613a13d0124 100644 --- a/Content.Shared/Fax/AdminFaxEui.cs +++ b/Content.Shared/Fax/AdminFaxEui.cs @@ -56,8 +56,9 @@ public sealed class Send : EuiMessageBase public string Content { get; } public string StampState { get; } public Color StampColor { get; } + public bool Locked { get; } - public Send(NetEntity target, string title, string from, string content, string stamp, Color stampColor) + public Send(NetEntity target, string title, string from, string content, string stamp, Color stampColor, bool locked) { Target = target; Title = title; @@ -65,6 +66,7 @@ public Send(NetEntity target, string title, string from, string content, string Content = content; StampState = stamp; StampColor = stampColor; + Locked = locked; } } } diff --git a/Content.Shared/Fax/Components/FaxMachineComponent.cs b/Content.Shared/Fax/Components/FaxMachineComponent.cs index 6664ce023dd..1c089865088 100644 --- a/Content.Shared/Fax/Components/FaxMachineComponent.cs +++ b/Content.Shared/Fax/Components/FaxMachineComponent.cs @@ -150,11 +150,14 @@ public sealed partial class FaxPrintout [DataField("stampedBy")] public List StampedBy { get; private set; } = new(); + [DataField] + public bool Locked { get; private set; } + private FaxPrintout() { } - public FaxPrintout(string content, string name, string? label = null, string? prototypeId = null, string? stampState = null, List? stampedBy = null) + public FaxPrintout(string content, string name, string? label = null, string? prototypeId = null, string? stampState = null, List? stampedBy = null, bool locked = false) { Content = content; Name = name; @@ -162,5 +165,6 @@ public FaxPrintout(string content, string name, string? label = null, string? pr PrototypeId = prototypeId ?? ""; StampState = stampState; StampedBy = stampedBy ?? new List(); + Locked = locked; } } diff --git a/Resources/Locale/en-US/fax/fax-admin.ftl b/Resources/Locale/en-US/fax/fax-admin.ftl index eff7e15fe8b..8a8f37809e1 100644 --- a/Resources/Locale/en-US/fax/fax-admin.ftl +++ b/Resources/Locale/en-US/fax/fax-admin.ftl @@ -12,3 +12,5 @@ admin-fax-message-placeholder = Your message here... admin-fax-stamp = Stamp icon: admin-fax-stamp-color = Stamp color: admin-fax-send = Send +admin-fax-lock-page = Lock Page +admin-fax-lock-page-tooltip = Lock the paper such that it cannot be edited even by things such as cybersun pens. diff --git a/Resources/Locale/en-US/paper/paper-component.ftl b/Resources/Locale/en-US/paper/paper-component.ftl index a62616631f4..c2d9d5712bf 100644 --- a/Resources/Locale/en-US/paper/paper-component.ftl +++ b/Resources/Locale/en-US/paper/paper-component.ftl @@ -12,3 +12,5 @@ paper-component-action-stamp-paper-other = {CAPITALIZE(THE($user))} stamps {THE( paper-component-action-stamp-paper-self = You stamp {THE($target)} with {THE($stamp)}. paper-ui-save-button = Save ({$keybind}) + +paper-tamper-proof-modified-message = This page was written using tamper-proof ink. From f999a678e1c28c2e4e9353a53f47e728f3e6b614 Mon Sep 17 00:00:00 2001 From: PJBot Date: Wed, 10 Jul 2024 05:29:42 +0000 Subject: [PATCH 131/765] Automatic changelog update --- Resources/Changelog/Changelog.yml | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 4b10c79f6b4..b48710ed445 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,11 +1,4 @@ Entries: -- author: superjj18 - changes: - - message: Pneumatic cannon inventory reduced in size to 2x2, item blacklist removed - type: Tweak - id: 6395 - time: '2024-04-19T23:22:37.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/26878 - author: Aquif changes: - message: The Communication Console will no longer cut off your messages. @@ -3822,3 +3815,11 @@ id: 6894 time: '2024-07-10T05:26:33.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/29779 +- author: Aquif + changes: + - message: It is now possible to "lock" admin faxes such that they cannot be edited + by cybersun pens or any other IC means. + type: Add + id: 6895 + time: '2024-07-10T05:28:36.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/28972 From 811389a2513a78f0cf3b49c277346b651eb17fad Mon Sep 17 00:00:00 2001 From: Ghagliiarghii <68826635+Ghagliiarghii@users.noreply.github.com> Date: Wed, 10 Jul 2024 01:51:01 -0400 Subject: [PATCH 132/765] books bag tabletop (#29863) * books bag tabletop * Update Resources/Prototypes/Entities/Objects/Specific/Librarian/books_bag.yml --------- Co-authored-by: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com> --- Resources/Prototypes/Entities/Objects/Fun/Tabletop/base.yml | 3 +++ .../Entities/Objects/Specific/Librarian/books_bag.yml | 4 ++++ 2 files changed, 7 insertions(+) diff --git a/Resources/Prototypes/Entities/Objects/Fun/Tabletop/base.yml b/Resources/Prototypes/Entities/Objects/Fun/Tabletop/base.yml index 351396b5b91..64e7d7ace98 100644 --- a/Resources/Prototypes/Entities/Objects/Fun/Tabletop/base.yml +++ b/Resources/Prototypes/Entities/Objects/Fun/Tabletop/base.yml @@ -10,6 +10,9 @@ setup: !type:TabletopEmptySetup boardPrototype: Crowbar + - type: Tag + tags: + - TabletopBoard - type: entity id: BaseTabletopPiece # Board piece diff --git a/Resources/Prototypes/Entities/Objects/Specific/Librarian/books_bag.yml b/Resources/Prototypes/Entities/Objects/Specific/Librarian/books_bag.yml index e4befcbb670..9972fad4146 100644 --- a/Resources/Prototypes/Entities/Objects/Specific/Librarian/books_bag.yml +++ b/Resources/Prototypes/Entities/Objects/Specific/Librarian/books_bag.yml @@ -22,5 +22,9 @@ whitelist: tags: - Book + - Dice - Document + - Figurine + - TabletopBoard + - Write - type: Dumpable From fdf502c9290a27e74cf6e5aa9c143626c71b2cae Mon Sep 17 00:00:00 2001 From: beck-thompson <107373427+beck-thompson@users.noreply.github.com> Date: Tue, 9 Jul 2024 22:51:47 -0700 Subject: [PATCH 133/765] Fix typing indicators! (#29492) * First commit * Removed pause stuff * Make the event better * Forgot to add the comment * Proto id stuff * cool comments * serializer * Added the time stuff --- .../TypingIndicatorVisualizerSystem.cs | 19 +++++- .../SharedTypingIndicatorSystem.cs | 21 ++++--- .../TypingIndicator/TypingChangedEvent.cs | 18 ------ .../TypingIndicatorClothingComponent.cs | 23 +++++-- .../TypingIndicatorComponent.cs | 7 +-- .../TypingIndicator/TypingIndicatorEvents.cs | 60 +++++++++++++++++++ 6 files changed, 111 insertions(+), 37 deletions(-) delete mode 100644 Content.Shared/Chat/TypingIndicator/TypingChangedEvent.cs create mode 100644 Content.Shared/Chat/TypingIndicator/TypingIndicatorEvents.cs diff --git a/Content.Client/Chat/TypingIndicator/TypingIndicatorVisualizerSystem.cs b/Content.Client/Chat/TypingIndicator/TypingIndicatorVisualizerSystem.cs index d04c9d661dd..e89f7ab5002 100644 --- a/Content.Client/Chat/TypingIndicator/TypingIndicatorVisualizerSystem.cs +++ b/Content.Client/Chat/TypingIndicator/TypingIndicatorVisualizerSystem.cs @@ -2,21 +2,36 @@ using Robust.Client.GameObjects; using Robust.Client.Graphics; using Robust.Shared.Prototypes; +using Content.Shared.Inventory; namespace Content.Client.Chat.TypingIndicator; public sealed class TypingIndicatorVisualizerSystem : VisualizerSystem { [Dependency] private readonly IPrototypeManager _prototypeManager = default!; + [Dependency] private readonly InventorySystem _inventory = default!; + protected override void OnAppearanceChange(EntityUid uid, TypingIndicatorComponent component, ref AppearanceChangeEvent args) { if (args.Sprite == null) return; - if (!_prototypeManager.TryIndex(component.Prototype, out var proto)) + var currentTypingIndicator = component.TypingIndicatorPrototype; + + var evt = new BeforeShowTypingIndicatorEvent(); + + if (TryComp(uid, out var inventoryComp)) + _inventory.RelayEvent((uid, inventoryComp), ref evt); + + var overrideIndicator = evt.GetMostRecentIndicator(); + + if (overrideIndicator != null) + currentTypingIndicator = overrideIndicator.Value; + + if (!_prototypeManager.TryIndex(currentTypingIndicator, out var proto)) { - Log.Error($"Unknown typing indicator id: {component.Prototype}"); + Log.Error($"Unknown typing indicator id: {component.TypingIndicatorPrototype}"); return; } diff --git a/Content.Shared/Chat/TypingIndicator/SharedTypingIndicatorSystem.cs b/Content.Shared/Chat/TypingIndicator/SharedTypingIndicatorSystem.cs index dffe3cc185b..9d60d334dbe 100644 --- a/Content.Shared/Chat/TypingIndicator/SharedTypingIndicatorSystem.cs +++ b/Content.Shared/Chat/TypingIndicator/SharedTypingIndicatorSystem.cs @@ -1,6 +1,8 @@ using Content.Shared.ActionBlocker; using Content.Shared.Clothing; +using Content.Shared.Inventory; using Robust.Shared.Player; +using Robust.Shared.Timing; namespace Content.Shared.Chat.TypingIndicator; @@ -11,6 +13,7 @@ public abstract class SharedTypingIndicatorSystem : EntitySystem { [Dependency] private readonly ActionBlockerSystem _actionBlocker = default!; [Dependency] private readonly SharedAppearanceSystem _appearance = default!; + [Dependency] private readonly IGameTiming _timing = default!; /// /// Default ID of @@ -26,6 +29,7 @@ public override void Initialize() SubscribeLocalEvent(OnGotEquipped); SubscribeLocalEvent(OnGotUnequipped); + SubscribeLocalEvent>(BeforeShow); SubscribeAllEvent(OnTypingChanged); } @@ -44,20 +48,19 @@ private void OnPlayerDetached(EntityUid uid, TypingIndicatorComponent component, SetTypingIndicatorEnabled(uid, false); } - private void OnGotEquipped(EntityUid uid, TypingIndicatorClothingComponent component, ClothingGotEquippedEvent args) + private void OnGotEquipped(Entity entity, ref ClothingGotEquippedEvent args) { - if (!TryComp(args.Wearer, out var indicator)) - return; - - indicator.Prototype = component.Prototype; + entity.Comp.GotEquippedTime = _timing.CurTime; } - private void OnGotUnequipped(EntityUid uid, TypingIndicatorClothingComponent component, ClothingGotUnequippedEvent args) + private void OnGotUnequipped(Entity entity, ref ClothingGotUnequippedEvent args) { - if (!TryComp(args.Wearer, out var indicator)) - return; + entity.Comp.GotEquippedTime = null; + } - indicator.Prototype = InitialIndicatorId; + private void BeforeShow(Entity entity, ref InventoryRelayedEvent args) + { + args.Args.TryUpdateTimeAndIndicator(entity.Comp.TypingIndicatorPrototype, entity.Comp.GotEquippedTime); } private void OnTypingChanged(TypingChangedEvent ev, EntitySessionEventArgs args) diff --git a/Content.Shared/Chat/TypingIndicator/TypingChangedEvent.cs b/Content.Shared/Chat/TypingIndicator/TypingChangedEvent.cs deleted file mode 100644 index 6245f19b5d4..00000000000 --- a/Content.Shared/Chat/TypingIndicator/TypingChangedEvent.cs +++ /dev/null @@ -1,18 +0,0 @@ -using Robust.Shared.Serialization; - -namespace Content.Shared.Chat.TypingIndicator; - -/// -/// Networked event from client. -/// Send to server when client started/stopped typing in chat input field. -/// -[Serializable, NetSerializable] -public sealed class TypingChangedEvent : EntityEventArgs -{ - public readonly bool IsTyping; - - public TypingChangedEvent(bool isTyping) - { - IsTyping = isTyping; - } -} diff --git a/Content.Shared/Chat/TypingIndicator/TypingIndicatorClothingComponent.cs b/Content.Shared/Chat/TypingIndicator/TypingIndicatorClothingComponent.cs index 5ec8185587a..4993e912e93 100644 --- a/Content.Shared/Chat/TypingIndicator/TypingIndicatorClothingComponent.cs +++ b/Content.Shared/Chat/TypingIndicator/TypingIndicatorClothingComponent.cs @@ -1,13 +1,28 @@ using Robust.Shared.GameStates; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; +using Robust.Shared.Prototypes; +using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom; namespace Content.Shared.Chat.TypingIndicator; -[RegisterComponent, NetworkedComponent] +/// +/// If an item is equipped to someones inventory (Anything but the pockets), and has this component +/// the users typing indicator will be replaced by the prototype given in TypingIndicatorPrototype. +/// +[RegisterComponent, NetworkedComponent, AutoGenerateComponentPause] [Access(typeof(SharedTypingIndicatorSystem))] public sealed partial class TypingIndicatorClothingComponent : Component { + /// + /// The typing indicator that will override the default typing indicator when the item is equipped to a users + /// inventory. + /// [ViewVariables(VVAccess.ReadWrite)] - [DataField("proto", required: true, customTypeSerializer: typeof(PrototypeIdSerializer))] - public string Prototype = default!; + [DataField("proto", required: true)] + public ProtoId TypingIndicatorPrototype = default!; + + /// + /// This stores the time the item was equipped in someones inventory. If null, item is currently not equipped. + /// + [DataField, AutoPausedField] + public TimeSpan? GotEquippedTime = null; } diff --git a/Content.Shared/Chat/TypingIndicator/TypingIndicatorComponent.cs b/Content.Shared/Chat/TypingIndicator/TypingIndicatorComponent.cs index a4507b06b8a..f263de49136 100644 --- a/Content.Shared/Chat/TypingIndicator/TypingIndicatorComponent.cs +++ b/Content.Shared/Chat/TypingIndicator/TypingIndicatorComponent.cs @@ -1,5 +1,5 @@ using Robust.Shared.GameStates; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; +using Robust.Shared.Prototypes; namespace Content.Shared.Chat.TypingIndicator; @@ -14,7 +14,6 @@ public sealed partial class TypingIndicatorComponent : Component /// /// Prototype id that store all visual info about typing indicator. /// - [ViewVariables(VVAccess.ReadWrite)] - [DataField("proto", customTypeSerializer: typeof(PrototypeIdSerializer))] - public string Prototype = SharedTypingIndicatorSystem.InitialIndicatorId; + [DataField("proto")] + public ProtoId TypingIndicatorPrototype = "default"; } diff --git a/Content.Shared/Chat/TypingIndicator/TypingIndicatorEvents.cs b/Content.Shared/Chat/TypingIndicator/TypingIndicatorEvents.cs new file mode 100644 index 00000000000..600f86c0d2c --- /dev/null +++ b/Content.Shared/Chat/TypingIndicator/TypingIndicatorEvents.cs @@ -0,0 +1,60 @@ +using Robust.Shared.Serialization; +using Content.Shared.Inventory; +using Robust.Shared.Prototypes; +using Robust.Shared.Serialization.Manager.Exceptions; + +namespace Content.Shared.Chat.TypingIndicator; + +/// +/// Networked event from client. +/// Send to server when client started/stopped typing in chat input field. +/// +[Serializable, NetSerializable] +public sealed class TypingChangedEvent : EntityEventArgs +{ + public readonly bool IsTyping; + + public TypingChangedEvent(bool isTyping) + { + IsTyping = isTyping; + } +} + +/// +/// This event will be broadcast right before displaying an entities typing indicator. +/// If _overrideIndicator is not null after the event is finished it will be used. +/// +[Serializable, NetSerializable] +public sealed class BeforeShowTypingIndicatorEvent : IInventoryRelayEvent +{ + public SlotFlags TargetSlots { get; } = SlotFlags.WITHOUT_POCKET; + + private ProtoId? _overrideIndicator = null; + private TimeSpan? _latestEquipTime = null; + public BeforeShowTypingIndicatorEvent() + { + _overrideIndicator = null; + _latestEquipTime = null; + } + /// + /// Will only update the time and indicator if the given time is more recent than + /// the stored time or if the stored time is null. + /// + /// + /// True if the given time is more recent than the stored time, and false otherwise. + /// + public bool TryUpdateTimeAndIndicator(ProtoId? indicator, TimeSpan? equipTime) + { + if (equipTime != null && (_latestEquipTime == null || _latestEquipTime < equipTime)) + { + _latestEquipTime = equipTime; + _overrideIndicator = indicator; + return true; + } + return false; + } + public ProtoId? GetMostRecentIndicator() + { + return _overrideIndicator; + } +} From f1b9524cdb2f34a6239ba5659b801e1461005992 Mon Sep 17 00:00:00 2001 From: saga3152 <133799418+saga3152@users.noreply.github.com> Date: Wed, 10 Jul 2024 07:52:33 +0200 Subject: [PATCH 134/765] Crafting pizza boxes. (#29680) * We can now craft pizza boxes * Fixing errors --- .../Crafting/Graphs/storage/foodboxpizza.yml | 15 +++++++++++++++ Resources/Prototypes/Recipes/Crafting/crates.yml | 13 +++++++++++++ 2 files changed, 28 insertions(+) create mode 100644 Resources/Prototypes/Recipes/Crafting/Graphs/storage/foodboxpizza.yml diff --git a/Resources/Prototypes/Recipes/Crafting/Graphs/storage/foodboxpizza.yml b/Resources/Prototypes/Recipes/Crafting/Graphs/storage/foodboxpizza.yml new file mode 100644 index 00000000000..b475289e11f --- /dev/null +++ b/Resources/Prototypes/Recipes/Crafting/Graphs/storage/foodboxpizza.yml @@ -0,0 +1,15 @@ +- type: constructionGraph + id: FoodBoxPizza + start: start + graph: + - node: start + edges: + - to: foodboxpizza + steps: + - material: Cardboard + amount: 1 + doAfter: 4 + + + - node: foodboxpizza + entity: FoodBoxPizza \ No newline at end of file diff --git a/Resources/Prototypes/Recipes/Crafting/crates.yml b/Resources/Prototypes/Recipes/Crafting/crates.yml index 4177b3fa2a6..72fabc2221b 100644 --- a/Resources/Prototypes/Recipes/Crafting/crates.yml +++ b/Resources/Prototypes/Recipes/Crafting/crates.yml @@ -64,6 +64,19 @@ icon: { sprite: Objects/Storage/boxes.rsi, state: box } objectType: Item +- type: construction + name: pizza box + id: FoodBoxPizza + graph: FoodBoxPizza + startNode: start + targetNode: foodboxpizza + category: construction-category-storage + description: A box for pizza. + icon: + sprite: Objects/Consumable/Food/Baked/pizza.rsi + state: box + objectType: Item + - type: construction name: coffin id: CrateCoffin From 5ddd785cf7f886a5e10fa4c536ceb937bcd2d980 Mon Sep 17 00:00:00 2001 From: PJBot Date: Wed, 10 Jul 2024 05:52:53 +0000 Subject: [PATCH 135/765] Automatic changelog update --- Resources/Changelog/Changelog.yml | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index b48710ed445..2853c298123 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,18 +1,4 @@ Entries: -- author: Aquif - changes: - - message: The Communication Console will no longer cut off your messages. - type: Fix - id: 6396 - time: '2024-04-20T01:07:10.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/27145 -- author: osjarw - changes: - - message: Wallmount substation electronics can now be created at an autolathe. - type: Add - id: 6397 - time: '2024-04-20T01:14:58.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/27138 - author: Gyrandola changes: - message: Pepper sprites are now properly centered! @@ -3823,3 +3809,19 @@ id: 6895 time: '2024-07-10T05:28:36.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/28972 +- author: Ghagliiarghii + changes: + - message: The Librarian's Books Bag can now hold D&D related items such as dice + and battlemats. + type: Tweak + id: 6896 + time: '2024-07-10T05:51:01.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/29863 +- author: Beck Thompson, Tayrtahn + changes: + - message: Typing indicators now correctly stack and will not overwrite your default + species indicator. + type: Fix + id: 6897 + time: '2024-07-10T05:51:48.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/29492 From 92ba8c1a58bcb16a25d1a5e01df111de513b0898 Mon Sep 17 00:00:00 2001 From: Winkarst-cpu <74284083+Winkarst-cpu@users.noreply.github.com> Date: Wed, 10 Jul 2024 13:32:30 +0300 Subject: [PATCH 136/765] Custom solution transfer volume popup and item status panel fix (#29852) * Fix for custom solution transfer volume * Dirty call to prevent issues * Another fix, git issue --------- Co-authored-by: Winkarst-cpu --- .../Components/SolutionTransferComponent.cs | 3 ++- .../EntitySystems/SolutionTransferSystem.cs | 13 ++++++++++--- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/Content.Shared/Chemistry/Components/SolutionTransferComponent.cs b/Content.Shared/Chemistry/Components/SolutionTransferComponent.cs index b130304afc8..86d8da9d3d9 100644 --- a/Content.Shared/Chemistry/Components/SolutionTransferComponent.cs +++ b/Content.Shared/Chemistry/Components/SolutionTransferComponent.cs @@ -6,7 +6,7 @@ namespace Content.Shared.Chemistry.Components; /// /// Gives click behavior for transferring to/from other reagent containers. /// -[RegisterComponent, NetworkedComponent] +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] public sealed partial class SolutionTransferComponent : Component { /// @@ -14,6 +14,7 @@ public sealed partial class SolutionTransferComponent : Component /// [DataField("transferAmount")] [ViewVariables(VVAccess.ReadWrite)] + [AutoNetworkedField] public FixedPoint2 TransferAmount { get; set; } = FixedPoint2.New(5); /// diff --git a/Content.Shared/Chemistry/EntitySystems/SolutionTransferSystem.cs b/Content.Shared/Chemistry/EntitySystems/SolutionTransferSystem.cs index 93e9765b164..3b753925088 100644 --- a/Content.Shared/Chemistry/EntitySystems/SolutionTransferSystem.cs +++ b/Content.Shared/Chemistry/EntitySystems/SolutionTransferSystem.cs @@ -38,11 +38,15 @@ public override void Initialize() private void OnTransferAmountSetValueMessage(Entity ent, ref TransferAmountSetValueMessage message) { - var newTransferAmount = FixedPoint2.Clamp(message.Value, ent.Comp.MinimumTransferAmount, ent.Comp.MaximumTransferAmount); - ent.Comp.TransferAmount = newTransferAmount; + var (uid, comp) = ent; + + var newTransferAmount = FixedPoint2.Clamp(message.Value, comp.MinimumTransferAmount, comp.MaximumTransferAmount); + comp.TransferAmount = newTransferAmount; if (message.Actor is { Valid: true } user) - _popup.PopupClient(Loc.GetString("comp-solution-transfer-set-amount", ("amount", newTransferAmount)), ent, user); + _popup.PopupEntity(Loc.GetString("comp-solution-transfer-set-amount", ("amount", newTransferAmount)), uid, user); + + Dirty(uid, comp); } private void AddSetTransferVerbs(Entity ent, ref GetVerbsEvent args) @@ -78,7 +82,10 @@ private void AddSetTransferVerbs(Entity ent, ref GetV verb.Act = () => { comp.TransferAmount = amount; + _popup.PopupClient(Loc.GetString("comp-solution-transfer-set-amount", ("amount", amount)), uid, user); + + Dirty(uid, comp); }; // we want to sort by size, not alphabetically by the verb text. From f5cd1c01d8533b1973bcd791e5dd2a57c72aa110 Mon Sep 17 00:00:00 2001 From: PJBot Date: Wed, 10 Jul 2024 10:33:36 +0000 Subject: [PATCH 137/765] Automatic changelog update --- Resources/Changelog/Changelog.yml | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 2853c298123..1684c08e68b 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,11 +1,4 @@ Entries: -- author: Gyrandola - changes: - - message: Pepper sprites are now properly centered! - type: Fix - id: 6398 - time: '2024-04-20T02:06:48.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/25971 - author: ElectroJr changes: - message: Fixed a bug causing the emergency shuttle to not spawn @@ -3825,3 +3818,11 @@ id: 6897 time: '2024-07-10T05:51:48.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/29492 +- author: Winkarst-cpu + changes: + - message: Now confirmation popup is displayed and item panel status is updated + after setting a custom solution transfer volume. + type: Fix + id: 6898 + time: '2024-07-10T10:32:30.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/29852 From 06c31c3b9a9ff4c8c6461412a9a10d9efbbb41b3 Mon Sep 17 00:00:00 2001 From: Tunguso4ka <71643624+Tunguso4ka@users.noreply.github.com> Date: Wed, 10 Jul 2024 16:27:44 +0300 Subject: [PATCH 138/765] Fixed jobwhitelist locale (#29878) Fixed whitelist locale --- Resources/Locale/en-US/commands/job-whitelist-command.ftl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Resources/Locale/en-US/commands/job-whitelist-command.ftl b/Resources/Locale/en-US/commands/job-whitelist-command.ftl index 7fa20f03dec..a188f9ba5ce 100644 --- a/Resources/Locale/en-US/commands/job-whitelist-command.ftl +++ b/Resources/Locale/en-US/commands/job-whitelist-command.ftl @@ -9,12 +9,12 @@ cmd-jobwhitelistadd-already-whitelisted = {$player} is already whitelisted to pl cmd-jobwhitelistadd-added = Added {$player} to the {$jobId} ({$jobName}) whitelist. cmd-jobwhitelistget-desc = Gets all the jobs that a player has been whitelisted for. -cmd-jobwhitelistget-help = Usage: jobwhitelistadd +cmd-jobwhitelistget-help = Usage: jobwhitelistget cmd-jobwhitelistget-whitelisted-none = Player {$player} is not whitelisted for any jobs. cmd-jobwhitelistget-whitelisted-for = "Player {$player} is whitelisted for: {$jobs}" cmd-jobwhitelistremove-desc = Removes a player's ability to play a whitelisted job. -cmd-jobwhitelistremove-help = Usage: jobwhitelistadd +cmd-jobwhitelistremove-help = Usage: jobwhitelistremove cmd-jobwhitelistremove-was-not-whitelisted = {$player} was not whitelisted to play as {$jobId} ({$jobName}). cmd-jobwhitelistremove-removed = Removed {$player} from the whitelist for {$jobId} ({$jobName}). From 87fb12b6cb7b625d3b729b95579917f5b7e65b44 Mon Sep 17 00:00:00 2001 From: Tayrtahn Date: Wed, 10 Jul 2024 20:01:30 -0400 Subject: [PATCH 139/765] Replace ProtoId uses with EntProtoId (#29892) --- Content.Server/Geras/GerasComponent.cs | 2 +- Content.Shared/Bed/Sleep/SleepingSystem.cs | 4 ++-- .../Explosion/Components/OnTrigger/SmokeOnTriggerComponent.cs | 2 +- Content.Shared/PAI/PAIComponent.cs | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Content.Server/Geras/GerasComponent.cs b/Content.Server/Geras/GerasComponent.cs index eaf792502f4..df1fccd7185 100644 --- a/Content.Server/Geras/GerasComponent.cs +++ b/Content.Server/Geras/GerasComponent.cs @@ -12,7 +12,7 @@ public sealed partial class GerasComponent : Component { [DataField] public ProtoId GerasPolymorphId = "SlimeMorphGeras"; - [DataField] public ProtoId GerasAction = "ActionMorphGeras"; + [DataField] public EntProtoId GerasAction = "ActionMorphGeras"; [DataField] public EntityUid? GerasActionEntity; } diff --git a/Content.Shared/Bed/Sleep/SleepingSystem.cs b/Content.Shared/Bed/Sleep/SleepingSystem.cs index 581924c053b..648d1b40103 100644 --- a/Content.Shared/Bed/Sleep/SleepingSystem.cs +++ b/Content.Shared/Bed/Sleep/SleepingSystem.cs @@ -34,8 +34,8 @@ public sealed partial class SleepingSystem : EntitySystem [Dependency] private readonly SharedEmitSoundSystem _emitSound = default!; [Dependency] private readonly StatusEffectsSystem _statusEffectsSystem = default!; - public static readonly ProtoId SleepActionId = "ActionSleep"; - public static readonly ProtoId WakeActionId = "ActionWake"; + public static readonly EntProtoId SleepActionId = "ActionSleep"; + public static readonly EntProtoId WakeActionId = "ActionWake"; public override void Initialize() { diff --git a/Content.Shared/Explosion/Components/OnTrigger/SmokeOnTriggerComponent.cs b/Content.Shared/Explosion/Components/OnTrigger/SmokeOnTriggerComponent.cs index 80d65f4c2cd..1138e74af8f 100644 --- a/Content.Shared/Explosion/Components/OnTrigger/SmokeOnTriggerComponent.cs +++ b/Content.Shared/Explosion/Components/OnTrigger/SmokeOnTriggerComponent.cs @@ -29,7 +29,7 @@ public sealed partial class SmokeOnTriggerComponent : Component /// Defaults to smoke but you can use foam if you want. /// [DataField, ViewVariables(VVAccess.ReadWrite)] - public ProtoId SmokePrototype = "Smoke"; + public EntProtoId SmokePrototype = "Smoke"; /// /// Solution to add to each smoke cloud. diff --git a/Content.Shared/PAI/PAIComponent.cs b/Content.Shared/PAI/PAIComponent.cs index b4e4c927354..9d5be302758 100644 --- a/Content.Shared/PAI/PAIComponent.cs +++ b/Content.Shared/PAI/PAIComponent.cs @@ -31,7 +31,7 @@ public sealed partial class PAIComponent : Component public EntityUid? MidiAction; [DataField] - public ProtoId MapActionId = "ActionPAIOpenMap"; + public EntProtoId MapActionId = "ActionPAIOpenMap"; [DataField, AutoNetworkedField] public EntityUid? MapAction; From db596793c1b51519c133f18532d681f1c120ac6f Mon Sep 17 00:00:00 2001 From: Winkarst-cpu <74284083+Winkarst-cpu@users.noreply.github.com> Date: Thu, 11 Jul 2024 03:24:37 +0300 Subject: [PATCH 140/765] Character menu asks if you want to save your character on exit (#29875) * Character menu asks if you want to save your character on exit * Fix * Another fix, little mistake by me * Update Content.Client/Lobby/UI/CharacterSetupGuiSavePanel.xaml.cs --------- Co-authored-by: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com> --- Content.Client/Lobby/LobbyUIController.cs | 55 +++++++++++++++++-- .../Lobby/UI/CharacterSetupGuiSavePanel.xaml | 10 ++++ .../UI/CharacterSetupGuiSavePanel.xaml.cs | 21 +++++++ .../Lobby/UI/HumanoidProfileEditor.xaml.cs | 2 +- .../preferences/ui/character-setup-gui.ftl | 5 ++ 5 files changed, 86 insertions(+), 7 deletions(-) create mode 100644 Content.Client/Lobby/UI/CharacterSetupGuiSavePanel.xaml create mode 100644 Content.Client/Lobby/UI/CharacterSetupGuiSavePanel.xaml.cs diff --git a/Content.Client/Lobby/LobbyUIController.cs b/Content.Client/Lobby/LobbyUIController.cs index e4a13ed8c6b..824a842d560 100644 --- a/Content.Client/Lobby/LobbyUIController.cs +++ b/Content.Client/Lobby/LobbyUIController.cs @@ -46,6 +46,7 @@ public sealed class LobbyUIController : UIController, IOnStateEntered /// This is the characher preview panel in the chat. This should only update if their character updates. @@ -214,6 +215,46 @@ private void SaveProfile() ReloadCharacterSetup(); } + private void CloseProfileEditor() + { + if (_profileEditor == null) + return; + + _profileEditor.SetProfile(null, null); + _profileEditor.Visible = false; + + if (_stateManager.CurrentState is LobbyState lobbyGui) + { + lobbyGui.SwitchState(LobbyGui.LobbyGuiState.Default); + } + } + + private void OpenSavePanel() + { + if (_savePanel is { IsOpen: true }) + return; + + _savePanel = new CharacterSetupGuiSavePanel(); + + _savePanel.SaveButton.OnPressed += _ => + { + SaveProfile(); + + _savePanel.Close(); + + CloseProfileEditor(); + }; + + _savePanel.NoSaveButton.OnPressed += _ => + { + _savePanel.Close(); + + CloseProfileEditor(); + }; + + _savePanel.OpenCentered(); + } + private (CharacterSetupGui, HumanoidProfileEditor) EnsureGui() { if (_characterSetup != null && _profileEditor != null) @@ -240,14 +281,16 @@ private void SaveProfile() _characterSetup.CloseButton.OnPressed += _ => { - // Reset sliders etc. - _profileEditor.SetProfile(null, null); - _profileEditor.Visible = false; - - if (_stateManager.CurrentState is LobbyState lobbyGui) + // Open the save panel if we have unsaved changes. + if (_profileEditor.Profile != null && _profileEditor.IsDirty) { - lobbyGui.SwitchState(LobbyGui.LobbyGuiState.Default); + OpenSavePanel(); + + return; } + + // Reset sliders etc. + CloseProfileEditor(); }; _profileEditor.Save += SaveProfile; diff --git a/Content.Client/Lobby/UI/CharacterSetupGuiSavePanel.xaml b/Content.Client/Lobby/UI/CharacterSetupGuiSavePanel.xaml new file mode 100644 index 00000000000..2dcf9143533 --- /dev/null +++ b/Content.Client/Lobby/UI/CharacterSetupGuiSavePanel.xaml @@ -0,0 +1,10 @@ + + + + -[RegisterComponent, Access(typeof(SharedBatteryDrainerSystem))] +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +[Access(typeof(SharedBatteryDrainerSystem))] public sealed partial class BatteryDrainerComponent : Component { /// /// The powercell entity to drain power into. /// Determines whether draining is possible. /// - [DataField("batteryUid"), ViewVariables(VVAccess.ReadWrite)] + [DataField, AutoNetworkedField] public EntityUid? BatteryUid; /// /// Conversion rate between joules in a device and joules added to battery. /// Should be very low since powercells store nothing compared to even an APC. /// - [DataField("drainEfficiency"), ViewVariables(VVAccess.ReadWrite)] + [DataField] public float DrainEfficiency = 0.001f; /// /// Time that the do after takes to drain charge from a battery, in seconds /// - [DataField("drainTime"), ViewVariables(VVAccess.ReadWrite)] + [DataField] public float DrainTime = 1f; /// /// Sound played after the doafter ends. /// - [DataField("sparkSound")] + [DataField] public SoundSpecifier SparkSound = new SoundCollectionSpecifier("sparks"); } diff --git a/Content.Shared/Ninja/Components/BombingTargetComponent.cs b/Content.Shared/Ninja/Components/BombingTargetComponent.cs index bf0eaec84be..c429eb6880e 100644 --- a/Content.Shared/Ninja/Components/BombingTargetComponent.cs +++ b/Content.Shared/Ninja/Components/BombingTargetComponent.cs @@ -4,6 +4,4 @@ namespace Content.Shared.Ninja.Components; /// Makes this warp point a valid bombing target for ninja's spider charge. /// [RegisterComponent] -public sealed partial class BombingTargetComponent : Component -{ -} +public sealed partial class BombingTargetComponent : Component; diff --git a/Content.Shared/Ninja/Components/DashAbilityComponent.cs b/Content.Shared/Ninja/Components/DashAbilityComponent.cs index ba4060c7035..464f48f187e 100644 --- a/Content.Shared/Ninja/Components/DashAbilityComponent.cs +++ b/Content.Shared/Ninja/Components/DashAbilityComponent.cs @@ -8,6 +8,7 @@ namespace Content.Shared.Ninja.Components; /// /// Adds an action to dash, teleport to clicked position, when this item is held. +/// Cancel to prevent using it. /// [RegisterComponent, NetworkedComponent, Access(typeof(DashAbilitySystem)), AutoGenerateComponentState] public sealed partial class DashAbilityComponent : Component @@ -16,19 +17,10 @@ public sealed partial class DashAbilityComponent : Component /// The action id for dashing. /// [DataField] - public EntProtoId DashAction = "ActionEnergyKatanaDash"; + public EntProtoId DashAction = "ActionEnergyKatanaDash"; [DataField, AutoNetworkedField] public EntityUid? DashActionEntity; - - /// - /// Sound played when using dash action. - /// - [DataField("blinkSound"), ViewVariables(VVAccess.ReadWrite)] - public SoundSpecifier BlinkSound = new SoundPathSpecifier("/Audio/Magic/blink.ogg") - { - Params = AudioParams.Default.WithVolume(5f) - }; } -public sealed partial class DashEvent : WorldTargetActionEvent { } +public sealed partial class DashEvent : WorldTargetActionEvent; diff --git a/Content.Shared/Ninja/Components/EmagProviderComponent.cs b/Content.Shared/Ninja/Components/EmagProviderComponent.cs index db7678f61d7..ae3e85cbe42 100644 --- a/Content.Shared/Ninja/Components/EmagProviderComponent.cs +++ b/Content.Shared/Ninja/Components/EmagProviderComponent.cs @@ -2,7 +2,7 @@ using Content.Shared.Tag; using Content.Shared.Whitelist; using Robust.Shared.GameStates; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; +using Robust.Shared.Prototypes; namespace Content.Shared.Ninja.Components; @@ -10,19 +10,18 @@ namespace Content.Shared.Ninja.Components; /// Component for emagging things on click. /// No charges but checks against a whitelist. /// -[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] -[Access(typeof(EmagProviderSystem))] +[RegisterComponent, NetworkedComponent, Access(typeof(EmagProviderSystem))] public sealed partial class EmagProviderComponent : Component { /// /// The tag that marks an entity as immune to emagging. /// - [DataField("emagImmuneTag", customTypeSerializer: typeof(PrototypeIdSerializer))] - public string EmagImmuneTag = "EmagImmune"; + [DataField] + public ProtoId EmagImmuneTag = "EmagImmune"; /// /// Whitelist that entities must be on to work. /// - [DataField("whitelist"), ViewVariables(VVAccess.ReadWrite), AutoNetworkedField] - public EntityWhitelist? Whitelist = null; + [DataField] + public EntityWhitelist? Whitelist; } diff --git a/Content.Shared/Ninja/Components/EnergyKatanaComponent.cs b/Content.Shared/Ninja/Components/EnergyKatanaComponent.cs index 33b8fc78933..84c58bb6480 100644 --- a/Content.Shared/Ninja/Components/EnergyKatanaComponent.cs +++ b/Content.Shared/Ninja/Components/EnergyKatanaComponent.cs @@ -7,6 +7,4 @@ namespace Content.Shared.Ninja.Components; /// Requires a ninja with a suit for abilities to work. /// [RegisterComponent, NetworkedComponent] -public sealed partial class EnergyKatanaComponent : Component -{ -} +public sealed partial class EnergyKatanaComponent : Component; diff --git a/Content.Shared/Ninja/Components/ItemCreatorComponent.cs b/Content.Shared/Ninja/Components/ItemCreatorComponent.cs new file mode 100644 index 00000000000..d9f66d21a31 --- /dev/null +++ b/Content.Shared/Ninja/Components/ItemCreatorComponent.cs @@ -0,0 +1,52 @@ +using Content.Shared.Actions; +using Content.Shared.Ninja.Systems; +using Robust.Shared.GameStates; +using Robust.Shared.Prototypes; + +namespace Content.Shared.Ninja.Components; + +/// +/// Uses battery charge to spawn an item and place it in the user's hands. +/// +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +[Access(typeof(SharedItemCreatorSystem))] +public sealed partial class ItemCreatorComponent : Component +{ + /// + /// The battery entity to use charge from + /// + [DataField, AutoNetworkedField] + public EntityUid? Battery; + + /// + /// The action id for creating an item. + /// + [DataField(required: true)] + public EntProtoId Action = string.Empty; + + [DataField, AutoNetworkedField] + public EntityUid? ActionEntity; + + /// + /// Battery charge used to create an item. + /// + [DataField(required: true)] + public float Charge = 14.4f; + + /// + /// Item to create with the action + /// + [DataField(required: true)] + public EntProtoId SpawnedPrototype = string.Empty; + + /// + /// Popup shown to the user when there isn't enough power to create an item. + /// + [DataField(required: true)] + public LocId NoPowerPopup = string.Empty; +} + +/// +/// Action event to use an . +/// +public sealed partial class CreateItemEvent : InstantActionEvent; diff --git a/Content.Shared/Ninja/Components/NinjaGlovesComponent.cs b/Content.Shared/Ninja/Components/NinjaGlovesComponent.cs index 7b57926330b..3b9e2a5e356 100644 --- a/Content.Shared/Ninja/Components/NinjaGlovesComponent.cs +++ b/Content.Shared/Ninja/Components/NinjaGlovesComponent.cs @@ -1,20 +1,17 @@ -using Content.Shared.DoAfter; using Content.Shared.Ninja.Systems; -using Content.Shared.Toggleable; -using Content.Shared.Whitelist; +using Content.Shared.Objectives.Components; using Robust.Shared.Audio; using Robust.Shared.GameStates; using Robust.Shared.Prototypes; -using Robust.Shared.Serialization; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; -using Robust.Shared.Utility; namespace Content.Shared.Ninja.Components; /// /// Component for toggling glove powers. -/// Powers being enabled is controlled by User not being null. /// +/// +/// Requires ItemToggleComponent. +/// [RegisterComponent, NetworkedComponent, AutoGenerateComponentState] [Access(typeof(SharedNinjaGlovesSystem))] public sealed partial class NinjaGlovesComponent : Component @@ -22,24 +19,33 @@ public sealed partial class NinjaGlovesComponent : Component /// /// Entity of the ninja using these gloves, usually means enabled /// - [DataField("user"), AutoNetworkedField] + [DataField, AutoNetworkedField] public EntityUid? User; /// - /// The action id for toggling ninja gloves abilities + /// Abilities to give to the user when enabled. /// - [DataField("toggleAction", customTypeSerializer: typeof(PrototypeIdSerializer))] - public string ToggleAction = "ActionToggleNinjaGloves"; + [DataField(required: true)] + public List Abilities = new(); +} - [DataField, AutoNetworkedField] - public EntityUid? ToggleActionEntity; +/// +/// An ability that adds components to the user when the gloves are enabled. +/// +[DataRecord] +public record struct NinjaGloveAbility() +{ + /// + /// If not null, checks if an objective with this prototype has been completed. + /// If it has, the ability components are skipped to prevent doing the objective twice. + /// The objective must have CodeConditionComponent to be checked. + /// + [DataField] + public EntProtoId? Objective; /// - /// The whitelist used for the emag provider to emag airlocks only (not regular doors). + /// Components to add and remove. /// - [DataField("doorjackWhitelist")] - public EntityWhitelist DoorjackWhitelist = new() - { - Components = new[] {"Airlock"} - }; + [DataField(required: true)] + public ComponentRegistry Components = new(); } diff --git a/Content.Shared/Ninja/Components/NinjaSuitComponent.cs b/Content.Shared/Ninja/Components/NinjaSuitComponent.cs index 7e7b1ffcd30..8b477b2aa5f 100644 --- a/Content.Shared/Ninja/Components/NinjaSuitComponent.cs +++ b/Content.Shared/Ninja/Components/NinjaSuitComponent.cs @@ -3,9 +3,6 @@ using Robust.Shared.Audio; using Robust.Shared.GameStates; using Robust.Shared.Prototypes; -using Robust.Shared.Serialization; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; using Robust.Shared.Utility; namespace Content.Shared.Ninja.Components; @@ -14,68 +11,27 @@ namespace Content.Shared.Ninja.Components; /// Component for ninja suit abilities and power consumption. /// As an implementation detail, dashing with katana is a suit action which isn't ideal. /// -[RegisterComponent, NetworkedComponent, Access(typeof(SharedNinjaSuitSystem)), AutoGenerateComponentState] -[AutoGenerateComponentPause] +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +[Access(typeof(SharedNinjaSuitSystem))] public sealed partial class NinjaSuitComponent : Component { - /// - /// Battery charge used passively, in watts. Will last 1000 seconds on a small-capacity power cell. - /// - [DataField("passiveWattage")] - public float PassiveWattage = 0.36f; - - /// - /// Battery charge used while cloaked, stacks with passive. Will last 200 seconds while cloaked on a small-capacity power cell. - /// - [DataField("cloakWattage")] - public float CloakWattage = 1.44f; - /// /// Sound played when a ninja is hit while cloaked. /// - [DataField("revealSound")] + [DataField] public SoundSpecifier RevealSound = new SoundPathSpecifier("/Audio/Effects/chime.ogg"); /// - /// How long to disable all abilities when revealed. - /// Normally, ninjas are revealed when attacking or getting damaged. - /// - [DataField("disableTime")] - public TimeSpan DisableTime = TimeSpan.FromSeconds(5); - - /// - /// Time at which we will be able to use our abilities again + /// ID of the use delay to disable all ninja abilities. /// - [DataField(customTypeSerializer: typeof(TimeOffsetSerializer))] - [AutoPausedField] - public TimeSpan DisableCooldown; - - /// - /// The action id for creating throwing stars. - /// - [DataField("createThrowingStarAction", customTypeSerializer: typeof(PrototypeIdSerializer))] - public string CreateThrowingStarAction = "ActionCreateThrowingStar"; - - [DataField, AutoNetworkedField] - public EntityUid? CreateThrowingStarActionEntity; - - /// - /// Battery charge used to create a throwing star. Can do it 25 times on a small-capacity power cell. - /// - [DataField("throwingStarCharge")] - public float ThrowingStarCharge = 14.4f; - - /// - /// Throwing star item to create with the action - /// - [DataField("throwingStarPrototype", customTypeSerializer: typeof(PrototypeIdSerializer))] - public string ThrowingStarPrototype = "ThrowingStarNinja"; + [DataField] + public string DisableDelayId = "suit_powers"; /// /// The action id for recalling a bound energy katana /// - [DataField("recallKatanaAction", customTypeSerializer: typeof(PrototypeIdSerializer))] - public string RecallKatanaAction = "ActionRecallKatana"; + [DataField] + public EntProtoId RecallKatanaAction = "ActionRecallKatana"; [DataField, AutoNetworkedField] public EntityUid? RecallKatanaActionEntity; @@ -84,14 +40,14 @@ public sealed partial class NinjaSuitComponent : Component /// Battery charge used per tile the katana teleported. /// Uses 1% of a default battery per tile. /// - [DataField("recallCharge")] + [DataField] public float RecallCharge = 3.6f; /// /// The action id for creating an EMP burst /// - [DataField("empAction", customTypeSerializer: typeof(PrototypeIdSerializer))] - public string EmpAction = "ActionNinjaEmp"; + [DataField] + public EntProtoId EmpAction = "ActionNinjaEmp"; [DataField, AutoNetworkedField] public EntityUid? EmpActionEntity; @@ -99,36 +55,29 @@ public sealed partial class NinjaSuitComponent : Component /// /// Battery charge used to create an EMP burst. Can do it 2 times on a small-capacity power cell. /// - [DataField("empCharge")] + [DataField] public float EmpCharge = 180f; + // TODO: EmpOnTrigger bruh /// /// Range of the EMP in tiles. /// - [DataField("empRange")] + [DataField] public float EmpRange = 6f; /// /// Power consumed from batteries by the EMP /// - [DataField("empConsumption")] + [DataField] public float EmpConsumption = 100000f; /// /// How long the EMP effects last for, in seconds /// - [DataField("empDuration")] + [DataField] public float EmpDuration = 60f; } -public sealed partial class CreateThrowingStarEvent : InstantActionEvent -{ -} - -public sealed partial class RecallKatanaEvent : InstantActionEvent -{ -} +public sealed partial class RecallKatanaEvent : InstantActionEvent; -public sealed partial class NinjaEmpEvent : InstantActionEvent -{ -} +public sealed partial class NinjaEmpEvent : InstantActionEvent; diff --git a/Content.Shared/Ninja/Components/SpaceNinjaComponent.cs b/Content.Shared/Ninja/Components/SpaceNinjaComponent.cs index 91c816df5c9..a19537be1c8 100644 --- a/Content.Shared/Ninja/Components/SpaceNinjaComponent.cs +++ b/Content.Shared/Ninja/Components/SpaceNinjaComponent.cs @@ -7,34 +7,28 @@ namespace Content.Shared.Ninja.Components; /// /// Component placed on a mob to make it a space ninja, able to use suit and glove powers. -/// Contains ids of all ninja equipment and the game rule. +/// Contains ids of all ninja equipment. /// [RegisterComponent, NetworkedComponent, AutoGenerateComponentState] [Access(typeof(SharedSpaceNinjaSystem))] public sealed partial class SpaceNinjaComponent : Component { - /// - /// The ninja game rule that spawned this ninja. - /// - [DataField("rule")] - public EntityUid? Rule; - /// /// Currently worn suit /// - [DataField("suit"), AutoNetworkedField] + [DataField, AutoNetworkedField] public EntityUid? Suit; /// - /// Currently worn gloves + /// Currently worn gloves, if enabled. /// - [DataField("gloves"), AutoNetworkedField] + [DataField, AutoNetworkedField] public EntityUid? Gloves; /// /// Bound katana, set once picked up and never removed /// - [DataField("katana"), AutoNetworkedField] + [DataField, AutoNetworkedField] public EntityUid? Katana; /// @@ -55,6 +49,9 @@ public sealed partial class SpaceNinjaComponent : Component [DataField] public EntProtoId SpiderChargeObjective = "SpiderChargeObjective"; + /// + /// Alert to show for suit power. + /// [DataField] public ProtoId SuitPowerAlert = "SuitPower"; } diff --git a/Content.Shared/Ninja/Components/SpiderChargeComponent.cs b/Content.Shared/Ninja/Components/SpiderChargeComponent.cs index dacf47bb235..3ba4494cca4 100644 --- a/Content.Shared/Ninja/Components/SpiderChargeComponent.cs +++ b/Content.Shared/Ninja/Components/SpiderChargeComponent.cs @@ -1,3 +1,4 @@ +using Content.Shared.Ninja.Systems; using Robust.Shared.GameStates; namespace Content.Shared.Ninja.Components; @@ -6,14 +7,14 @@ namespace Content.Shared.Ninja.Components; /// Component for the Space Ninja's unique Spider Charge. /// Only this component detonating can trigger the ninja's objective. /// -[RegisterComponent, NetworkedComponent] +[RegisterComponent, NetworkedComponent, Access(typeof(SharedSpiderChargeSystem))] public sealed partial class SpiderChargeComponent : Component { /// Range for planting within the target area - [DataField("range")] + [DataField] public float Range = 10f; /// The ninja that planted this charge - [DataField("planter")] - public EntityUid? Planter = null; + [DataField] + public EntityUid? Planter; } diff --git a/Content.Shared/Ninja/Components/StunProviderComponent.cs b/Content.Shared/Ninja/Components/StunProviderComponent.cs index 37a27074a49..2da094291d7 100644 --- a/Content.Shared/Ninja/Components/StunProviderComponent.cs +++ b/Content.Shared/Ninja/Components/StunProviderComponent.cs @@ -3,7 +3,6 @@ using Content.Shared.Whitelist; using Robust.Shared.Audio; using Robust.Shared.GameStates; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom; namespace Content.Shared.Ninja.Components; @@ -11,32 +10,33 @@ namespace Content.Shared.Ninja.Components; /// Component for stunning mobs on click outside of harm mode. /// Knocks them down for a bit and deals shock damage. /// -[RegisterComponent, NetworkedComponent, AutoGenerateComponentState, Access(typeof(SharedStunProviderSystem))] +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +[Access(typeof(SharedStunProviderSystem))] public sealed partial class StunProviderComponent : Component { /// /// The powercell entity to take power from. /// Determines whether stunning is possible. /// - [DataField, ViewVariables(VVAccess.ReadWrite), AutoNetworkedField] + [DataField, AutoNetworkedField] public EntityUid? BatteryUid; /// /// Sound played when stunning someone. /// - [DataField, ViewVariables(VVAccess.ReadWrite)] + [DataField] public SoundSpecifier Sound = new SoundCollectionSpecifier("sparks"); /// /// Joules required in the battery to stun someone. Defaults to 10 uses on a small battery. /// - [DataField, ViewVariables(VVAccess.ReadWrite)] + [DataField] public float StunCharge = 36f; /// /// Damage dealt when stunning someone /// - [DataField, ViewVariables(VVAccess.ReadWrite)] + [DataField] public DamageSpecifier StunDamage = new() { DamageDict = new() @@ -48,34 +48,30 @@ public sealed partial class StunProviderComponent : Component /// /// Time that someone is stunned for, stacks if done multiple times. /// - [DataField, ViewVariables(VVAccess.ReadWrite)] + [DataField] public TimeSpan StunTime = TimeSpan.FromSeconds(5); /// /// How long stunning is disabled after stunning something. /// - [DataField, ViewVariables(VVAccess.ReadWrite)] + [DataField] public TimeSpan Cooldown = TimeSpan.FromSeconds(2); /// - /// Locale string to popup when there is no power + /// ID of the cooldown use delay. /// - [DataField(required: true), ViewVariables(VVAccess.ReadWrite)] - public string NoPowerPopup = string.Empty; + [DataField] + public string DelayId = "stun_cooldown"; /// - /// Whitelist for what counts as a mob. + /// Locale string to popup when there is no power /// - [DataField] - public EntityWhitelist Whitelist = new() - { - Components = new[] {"Stamina"} - }; + [DataField(required: true)] + public LocId NoPowerPopup = string.Empty; /// - /// When someone can next be stunned. - /// Essentially a UseDelay unique to this component. + /// Whitelist for what counts as a mob. /// - [DataField(customTypeSerializer: typeof(TimeOffsetSerializer)), ViewVariables(VVAccess.ReadWrite)] - public TimeSpan NextStun = TimeSpan.Zero; + [DataField(required: true)] + public EntityWhitelist Whitelist = new(); } diff --git a/Content.Shared/Ninja/Systems/DashAbilitySystem.cs b/Content.Shared/Ninja/Systems/DashAbilitySystem.cs index 4853968b61f..1385219e473 100644 --- a/Content.Shared/Ninja/Systems/DashAbilitySystem.cs +++ b/Content.Shared/Ninja/Systems/DashAbilitySystem.cs @@ -16,6 +16,7 @@ namespace Content.Shared.Ninja.Systems; /// public sealed class DashAbilitySystem : EntitySystem { + [Dependency] private readonly ActionContainerSystem _actionContainer = default!; [Dependency] private readonly IGameTiming _timing = default!; [Dependency] private readonly SharedAudioSystem _audio = default!; [Dependency] private readonly SharedChargesSystem _charges = default!; @@ -23,48 +24,40 @@ public sealed class DashAbilitySystem : EntitySystem [Dependency] private readonly ExamineSystemShared _examine = default!; [Dependency] private readonly SharedPopupSystem _popup = default!; [Dependency] private readonly SharedTransformSystem _transform = default!; - [Dependency] private readonly ActionContainerSystem _actionContainer = default!; public override void Initialize() { base.Initialize(); - SubscribeLocalEvent(OnGetItemActions); + SubscribeLocalEvent(OnGetActions); SubscribeLocalEvent(OnDash); SubscribeLocalEvent(OnMapInit); } - private void OnMapInit(EntityUid uid, DashAbilityComponent component, MapInitEvent args) + private void OnMapInit(Entity ent, ref MapInitEvent args) { - _actionContainer.EnsureAction(uid, ref component.DashActionEntity, component.DashAction); - Dirty(uid, component); + var (uid, comp) = ent; + _actionContainer.EnsureAction(uid, ref comp.DashActionEntity, comp.DashAction); + Dirty(uid, comp); } - private void OnGetItemActions(EntityUid uid, DashAbilityComponent comp, GetItemActionsEvent args) + private void OnGetActions(Entity ent, ref GetItemActionsEvent args) { - var ev = new AddDashActionEvent(args.User); - RaiseLocalEvent(uid, ev); - - if (ev.Cancelled) - return; - - args.AddAction(ref comp.DashActionEntity, comp.DashAction); + if (CheckDash(ent, args.User)) + args.AddAction(ent.Comp.DashActionEntity); } /// /// Handle charges and teleport to a visible location. /// - private void OnDash(EntityUid uid, DashAbilityComponent comp, DashEvent args) + private void OnDash(Entity ent, ref DashEvent args) { if (!_timing.IsFirstTimePredicted) return; + var (uid, comp) = ent; var user = args.Performer; - args.Handled = true; - - var ev = new DashAttemptEvent(user); - RaiseLocalEvent(uid, ev); - if (ev.Cancelled) + if (!CheckDash(uid, user)) return; if (!_hands.IsHolding(user, uid, out var _)) @@ -73,15 +66,8 @@ private void OnDash(EntityUid uid, DashAbilityComponent comp, DashEvent args) return; } - TryComp(uid, out var charges); - if (_charges.IsEmpty(uid, charges)) - { - _popup.PopupClient(Loc.GetString("dash-ability-no-charges", ("item", uid)), user, user); - return; - } var origin = _transform.GetMapCoordinates(user); var target = args.Target.ToMap(EntityManager, _transform); - // prevent collision with the user duh if (!_examine.InRangeUnOccluded(origin, target, SharedInteractionSystem.MaxRaycastRange, null)) { // can only dash if the destination is visible on screen @@ -89,36 +75,28 @@ private void OnDash(EntityUid uid, DashAbilityComponent comp, DashEvent args) return; } - _transform.SetCoordinates(user, args.Target); - _transform.AttachToGridOrMap(user); - _audio.PlayPredicted(comp.BlinkSound, user, user); - if (charges != null) - _charges.UseCharge(uid, charges); - } -} + if (!_charges.TryUseCharge(uid)) + { + _popup.PopupClient(Loc.GetString("dash-ability-no-charges", ("item", uid)), user, user); + return; + } -/// -/// Raised on the item before adding the dash action -/// -public sealed class AddDashActionEvent : CancellableEntityEventArgs -{ - public EntityUid User; + var xform = Transform(user); + _transform.SetCoordinates(user, xform, args.Target); + _transform.AttachToGridOrMap(user, xform); + args.Handled = true; + } - public AddDashActionEvent(EntityUid user) + public bool CheckDash(EntityUid uid, EntityUid user) { - User = user; + var ev = new CheckDashEvent(user); + RaiseLocalEvent(uid, ref ev); + return !ev.Cancelled; } } /// -/// Raised on the item before dashing is done. +/// Raised on the item before adding the dash action and when using the action. /// -public sealed class DashAttemptEvent : CancellableEntityEventArgs -{ - public EntityUid User; - - public DashAttemptEvent(EntityUid user) - { - User = user; - } -} +[ByRefEvent] +public record struct CheckDashEvent(EntityUid User, bool Cancelled = false); diff --git a/Content.Shared/Ninja/Systems/EmagProviderSystem.cs b/Content.Shared/Ninja/Systems/EmagProviderSystem.cs index 6838e7982cb..ae0bacaf5f6 100644 --- a/Content.Shared/Ninja/Systems/EmagProviderSystem.cs +++ b/Content.Shared/Ninja/Systems/EmagProviderSystem.cs @@ -1,6 +1,6 @@ using Content.Shared.Administration.Logs; -using Content.Shared.Emag.Systems; using Content.Shared.Database; +using Content.Shared.Emag.Systems; using Content.Shared.Interaction; using Content.Shared.Ninja.Components; using Content.Shared.Tag; @@ -14,10 +14,10 @@ namespace Content.Shared.Ninja.Systems; public sealed class EmagProviderSystem : EntitySystem { [Dependency] private readonly EmagSystem _emag = default!; + [Dependency] private readonly EntityWhitelistSystem _whitelist = default!; [Dependency] private readonly ISharedAdminLogManager _adminLogger = default!; [Dependency] private readonly SharedNinjaGlovesSystem _gloves = default!; - [Dependency] private readonly TagSystem _tags = default!; - [Dependency] private readonly EntityWhitelistSystem _whitelistSystem = default!; + [Dependency] private readonly TagSystem _tag = default!; public override void Initialize() { @@ -29,18 +29,20 @@ public override void Initialize() /// /// Emag clicked entities that are on the whitelist. /// - private void OnBeforeInteractHand(EntityUid uid, EmagProviderComponent comp, BeforeInteractHandEvent args) + private void OnBeforeInteractHand(Entity ent, ref BeforeInteractHandEvent args) { // TODO: change this into a generic check event thing - if (args.Handled || !_gloves.AbilityCheck(uid, args, out var target)) + if (args.Handled || !_gloves.AbilityCheck(ent, args, out var target)) return; + var (uid, comp) = ent; + // only allowed to emag entities on the whitelist - if (_whitelistSystem.IsWhitelistFail(comp.Whitelist, target)) + if (_whitelist.IsWhitelistFail(comp.Whitelist, target)) return; // only allowed to emag non-immune entities - if (_tags.HasTag(target, comp.EmagImmuneTag)) + if (_tag.HasTag(target, comp.EmagImmuneTag)) return; var handled = _emag.DoEmagEffect(uid, target); @@ -52,18 +54,6 @@ private void OnBeforeInteractHand(EntityUid uid, EmagProviderComponent comp, Bef RaiseLocalEvent(uid, ref ev); args.Handled = true; } - - /// - /// Set the whitelist for emagging something outside of yaml. - /// - public void SetWhitelist(EntityUid uid, EntityWhitelist? whitelist, EmagProviderComponent? comp = null) - { - if (!Resolve(uid, ref comp)) - return; - - comp.Whitelist = whitelist; - Dirty(uid, comp); - } } /// diff --git a/Content.Shared/Ninja/Systems/EnergyKatanaSystem.cs b/Content.Shared/Ninja/Systems/EnergyKatanaSystem.cs index d427ffa39b4..281b97a648a 100644 --- a/Content.Shared/Ninja/Systems/EnergyKatanaSystem.cs +++ b/Content.Shared/Ninja/Systems/EnergyKatanaSystem.cs @@ -15,33 +15,20 @@ public override void Initialize() base.Initialize(); SubscribeLocalEvent(OnEquipped); - SubscribeLocalEvent(OnAddDashAction); - SubscribeLocalEvent(OnDashAttempt); + SubscribeLocalEvent(OnCheckDash); } /// /// When equipped by a ninja, try to bind it. /// - private void OnEquipped(EntityUid uid, EnergyKatanaComponent comp, GotEquippedEvent args) + private void OnEquipped(Entity ent, ref GotEquippedEvent args) { - // check if user isnt a ninja or already has a katana bound - var user = args.Equipee; - if (!TryComp(user, out var ninja) || ninja.Katana != null) - return; - - // bind it since its unbound - _ninja.BindKatana(user, uid, ninja); - } - - private void OnAddDashAction(EntityUid uid, EnergyKatanaComponent comp, AddDashActionEvent args) - { - if (!HasComp(args.User)) - args.Cancel(); + _ninja.BindKatana(args.Equipee, ent); } - private void OnDashAttempt(EntityUid uid, EnergyKatanaComponent comp, DashAttemptEvent args) + private void OnCheckDash(Entity ent, ref CheckDashEvent args) { - if (!TryComp(args.User, out var ninja) || ninja.Katana != uid) - args.Cancel(); + if (!_ninja.IsNinja(args.User)) + args.Cancelled = true; } } diff --git a/Content.Shared/Ninja/Systems/ItemCreatorSystem.cs b/Content.Shared/Ninja/Systems/ItemCreatorSystem.cs new file mode 100644 index 00000000000..56112e9a697 --- /dev/null +++ b/Content.Shared/Ninja/Systems/ItemCreatorSystem.cs @@ -0,0 +1,56 @@ +using Content.Shared.Actions; +using Content.Shared.Ninja.Components; + +namespace Content.Shared.Ninja.Systems; + +/// +/// Handles predicting that the action exists, creating items is done serverside. +/// +public abstract class SharedItemCreatorSystem : EntitySystem +{ + [Dependency] private readonly ActionContainerSystem _actionContainer = default!; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnMapInit); + SubscribeLocalEvent(OnGetActions); + } + + private void OnMapInit(Entity ent, ref MapInitEvent args) + { + var (uid, comp) = ent; + // test funny dont mind me + if (string.IsNullOrEmpty(comp.Action)) + return; + + _actionContainer.EnsureAction(uid, ref comp.ActionEntity, comp.Action); + Dirty(uid, comp); + } + + private void OnGetActions(Entity ent, ref GetItemActionsEvent args) + { + if (CheckItemCreator(ent, args.User)) + args.AddAction(ent.Comp.ActionEntity); + } + + public bool CheckItemCreator(EntityUid uid, EntityUid user) + { + var ev = new CheckItemCreatorEvent(user); + RaiseLocalEvent(uid, ref ev); + return !ev.Cancelled; + } +} + +/// +/// Raised on the item creator before adding the action. +/// +[ByRefEvent] +public record struct CheckItemCreatorEvent(EntityUid User, bool Cancelled = false); + +/// +/// Raised on the item creator before creating an item. +/// +[ByRefEvent] +public record struct CreateItemAttemptEvent(EntityUid User, bool Cancelled = false); diff --git a/Content.Shared/Ninja/Systems/SharedBatteryDrainerSystem.cs b/Content.Shared/Ninja/Systems/SharedBatteryDrainerSystem.cs index ac11063eb71..0abcca7d1bd 100644 --- a/Content.Shared/Ninja/Systems/SharedBatteryDrainerSystem.cs +++ b/Content.Shared/Ninja/Systems/SharedBatteryDrainerSystem.cs @@ -18,34 +18,32 @@ public override void Initialize() } /// - /// Cancel any drain doafters if the battery is removed or gets filled. + /// Cancel any drain doafters if the battery is removed or, on the server, gets filled. /// - protected virtual void OnDoAfterAttempt(EntityUid uid, BatteryDrainerComponent comp, DoAfterAttemptEvent args) + protected virtual void OnDoAfterAttempt(Entity ent, ref DoAfterAttemptEvent args) { - if (comp.BatteryUid == null) - { + if (ent.Comp.BatteryUid == null) args.Cancel(); - } } /// /// Drain power from a power source (on server) and repeat if it succeeded. /// Client will predict always succeeding since power is serverside. /// - private void OnDoAfter(EntityUid uid, BatteryDrainerComponent comp, DrainDoAfterEvent args) + private void OnDoAfter(Entity ent, ref DrainDoAfterEvent args) { - if (args.Cancelled || args.Handled || args.Target == null) + if (args.Cancelled || args.Handled || args.Target is not {} target) return; // repeat if there is still power to drain - args.Repeat = TryDrainPower(uid, comp, args.Target.Value); + args.Repeat = TryDrainPower(ent, target); } /// /// Attempt to drain as much power as possible into the powercell. /// Client always predicts this as succeeding since power is serverside and it can only fail once, when the powercell is filled or the target is emptied. /// - protected virtual bool TryDrainPower(EntityUid uid, BatteryDrainerComponent comp, EntityUid target) + protected virtual bool TryDrainPower(Entity ent, EntityUid target) { return true; } @@ -53,12 +51,13 @@ protected virtual bool TryDrainPower(EntityUid uid, BatteryDrainerComponent comp /// /// Sets the battery field on the drainer. /// - public void SetBattery(EntityUid uid, EntityUid? battery, BatteryDrainerComponent? comp = null) + public void SetBattery(Entity ent, EntityUid? battery) { - if (!Resolve(uid, ref comp)) + if (!Resolve(ent, ref ent.Comp) || ent.Comp.BatteryUid == battery) return; - comp.BatteryUid = battery; + ent.Comp.BatteryUid = battery; + Dirty(ent, ent.Comp); } } @@ -66,4 +65,4 @@ public void SetBattery(EntityUid uid, EntityUid? battery, BatteryDrainerComponen /// DoAfter event for . /// [Serializable, NetSerializable] -public sealed partial class DrainDoAfterEvent : SimpleDoAfterEvent { } +public sealed partial class DrainDoAfterEvent : SimpleDoAfterEvent; diff --git a/Content.Shared/Ninja/Systems/SharedNinjaGlovesSystem.cs b/Content.Shared/Ninja/Systems/SharedNinjaGlovesSystem.cs index f61d0c6a908..8b892190b7b 100644 --- a/Content.Shared/Ninja/Systems/SharedNinjaGlovesSystem.cs +++ b/Content.Shared/Ninja/Systems/SharedNinjaGlovesSystem.cs @@ -1,15 +1,13 @@ -using Content.Shared.Actions; +using Content.Shared.Clothing.Components; using Content.Shared.CombatMode; -using Content.Shared.Communications; -using Content.Shared.CriminalRecords.Components; using Content.Shared.Examine; using Content.Shared.Hands.Components; using Content.Shared.Interaction; using Content.Shared.Inventory.Events; +using Content.Shared.Item.ItemToggle; +using Content.Shared.Item.ItemToggle.Components; using Content.Shared.Ninja.Components; using Content.Shared.Popups; -using Content.Shared.Research.Components; -using Content.Shared.Toggleable; using Robust.Shared.Timing; namespace Content.Shared.Ninja.Systems; @@ -20,85 +18,105 @@ namespace Content.Shared.Ninja.Systems; public abstract class SharedNinjaGlovesSystem : EntitySystem { [Dependency] private readonly IGameTiming _timing = default!; - [Dependency] protected readonly SharedAppearanceSystem Appearance = default!; [Dependency] private readonly SharedCombatModeSystem _combatMode = default!; - [Dependency] protected readonly SharedInteractionSystem Interaction = default!; - [Dependency] protected readonly SharedPopupSystem Popup = default!; - [Dependency] private readonly ActionContainerSystem _actionContainer = default!; + [Dependency] private readonly SharedInteractionSystem _interaction = default!; + [Dependency] private readonly ItemToggleSystem _toggle = default!; + [Dependency] private readonly SharedPopupSystem _popup = default!; + [Dependency] private readonly SharedSpaceNinjaSystem _ninja = default!; public override void Initialize() { base.Initialize(); - SubscribeLocalEvent(OnGetItemActions); + SubscribeLocalEvent(OnToggleCheck); + SubscribeLocalEvent(OnActivateAttempt); + SubscribeLocalEvent(OnToggled); SubscribeLocalEvent(OnExamined); - SubscribeLocalEvent(OnUnequipped); - SubscribeLocalEvent(OnMapInit); - } - - private void OnMapInit(EntityUid uid, NinjaGlovesComponent component, MapInitEvent args) - { - _actionContainer.EnsureAction(uid, ref component.ToggleActionEntity, component.ToggleAction); - Dirty(uid, component); } /// /// Disable glove abilities and show the popup if they were enabled previously. /// - public void DisableGloves(EntityUid uid, NinjaGlovesComponent? comp = null) + private void DisableGloves(Entity ent) { + var (uid, comp) = ent; + // already disabled? - if (!Resolve(uid, ref comp) || comp.User == null) + if (comp.User is not {} user) return; - var user = comp.User.Value; comp.User = null; Dirty(uid, comp); - Appearance.SetData(uid, ToggleVisuals.Toggled, false); - Popup.PopupClient(Loc.GetString("ninja-gloves-off"), user, user); - - RemComp(user); - RemComp(user); - RemComp(user); - RemComp(user); - RemComp(user); - RemComp(user); + foreach (var ability in comp.Abilities) + { + EntityManager.RemoveComponents(user, ability.Components); + } } /// - /// Adds the toggle action when equipped. + /// Adds the toggle action when equipped by a ninja only. /// - private void OnGetItemActions(EntityUid uid, NinjaGlovesComponent comp, GetItemActionsEvent args) + private void OnToggleCheck(Entity ent, ref ToggleClothingCheckEvent args) { - if (HasComp(args.User)) - args.AddAction(ref comp.ToggleActionEntity, comp.ToggleAction); + if (!_ninja.IsNinja(args.User)) + args.Cancelled = true; } /// /// Show if the gloves are enabled when examining. /// - private void OnExamined(EntityUid uid, NinjaGlovesComponent comp, ExaminedEvent args) + private void OnExamined(Entity ent, ref ExaminedEvent args) { if (!args.IsInDetailsRange) return; - args.PushText(Loc.GetString(comp.User != null ? "ninja-gloves-examine-on" : "ninja-gloves-examine-off")); + var on = _toggle.IsActivated(ent.Owner) ? "on" : "off"; + args.PushText(Loc.GetString($"ninja-gloves-examine-{on}")); } - /// - /// Disable gloves when unequipped and clean up ninja's gloves reference - /// - private void OnUnequipped(EntityUid uid, NinjaGlovesComponent comp, GotUnequippedEvent args) + private void OnActivateAttempt(Entity ent, ref ItemToggleActivateAttemptEvent args) { - if (comp.User != null) + if (args.User is not {} user + || !_ninja.NinjaQuery.TryComp(user, out var ninja) + // need to wear suit to enable gloves + || !HasComp(ninja.Suit)) { - var user = comp.User.Value; - Popup.PopupClient(Loc.GetString("ninja-gloves-off"), user, user); - DisableGloves(uid, comp); + args.Cancelled = true; + args.Popup = Loc.GetString("ninja-gloves-not-wearing-suit"); + return; } } + private void OnToggled(Entity ent, ref ItemToggledEvent args) + { + if ((args.User ?? ent.Comp.User) is not {} user) + return; + + var message = Loc.GetString(args.Activated ? "ninja-gloves-on" : "ninja-gloves-off"); + _popup.PopupClient(message, user, user); + + if (args.Activated && _ninja.NinjaQuery.TryComp(user, out var ninja)) + EnableGloves(ent, (user, ninja)); + else + DisableGloves(ent); + } + + protected virtual void EnableGloves(Entity ent, Entity user) + { + var (uid, comp) = ent; + comp.User = user; + Dirty(uid, comp); + _ninja.AssignGloves(user, uid); + + // yeah this is just ComponentToggler but with objective checking + foreach (var ability in comp.Abilities) + { + // can't predict the objective related abilities + if (ability.Objective == null) + EntityManager.AddComponents(user, ability.Components); + } + } // TODO: generic event thing /// @@ -112,6 +130,6 @@ public bool AbilityCheck(EntityUid uid, BeforeInteractHandEvent args, out Entity && !_combatMode.IsInCombatMode(uid) && TryComp(uid, out var hands) && hands.ActiveHandEntity == null - && Interaction.InRangeUnobstructed(uid, target); + && _interaction.InRangeUnobstructed(uid, target); } } diff --git a/Content.Shared/Ninja/Systems/SharedNinjaSuitSystem.cs b/Content.Shared/Ninja/Systems/SharedNinjaSuitSystem.cs index fed41eaed8a..3800d15b267 100644 --- a/Content.Shared/Ninja/Systems/SharedNinjaSuitSystem.cs +++ b/Content.Shared/Ninja/Systems/SharedNinjaSuitSystem.cs @@ -1,11 +1,14 @@ using Content.Shared.Actions; +using Content.Shared.Clothing; using Content.Shared.Clothing.Components; using Content.Shared.Clothing.EntitySystems; using Content.Shared.Inventory.Events; +using Content.Shared.Item.ItemToggle; +using Content.Shared.Item.ItemToggle.Components; using Content.Shared.Ninja.Components; using Content.Shared.Popups; +using Content.Shared.Timing; using Robust.Shared.Audio.Systems; -using Robust.Shared.Timing; namespace Content.Shared.Ninja.Systems; @@ -14,137 +17,158 @@ namespace Content.Shared.Ninja.Systems; /// public abstract class SharedNinjaSuitSystem : EntitySystem { - [Dependency] protected readonly IGameTiming GameTiming = default!; - [Dependency] private readonly SharedAudioSystem _audio = default!; - [Dependency] private readonly SharedNinjaGlovesSystem _gloves = default!; - [Dependency] private readonly SharedSpaceNinjaSystem _ninja = default!; [Dependency] private readonly ActionContainerSystem _actionContainer = default!; + [Dependency] private readonly SharedAudioSystem _audio = default!; + [Dependency] private readonly ItemToggleSystem _toggle = default!; [Dependency] protected readonly SharedPopupSystem Popup = default!; - [Dependency] protected readonly StealthClothingSystem StealthClothing = default!; + [Dependency] private readonly SharedSpaceNinjaSystem _ninja = default!; + [Dependency] private readonly UseDelaySystem _useDelay = default!; public override void Initialize() { base.Initialize(); SubscribeLocalEvent(OnMapInit); - - SubscribeLocalEvent(OnEquipped); + SubscribeLocalEvent(OnEquipped); SubscribeLocalEvent(OnGetItemActions); - SubscribeLocalEvent(OnAddStealthAction); + SubscribeLocalEvent(OnCloakCheck); + SubscribeLocalEvent(OnStarCheck); + SubscribeLocalEvent(OnCreateStarAttempt); + SubscribeLocalEvent(OnActivateAttempt); SubscribeLocalEvent(OnUnequipped); } - private void OnMapInit(EntityUid uid, NinjaSuitComponent component, MapInitEvent args) + private void OnEquipped(Entity ent, ref ClothingGotEquippedEvent args) { - _actionContainer.EnsureAction(uid, ref component.RecallKatanaActionEntity, component.RecallKatanaAction); - _actionContainer.EnsureAction(uid, ref component.CreateThrowingStarActionEntity, component.CreateThrowingStarAction); - _actionContainer.EnsureAction(uid, ref component.EmpActionEntity, component.EmpAction); - Dirty(uid, component); + var user = args.Wearer; + if (_ninja.NinjaQuery.TryComp(user, out var ninja)) + NinjaEquipped(ent, (user, ninja)); } - /// - /// Call the shared and serverside code for when a ninja equips the suit. - /// - private void OnEquipped(EntityUid uid, NinjaSuitComponent comp, GotEquippedEvent args) + protected virtual void NinjaEquipped(Entity ent, Entity user) { - var user = args.Equipee; - if (!TryComp(user, out var ninja)) - return; + // mark the user as wearing this suit, used when being attacked among other things + _ninja.AssignSuit(user, ent); + } - NinjaEquippedSuit(uid, comp, user, ninja); + private void OnMapInit(Entity ent, ref MapInitEvent args) + { + var (uid, comp) = ent; + _actionContainer.EnsureAction(uid, ref comp.RecallKatanaActionEntity, comp.RecallKatanaAction); + _actionContainer.EnsureAction(uid, ref comp.EmpActionEntity, comp.EmpAction); + Dirty(uid, comp); } /// /// Add all the actions when a suit is equipped by a ninja. /// - private void OnGetItemActions(EntityUid uid, NinjaSuitComponent comp, GetItemActionsEvent args) + private void OnGetItemActions(Entity ent, ref GetItemActionsEvent args) { - if (!HasComp(args.User)) + if (!_ninja.IsNinja(args.User)) return; + var comp = ent.Comp; args.AddAction(ref comp.RecallKatanaActionEntity, comp.RecallKatanaAction); - args.AddAction(ref comp.CreateThrowingStarActionEntity, comp.CreateThrowingStarAction); args.AddAction(ref comp.EmpActionEntity, comp.EmpAction); } /// - /// Only add stealth clothing's toggle action when equipped by a ninja. + /// Only add toggle cloak action when equipped by a ninja. /// - private void OnAddStealthAction(EntityUid uid, NinjaSuitComponent comp, AddStealthActionEvent args) + private void OnCloakCheck(Entity ent, ref ToggleClothingCheckEvent args) { - if (!HasComp(args.User)) - args.Cancel(); + if (!_ninja.IsNinja(args.User)) + args.Cancelled = true; } - /// - /// Call the shared and serverside code for when anyone unequips a suit. - /// - private void OnUnequipped(EntityUid uid, NinjaSuitComponent comp, GotUnequippedEvent args) + private void OnStarCheck(Entity ent, ref CheckItemCreatorEvent args) + { + if (!_ninja.IsNinja(args.User)) + args.Cancelled = true; + } + + private void OnCreateStarAttempt(Entity ent, ref CreateItemAttemptEvent args) { - UserUnequippedSuit(uid, comp, args.Equipee); + if (CheckDisabled(ent, args.User)) + args.Cancelled = true; } /// - /// Called when a suit is equipped by a space ninja. - /// In the future it might be changed to an explicit activation toggle/verb like gloves are. + /// Call the shared and serverside code for when anyone unequips a suit. /// - protected virtual void NinjaEquippedSuit(EntityUid uid, NinjaSuitComponent comp, EntityUid user, SpaceNinjaComponent ninja) + private void OnUnequipped(Entity ent, ref GotUnequippedEvent args) { - // mark the user as wearing this suit, used when being attacked among other things - _ninja.AssignSuit(user, uid, ninja); - - // initialize phase cloak, but keep it off - StealthClothing.SetEnabled(uid, user, false); + var user = args.Equipee; + if (_ninja.NinjaQuery.TryComp(user, out var ninja)) + UserUnequippedSuit(ent, (user, ninja)); } /// /// Force uncloaks the user and disables suit abilities. /// - public void RevealNinja(EntityUid uid, EntityUid user, bool disable = true, NinjaSuitComponent? comp = null, StealthClothingComponent? stealthClothing = null) + public void RevealNinja(Entity ent, EntityUid user, bool disable = true) { - if (!Resolve(uid, ref comp, ref stealthClothing)) + if (!Resolve(ent, ref ent.Comp)) return; - if (!StealthClothing.SetEnabled(uid, user, false, stealthClothing)) - return; - - if (!disable) + var uid = ent.Owner; + var comp = ent.Comp; + if (_toggle.TryDeactivate(uid, user) || !disable) return; // previously cloaked, disable abilities for a short time _audio.PlayPredicted(comp.RevealSound, uid, user); Popup.PopupClient(Loc.GetString("ninja-revealed"), user, user, PopupType.MediumCaution); - comp.DisableCooldown = GameTiming.CurTime + comp.DisableTime; + _useDelay.TryResetDelay(uid, id: comp.DisableDelayId); + } + + private void OnActivateAttempt(Entity ent, ref ItemToggleActivateAttemptEvent args) + { + if (!_ninja.IsNinja(args.User)) + { + args.Cancelled = true; + return; + } + + if (IsDisabled((ent, ent.Comp, null))) + { + args.Cancelled = true; + args.Popup = Loc.GetString("ninja-suit-cooldown"); + } } - // TODO: modify PowerCellDrain /// - /// Returns the power used by a suit + /// Returns true if the suit is currently disabled /// - public float SuitWattage(EntityUid uid, NinjaSuitComponent? suit = null) + public bool IsDisabled(Entity ent) + { + if (!Resolve(ent, ref ent.Comp1, ref ent.Comp2)) + return false; + + return _useDelay.IsDelayed((ent, ent.Comp2), ent.Comp1.DisableDelayId); + } + + protected bool CheckDisabled(Entity ent, EntityUid user) { - if (!Resolve(uid, ref suit)) - return 0f; + if (IsDisabled((ent, ent.Comp, null))) + { + Popup.PopupEntity(Loc.GetString("ninja-suit-cooldown"), user, user, PopupType.Medium); + return true; + } - float wattage = suit.PassiveWattage; - if (TryComp(uid, out var stealthClothing) && stealthClothing.Enabled) - wattage += suit.CloakWattage; - return wattage; + return false; } /// /// Called when a suit is unequipped, not necessarily by a space ninja. /// In the future it might be changed to also have explicit deactivation via toggle. /// - protected virtual void UserUnequippedSuit(EntityUid uid, NinjaSuitComponent comp, EntityUid user) + protected virtual void UserUnequippedSuit(Entity ent, Entity user) { - if (!TryComp(user, out var ninja)) - return; - // mark the user as not wearing a suit - _ninja.AssignSuit(user, null, ninja); + _ninja.AssignSuit(user, null); // disable glove abilities - if (ninja.Gloves != null && TryComp(ninja.Gloves.Value, out var gloves)) - _gloves.DisableGloves(ninja.Gloves.Value, gloves); + if (user.Comp.Gloves is {} uid) + _toggle.TryDeactivate(uid, user: user); } } diff --git a/Content.Shared/Ninja/Systems/SharedSpaceNinjaSystem.cs b/Content.Shared/Ninja/Systems/SharedSpaceNinjaSystem.cs index 522f29fe420..d738f2dd8a2 100644 --- a/Content.Shared/Ninja/Systems/SharedSpaceNinjaSystem.cs +++ b/Content.Shared/Ninja/Systems/SharedSpaceNinjaSystem.cs @@ -3,6 +3,7 @@ using Content.Shared.Weapons.Melee.Events; using Content.Shared.Weapons.Ranged.Events; using Content.Shared.Popups; +using System.Diagnostics.CodeAnalysis; namespace Content.Shared.Ninja.Systems; @@ -14,49 +15,59 @@ public abstract class SharedSpaceNinjaSystem : EntitySystem [Dependency] protected readonly SharedNinjaSuitSystem Suit = default!; [Dependency] protected readonly SharedPopupSystem Popup = default!; + public EntityQuery NinjaQuery; + public override void Initialize() { base.Initialize(); + NinjaQuery = GetEntityQuery(); + SubscribeLocalEvent(OnNinjaAttacked); SubscribeLocalEvent(OnNinjaAttack); SubscribeLocalEvent(OnShotAttempted); } + public bool IsNinja([NotNullWhen(true)] EntityUid? uid) + { + return NinjaQuery.HasComp(uid); + } + /// /// Set the ninja's worn suit entity /// - public void AssignSuit(EntityUid uid, EntityUid? suit, SpaceNinjaComponent? comp = null) + public void AssignSuit(Entity ent, EntityUid? suit) { - if (!Resolve(uid, ref comp) || comp.Suit == suit) + if (ent.Comp.Suit == suit) return; - comp.Suit = suit; - Dirty(uid, comp); + ent.Comp.Suit = suit; + Dirty(ent, ent.Comp); } /// /// Set the ninja's worn gloves entity /// - public void AssignGloves(EntityUid uid, EntityUid? gloves, SpaceNinjaComponent? comp = null) + public void AssignGloves(Entity ent, EntityUid? gloves) { - if (!Resolve(uid, ref comp) || comp.Gloves == gloves) + if (ent.Comp.Gloves == gloves) return; - comp.Gloves = gloves; - Dirty(uid, comp); + ent.Comp.Gloves = gloves; + Dirty(ent, ent.Comp); } /// /// Bind a katana entity to a ninja, letting it be recalled and dash. + /// Does nothing if the player is not a ninja or already has a katana bound. /// - public void BindKatana(EntityUid uid, EntityUid? katana, SpaceNinjaComponent? comp = null) + public void BindKatana(Entity ent, EntityUid katana) { - if (!Resolve(uid, ref comp) || comp.Katana == katana) + if (!NinjaQuery.Resolve(ent, ref ent.Comp) || ent.Comp.Katana != null) return; - comp.Katana = katana; - Dirty(uid, comp); + ent.Comp.Katana = katana; + Dirty(ent, ent.Comp); } /// @@ -71,32 +82,32 @@ public virtual bool TryUseCharge(EntityUid user, float charge) /// /// Handle revealing ninja if cloaked when attacked. /// - private void OnNinjaAttacked(EntityUid uid, SpaceNinjaComponent comp, AttackedEvent args) + private void OnNinjaAttacked(Entity ent, ref AttackedEvent args) { - if (comp.Suit != null && TryComp(comp.Suit, out var stealthClothing) && stealthClothing.Enabled) - { - Suit.RevealNinja(comp.Suit.Value, uid, true, null, stealthClothing); - } + TryRevealNinja(ent, disable: true); } /// /// Handle revealing ninja if cloaked when attacking. /// Only reveals, there is no cooldown. /// - private void OnNinjaAttack(EntityUid uid, SpaceNinjaComponent comp, ref MeleeAttackEvent args) + private void OnNinjaAttack(Entity ent, ref MeleeAttackEvent args) + { + TryRevealNinja(ent, disable: false); + } + + private void TryRevealNinja(Entity ent, bool disable) { - if (comp.Suit != null && TryComp(comp.Suit, out var stealthClothing) && stealthClothing.Enabled) - { - Suit.RevealNinja(comp.Suit.Value, uid, false, null, stealthClothing); - } + if (ent.Comp.Suit is {} uid && TryComp(ent.Comp.Suit, out var suit)) + Suit.RevealNinja((uid, suit), ent, disable: disable); } /// /// Require ninja to fight with HONOR, no guns! /// - private void OnShotAttempted(EntityUid uid, SpaceNinjaComponent comp, ref ShotAttemptedEvent args) + private void OnShotAttempted(Entity ent, ref ShotAttemptedEvent args) { - Popup.PopupClient(Loc.GetString("gun-disabled"), uid, uid); + Popup.PopupClient(Loc.GetString("gun-disabled"), ent, ent); args.Cancel(); } } diff --git a/Content.Shared/Ninja/Systems/SharedSpiderChargeSystem.cs b/Content.Shared/Ninja/Systems/SharedSpiderChargeSystem.cs new file mode 100644 index 00000000000..f4b158aced4 --- /dev/null +++ b/Content.Shared/Ninja/Systems/SharedSpiderChargeSystem.cs @@ -0,0 +1,6 @@ +namespace Content.Shared.Ninja.Systems; + +/// +/// Sticking triggering and exploding are all in server so this is just for access. +/// +public abstract class SharedSpiderChargeSystem : EntitySystem; diff --git a/Content.Shared/Ninja/Systems/SharedStunProviderSystem.cs b/Content.Shared/Ninja/Systems/SharedStunProviderSystem.cs index 61b6e4313ed..061c019c9b6 100644 --- a/Content.Shared/Ninja/Systems/SharedStunProviderSystem.cs +++ b/Content.Shared/Ninja/Systems/SharedStunProviderSystem.cs @@ -11,22 +11,12 @@ public abstract class SharedStunProviderSystem : EntitySystem /// /// Set the battery field on the stun provider. /// - public void SetBattery(EntityUid uid, EntityUid? battery, StunProviderComponent? comp = null) + public void SetBattery(Entity ent, EntityUid? battery) { - if (!Resolve(uid, ref comp)) + if (!Resolve(ent, ref ent.Comp) || ent.Comp.BatteryUid == battery) return; - comp.BatteryUid = battery; - } - - /// - /// Set the no power popup field on the stun provider. - /// - public void SetNoPowerPopup(EntityUid uid, string popup, StunProviderComponent? comp = null) - { - if (!Resolve(uid, ref comp)) - return; - - comp.NoPowerPopup = popup; + ent.Comp.BatteryUid = battery; + Dirty(ent, ent.Comp); } } diff --git a/Content.Shared/Objectives/Systems/SharedObjectivesSystem.cs b/Content.Shared/Objectives/Systems/SharedObjectivesSystem.cs index 07032a00ce9..8d2c4dcfebe 100644 --- a/Content.Shared/Objectives/Systems/SharedObjectivesSystem.cs +++ b/Content.Shared/Objectives/Systems/SharedObjectivesSystem.cs @@ -92,7 +92,7 @@ public bool CanBeAssigned(EntityUid uid, EntityUid mindId, MindComponent mind, O } /// - /// Get the title, description, icon and progress of an objective using . + /// Get the title, description, icon and progress of an objective using . /// If any of them are null it is logged and null is returned. /// /// ID of the condition entity @@ -103,20 +103,43 @@ public bool CanBeAssigned(EntityUid uid, EntityUid mindId, MindComponent mind, O if (!Resolve(mindId, ref mind)) return null; - var ev = new ObjectiveGetProgressEvent(mindId, mind); - RaiseLocalEvent(uid, ref ev); + if (GetProgress(uid, (mindId, mind)) is not {} progress) + return null; var comp = Comp(uid); var meta = MetaData(uid); var title = meta.EntityName; var description = meta.EntityDescription; - if (comp.Icon == null || ev.Progress == null) + if (comp.Icon == null) { - Log.Error($"An objective {ToPrettyString(uid):objective} of {_mind.MindOwnerLoggingString(mind)} is missing icon or progress ({ev.Progress})"); + Log.Error($"An objective {ToPrettyString(uid):objective} of {_mind.MindOwnerLoggingString(mind)} is missing an icon!"); return null; } - return new ObjectiveInfo(title, description, comp.Icon, ev.Progress.Value); + return new ObjectiveInfo(title, description, comp.Icon, progress); + } + + /// + /// Gets the progress of an objective using . + /// Returning null is a programmer error. + /// + public float? GetProgress(EntityUid uid, Entity mind) + { + var ev = new ObjectiveGetProgressEvent(mind, mind.Comp); + RaiseLocalEvent(uid, ref ev); + if (ev.Progress != null) + return ev.Progress; + + Log.Error($"Objective {ToPrettyString(uid):objective} of {_mind.MindOwnerLoggingString(mind.Comp)} didn't set a progress value!"); + return null; + } + + /// + /// Returns true if an objective is completed. + /// + public bool IsCompleted(EntityUid uid, Entity mind) + { + return (GetProgress(uid, mind) ?? 0f) >= 0.999f; } /// diff --git a/Content.Shared/Pinpointer/SharedProximityBeeper.cs b/Content.Shared/Pinpointer/SharedProximityBeeper.cs deleted file mode 100644 index 51631126833..00000000000 --- a/Content.Shared/Pinpointer/SharedProximityBeeper.cs +++ /dev/null @@ -1,9 +0,0 @@ -using Robust.Shared.Serialization; - -namespace Content.Shared.Pinpointer; - -[Serializable, NetSerializable] -public enum ProximityBeeperVisuals : byte -{ - Enabled -} diff --git a/Content.Shared/PowerCell/PowerCellDrawComponent.cs b/Content.Shared/PowerCell/PowerCellDrawComponent.cs index 708a86a8eaf..94de7c77878 100644 --- a/Content.Shared/PowerCell/PowerCellDrawComponent.cs +++ b/Content.Shared/PowerCell/PowerCellDrawComponent.cs @@ -6,6 +6,10 @@ namespace Content.Shared.PowerCell; /// /// Indicates that the entity's ActivatableUI requires power or else it closes. /// +/// +/// With ActivatableUI it will activate and deactivate when the ui is opened and closed, drawing power inbetween. +/// Requires to work. +/// [RegisterComponent, NetworkedComponent, AutoGenerateComponentState, AutoGenerateComponentPause] public sealed partial class PowerCellDrawComponent : Component { @@ -26,10 +30,12 @@ public sealed partial class PowerCellDrawComponent : Component #endregion /// - /// Is this power cell currently drawing power every tick. + /// Whether drawing is enabled, regardless of ItemToggle. + /// Having no cell will still disable it. + /// Only use this if you really don't want it to use power for some time. /// - [ViewVariables(VVAccess.ReadWrite), DataField("enabled")] - public bool Drawing; + [DataField, AutoNetworkedField] + public bool Enabled = true; /// /// How much the entity draws while the UI is open. @@ -51,4 +57,10 @@ public sealed partial class PowerCellDrawComponent : Component [DataField("nextUpdate", customTypeSerializer: typeof(TimeOffsetSerializer))] [AutoPausedField] public TimeSpan NextUpdateTime; + + /// + /// How long to wait between power drawing. + /// + [DataField] + public TimeSpan Delay = TimeSpan.FromSeconds(1); } diff --git a/Content.Shared/PowerCell/SharedPowerCellSystem.cs b/Content.Shared/PowerCell/SharedPowerCellSystem.cs index 508bfc85f08..2b2a836633c 100644 --- a/Content.Shared/PowerCell/SharedPowerCellSystem.cs +++ b/Content.Shared/PowerCell/SharedPowerCellSystem.cs @@ -1,4 +1,6 @@ using Content.Shared.Containers.ItemSlots; +using Content.Shared.Item.ItemToggle; +using Content.Shared.Item.ItemToggle.Components; using Content.Shared.PowerCell.Components; using Content.Shared.Rejuvenate; using Robust.Shared.Containers; @@ -11,14 +13,19 @@ public abstract class SharedPowerCellSystem : EntitySystem [Dependency] protected readonly IGameTiming Timing = default!; [Dependency] private readonly ItemSlotsSystem _itemSlots = default!; [Dependency] private readonly SharedAppearanceSystem _appearance = default!; + [Dependency] protected readonly ItemToggleSystem Toggle = default!; public override void Initialize() { base.Initialize(); + SubscribeLocalEvent(OnRejuvenate); SubscribeLocalEvent(OnCellInserted); SubscribeLocalEvent(OnCellRemoved); SubscribeLocalEvent(OnCellInsertAttempt); + + SubscribeLocalEvent(OnActivateAttempt); + SubscribeLocalEvent(OnToggled); } private void OnRejuvenate(EntityUid uid, PowerCellSlotComponent component, RejuvenateEvent args) @@ -63,13 +70,25 @@ protected virtual void OnCellRemoved(EntityUid uid, PowerCellSlotComponent compo RaiseLocalEvent(uid, new PowerCellChangedEvent(true), false); } - public void SetPowerCellDrawEnabled(EntityUid uid, bool enabled, PowerCellDrawComponent? component = null) + private void OnActivateAttempt(Entity ent, ref ItemToggleActivateAttemptEvent args) + { + if (!HasDrawCharge(ent, ent.Comp, user: args.User) + || !HasActivatableCharge(ent, ent.Comp, user: args.User)) + args.Cancelled = true; + } + + private void OnToggled(Entity ent, ref ItemToggledEvent args) + { + ent.Comp.NextUpdateTime = Timing.CurTime; + } + + public void SetDrawEnabled(Entity ent, bool enabled) { - if (!Resolve(uid, ref component, false) || enabled == component.Drawing) + if (!Resolve(ent, ref ent.Comp, false) || ent.Comp.Enabled == enabled) return; - component.Drawing = enabled; - component.NextUpdateTime = Timing.CurTime; + ent.Comp.Enabled = enabled; + Dirty(ent, ent.Comp); } /// diff --git a/Content.Shared/ProximityDetection/Components/ProximityDetectorComponent.cs b/Content.Shared/ProximityDetection/Components/ProximityDetectorComponent.cs index 09cb7f06d5d..7e2bb4dfe62 100644 --- a/Content.Shared/ProximityDetection/Components/ProximityDetectorComponent.cs +++ b/Content.Shared/ProximityDetection/Components/ProximityDetectorComponent.cs @@ -10,12 +10,6 @@ namespace Content.Shared.ProximityDetection.Components; [RegisterComponent, NetworkedComponent, AutoGenerateComponentState ,Access(typeof(ProximityDetectionSystem))] public sealed partial class ProximityDetectorComponent : Component { - /// - /// Whether or not it's on. - /// - [DataField, AutoNetworkedField, ViewVariables(VVAccess.ReadWrite)] - public bool Enabled = true; - /// /// The criteria used to filter entities /// Note: RequireAll is only supported for tags, all components are required to count as a match! @@ -35,13 +29,13 @@ public sealed partial class ProximityDetectorComponent : Component [ViewVariables(VVAccess.ReadWrite), AutoNetworkedField] public FixedPoint2 Distance = -1; - /// /// The farthest distance to search for targets /// [DataField, ViewVariables(VVAccess.ReadWrite), AutoNetworkedField] public FixedPoint2 Range = 10f; + // TODO: use timespans not this public float AccumulatedFrameTime; [DataField, ViewVariables(VVAccess.ReadWrite), AutoNetworkedField] diff --git a/Content.Shared/ProximityDetection/Systems/ProximityDetectionSystem.cs b/Content.Shared/ProximityDetection/Systems/ProximityDetectionSystem.cs index db25e8bc511..df302f94771 100644 --- a/Content.Shared/ProximityDetection/Systems/ProximityDetectionSystem.cs +++ b/Content.Shared/ProximityDetection/Systems/ProximityDetectionSystem.cs @@ -1,4 +1,6 @@ -using Content.Shared.ProximityDetection.Components; +using Content.Shared.Item.ItemToggle; +using Content.Shared.Item.ItemToggle.Components; +using Content.Shared.ProximityDetection.Components; using Content.Shared.Tag; using Robust.Shared.Network; @@ -9,6 +11,7 @@ namespace Content.Shared.ProximityDetection.Systems; public sealed class ProximityDetectionSystem : EntitySystem { [Dependency] private readonly EntityLookupSystem _entityLookup = default!; + [Dependency] private readonly ItemToggleSystem _toggle = default!; [Dependency] private readonly SharedTransformSystem _transform = default!; [Dependency] private readonly TagSystem _tagSystem = default!; [Dependency] private readonly INetManager _net = default!; @@ -17,10 +20,10 @@ public sealed class ProximityDetectionSystem : EntitySystem public override void Initialize() { - SubscribeLocalEvent(OnPaused); - SubscribeLocalEvent(OnUnpaused); - SubscribeLocalEvent(OnCompInit); + base.Initialize(); + SubscribeLocalEvent(OnCompInit); + SubscribeLocalEvent(OnToggled); } private void OnCompInit(EntityUid uid, ProximityDetectorComponent component, ComponentInit args) @@ -30,57 +33,39 @@ private void OnCompInit(EntityUid uid, ProximityDetectorComponent component, Com Log.Debug("DetectorComponent only supports requireAll = false for tags. All components are required for a match!"); } - private void OnPaused(EntityUid owner, ProximityDetectorComponent component, EntityPausedEvent args) - { - SetEnable_Internal(owner,component,false); - } - - private void OnUnpaused(EntityUid owner, ProximityDetectorComponent detector, ref EntityUnpausedEvent args) - { - SetEnable_Internal(owner, detector,true); - } - public void SetEnable(EntityUid owner, bool enabled, ProximityDetectorComponent? detector = null) - { - if (!Resolve(owner, ref detector) || detector.Enabled == enabled) - return; - SetEnable_Internal(owner ,detector, enabled); - } - public override void Update(float frameTime) { if (_net.IsClient) return; + var query = EntityQueryEnumerator(); while (query.MoveNext(out var owner, out var detector)) { - if (!detector.Enabled) + if (!_toggle.IsActivated(owner)) continue; + detector.AccumulatedFrameTime += frameTime; if (detector.AccumulatedFrameTime < detector.UpdateRate) continue; + detector.AccumulatedFrameTime -= detector.UpdateRate; RunUpdate_Internal(owner, detector); } } - public bool GetEnable(EntityUid owner, ProximityDetectorComponent? detector = null) + private void OnToggled(Entity ent, ref ItemToggledEvent args) { - return Resolve(owner, ref detector, false) && detector.Enabled; - } - - private void SetEnable_Internal(EntityUid owner,ProximityDetectorComponent detector, bool enabled) - { - detector.Enabled = enabled; - var noDetectEvent = new ProximityTargetUpdatedEvent(detector, detector.TargetEnt, detector.Distance); - RaiseLocalEvent(owner, ref noDetectEvent); - if (!enabled) + if (args.Activated) { - detector.AccumulatedFrameTime = 0; - RunUpdate_Internal(owner, detector); - Dirty(owner, detector); + RunUpdate_Internal(ent, ent.Comp); return; } - RunUpdate_Internal(owner, detector); + + var noDetectEvent = new ProximityTargetUpdatedEvent(ent.Comp, Target: null, ent.Comp.Distance); + RaiseLocalEvent(ent, ref noDetectEvent); + + ent.Comp.AccumulatedFrameTime = 0; + Dirty(ent, ent.Comp); } public void ForceUpdate(EntityUid owner, ProximityDetectorComponent? detector = null) @@ -90,11 +75,31 @@ public void ForceUpdate(EntityUid owner, ProximityDetectorComponent? detector = RunUpdate_Internal(owner, detector); } + private void ClearTarget(Entity ent) + { + var (uid, comp) = ent; + if (comp.TargetEnt == null) + return; + + comp.Distance = -1; + comp.TargetEnt = null; + var noDetectEvent = new ProximityTargetUpdatedEvent(comp, null, -1); + RaiseLocalEvent(uid, ref noDetectEvent); + var newTargetEvent = new NewProximityTargetEvent(comp, null); + RaiseLocalEvent(uid, ref newTargetEvent); + Dirty(uid, comp); + } private void RunUpdate_Internal(EntityUid owner,ProximityDetectorComponent detector) { if (!_net.IsServer) //only run detection checks on the server! return; + + if (Deleted(detector.TargetEnt)) + { + ClearTarget((owner, detector)); + } + var xformQuery = GetEntityQuery(); var xform = xformQuery.GetComponent(owner); List<(EntityUid TargetEnt, float Distance)> detections = new(); @@ -173,15 +178,7 @@ private void UpdateTargetFromClosest(EntityUid owner, ProximityDetectorComponent { if (detections.Count == 0) { - if (detector.TargetEnt == null) - return; - detector.Distance = -1; - detector.TargetEnt = null; - var noDetectEvent = new ProximityTargetUpdatedEvent(detector, null, -1); - RaiseLocalEvent(owner, ref noDetectEvent); - var newTargetEvent = new NewProximityTargetEvent(detector, null); - RaiseLocalEvent(owner, ref newTargetEvent); - Dirty(owner, detector); + ClearTarget((owner, detector)); return; } var closestDistance = detections[0].Distance; @@ -198,6 +195,7 @@ private void UpdateTargetFromClosest(EntityUid owner, ProximityDetectorComponent var newData = newTarget || detector.Distance != closestDistance; detector.TargetEnt = closestEnt; detector.Distance = closestDistance; + Dirty(owner, detector); if (newTarget) { var newTargetEvent = new NewProximityTargetEvent(detector, closestEnt); diff --git a/Content.Shared/Silicons/Borgs/Components/BorgChassisComponent.cs b/Content.Shared/Silicons/Borgs/Components/BorgChassisComponent.cs index e1776873da9..de0fe0bce38 100644 --- a/Content.Shared/Silicons/Borgs/Components/BorgChassisComponent.cs +++ b/Content.Shared/Silicons/Borgs/Components/BorgChassisComponent.cs @@ -15,12 +15,6 @@ namespace Content.Shared.Silicons.Borgs.Components; [RegisterComponent, NetworkedComponent, Access(typeof(SharedBorgSystem)), AutoGenerateComponentState] public sealed partial class BorgChassisComponent : Component { - /// - /// Whether or not the borg is activated, meaning it has access to modules and a heightened movement speed - /// - [DataField("activated"), ViewVariables(VVAccess.ReadWrite), AutoNetworkedField] - public bool Activated; - #region Brain /// /// A whitelist for which entities count as valid brains @@ -68,7 +62,7 @@ public sealed partial class BorgChassisComponent : Component /// /// The currently selected module /// - [DataField("selectedModule")] + [DataField("selectedModule"), AutoNetworkedField] public EntityUid? SelectedModule; #region Visuals diff --git a/Content.Shared/Silicons/Borgs/SharedBorgSystem.cs b/Content.Shared/Silicons/Borgs/SharedBorgSystem.cs index 2983c0d642f..48d23578368 100644 --- a/Content.Shared/Silicons/Borgs/SharedBorgSystem.cs +++ b/Content.Shared/Silicons/Borgs/SharedBorgSystem.cs @@ -1,5 +1,6 @@ using Content.Shared.Access.Components; using Content.Shared.Containers.ItemSlots; +using Content.Shared.Item.ItemToggle; using Content.Shared.Movement.Components; using Content.Shared.Movement.Systems; using Content.Shared.Popups; @@ -18,6 +19,7 @@ public abstract partial class SharedBorgSystem : EntitySystem { [Dependency] protected readonly SharedContainerSystem Container = default!; [Dependency] protected readonly ItemSlotsSystem ItemSlots = default!; + [Dependency] protected readonly ItemToggleSystem Toggle = default!; [Dependency] protected readonly SharedPopupSystem Popup = default!; /// @@ -96,7 +98,7 @@ protected virtual void OnRemoved(EntityUid uid, BorgChassisComponent component, private void OnRefreshMovementSpeedModifiers(EntityUid uid, BorgChassisComponent component, RefreshMovementSpeedModifiersEvent args) { - if (component.Activated) + if (Toggle.IsActivated(uid)) return; if (!TryComp(uid, out var movement)) diff --git a/Content.Shared/Toggleable/ToggleActionEvent.cs b/Content.Shared/Toggleable/ToggleActionEvent.cs index 1283b6699bf..f28e62e7dd1 100644 --- a/Content.Shared/Toggleable/ToggleActionEvent.cs +++ b/Content.Shared/Toggleable/ToggleActionEvent.cs @@ -4,9 +4,12 @@ namespace Content.Shared.Toggleable; /// -/// Generic action-event for toggle-able components. +/// Generic action-event for toggle-able components. /// -public sealed partial class ToggleActionEvent : InstantActionEvent { } +/// +/// If you are using ItemToggleComponent subscribe to ItemToggledEvent instead. +/// +public sealed partial class ToggleActionEvent : InstantActionEvent; /// /// Generic enum keys for toggle-visualizer appearance data & sprite layers. diff --git a/Content.Shared/Tools/Systems/SharedToolSystem.cs b/Content.Shared/Tools/Systems/SharedToolSystem.cs index 56ce81413fb..201eb19a88b 100644 --- a/Content.Shared/Tools/Systems/SharedToolSystem.cs +++ b/Content.Shared/Tools/Systems/SharedToolSystem.cs @@ -24,7 +24,7 @@ public abstract partial class SharedToolSystem : EntitySystem [Dependency] private readonly SharedAudioSystem _audioSystem = default!; [Dependency] private readonly SharedDoAfterSystem _doAfterSystem = default!; [Dependency] protected readonly SharedInteractionSystem InteractionSystem = default!; - [Dependency] protected readonly SharedItemToggleSystem ItemToggle = default!; + [Dependency] protected readonly ItemToggleSystem ItemToggle = default!; [Dependency] private readonly SharedMapSystem _maps = default!; [Dependency] private readonly SharedPopupSystem _popup = default!; [Dependency] protected readonly SharedSolutionContainerSystem SolutionContainerSystem = default!; diff --git a/Content.Shared/UserInterface/ActivatableUISystem.Power.cs b/Content.Shared/UserInterface/ActivatableUISystem.Power.cs index b8a815c7a81..e494253c832 100644 --- a/Content.Shared/UserInterface/ActivatableUISystem.Power.cs +++ b/Content.Shared/UserInterface/ActivatableUISystem.Power.cs @@ -1,3 +1,5 @@ +using Content.Shared.Item.ItemToggle; +using Content.Shared.Item.ItemToggle.Components; using Content.Shared.PowerCell; using Robust.Shared.Containers; @@ -5,6 +7,7 @@ namespace Content.Shared.UserInterface; public sealed partial class ActivatableUISystem { + [Dependency] private readonly ItemToggleSystem _toggle = default!; [Dependency] private readonly SharedPowerCellSystem _cell = default!; private void InitializePower() @@ -12,27 +15,22 @@ private void InitializePower() SubscribeLocalEvent(OnBatteryOpenAttempt); SubscribeLocalEvent(OnBatteryOpened); SubscribeLocalEvent(OnBatteryClosed); - - SubscribeLocalEvent(OnPowerCellRemoved); + SubscribeLocalEvent(OnToggled); } - private void OnPowerCellRemoved(EntityUid uid, PowerCellDrawComponent component, EntRemovedFromContainerMessage args) + private void OnToggled(Entity ent, ref ItemToggledEvent args) { - _cell.SetPowerCellDrawEnabled(uid, false); - - if (!HasComp(uid) || - !TryComp(uid, out ActivatableUIComponent? activatable)) - { + // only close ui when losing power + if (!TryComp(ent, out var activatable) || args.Activated) return; - } if (activatable.Key == null) { - Log.Error($"Encountered null key in activatable ui on entity {ToPrettyString(uid)}"); + Log.Error($"Encountered null key in activatable ui on entity {ToPrettyString(ent)}"); return; } - _uiSystem.CloseUi(uid, activatable.Key); + _uiSystem.CloseUi(ent.Owner, activatable.Key); } private void OnBatteryOpened(EntityUid uid, ActivatableUIRequiresPowerCellComponent component, BoundUIOpenedEvent args) @@ -42,7 +40,7 @@ private void OnBatteryOpened(EntityUid uid, ActivatableUIRequiresPowerCellCompon if (!args.UiKey.Equals(activatable.Key)) return; - _cell.SetPowerCellDrawEnabled(uid, true); + _toggle.TryActivate(uid); } private void OnBatteryClosed(EntityUid uid, ActivatableUIRequiresPowerCellComponent component, BoundUIClosedEvent args) @@ -54,7 +52,7 @@ private void OnBatteryClosed(EntityUid uid, ActivatableUIRequiresPowerCellCompon // Stop drawing power if this was the last person with the UI open. if (!_uiSystem.IsUiOpen(uid, activatable.Key)) - _cell.SetPowerCellDrawEnabled(uid, false); + _toggle.TryDeactivate(uid); } /// diff --git a/Content.Shared/Weapons/Reflect/ReflectComponent.cs b/Content.Shared/Weapons/Reflect/ReflectComponent.cs index 8e7b8975d9d..8418c1f3efb 100644 --- a/Content.Shared/Weapons/Reflect/ReflectComponent.cs +++ b/Content.Shared/Weapons/Reflect/ReflectComponent.cs @@ -5,16 +5,11 @@ namespace Content.Shared.Weapons.Reflect; /// /// Entities with this component have a chance to reflect projectiles and hitscan shots +/// Uses ItemToggleComponent to control reflection. /// [RegisterComponent, NetworkedComponent, AutoGenerateComponentState] public sealed partial class ReflectComponent : Component { - /// - /// Can only reflect when enabled - /// - [DataField("enabled"), ViewVariables(VVAccess.ReadWrite), AutoNetworkedField] - public bool Enabled = true; - /// /// What we reflect. /// diff --git a/Content.Shared/Weapons/Reflect/ReflectSystem.cs b/Content.Shared/Weapons/Reflect/ReflectSystem.cs index 7a2e733bf7c..881b547f27f 100644 --- a/Content.Shared/Weapons/Reflect/ReflectSystem.cs +++ b/Content.Shared/Weapons/Reflect/ReflectSystem.cs @@ -7,6 +7,7 @@ using Content.Shared.Hands; using Content.Shared.Inventory; using Content.Shared.Inventory.Events; +using Content.Shared.Item.ItemToggle; using Content.Shared.Item.ItemToggle.Components; using Content.Shared.Popups; using Content.Shared.Projectiles; @@ -27,10 +28,11 @@ namespace Content.Shared.Weapons.Reflect; /// public sealed class ReflectSystem : EntitySystem { + [Dependency] private readonly IGameTiming _gameTiming = default!; [Dependency] private readonly INetManager _netManager = default!; [Dependency] private readonly IRobustRandom _random = default!; [Dependency] private readonly ISharedAdminLogManager _adminLogger = default!; - [Dependency] private readonly IGameTiming _gameTiming = default!; + [Dependency] private readonly ItemToggleSystem _toggle = default!; [Dependency] private readonly SharedPopupSystem _popup = default!; [Dependency] private readonly SharedPhysicsSystem _physics = default!; [Dependency] private readonly SharedAudioSystem _audio = default!; @@ -93,7 +95,7 @@ private void OnReflectCollide(EntityUid uid, ReflectComponent component, ref Pro private bool TryReflectProjectile(EntityUid user, EntityUid reflector, EntityUid projectile, ProjectileComponent? projectileComp = null, ReflectComponent? reflect = null) { if (!Resolve(reflector, ref reflect, false) || - !reflect.Enabled || + !_toggle.IsActivated(reflector) || !TryComp(projectile, out var reflective) || (reflect.Reflects & reflective.Reflective) == 0x0 || !_random.Prob(reflect.ReflectProb) || @@ -162,7 +164,7 @@ private bool TryReflectHitscan( [NotNullWhen(true)] out Vector2? newDirection) { if (!TryComp(reflector, out var reflect) || - !reflect.Enabled || + !_toggle.IsActivated(reflector) || !_random.Prob(reflect.ReflectProb)) { newDirection = null; @@ -214,8 +216,8 @@ private void OnReflectHandUnequipped(EntityUid uid, ReflectComponent component, private void OnToggleReflect(EntityUid uid, ReflectComponent comp, ref ItemToggledEvent args) { - comp.Enabled = args.Activated; - Dirty(uid, comp); + if (args.User is {} user) + RefreshReflectUser(user); } /// @@ -225,7 +227,7 @@ private void RefreshReflectUser(EntityUid user) { foreach (var ent in _inventorySystem.GetHandOrInventoryEntities(user, SlotFlags.All & ~SlotFlags.POCKET)) { - if (!HasComp(ent)) + if (!HasComp(ent) || !_toggle.IsActivated(ent)) continue; EnsureComp(user); diff --git a/Resources/Prototypes/Actions/ninja.yml b/Resources/Prototypes/Actions/ninja.yml index adaf563692d..47cb8a83f44 100644 --- a/Resources/Prototypes/Actions/ninja.yml +++ b/Resources/Prototypes/Actions/ninja.yml @@ -2,7 +2,7 @@ - type: entity id: ActionToggleNinjaGloves name: Toggle ninja gloves - description: Toggles all glove actions on left click. Includes your doorjack, draining power, stunning enemies, downloading research and calling in a threat. + description: Toggles all glove actions on left click. Includes your doorjack, draining power, stunning enemies and hacking certain computers. components: - type: InstantAction priority: -13 @@ -21,7 +21,7 @@ state: icon itemIconStyle: NoItem priority: -10 - event: !type:CreateThrowingStarEvent {} + event: !type:CreateItemEvent {} - type: entity id: ActionRecallKatana @@ -59,7 +59,7 @@ # have to plan (un)cloaking ahead of time useDelay: 5 priority: -9 - event: !type:ToggleStealthEvent + event: !type:ToggleActionEvent # katana - type: entity @@ -72,6 +72,10 @@ sprite: Objects/Magic/magicactions.rsi state: blink itemIconStyle: NoItem + sound: + path: /Audio/Magic/blink.ogg + params: + volume: 5 priority: -12 event: !type:DashEvent checkCanAccess: false diff --git a/Resources/Prototypes/Entities/Clothing/Hands/gloves.yml b/Resources/Prototypes/Entities/Clothing/Hands/gloves.yml index 8b73eee0d24..f1d99884658 100644 --- a/Resources/Prototypes/Entities/Clothing/Hands/gloves.yml +++ b/Resources/Prototypes/Entities/Clothing/Hands/gloves.yml @@ -206,7 +206,7 @@ - type: FingerprintMask - type: entity - parent: ClothingHandsBase + parent: [ClothingHandsBase, BaseToggleClothing] id: ClothingHandsGlovesSpaceNinja name: space ninja gloves description: These black nano-enhanced gloves insulate from electricity and provide fire resistance. @@ -234,7 +234,31 @@ - type: Thieving stripTimeReduction: 1 stealthy: true + - type: ToggleClothing + action: ActionToggleNinjaGloves - type: NinjaGloves + abilities: + - components: + - type: BatteryDrainer + - type: StunProvider + noPowerPopup: ninja-no-power + whitelist: + components: + - Stamina + - type: EmagProvider + whitelist: + components: + - Airlock + - objective: StealResearchObjective + components: + - type: ResearchStealer + - objective: TerrorObjective + components: + - type: CommsHacker + threats: NinjaThreats + - objective: MassArrestObjective + components: + - type: CriminalRecordsHacker - type: entity parent: ClothingHandsGlovesColorBlack diff --git a/Resources/Prototypes/Entities/Clothing/Head/misc.yml b/Resources/Prototypes/Entities/Clothing/Head/misc.yml index c6a556b2d32..c32f485f9ca 100644 --- a/Resources/Prototypes/Entities/Clothing/Head/misc.yml +++ b/Resources/Prototypes/Entities/Clothing/Head/misc.yml @@ -183,6 +183,36 @@ - type: AddAccentClothing accent: OwOAccent +- type: entity + parent: [ClothingHeadHatCatEars, BaseToggleClothing] + id: ClothingHeadHatCatEarsValid + suffix: Valid, DO NOT MAP + components: + - type: ToggleClothing + action: ActionBecomeValid + disableOnUnequip: true + - type: ComponentToggler + parent: true + components: + - type: KillSign + - type: Tag + tags: [] # ignore "WhitelistChameleon" tag + - type: Sprite + sprite: Clothing/Head/Hats/catears.rsi + - type: Clothing + sprite: Clothing/Head/Hats/catears.rsi + - type: AddAccentClothing + accent: OwOAccent + +- type: entity + noSpawn: true + id: ActionBecomeValid + name: Become Valid + description: "*notices your killsign* owo whats this" + components: + - type: InstantAction + event: !type:ToggleActionEvent + - type: entity parent: ClothingHeadBase id: ClothingHeadHatDogEars diff --git a/Resources/Prototypes/Entities/Clothing/OuterClothing/suits.yml b/Resources/Prototypes/Entities/Clothing/OuterClothing/suits.yml index 2053ced0f63..bacdd0046f8 100644 --- a/Resources/Prototypes/Entities/Clothing/OuterClothing/suits.yml +++ b/Resources/Prototypes/Entities/Clothing/OuterClothing/suits.yml @@ -127,7 +127,7 @@ slots: WITHOUT_POCKET - type: entity - parent: [ClothingOuterBaseLarge, AllowSuitStorageClothing] + parent: [ClothingOuterBaseLarge, AllowSuitStorageClothing, BaseToggleClothing] id: ClothingOuterSuitSpaceNinja name: space ninja suit description: This black technologically advanced, cybernetically-enhanced suit provides many abilities like invisibility or teleportation. @@ -136,9 +136,7 @@ sprite: Clothing/OuterClothing/Suits/spaceninja.rsi - type: Clothing sprite: Clothing/OuterClothing/Suits/spaceninja.rsi - - type: StealthClothing - visibility: 1.1 - toggleAction: ActionTogglePhaseCloak + # hardsuit stuff - type: PressureProtection highPressureMultiplier: 0.6 lowPressureMultiplier: 1000 @@ -151,7 +149,27 @@ Slash: 0.8 Piercing: 0.8 Heat: 0.8 + # phase cloak + - type: ToggleClothing + action: ActionTogglePhaseCloak + - type: ComponentToggler + parent: true + components: + - type: Stealth + minVisibility: 0.1 + lastVisibility: 0.1 + - type: PowerCellDraw + drawRate: 1.8 # 200 seconds on the default cell + # throwing star ability + - type: ItemCreator + action: ActionCreateThrowingStar + charge: 14.4 + spawnedPrototype: ThrowingStarNinja + noPowerPopup: ninja-no-power + # core ninja suit stuff - type: NinjaSuit + - type: UseDelay + delay: 5 # disable time - type: PowerCellSlot cellSlotId: cell_slot # throwing in a recharger would bypass glove charging mechanic diff --git a/Resources/Prototypes/Entities/Clothing/Shoes/magboots.yml b/Resources/Prototypes/Entities/Clothing/Shoes/magboots.yml index 80a9159c722..cd6af152f15 100644 --- a/Resources/Prototypes/Entities/Clothing/Shoes/magboots.yml +++ b/Resources/Prototypes/Entities/Clothing/Shoes/magboots.yml @@ -1,37 +1,43 @@ - type: entity - parent: ClothingShoesBase + parent: [ClothingShoesBase, BaseToggleClothing] id: ClothingShoesBootsMag name: magboots description: Magnetic boots, often used during extravehicular activity to ensure the user remains safely attached to the vehicle. components: - - type: Sprite - sprite: Clothing/Shoes/Boots/magboots.rsi - layers: - - state: icon - map: [ "enum.ToggleVisuals.Layer" ] - - type: Clothing - sprite: Clothing/Shoes/Boots/magboots.rsi - - type: Magboots - - type: ClothingSpeedModifier - walkModifier: 0.85 - sprintModifier: 0.8 - enabled: false - - type: Appearance - - type: GenericVisualizer - visuals: - enum.ToggleVisuals.Toggled: - enum.ToggleVisuals.Layer: - True: {state: icon-on} - False: {state: icon} - - type: StaticPrice - price: 200 - - type: Tag - tags: - - WhitelistChameleon - - type: ReverseEngineering # delta - difficulty: 2 - recipes: - - ClothingShoesBootsMagSci + - type: Sprite + sprite: Clothing/Shoes/Boots/magboots.rsi + layers: + - state: icon + map: [ "enum.ToggleVisuals.Layer" ] + - type: Clothing + sprite: Clothing/Shoes/Boots/magboots.rsi + - type: ToggleClothing + action: ActionToggleMagboots + - type: ToggleVerb + text: toggle-magboots-verb-get-data-text + - type: ComponentToggler + components: + - type: NoSlip + - type: Magboots + - type: ClothingSpeedModifier + walkModifier: 0.85 + sprintModifier: 0.8 + - type: Appearance + - type: GenericVisualizer + visuals: + enum.ToggleVisuals.Toggled: + enum.ToggleVisuals.Layer: + True: {state: icon-on} + False: {state: icon} + - type: StaticPrice + price: 200 + - type: Tag + tags: + - WhitelistChameleon + - type: ReverseEngineering # DeltaV + difficulty: 2 + recipes: + - ClothingShoesBootsMagSci - type: entity parent: ClothingShoesBootsMag @@ -44,13 +50,9 @@ state: icon - type: Clothing sprite: Clothing/Shoes/Boots/magboots-advanced.rsi - - type: Magboots - toggleAction: ActionToggleMagbootsAdvanced - type: ClothingSpeedModifier walkModifier: 1 sprintModifier: 1 - enabled: false - - type: NoSlip - type: Tag tags: - WhitelistChameleon @@ -68,8 +70,6 @@ sprite: Clothing/Shoes/Boots/magboots-science.rsi - type: Clothing sprite: Clothing/Shoes/Boots/magboots-science.rsi - - type: Magboots - toggleAction: ActionToggleMagbootsSci - type: entity parent: ClothingShoesBootsMag @@ -80,7 +80,6 @@ - type: ClothingSpeedModifier walkModifier: 1.10 #PVS isn't too much of an issue when you are blind... sprintModifier: 1.10 - enabled: false - type: StaticPrice price: 3000 @@ -95,12 +94,9 @@ state: icon - type: Clothing sprite: Clothing/Shoes/Boots/magboots-syndicate.rsi - - type: Magboots - toggleAction: ActionToggleMagbootsSyndie - type: ClothingSpeedModifier walkModifier: 0.95 sprintModifier: 0.9 - enabled: false - type: GasTank outputPressure: 42.6 air: @@ -108,49 +104,17 @@ volume: 0.75 temperature: 293.15 moles: - - 0.153853429 # oxygen - - 0.153853429 # nitrogen + - 0.153853429 # oxygen + - 0.153853429 # nitrogen - type: Item sprite: null size: Normal - type: entity - id: ActionBaseToggleMagboots + id: ActionToggleMagboots name: Toggle Magboots description: Toggles the magboots on and off. components: - type: InstantAction - itemIconStyle: NoItem - event: !type:ToggleMagbootsEvent - -- type: entity - id: ActionToggleMagboots - parent: ActionBaseToggleMagboots - components: - - type: InstantAction - icon: { sprite: Clothing/Shoes/Boots/magboots.rsi, state: icon } - iconOn: { sprite : Clothing/Shoes/Boots/magboots.rsi, state: icon-on } - -- type: entity - id: ActionToggleMagbootsAdvanced - parent: ActionBaseToggleMagboots - components: - - type: InstantAction - icon: { sprite: Clothing/Shoes/Boots/magboots-advanced.rsi, state: icon } - iconOn: Clothing/Shoes/Boots/magboots-advanced.rsi/icon-on.png - -- type: entity - id: ActionToggleMagbootsSci - parent: ActionBaseToggleMagboots - components: - - type: InstantAction - icon: { sprite: Clothing/Shoes/Boots/magboots-science.rsi, state: icon } - iconOn: Clothing/Shoes/Boots/magboots-science.rsi/icon-on.png - -- type: entity - id: ActionToggleMagbootsSyndie - parent: ActionBaseToggleMagboots - components: - - type: InstantAction - icon: { sprite: Clothing/Shoes/Boots/magboots-syndicate.rsi, state: icon } - iconOn: Clothing/Shoes/Boots/magboots-syndicate.rsi/icon-on.png + itemIconStyle: BigItem + event: !type:ToggleActionEvent diff --git a/Resources/Prototypes/Entities/Clothing/Shoes/misc.yml b/Resources/Prototypes/Entities/Clothing/Shoes/misc.yml index b7cbf1d053f..25331eb02a5 100644 --- a/Resources/Prototypes/Entities/Clothing/Shoes/misc.yml +++ b/Resources/Prototypes/Entities/Clothing/Shoes/misc.yml @@ -88,7 +88,7 @@ - type: NoSlip - type: entity - parent: [ClothingShoesBase, PowerCellSlotSmallItem] + parent: [ClothingShoesBase, PowerCellSlotSmallItem, BaseToggleClothing] id: ClothingShoesBootsSpeed name: speed boots description: High-tech boots woven with quantum fibers, able to convert electricity into pure speed! @@ -100,12 +100,11 @@ map: [ "enum.ToggleVisuals.Layer" ] - type: Clothing sprite: Clothing/Shoes/Boots/speedboots.rsi - - type: ToggleClothingSpeed - toggleAction: ActionToggleSpeedBoots + - type: ToggleClothing + action: ActionToggleSpeedBoots - type: ClothingSpeedModifier walkModifier: 1.5 sprintModifier: 1.5 - enabled: false - type: Appearance - type: GenericVisualizer visuals: @@ -134,10 +133,8 @@ description: Toggles the speed boots on and off. components: - type: InstantAction - itemIconStyle: NoItem - event: !type:ToggleClothingSpeedEvent - icon: { sprite: Clothing/Shoes/Boots/speedboots.rsi, state: icon } - iconOn: { sprite: Clothing/Shoes/Boots/speedboots.rsi, state: icon-on } + itemIconStyle: BigItem + event: !type:ToggleActionEvent - type: entity parent: ClothingShoesBase diff --git a/Resources/Prototypes/Entities/Clothing/base_clothing.yml b/Resources/Prototypes/Entities/Clothing/base_clothing.yml index a96ca2d23c8..02a2ddce411 100644 --- a/Resources/Prototypes/Entities/Clothing/base_clothing.yml +++ b/Resources/Prototypes/Entities/Clothing/base_clothing.yml @@ -57,3 +57,12 @@ - type: GroupExamine - type: Armor modifiers: {} + +# for clothing that can be toggled, like magboots +- type: entity + abstract: true + id: BaseToggleClothing + components: + - type: ItemToggle + onUse: false # can't really wear it like that + - type: ToggleClothing diff --git a/Resources/Prototypes/Entities/Markers/Spawners/ghost_roles.yml b/Resources/Prototypes/Entities/Markers/Spawners/ghost_roles.yml index 8c8ea607608..0d82a7ddf84 100644 --- a/Resources/Prototypes/Entities/Markers/Spawners/ghost_roles.yml +++ b/Resources/Prototypes/Entities/Markers/Spawners/ghost_roles.yml @@ -158,10 +158,9 @@ state: alive - type: entity + noSpawn: true + parent: BaseAntagSpawner id: SpawnPointGhostSpaceNinja - name: ghost role spawn point - suffix: space ninja - parent: MarkerBase components: - type: GhostRole name: ghost-role-information-space-ninja-name @@ -172,8 +171,6 @@ requirements: - !type:OverallPlaytimeRequirement # DeltaV - Playtime requirement time: 259200 # DeltaV - 72 hours - - type: GhostRoleMobSpawner - prototype: MobHumanSpaceNinja - type: Sprite sprite: Markers/jobs.rsi layers: diff --git a/Resources/Prototypes/Entities/Mobs/Cyborgs/base_borg_chassis.yml b/Resources/Prototypes/Entities/Mobs/Cyborgs/base_borg_chassis.yml index 0f30c162b81..128a56814ab 100644 --- a/Resources/Prototypes/Entities/Mobs/Cyborgs/base_borg_chassis.yml +++ b/Resources/Prototypes/Entities/Mobs/Cyborgs/base_borg_chassis.yml @@ -112,6 +112,11 @@ - type: PowerCellSlot cellSlotId: cell_slot fitsInCharger: true + - type: ItemToggle + onUse: false # no item-borg toggling sorry + - type: AccessToggle + # TODO: refactor movement to just be based on toggle like speedboots but for the boots themselves + # TODO: or just have sentient speedboots be fast idk - type: PowerCellDraw drawRate: 0.6 - type: ItemSlots diff --git a/Resources/Prototypes/Entities/Mobs/Player/arachnid.yml b/Resources/Prototypes/Entities/Mobs/Player/arachnid.yml index 5ebd43ddf48..d9dea3c18d9 100644 --- a/Resources/Prototypes/Entities/Mobs/Player/arachnid.yml +++ b/Resources/Prototypes/Entities/Mobs/Player/arachnid.yml @@ -11,4 +11,3 @@ damageRecovery: types: Asphyxiation: -0.5 - - type: PotentialPsionic #Nyano - Summary: makes potentially psionic. diff --git a/Resources/Prototypes/Entities/Mobs/Player/diona.yml b/Resources/Prototypes/Entities/Mobs/Player/diona.yml index 28687c68bfc..dfd5e9a1be7 100644 --- a/Resources/Prototypes/Entities/Mobs/Player/diona.yml +++ b/Resources/Prototypes/Entities/Mobs/Player/diona.yml @@ -11,7 +11,6 @@ damageRecovery: types: Asphyxiation: -1.0 - - type: PotentialPsionic #Nyano - Summary: makes potentially psionic. # Reformed Diona - type: entity diff --git a/Resources/Prototypes/Entities/Mobs/Player/dwarf.yml b/Resources/Prototypes/Entities/Mobs/Player/dwarf.yml index fb84ad3650f..d1de65df012 100644 --- a/Resources/Prototypes/Entities/Mobs/Player/dwarf.yml +++ b/Resources/Prototypes/Entities/Mobs/Player/dwarf.yml @@ -3,5 +3,3 @@ name: Urist McHands The Dwarf parent: BaseMobDwarf id: MobDwarf - components: - - type: PotentialPsionic #Nyano - Summary: makes potentially psionic. \ No newline at end of file diff --git a/Resources/Prototypes/Entities/Mobs/Player/human.yml b/Resources/Prototypes/Entities/Mobs/Player/human.yml index c6b9ada1b8e..1bfd016cd50 100644 --- a/Resources/Prototypes/Entities/Mobs/Player/human.yml +++ b/Resources/Prototypes/Entities/Mobs/Player/human.yml @@ -3,8 +3,6 @@ name: Urist McHands parent: BaseMobHuman id: MobHuman - components: - - type: PotentialPsionic #Nyano - Summary: makes potentially psionic. #Syndie - type: entity @@ -76,28 +74,3 @@ - type: PsionicBonusChance #Nyano - Summary: makes more likely to be psionic. multiplier: 7 warn: false - -# Space Ninja -- type: entity - noSpawn: true - name: Space Ninja - parent: MobHuman - id: MobHumanSpaceNinja - components: - - type: RandomHumanoidAppearance - randomizeName: false - - type: Loadout - prototypes: [SpaceNinjaGear] - - type: NpcFactionMember - factions: - - Syndicate - - type: SpaceNinja - - type: GenericAntag - rule: Ninja - - type: AutoImplant - implants: - - DeathAcidifierImplant - - type: RandomMetadata - nameSegments: - - names_ninja_title - - names_ninja diff --git a/Resources/Prototypes/Entities/Mobs/Player/moth.yml b/Resources/Prototypes/Entities/Mobs/Player/moth.yml index ffdb36d86bd..72feba958ab 100644 --- a/Resources/Prototypes/Entities/Mobs/Player/moth.yml +++ b/Resources/Prototypes/Entities/Mobs/Player/moth.yml @@ -3,5 +3,3 @@ name: Urist McFluff parent: BaseMobMoth id: MobMoth - components: - - type: PotentialPsionic #Nyano - Summary: makes potentially psionic. \ No newline at end of file diff --git a/Resources/Prototypes/Entities/Mobs/Player/reptilian.yml b/Resources/Prototypes/Entities/Mobs/Player/reptilian.yml index 871512fe7e9..b332f573fb5 100644 --- a/Resources/Prototypes/Entities/Mobs/Player/reptilian.yml +++ b/Resources/Prototypes/Entities/Mobs/Player/reptilian.yml @@ -4,7 +4,5 @@ suffix: Urisst' Mzhand parent: BaseMobReptilian id: MobReptilian - components: - - type: PotentialPsionic #Nyano - Summary: makes potentially psionic. #Weh diff --git a/Resources/Prototypes/Entities/Mobs/Player/skeleton.yml b/Resources/Prototypes/Entities/Mobs/Player/skeleton.yml index 5e71e6b7282..84f8d078099 100644 --- a/Resources/Prototypes/Entities/Mobs/Player/skeleton.yml +++ b/Resources/Prototypes/Entities/Mobs/Player/skeleton.yml @@ -8,7 +8,6 @@ interactSuccessString: hugging-success-generic interactSuccessSound: /Audio/Effects/thudswoosh.ogg messagePerceivedByOthers: hugging-success-generic-others - - type: PotentialPsionic #Nyano - Summary: makes potentially psionic. - type: entity name: skeleton pirate diff --git a/Resources/Prototypes/Entities/Mobs/Player/slime.yml b/Resources/Prototypes/Entities/Mobs/Player/slime.yml index 79669a8fe2a..4e5974b3084 100644 --- a/Resources/Prototypes/Entities/Mobs/Player/slime.yml +++ b/Resources/Prototypes/Entities/Mobs/Player/slime.yml @@ -2,5 +2,3 @@ save: false parent: BaseMobSlimePerson id: MobSlimePerson - components: - - type: PotentialPsionic #Nyano - Summary: makes potentially psionic. \ No newline at end of file diff --git a/Resources/Prototypes/Entities/Mobs/Player/vox.yml b/Resources/Prototypes/Entities/Mobs/Player/vox.yml index 0a3e566b37c..d88732bafa6 100644 --- a/Resources/Prototypes/Entities/Mobs/Player/vox.yml +++ b/Resources/Prototypes/Entities/Mobs/Player/vox.yml @@ -3,5 +3,3 @@ name: Urist McVox parent: BaseMobVox id: MobVox - components: - - type: PotentialPsionic #Nyano - Summary: makes potentially psionic. diff --git a/Resources/Prototypes/Entities/Mobs/Species/base.yml b/Resources/Prototypes/Entities/Mobs/Species/base.yml index 9604d7135e2..7a3f1e05f65 100644 --- a/Resources/Prototypes/Entities/Mobs/Species/base.yml +++ b/Resources/Prototypes/Entities/Mobs/Species/base.yml @@ -144,9 +144,6 @@ - Flashed - PsionicsDisabled #Nyano - Summary: PCs can have psionics disabled. - PsionicallyInsulated #Nyano - Summary: PCs can be made insulated from psionic powers. - - type: Reflect - enabled: false - reflectProb: 0 - type: Body prototype: Human requiredLegs: 2 diff --git a/Resources/Prototypes/Entities/Objects/Devices/base_handheld.yml b/Resources/Prototypes/Entities/Objects/Devices/base_handheld.yml new file mode 100644 index 00000000000..259323fede3 --- /dev/null +++ b/Resources/Prototypes/Entities/Objects/Devices/base_handheld.yml @@ -0,0 +1,11 @@ +- type: entity + abstract: true + parent: [BaseItem, PowerCellSlotSmallItem] + id: BaseHandheldComputer + components: + - type: ActivatableUIRequiresPowerCell + - type: ItemToggle + onUse: false # above component does the toggling + - type: PowerCellDraw + drawRate: 0 + useRate: 20 diff --git a/Resources/Prototypes/Entities/Objects/Devices/pda.yml b/Resources/Prototypes/Entities/Objects/Devices/pda.yml index 7f74cd995a5..eca1dbf5b63 100644 --- a/Resources/Prototypes/Entities/Objects/Devices/pda.yml +++ b/Resources/Prototypes/Entities/Objects/Devices/pda.yml @@ -113,6 +113,9 @@ id: BaseMedicalPDA abstract: true components: + - type: ItemToggle + toggleLight: false + onUse: false - type: HealthAnalyzer scanDelay: 1 scanningEndSound: diff --git a/Resources/Prototypes/Entities/Objects/Devices/station_map.yml b/Resources/Prototypes/Entities/Objects/Devices/station_map.yml index 0d2f890a1d3..54fc4a70c5a 100644 --- a/Resources/Prototypes/Entities/Objects/Devices/station_map.yml +++ b/Resources/Prototypes/Entities/Objects/Devices/station_map.yml @@ -1,9 +1,9 @@ - type: entity + parent: BaseItem id: BaseHandheldStationMap name: station map description: Displays a readout of the current station. abstract: true - parent: BaseItem components: - type: StationMap - type: Sprite @@ -34,14 +34,9 @@ - type: entity id: HandheldStationMap parent: - - BaseHandheldStationMap - - PowerCellSlotSmallItem + - BaseHandheldStationMap + - BaseHandheldComputer suffix: Handheld, Powered - components: - - type: PowerCellDraw - drawRate: 0 - useRate: 20 - - type: ActivatableUIRequiresPowerCell - type: entity id: HandheldStationMapEmpty diff --git a/Resources/Prototypes/Entities/Objects/Shields/shields.yml b/Resources/Prototypes/Entities/Objects/Shields/shields.yml index dc24ac485a1..8182accfb6f 100644 --- a/Resources/Prototypes/Entities/Objects/Shields/shields.yml +++ b/Resources/Prototypes/Entities/Objects/Shields/shields.yml @@ -382,8 +382,10 @@ path: /Audio/Weapons/ebladehum.ogg - type: ItemToggleSize activatedSize: Huge - - type: ItemToggleDisarmMalus - activatedDisarmMalus: 0.6 + - type: ComponentToggler + components: + - type: DisarmMalus + malus: 0.6 - type: Sprite sprite: Objects/Weapons/Melee/e_shield.rsi layers: @@ -415,7 +417,6 @@ energy: 2 color: blue - type: Reflect - enabled: false reflectProb: 0.95 reflects: - Energy @@ -492,8 +493,10 @@ path: /Audio/Weapons/telescopicoff.ogg params: volume: -5 - - type: ItemToggleDisarmMalus - activatedDisarmMalus: 0.6 + - type: ComponentToggler + components: + - type: DisarmMalus + malus: 0.6 - type: ItemToggleSize activatedSize: Huge - type: Sprite diff --git a/Resources/Prototypes/Entities/Objects/Specific/Medical/defib.yml b/Resources/Prototypes/Entities/Objects/Specific/Medical/defib.yml index 4a61074a8d5..2d06ed0f1dc 100644 --- a/Resources/Prototypes/Entities/Objects/Specific/Medical/defib.yml +++ b/Resources/Prototypes/Entities/Objects/Specific/Medical/defib.yml @@ -31,6 +31,11 @@ size: Large - type: Speech speechVerb: Robotic + - type: ItemToggle + soundActivate: + path: /Audio/Items/Defib/defib_safety_on.ogg + soundDeactivate: + path: /Audio/Items/Defib/defib_safety_off.ogg - type: Defibrillator zapHeal: types: 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 ab338b9da95..5f0cf2b0d51 100644 --- a/Resources/Prototypes/Entities/Objects/Specific/Medical/handheld_crew_monitor.yml +++ b/Resources/Prototypes/Entities/Objects/Specific/Medical/handheld_crew_monitor.yml @@ -1,19 +1,14 @@ - type: entity name: handheld crew monitor suffix: DO NOT MAP - parent: - - BaseItem - - PowerCellSlotSmallItem + parent: BaseHandheldComputer + # CMO-only bud, don't add more. id: HandheldCrewMonitor description: A hand-held crew monitor displaying the status of suit sensors. components: - type: Sprite sprite: Objects/Specific/Medical/handheldcrewmonitor.rsi state: scanner - - type: PowerCellDraw - drawRate: 0 - useRate: 20 - - type: ActivatableUIRequiresPowerCell - type: ActivatableUI key: enum.CrewMonitoringUIKey.Key - type: UserInterface @@ -98,4 +93,4 @@ slots: cell_slot: name: power-cell-slot-component-slot-name-default - \ No newline at end of file + diff --git a/Resources/Prototypes/Entities/Objects/Specific/Medical/healthanalyzer.yml b/Resources/Prototypes/Entities/Objects/Specific/Medical/healthanalyzer.yml index c01aaa84a9d..d8547d92948 100644 --- a/Resources/Prototypes/Entities/Objects/Specific/Medical/healthanalyzer.yml +++ b/Resources/Prototypes/Entities/Objects/Specific/Medical/healthanalyzer.yml @@ -21,6 +21,8 @@ interfaces: enum.HealthAnalyzerUiKey.Key: type: HealthAnalyzerBoundUserInterface + - type: ItemToggle + onUse: false - type: HealthAnalyzer scanningEndSound: path: "/Audio/Items/Medical/healthscanner.ogg" diff --git a/Resources/Prototypes/Entities/Objects/Specific/Research/anomaly.yml b/Resources/Prototypes/Entities/Objects/Specific/Research/anomaly.yml index 113017cc84a..e480ff7dd64 100644 --- a/Resources/Prototypes/Entities/Objects/Specific/Research/anomaly.yml +++ b/Resources/Prototypes/Entities/Objects/Specific/Research/anomaly.yml @@ -40,23 +40,22 @@ - state: screen shader: unshaded visible: false - map: ["enum.PowerDeviceVisualLayers.Powered"] + map: ["enum.ToggleVisuals.Layer"] - type: Appearance - type: GenericVisualizer visuals: - enum.ProximityBeeperVisuals.Enabled: - enum.PowerDeviceVisualLayers.Powered: + enum.ToggleVisuals.Toggled: + enum.ToggleVisuals.Layer: True: { visible: true } False: { visible: false } + - type: ItemToggle - type: ProximityBeeper - type: ProximityDetector - enabled: false range: 20 criteria: components: - Anomaly - type: Beeper - enabled: false minBeepInterval: 0.15 maxBeepInterval: 1.00 beepSound: diff --git a/Resources/Prototypes/Entities/Objects/Tools/handheld_mass_scanner.yml b/Resources/Prototypes/Entities/Objects/Tools/handheld_mass_scanner.yml index 1b92b4ace22..eecc6a1bb64 100644 --- a/Resources/Prototypes/Entities/Objects/Tools/handheld_mass_scanner.yml +++ b/Resources/Prototypes/Entities/Objects/Tools/handheld_mass_scanner.yml @@ -1,6 +1,6 @@ - type: entity name: handheld mass scanner - parent: [ BaseItem, PowerCellSlotSmallItem] + parent: BaseHandheldComputer id: HandHeldMassScanner description: A hand-held mass scanner. components: @@ -27,7 +27,6 @@ - type: PowerCellDraw drawRate: 3 useRate: 100 - - type: ActivatableUIRequiresPowerCell - type: ActivatableUI key: enum.RadarConsoleUiKey.Key inHandsOnly: true diff --git a/Resources/Prototypes/Entities/Objects/Tools/welders.yml b/Resources/Prototypes/Entities/Objects/Tools/welders.yml index 9db30edb52e..cd188969b53 100644 --- a/Resources/Prototypes/Entities/Objects/Tools/welders.yml +++ b/Resources/Prototypes/Entities/Objects/Tools/welders.yml @@ -55,8 +55,10 @@ - type: ItemToggleSize activatedSize: Large - type: ItemToggleHot - - type: ItemToggleDisarmMalus - activatedDisarmMalus: 0.6 + - type: ComponentToggler + components: + - type: DisarmMalus + malus: 0.6 - type: ToggleableLightVisuals spriteLayer: flame inhandVisuals: diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Launchers/launchers.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Launchers/launchers.yml index 728783fb3ea..0f94825ad0e 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Launchers/launchers.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Launchers/launchers.yml @@ -166,6 +166,8 @@ - type: TetherGun frequency: 5 dampingRatio: 4 + - type: ItemToggle + onUse: false - type: PowerCellDraw - type: Sprite sprite: Objects/Weapons/Guns/Launchers/tether_gun.rsi @@ -211,6 +213,8 @@ path: /Audio/Weapons/soup.ogg params: volume: 2 + - type: ItemToggle + onUse: false - type: PowerCellDraw - type: Sprite sprite: Objects/Weapons/Guns/Launchers/force_gun.rsi diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Melee/e_sword.yml b/Resources/Prototypes/Entities/Objects/Weapons/Melee/e_sword.yml index 31606a2278a..aea31a06ef8 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Melee/e_sword.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Melee/e_sword.yml @@ -13,10 +13,12 @@ - type: ItemToggleActiveSound activeSound: path: /Audio/Weapons/ebladehum.ogg - - type: ItemToggleSharp + - type: ComponentToggler + components: + - type: Sharp + - type: DisarmMalus + malus: 0.6 - type: ItemToggleHot - - type: ItemToggleDisarmMalus - activatedDisarmMalus: 0.6 - type: ItemToggleSize activatedSize: Huge - type: ItemToggleMeleeWeapon @@ -74,10 +76,7 @@ right: - state: inhand-right-blade shader: unshaded - - type: DisarmMalus - malus: 0 - type: Reflect - enabled: false - type: IgnitionSource temperature: 700 @@ -88,7 +87,6 @@ suffix: E-Dagger description: 'A dark ink pen.' components: - - type: EnergySword - type: ItemToggle soundActivate: path: /Audio/Weapons/ebladeon.ogg @@ -114,8 +112,11 @@ path: /Audio/Weapons/ebladehum.ogg params: volume: -6 - - type: ItemToggleDisarmMalus - activatedDisarmMalus: 0.4 + - type: ComponentToggler + components: + - type: Sharp + - type: DisarmMalus + malus: 0.4 - type: Sprite sprite: Objects/Weapons/Melee/e_dagger.rsi layers: @@ -183,15 +184,12 @@ id: EnergyCutlass description: An exotic energy weapon, brutal blade crackling with crudely harnessed plasma. #DeltaV - nicer description. components: - - type: EnergySword - type: ItemToggleMeleeWeapon activatedDamage: types: Slash: 10 Heat: 12 deactivatedSecret: true - - type: ItemToggleDisarmMalus - activatedDisarmMalus: 0.6 - type: Sprite sprite: DeltaV/Objects/Weapons/Melee/e_cutlass.rsi # DeltaV layers: @@ -227,8 +225,8 @@ id: EnergySwordDouble description: Syndicate Command Interns thought that having one blade on the energy sword was not enough. This can be stored in pockets. components: - - type: EnergySword - type: ItemToggle + onUse: false # wielding events control it instead soundActivate: path: /Audio/Weapons/ebladeon.ogg params: @@ -253,9 +251,13 @@ path: /Audio/Weapons/ebladehum.ogg params: volume: 3 - - type: ItemToggleDisarmMalus - activatedDisarmMalus: 0.7 + - type: ComponentToggler + components: + - type: Sharp + - type: DisarmMalus + malus: 0.7 - type: Wieldable + wieldSound: null # esword light sound instead - type: MeleeWeapon wideAnimationRotation: -135 attackRate: 1.5 diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Melee/sword.yml b/Resources/Prototypes/Entities/Objects/Weapons/Melee/sword.yml index 0d710b0d3cc..ed8be9a735c 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Melee/sword.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Melee/sword.yml @@ -30,7 +30,6 @@ soundHit: path: /Audio/Weapons/bladeslice.ogg - type: Reflect - enabled: true reflectProb: .1 spread: 90 - type: Item @@ -175,7 +174,6 @@ soundHit: path: /Audio/Effects/explosion_small1.ogg - type: Reflect - enabled: true reflectProb: .25 spread: 90 - type: Item diff --git a/Resources/Prototypes/Entities/Structures/Machines/Medical/cryo_pod.yml b/Resources/Prototypes/Entities/Structures/Machines/Medical/cryo_pod.yml index 4cb76ea4b92..0485b5a5178 100644 --- a/Resources/Prototypes/Entities/Structures/Machines/Medical/cryo_pod.yml +++ b/Resources/Prototypes/Entities/Structures/Machines/Medical/cryo_pod.yml @@ -85,6 +85,7 @@ whitelist: components: - FitsInDispenser + - type: ItemToggle - type: HealthAnalyzer scanDelay: 0 - type: UserInterface diff --git a/Resources/Prototypes/GameRules/events.yml b/Resources/Prototypes/GameRules/events.yml index 74d0dfb80c6..35ef33b24a2 100644 --- a/Resources/Prototypes/GameRules/events.yml +++ b/Resources/Prototypes/GameRules/events.yml @@ -118,9 +118,45 @@ weight: 5 # DeltaV - was 10 duration: 1 earliestStart: 30 - reoccurrenceDelay: 60 - minimumPlayers: 40 - - type: NinjaSpawnRule + reoccurrenceDelay: 60 # DeltaV - was 20 + minimumPlayers: 40 # DeltaV - was 30 + - type: SpaceSpawnRule + - type: AntagLoadProfileRule + - type: AntagObjectives + objectives: + - StealResearchObjective + - DoorjackObjective + - SpiderChargeObjective + - TerrorObjective + - MassArrestObjective + - NinjaSurviveObjective + - type: AntagSelection + agentName: ninja-round-end-agent-name + definitions: + - spawnerPrototype: SpawnPointGhostSpaceNinja + min: 1 + max: 1 + pickPlayer: false + startingGear: SpaceNinjaGear + briefing: + text: ninja-role-greeting + color: Green + sound: /Audio/Misc/ninja_greeting.ogg + components: + - type: SpaceNinja + - type: NpcFactionMember + factions: + - Syndicate + - type: AutoImplant + implants: + - DeathAcidifierImplant + - type: RandomMetadata + nameSegments: + - names_ninja_title + - names_ninja + mindComponents: + - type: NinjaRole + prototype: SpaceNinja - type: entity parent: BaseGameRule diff --git a/Resources/Prototypes/GameRules/midround.yml b/Resources/Prototypes/GameRules/midround.yml index 606f5fda781..b0e4efa6b1f 100644 --- a/Resources/Prototypes/GameRules/midround.yml +++ b/Resources/Prototypes/GameRules/midround.yml @@ -1,21 +1,3 @@ -# doesnt spawn a ninja or anything, just stores configuration for it -# see NinjaSpawn event for spawning -- type: entity - id: Ninja - parent: BaseGameRule - components: - - type: GenericAntagRule - agentName: ninja-round-end-agent-name - objectives: - - StealResearchObjective - - DoorjackObjective - - SpiderChargeObjective - - TerrorObjective - - MassArrestObjective - - NinjaSurviveObjective - - type: NinjaRule - threats: NinjaThreats - - type: entity noSpawn: true parent: BaseGameRule From d972a3647ffd701746a5af915e9092b273c985a7 Mon Sep 17 00:00:00 2001 From: Tayrtahn Date: Thu, 11 Jul 2024 02:14:34 -0400 Subject: [PATCH 153/765] Fix AtmosDeviceSystem debug assert Heisenbug (#29752) Fix AtmosDeviceSystem debug assertion Heisenbug --- .../Tests/Atmos/GridJoinTest.cs | 53 +++++++++++++++++++ .../Piping/EntitySystems/AtmosDeviceSystem.cs | 11 +++- 2 files changed, 63 insertions(+), 1 deletion(-) create mode 100644 Content.IntegrationTests/Tests/Atmos/GridJoinTest.cs diff --git a/Content.IntegrationTests/Tests/Atmos/GridJoinTest.cs b/Content.IntegrationTests/Tests/Atmos/GridJoinTest.cs new file mode 100644 index 00000000000..3a1ec7fd40e --- /dev/null +++ b/Content.IntegrationTests/Tests/Atmos/GridJoinTest.cs @@ -0,0 +1,53 @@ +using Content.Server.Atmos.Components; +using Content.Server.Atmos.EntitySystems; +using Content.Server.Atmos.Piping.Components; +using Content.Server.Atmos.Piping.EntitySystems; +using Robust.Shared.GameObjects; + +namespace Content.IntegrationTests.Tests.Atmos; + +[TestFixture] +public sealed class GridJoinTest +{ + private const string CanisterProtoId = "AirCanister"; + + [Test] + public async Task TestGridJoinAtmosphere() + { + await using var pair = await PoolManager.GetServerClient(); + var server = pair.Server; + + var entMan = server.EntMan; + var protoMan = server.ProtoMan; + var atmosSystem = entMan.System(); + var atmosDeviceSystem = entMan.System(); + var transformSystem = entMan.System(); + + var testMap = await pair.CreateTestMap(); + + await server.WaitPost(() => + { + // Spawn an atmos device on the grid + var canister = entMan.Spawn(CanisterProtoId); + transformSystem.SetCoordinates(canister, testMap.GridCoords); + var deviceComp = entMan.GetComponent(canister); + var canisterEnt = (canister, deviceComp); + + // Make sure the canister is tracked as an off-grid device + Assert.That(atmosDeviceSystem.IsJoinedOffGrid(canisterEnt)); + + // Add an atmosphere to the grid + entMan.AddComponent(testMap.Grid); + + // Force AtmosDeviceSystem to update off-grid devices + // This means the canister is now considered on-grid, + // but it's still tracked as off-grid! + Assert.DoesNotThrow(() => atmosDeviceSystem.Update(atmosSystem.AtmosTime)); + + // Make sure that the canister is now properly tracked as on-grid + Assert.That(atmosDeviceSystem.IsJoinedOffGrid(canisterEnt), Is.False); + }); + + await pair.CleanReturnAsync(); + } +} diff --git a/Content.Server/Atmos/Piping/EntitySystems/AtmosDeviceSystem.cs b/Content.Server/Atmos/Piping/EntitySystems/AtmosDeviceSystem.cs index 3c73a8f64ee..f932ef36208 100644 --- a/Content.Server/Atmos/Piping/EntitySystems/AtmosDeviceSystem.cs +++ b/Content.Server/Atmos/Piping/EntitySystems/AtmosDeviceSystem.cs @@ -132,10 +132,19 @@ public override void Update(float frameTime) var ev = new AtmosDeviceUpdateEvent(_atmosphereSystem.AtmosTime, null, null); foreach (var device in _joinedDevices) { - DebugTools.Assert(!HasComp(Transform(device).GridUid)); + var deviceGrid = Transform(device).GridUid; + if (HasComp(deviceGrid)) + { + RejoinAtmosphere(device); + } RaiseLocalEvent(device, ref ev); device.Comp.LastProcess = time; } } + + public bool IsJoinedOffGrid(Entity device) + { + return _joinedDevices.Contains(device); + } } } From 8f1c51e6617624645a8ae561552e0352cc7eea6c Mon Sep 17 00:00:00 2001 From: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com> Date: Thu, 11 Jul 2024 17:04:10 +1000 Subject: [PATCH 154/765] Revert "Picking a ghostrole as an admin will now deadmin you. (#29790)" (#29901) This reverts commit 1a50760e674134de6065bff3bc76739526ea5429. --- Content.Server/Ghost/Roles/GhostRoleSystem.cs | 13 ------------- Content.Shared/CCVar/CCVars.cs | 2 +- 2 files changed, 1 insertion(+), 14 deletions(-) diff --git a/Content.Server/Ghost/Roles/GhostRoleSystem.cs b/Content.Server/Ghost/Roles/GhostRoleSystem.cs index 84447c8c0fd..40e5af78596 100644 --- a/Content.Server/Ghost/Roles/GhostRoleSystem.cs +++ b/Content.Server/Ghost/Roles/GhostRoleSystem.cs @@ -31,9 +31,6 @@ using Content.Server.Popups; using Content.Shared.Verbs; using Robust.Shared.Collections; -using Content.Server.Administration.Managers; -using Content.Shared.CCVar; -using Robust.Shared.Configuration; namespace Content.Server.Ghost.Roles { @@ -51,8 +48,6 @@ namespace Content.Server.Ghost.Roles [Dependency] private readonly IGameTiming _timing = default!; [Dependency] private readonly PopupSystem _popupSystem = default!; [Dependency] private readonly IPrototypeManager _prototype = default!; - [Dependency] private readonly IAdminManager _adminManager = default!; - [Dependency] private readonly IConfigurationManager _cfg = default!; private uint _nextRoleIdentifier; private bool _needsUpdateGhostRoleCount = true; @@ -593,14 +588,6 @@ private void OnPlayerAttached(PlayerAttachedEvent message) // forced into a ghost role. LeaveAllRaffles(message.Player); CloseEui(message.Player); - - // The player is no longer a ghost, so they should not be adminned anymore. Deadmin them. - // Ensures that admins do not forget to deadmin themselves upon entering a ghost role. - var autoDeAdmin = _cfg.GetCVar(CCVars.AdminDeadminOnJoin); - if (autoDeAdmin && _adminManager.IsAdmin(message.Entity)) - { - _adminManager.DeAdmin(message.Player); - } } private void OnMindAdded(EntityUid uid, GhostTakeoverAvailableComponent component, MindAddedMessage args) diff --git a/Content.Shared/CCVar/CCVars.cs b/Content.Shared/CCVar/CCVars.cs index d824d04e8e2..8ed610adfcb 100644 --- a/Content.Shared/CCVar/CCVars.cs +++ b/Content.Shared/CCVar/CCVars.cs @@ -852,7 +852,7 @@ public static readonly CVarDef CVarDef.Create("admin.show_pii_onban", false, CVar.SERVERONLY); /// - /// If an admin joins a round by readying up or using the late join button, automatically + /// If an admin joins a round by reading up or using the late join button, automatically /// de-admin them. /// public static readonly CVarDef AdminDeadminOnJoin = From c0228a4f9ab769802a844bbe58904b78f56d8d74 Mon Sep 17 00:00:00 2001 From: chavonadelal <156101927+chavonadelal@users.noreply.github.com> Date: Thu, 11 Jul 2024 17:02:53 +0300 Subject: [PATCH 155/765] =?UTF-8?q?=D0=90nnouncement=20sender=20localizati?= =?UTF-8?q?on=20(#29907)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Content.Server/Chat/Systems/AnnounceOnSpawnSystem.cs | 2 +- Content.Server/Chat/Systems/ChatSystem.cs | 8 ++++++-- Resources/Locale/en-US/chat/managers/chat-manager.ftl | 1 + 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/Content.Server/Chat/Systems/AnnounceOnSpawnSystem.cs b/Content.Server/Chat/Systems/AnnounceOnSpawnSystem.cs index 0f0365e56ba..cc46545237b 100644 --- a/Content.Server/Chat/Systems/AnnounceOnSpawnSystem.cs +++ b/Content.Server/Chat/Systems/AnnounceOnSpawnSystem.cs @@ -16,7 +16,7 @@ public override void Initialize() private void OnInit(EntityUid uid, AnnounceOnSpawnComponent comp, MapInitEvent args) { var message = Loc.GetString(comp.Message); - var sender = comp.Sender != null ? Loc.GetString(comp.Sender) : "Central Command"; + var sender = comp.Sender != null ? Loc.GetString(comp.Sender) : Loc.GetString("chat-manager-sender-announcement"); _chat.DispatchGlobalAnnouncement(message, sender, playSound: true, comp.Sound, comp.Color); } } diff --git a/Content.Server/Chat/Systems/ChatSystem.cs b/Content.Server/Chat/Systems/ChatSystem.cs index 66fa02d1170..c4f793c7b77 100644 --- a/Content.Server/Chat/Systems/ChatSystem.cs +++ b/Content.Server/Chat/Systems/ChatSystem.cs @@ -329,12 +329,14 @@ public void TrySendInGameOOCMessage( /// Optional color for the announcement message public void DispatchGlobalAnnouncement( string message, - string sender = "Central Command", + string? sender = null, bool playSound = true, SoundSpecifier? announcementSound = null, Color? colorOverride = null ) { + sender ??= Loc.GetString("chat-manager-sender-announcement"); + var wrappedMessage = Loc.GetString("chat-manager-sender-announcement-wrap-message", ("sender", sender), ("message", FormattedMessage.EscapeText(message))); _chatManager.ChatMessageToAll(ChatChannel.Radio, message, wrappedMessage, default, false, true, colorOverride); if (playSound) @@ -355,11 +357,13 @@ public void DispatchGlobalAnnouncement( public void DispatchStationAnnouncement( EntityUid source, string message, - string sender = "Central Command", + string? sender = null, bool playDefaultSound = true, SoundSpecifier? announcementSound = null, Color? colorOverride = null) { + sender ??= Loc.GetString("chat-manager-sender-announcement"); + var wrappedMessage = Loc.GetString("chat-manager-sender-announcement-wrap-message", ("sender", sender), ("message", FormattedMessage.EscapeText(message))); var station = _stationSystem.GetOwningStation(source); diff --git a/Resources/Locale/en-US/chat/managers/chat-manager.ftl b/Resources/Locale/en-US/chat/managers/chat-manager.ftl index 787bb660283..083274da3f9 100644 --- a/Resources/Locale/en-US/chat/managers/chat-manager.ftl +++ b/Resources/Locale/en-US/chat/managers/chat-manager.ftl @@ -19,6 +19,7 @@ chat-manager-no-such-channel = There is no channel with key '{$key}'! chat-manager-whisper-headset-on-message = You can't whisper on the radio! chat-manager-server-wrap-message = [bold]{$message}[/bold] +chat-manager-sender-announcement = Central Command chat-manager-sender-announcement-wrap-message = [font size=14][bold]{$sender} Announcement:[/font][font size=12] {$message}[/bold][/font] chat-manager-entity-say-wrap-message = [BubbleHeader][Name]{$entityName}[/Name][/BubbleHeader] {$verb}, [font={$fontType} size={$fontSize}]"[BubbleContent]{$message}[/BubbleContent]"[/font] From 72a80e7fbf401d58a361202bd0ee18ee4216316f Mon Sep 17 00:00:00 2001 From: Winkarst-cpu <74284083+Winkarst-cpu@users.noreply.github.com> Date: Thu, 11 Jul 2024 17:03:21 +0300 Subject: [PATCH 156/765] Better admin note popups text visibility (#29909) * Better admin note popup text visibility * Bring buttons closer to the border --- .../Administration/UI/Notes/AdminNotesLinePopup.xaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Content.Client/Administration/UI/Notes/AdminNotesLinePopup.xaml b/Content.Client/Administration/UI/Notes/AdminNotesLinePopup.xaml index f978138ca58..4a3c0ef7ace 100644 --- a/Content.Client/Administration/UI/Notes/AdminNotesLinePopup.xaml +++ b/Content.Client/Administration/UI/Notes/AdminNotesLinePopup.xaml @@ -1,10 +1,10 @@ - + - + - + [DataField] [ViewVariables(VVAccess.ReadWrite)] - public float BaseThrowspeed { get; set; } = 10f; + public float BaseThrowspeed { get; set; } = 11f; /// /// Distance after which longer throw targets stop increasing throw impulse. diff --git a/Content.Shared/Throwing/ThrowingSystem.cs b/Content.Shared/Throwing/ThrowingSystem.cs index 56bbf4c2bf3..549473278e4 100644 --- a/Content.Shared/Throwing/ThrowingSystem.cs +++ b/Content.Shared/Throwing/ThrowingSystem.cs @@ -26,11 +26,6 @@ public sealed class ThrowingSystem : EntitySystem public const float PushbackDefault = 2f; - /// - /// The minimum amount of time an entity needs to be thrown before the timer can be run. - /// Anything below this threshold never enters the air. - /// - public const float MinFlyTime = 0.15f; public const float FlyTimePercentage = 0.8f; private float _frictionModifier; @@ -168,9 +163,6 @@ public void TryThrow(EntityUid uid, var flyTime = direction.Length() / baseThrowSpeed; if (compensateFriction) flyTime *= FlyTimePercentage; - - if (flyTime < MinFlyTime) - flyTime = 0f; comp.ThrownTime = _gameTiming.CurTime; comp.LandTime = comp.ThrownTime + TimeSpan.FromSeconds(flyTime); comp.PlayLandSound = playSound; From 36205efbd3098086f404fe50cf4d701526a048dc Mon Sep 17 00:00:00 2001 From: PJBot Date: Fri, 12 Jul 2024 10:33:53 +0000 Subject: [PATCH 171/765] Automatic changelog update --- Resources/Changelog/Changelog.yml | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 90c02169465..5784e248714 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,11 +1,4 @@ Entries: -- author: IProduceWidgets - changes: - - message: New map Oasis. - type: Add - id: 6409 - time: '2024-04-21T05:59:12.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/25736 - author: KittenColony changes: - message: Added a new lizard snout, featuring a split muzzle and snoot that can @@ -3821,3 +3814,14 @@ id: 6908 time: '2024-07-12T09:24:08.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/29900 +- author: coffeeware, slarticodefast + changes: + - message: Fixed items thrown very fast not being in the air. In particular this + fixes the pneumatic cannon. + type: Fix + - message: Buffed base hand throwing speed by 10% to be more similar to before the + recent throwing changes. + type: Tweak + id: 6909 + time: '2024-07-12T10:32:47.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/29935 From f3065fb5e3ee1d83260c6f69362478d8fb3447c1 Mon Sep 17 00:00:00 2001 From: lzk <124214523+lzk228@users.noreply.github.com> Date: Fri, 12 Jul 2024 13:36:40 +0200 Subject: [PATCH 172/765] Fix supplybot movement state (#29944) Fix supplybot movement sprite --- Resources/Prototypes/Entities/Mobs/NPCs/silicon.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/silicon.yml b/Resources/Prototypes/Entities/Mobs/NPCs/silicon.yml index 47378837ef1..77861c6c359 100644 --- a/Resources/Prototypes/Entities/Mobs/NPCs/silicon.yml +++ b/Resources/Prototypes/Entities/Mobs/NPCs/silicon.yml @@ -334,7 +334,8 @@ - type: Sprite sprite: Mobs/Silicon/Bots/supplybot.rsi layers: - - state: supplybot + - map: ["enum.DamageStateVisualLayers.Base", "movement"] + state: supplybot - type: SpriteMovement movementLayers: movement: From b33c8a024c934a68df35b80adaabf18a50047437 Mon Sep 17 00:00:00 2001 From: osjarw <62134478+osjarw@users.noreply.github.com> Date: Fri, 12 Jul 2024 14:37:47 +0300 Subject: [PATCH 173/765] Implement Health Consideration for NPCs (#29922) Implement TargetHealthCon --- .../NPC/Queries/Considerations/TargetHealthCon.cs | 10 ++++++++++ Content.Server/NPC/Systems/NPCUtilitySystem.cs | 12 +++++++++++- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/Content.Server/NPC/Queries/Considerations/TargetHealthCon.cs b/Content.Server/NPC/Queries/Considerations/TargetHealthCon.cs index d4e8a277ea6..cc9c6df83f3 100644 --- a/Content.Server/NPC/Queries/Considerations/TargetHealthCon.cs +++ b/Content.Server/NPC/Queries/Considerations/TargetHealthCon.cs @@ -1,6 +1,16 @@ +using Content.Shared.Mobs; + namespace Content.Server.NPC.Queries.Considerations; +/// +/// Goes linearly from 1f to 0f, with 0 damage returning 1f and damage returning 0f +/// public sealed partial class TargetHealthCon : UtilityConsideration { + /// + /// Which MobState the consideration returns 0f at, defaults to choosing earliest incapacitating MobState + /// + [DataField("targetState")] + public MobState TargetState = MobState.Invalid; } diff --git a/Content.Server/NPC/Systems/NPCUtilitySystem.cs b/Content.Server/NPC/Systems/NPCUtilitySystem.cs index ca74d713357..72833fc35ef 100644 --- a/Content.Server/NPC/Systems/NPCUtilitySystem.cs +++ b/Content.Server/NPC/Systems/NPCUtilitySystem.cs @@ -7,10 +7,13 @@ using Content.Server.Nutrition.Components; using Content.Server.Nutrition.EntitySystems; using Content.Server.Storage.Components; +using Content.Shared.Damage; using Content.Shared.Examine; using Content.Shared.Fluids.Components; using Content.Shared.Hands.Components; using Content.Shared.Inventory; +using Content.Shared.Mobs; +using Content.Shared.Mobs.Components; using Content.Shared.Mobs.Systems; using Content.Shared.NPC.Systems; using Content.Shared.Nutrition.Components; @@ -48,6 +51,7 @@ public sealed class NPCUtilitySystem : EntitySystem [Dependency] private readonly WeldableSystem _weldable = default!; [Dependency] private readonly ExamineSystemShared _examine = default!; [Dependency] private readonly EntityWhitelistSystem _whitelistSystem = default!; + [Dependency] private readonly MobThresholdSystem _thresholdSystem = default!; private EntityQuery _puddleQuery; private EntityQuery _xformQuery; @@ -293,8 +297,14 @@ private float GetScore(NPCBlackboard blackboard, EntityUid targetUid, UtilityCon return (float) ev.Count / ev.Capacity; } - case TargetHealthCon: + case TargetHealthCon con: { + if (!TryComp(targetUid, out DamageableComponent? damage)) + return 0f; + if (con.TargetState != MobState.Invalid && _thresholdSystem.TryGetPercentageForState(targetUid, con.TargetState, damage.TotalDamage, out var percentage)) + return Math.Clamp((float)(1 - percentage), 0f, 1f); + if (_thresholdSystem.TryGetIncapPercentage(targetUid, damage.TotalDamage, out var incapPercentage)) + return Math.Clamp((float)(1 - incapPercentage), 0f, 1f); return 0f; } case TargetInLOSCon: From c7e5c913d85d31be6bcf8ddb6b18f8553c2e2d08 Mon Sep 17 00:00:00 2001 From: themias <89101928+themias@users.noreply.github.com> Date: Fri, 12 Jul 2024 07:38:58 -0400 Subject: [PATCH 174/765] Fix timer deconstruction (#29917) Fix deconstruction for timers --- .../Entities/Structures/Wallmounts/timer.yml | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/Resources/Prototypes/Entities/Structures/Wallmounts/timer.yml b/Resources/Prototypes/Entities/Structures/Wallmounts/timer.yml index adc330171f2..6bb1b9c688d 100644 --- a/Resources/Prototypes/Entities/Structures/Wallmounts/timer.yml +++ b/Resources/Prototypes/Entities/Structures/Wallmounts/timer.yml @@ -44,6 +44,14 @@ - type: Construction graph: Timer node: signal + containers: + - board + - type: ContainerContainer + containers: + board: !type:Container + - type: ContainerFill + containers: + board: [ SignalTimerElectronics ] - type: entity id: ScreenTimer @@ -67,6 +75,11 @@ - type: Construction graph: Timer node: screen + containers: + - board + - type: ContainerFill + containers: + board: [ ScreenTimerElectronics ] - type: entity id: BrigTimer @@ -79,6 +92,11 @@ - type: Construction graph: Timer node: brig + containers: + - board + - type: ContainerFill + containers: + board: [ BrigTimerElectronics ] # Construction Frame From e1556d668439952dcc95f28938b73258d0fc9768 Mon Sep 17 00:00:00 2001 From: PJBot Date: Fri, 12 Jul 2024 11:40:04 +0000 Subject: [PATCH 175/765] Automatic changelog update --- Resources/Changelog/Changelog.yml | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 5784e248714..e51638b71e9 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,12 +1,4 @@ Entries: -- author: KittenColony - changes: - - message: Added a new lizard snout, featuring a split muzzle and snoot that can - be coloured independently - type: Add - id: 6410 - time: '2024-04-21T06:18:33.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/27143 - author: SpeltIncorrectyl changes: - message: Security Officers, Head of Security, and Warden can now choose to start @@ -3825,3 +3817,10 @@ id: 6909 time: '2024-07-12T10:32:47.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/29935 +- author: themias + changes: + - message: Timers can now be deconstructed + type: Fix + id: 6910 + time: '2024-07-12T11:38:59.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/29917 From 88b82ea54de70134fe0ec29bbf2bb0b022f26d17 Mon Sep 17 00:00:00 2001 From: Plykiya <58439124+Plykiya@users.noreply.github.com> Date: Fri, 12 Jul 2024 04:44:45 -0700 Subject: [PATCH 176/765] Updates GasTankSystem and InternalsSystem to not use Component.Owner (#29934) * blah, setup * Updates GasTankSystem and InternalsSystem to not use Component.Owner * squish the diff * Fixa the rest --------- Co-authored-by: plykiya --- .../Atmos/EntitySystems/GasTankSystem.cs | 72 +++++++++++++------ .../Body/Systems/InternalsSystem.cs | 21 +++--- 2 files changed, 60 insertions(+), 33 deletions(-) diff --git a/Content.Server/Atmos/EntitySystems/GasTankSystem.cs b/Content.Server/Atmos/EntitySystems/GasTankSystem.cs index baad739804b..2d703439c0f 100644 --- a/Content.Server/Atmos/EntitySystems/GasTankSystem.cs +++ b/Content.Server/Atmos/EntitySystems/GasTankSystem.cs @@ -81,7 +81,7 @@ public void UpdateUserInterface(Entity ent, bool initialUpdate TankPressure = component.Air?.Pressure ?? 0, OutputPressure = initialUpdate ? component.OutputPressure : null, InternalsConnected = component.IsConnected, - CanConnectInternals = CanConnectToInternals(component) + CanConnectInternals = CanConnectToInternals(ent) }); } @@ -217,24 +217,24 @@ public GasMixture RemoveAirVolume(Entity gasTank, float volume return air; } - public bool CanConnectToInternals(GasTankComponent component) + public bool CanConnectToInternals(Entity ent) { - var internals = GetInternalsComponent(component, component.User); - return internals != null && internals.BreathTools.Count != 0 && !component.IsValveOpen; + TryGetInternalsComp(ent, out _, out var internalsComp, ent.Comp.User); + return internalsComp != null && internalsComp.BreathTools.Count != 0 && !ent.Comp.IsValveOpen; } public void ConnectToInternals(Entity ent) { var (owner, component) = ent; - if (component.IsConnected || !CanConnectToInternals(component)) + if (component.IsConnected || !CanConnectToInternals(ent)) return; - var internals = GetInternalsComponent(component); - if (internals == null) + TryGetInternalsComp(ent, out var internalsUid, out var internalsComp, ent.Comp.User); + if (internalsUid == null || internalsComp == null) return; - if (_internals.TryConnectTank((internals.Owner, internals), owner)) - component.User = internals.Owner; + if (_internals.TryConnectTank((internalsUid.Value, internalsComp), owner)) + component.User = internalsUid.Value; _actions.SetToggled(component.ToggleActionEntity, component.IsConnected); @@ -243,7 +243,7 @@ public void ConnectToInternals(Entity ent) return; component.ConnectStream = _audioSys.Stop(component.ConnectStream); - component.ConnectStream = _audioSys.PlayPvs(component.ConnectSound, component.Owner)?.Entity; + component.ConnectStream = _audioSys.PlayPvs(component.ConnectSound, owner)?.Entity; UpdateUserInterface(ent); } @@ -251,29 +251,59 @@ public void ConnectToInternals(Entity ent) public void DisconnectFromInternals(Entity ent) { var (owner, component) = ent; + if (component.User == null) return; - var internals = GetInternalsComponent(component); + TryGetInternalsComp(ent, out var internalsUid, out var internalsComp, component.User); component.User = null; _actions.SetToggled(component.ToggleActionEntity, false); - _internals.DisconnectTank(internals); + if (internalsUid != null && internalsComp != null) + _internals.DisconnectTank((internalsUid.Value, internalsComp)); component.DisconnectStream = _audioSys.Stop(component.DisconnectStream); - component.DisconnectStream = _audioSys.PlayPvs(component.DisconnectSound, component.Owner)?.Entity; + component.DisconnectStream = _audioSys.PlayPvs(component.DisconnectSound, owner)?.Entity; UpdateUserInterface(ent); } - private InternalsComponent? GetInternalsComponent(GasTankComponent component, EntityUid? owner = null) + /// + /// Tries to retrieve the internals component of either the gas tank's user, + /// or the gas tank's... containing container + /// + /// The user of the gas tank + /// True if internals comp isn't null, false if it is null + private bool TryGetInternalsComp(Entity ent, out EntityUid? internalsUid, out InternalsComponent? internalsComp, EntityUid? user = null) { - owner ??= component.User; - if (Deleted(component.Owner))return null; - if (owner != null) return CompOrNull(owner.Value); - return _containers.TryGetContainingContainer(component.Owner, out var container) - ? CompOrNull(container.Owner) - : null; + internalsUid = default; + internalsComp = default; + + // If the gas tank doesn't exist for whatever reason, don't even bother + if (TerminatingOrDeleted(ent.Owner)) + return false; + + user ??= ent.Comp.User; + // Check if the gas tank's user actually has the component that allows them to use a gas tank and mask + if (TryComp(user, out var userInternalsComp) && userInternalsComp != null) + { + internalsUid = user; + internalsComp = userInternalsComp; + return true; + } + + // Yeah I have no clue what this actually does, I appreciate the lack of comments on the original function + if (_containers.TryGetContainingContainer((ent.Owner, Transform(ent.Owner)), out var container) && container != null) + { + if (TryComp(container.Owner, out var containerInternalsComp) && containerInternalsComp != null) + { + internalsUid = container.Owner; + internalsComp = containerInternalsComp; + return true; + } + } + + return false; } public void AssumeAir(Entity ent, GasMixture giver) @@ -321,7 +351,7 @@ public void CheckStatus(Entity ent) if(environment != null) _atmosphereSystem.Merge(environment, component.Air); - _audioSys.PlayPvs(component.RuptureSound, Transform(component.Owner).Coordinates, AudioParams.Default.WithVariation(0.125f)); + _audioSys.PlayPvs(component.RuptureSound, Transform(owner).Coordinates, AudioParams.Default.WithVariation(0.125f)); QueueDel(owner); return; diff --git a/Content.Server/Body/Systems/InternalsSystem.cs b/Content.Server/Body/Systems/InternalsSystem.cs index d6ece39d590..10ebd934aa4 100644 --- a/Content.Server/Body/Systems/InternalsSystem.cs +++ b/Content.Server/Body/Systems/InternalsSystem.cs @@ -102,7 +102,7 @@ public void ToggleInternals( { if (force) { - DisconnectTank(internals); + DisconnectTank((uid, internals)); return; } @@ -199,16 +199,13 @@ public void ConnectBreathTool(Entity ent, EntityUid toolEnti _alerts.ShowAlert(ent, ent.Comp.InternalsAlert, GetSeverity(ent)); } - public void DisconnectTank(InternalsComponent? component) + public void DisconnectTank(Entity ent) { - if (component is null) - return; - - if (TryComp(component.GasTankEntity, out GasTankComponent? tank)) - _gasTank.DisconnectFromInternals((component.GasTankEntity.Value, tank)); + if (TryComp(ent.Comp.GasTankEntity, out GasTankComponent? tank)) + _gasTank.DisconnectFromInternals((ent.Comp.GasTankEntity.Value, tank)); - component.GasTankEntity = null; - _alerts.ShowAlert(component.Owner, component.InternalsAlert, GetSeverity(component)); + ent.Comp.GasTankEntity = null; + _alerts.ShowAlert(ent.Owner, ent.Comp.InternalsAlert, GetSeverity(ent.Comp)); } public bool TryConnectTank(Entity ent, EntityUid tankEntity) @@ -267,21 +264,21 @@ private short GetSeverity(InternalsComponent component) if (_inventory.TryGetSlotEntity(user, "back", out var backEntity, user.Comp2, user.Comp3) && TryComp(backEntity, out var backGasTank) && - _gasTank.CanConnectToInternals(backGasTank)) + _gasTank.CanConnectToInternals((backEntity.Value, backGasTank))) { return (backEntity.Value, backGasTank); } if (_inventory.TryGetSlotEntity(user, "suitstorage", out var entity, user.Comp2, user.Comp3) && TryComp(entity, out var gasTank) && - _gasTank.CanConnectToInternals(gasTank)) + _gasTank.CanConnectToInternals((entity.Value, gasTank))) { return (entity.Value, gasTank); } foreach (var item in _inventory.GetHandOrInventoryEntities((user.Owner, user.Comp1, user.Comp2))) { - if (TryComp(item, out gasTank) && _gasTank.CanConnectToInternals(gasTank)) + if (TryComp(item, out gasTank) && _gasTank.CanConnectToInternals((item, gasTank))) return (item, gasTank); } From b9e3d154261bc09552b6f053b65117c45564e332 Mon Sep 17 00:00:00 2001 From: Jonathan Argo Date: Fri, 12 Jul 2024 11:00:40 -0400 Subject: [PATCH 177/765] Centered hard hat sprites (#29953) --- .../Clothing/Head/Hardhats/armored.rsi/icon.png | Bin 326 -> 288 bytes .../Head/Hardhats/armored.rsi/light-icon.png | Bin 256 -> 202 bytes .../Clothing/Head/Hardhats/blue.rsi/icon.png | Bin 242 -> 193 bytes .../Head/Hardhats/blue.rsi/light-icon.png | Bin 256 -> 204 bytes .../Head/Hardhats/dark_yellow.rsi/icon.png | Bin 242 -> 193 bytes .../Hardhats/dark_yellow.rsi/light-icon.png | Bin 256 -> 204 bytes .../Clothing/Head/Hardhats/orange.rsi/icon.png | Bin 242 -> 192 bytes .../Head/Hardhats/orange.rsi/light-icon.png | Bin 243 -> 204 bytes .../Clothing/Head/Hardhats/red.rsi/icon.png | Bin 242 -> 192 bytes .../Head/Hardhats/red.rsi/light-icon.png | Bin 256 -> 204 bytes .../Clothing/Head/Hardhats/white.rsi/icon.png | Bin 242 -> 193 bytes .../Head/Hardhats/white.rsi/light-icon.png | Bin 243 -> 204 bytes .../Clothing/Head/Hardhats/yellow.rsi/icon.png | Bin 242 -> 192 bytes .../Head/Hardhats/yellow.rsi/light-icon.png | Bin 256 -> 204 bytes 14 files changed, 0 insertions(+), 0 deletions(-) diff --git a/Resources/Textures/Clothing/Head/Hardhats/armored.rsi/icon.png b/Resources/Textures/Clothing/Head/Hardhats/armored.rsi/icon.png index 7adc2b1385919de3691bf660a7c812275c6f40da..fc2328e7d149e66e43586cab81345675bbee87ef 100644 GIT binary patch delta 247 zcmV%Q6F@FSSK}|sb0I`n?{9y$E000SaNLh0L01m60x&w?%HUJuEjTQbo6co zvf7vKRX8F0Z1-W#xX<=Wd@BBEaXAznQz_<9XkdtC0+CFcn7f|%=KCxO5iH-xyWjl5 zz0iJt^$XYLYcWhPF_bCiaOgQbuZr2Bih0%F1grREuYW9McpB};z{v81Z4b~5|Nk>H YTvV-`eDAP>9gxf5>FVdQ&MBb@0Q3h^A^-pY diff --git a/Resources/Textures/Clothing/Head/Hardhats/blue.rsi/icon.png b/Resources/Textures/Clothing/Head/Hardhats/blue.rsi/icon.png index fee14e7a8cd54b8eb6f24241f36bc1f00dad78cf..f3d81549e3d91dc7e42d2ee67330e0a7566ebec5 100644 GIT binary patch delta 98 zcmV-o0GJ5=02lFA*c0^Lt^BVlBP9JE_Ie% xI3l*>Y0#3(tbJd0=ub)zPGasqq-!q_!u~@|+WmgX7jdA`44$rjF6*2UngBnuI8Xop diff --git a/Resources/Textures/Clothing/Head/Hardhats/blue.rsi/light-icon.png b/Resources/Textures/Clothing/Head/Hardhats/blue.rsi/light-icon.png index 3a850ef0d89953c939f371809f8b31c012e41ea9..f385d0187d3475fbbaa1244ba2ba89f9f7a7b2ab 100644 GIT binary patch delta 176 zcmV;h08jsb0?YxBB!2;OQb$4nuFf3k0001nNkl60x&w?%HUJuEjTQbo6co zvf7vKRX8F0Z1-W#xX<=Wd@BBEaXAznQz_<9XkdtC0+CFcn7f|%=KCxO5iH-xyWjl5 zz0iJt^$XYLYcWhPF_bCiaOgQbuZr2Bih0%F1grREuYW9McpB};z{v81Z4b~5|Nk>H YTvV-`eDAP>9gxf5>FVdQ&MBb@0QJvOBme*a diff --git a/Resources/Textures/Clothing/Head/Hardhats/dark_yellow.rsi/icon.png b/Resources/Textures/Clothing/Head/Hardhats/dark_yellow.rsi/icon.png index 3d3aa75958dcf9f5e581b13ba9b5e6ba5b8a3554..2728bf501bddd75eede1b8e20096a8d394ae189d 100644 GIT binary patch delta 98 zcmV-o0GDmi~u>Vk#cE4ZpMI2}}gQu&X%Q~loCIGw4HxmE= diff --git a/Resources/Textures/Clothing/Head/Hardhats/dark_yellow.rsi/light-icon.png b/Resources/Textures/Clothing/Head/Hardhats/dark_yellow.rsi/light-icon.png index 3a850ef0d89953c939f371809f8b31c012e41ea9..f385d0187d3475fbbaa1244ba2ba89f9f7a7b2ab 100644 GIT binary patch delta 176 zcmV;h08jsb0?YxBB!2;OQb$4nuFf3k0001nNkl60x&w?%HUJuEjTQbo6co zvf7vKRX8F0Z1-W#xX<=Wd@BBEaXAznQz_<9XkdtC0+CFcn7f|%=KCxO5iH-xyWjl5 zz0iJt^$XYLYcWhPF_bCiaOgQbuZr2Bih0%F1grREuYW9McpB};z{v81Z4b~5|Nk>H YTvV-`eDAP>9gxf5>FVdQ&MBb@0QJvOBme*a diff --git a/Resources/Textures/Clothing/Head/Hardhats/orange.rsi/icon.png b/Resources/Textures/Clothing/Head/Hardhats/orange.rsi/icon.png index ba88c23f723c7f37cf76336606234cd3f7fbf881..b4bbfa0e09e99dfd09969b8553c849e0cf91a31b 100644 GIT binary patch delta 97 zcmeywcz|(&;Y3G^a3@a}#}JF&w`UB67!){|4@wyR`+q#?rN*tG8IvOU{uzmvv4FO#s`A BA=Ur@ delta 145 zcmV;C0B--l0rCNmF%1M~K}|sb0I`n?{9y%=E<1S%a7bBm000id000id0mpBsWB>pF zPf0{UR5(xVjKL0oAPhsxgzo?U*pYFt3h`)6c$cNiYvC_!A=yImf$%8k1I5ZskqEQH ztd5ji1vJJ2o0i7yRH8$f5FsWQ1507b4+QrU09+eR<{agB00000NkvXXu0mjf)|oi) diff --git a/Resources/Textures/Clothing/Head/Hardhats/orange.rsi/light-icon.png b/Resources/Textures/Clothing/Head/Hardhats/orange.rsi/light-icon.png index 316cf7a9bccd9d0bf418f16fc955c0afc93e7888..f385d0187d3475fbbaa1244ba2ba89f9f7a7b2ab 100644 GIT binary patch delta 163 zcmV;U09^m`0n7oAF@J_hL_t(oh3(d%4Z|=H1<-$|qOK7Z+ATUtMky(YN`gbPMdv6i zj}$4g)%)Gy0vzzaWa#tLCubvxmhq;q3m||10tj#hz$JY%ZVp@xh=9M-8!g>H#L)fX zwUYNfI|BefGIeVC?xm2m&Y$cIlKBSA9#6Mvb6dtE1(-f00vre+Kx=@aD1Vswd55Cn R3Sj^M002ovPDHLkV1g#GMt}eS delta 202 zcmX@Z_?dBnVLeN_qpu?a!^VE@KZ&di3=EtF9+AZi4BWyX%*Zfnjs#G!!_&nvB*H!U z&;S4ShaH&IG;9+Rt}rgh;8jB)dyiGZ0a=H-$#3QxUicW(<8aKLZQ0_K z?XOSpHP-*%H0A%l+23CNuh-XIAyCO6!t~_9{r&U)|M=?s`v3p?`={SKuI8_!X3ZiY zx%<~liS+u^q!@EnEf+C~+-dz*5UUc{4Gb6FVdQ&MBb@02<9s AivR!s diff --git a/Resources/Textures/Clothing/Head/Hardhats/red.rsi/icon.png b/Resources/Textures/Clothing/Head/Hardhats/red.rsi/icon.png index 011962037d6b4ab8f8612210bb9a50553287e788..5a8fb92ef916f063c6df7be23c9d514812f9adee 100644 GIT binary patch delta 97 zcmeywcz|(&;Y3G^a3@a}#}JF&w`UB67!){|4@wyR`+q#?rN*tG8IvOU{uzmvv4FO#s`A BA=Ur@ delta 145 zcmV;C0B--l0rCNmF%1M~K}|sb0I`n?{9y%=E<1S%a7bBm000id000id0mpBsWB>pF zPf0{UR5(xVjKL0oAPhsxgzo?U*pYFt3h`)6c$cNiYvC_!A=yImf$%8k1I5ZskqEQH ztd5ji1vJJ2o0i7yRH8$f5FsWQ1507b4+QrU09+eR<{agB00000NkvXXu0mjf)|oi) diff --git a/Resources/Textures/Clothing/Head/Hardhats/red.rsi/light-icon.png b/Resources/Textures/Clothing/Head/Hardhats/red.rsi/light-icon.png index 3a850ef0d89953c939f371809f8b31c012e41ea9..f385d0187d3475fbbaa1244ba2ba89f9f7a7b2ab 100644 GIT binary patch delta 176 zcmV;h08jsb0?YxBB!2;OQb$4nuFf3k0001nNkl60x&w?%HUJuEjTQbo6co zvf7vKRX8F0Z1-W#xX<=Wd@BBEaXAznQz_<9XkdtC0+CFcn7f|%=KCxO5iH-xyWjl5 zz0iJt^$XYLYcWhPF_bCiaOgQbuZr2Bih0%F1grREuYW9McpB};z{v81Z4b~5|Nk>H YTvV-`eDAP>9gxf5>FVdQ&MBb@0QJvOBme*a diff --git a/Resources/Textures/Clothing/Head/Hardhats/white.rsi/icon.png b/Resources/Textures/Clothing/Head/Hardhats/white.rsi/icon.png index 2a5093d619ea4aa930175f15f39eb8e2cdea69f4..06af0dcd0aec9f5523f4f8eec947871f33b33df7 100644 GIT binary patch delta 98 zcmV-o0GJ5=02lFA*c0^Lt^BVlBP9JE_Ie% xI3l*>Y0#3(tbJd0=ub)zPGasqq-!q_!u~@|+WmgX7jdA`44$rjF6*2UngBnuI8Xop diff --git a/Resources/Textures/Clothing/Head/Hardhats/white.rsi/light-icon.png b/Resources/Textures/Clothing/Head/Hardhats/white.rsi/light-icon.png index 316cf7a9bccd9d0bf418f16fc955c0afc93e7888..f385d0187d3475fbbaa1244ba2ba89f9f7a7b2ab 100644 GIT binary patch delta 163 zcmV;U09^m`0n7oAF@J_hL_t(oh3(d%4Z|=H1<-$|qOK7Z+ATUtMky(YN`gbPMdv6i zj}$4g)%)Gy0vzzaWa#tLCubvxmhq;q3m||10tj#hz$JY%ZVp@xh=9M-8!g>H#L)fX zwUYNfI|BefGIeVC?xm2m&Y$cIlKBSA9#6Mvb6dtE1(-f00vre+Kx=@aD1Vswd55Cn R3Sj^M002ovPDHLkV1g#GMt}eS delta 202 zcmX@Z_?dBnVLeN_qpu?a!^VE@KZ&di3=EtF9+AZi4BWyX%*Zfnjs#G!!_&nvB*H!U z&;S4ShaH&IG;9+Rt}rgh;8jB)dyiGZ0a=H-$#3QxUicW(<8aKLZQ0_K z?XOSpHP-*%H0A%l+23CNuh-XIAyCO6!t~_9{r&U)|M=?s`v3p?`={SKuI8_!X3ZiY zx%<~liS+u^q!@EnEf+C~+-dz*5UUc{4Gb6FVdQ&MBb@02<9s AivR!s diff --git a/Resources/Textures/Clothing/Head/Hardhats/yellow.rsi/icon.png b/Resources/Textures/Clothing/Head/Hardhats/yellow.rsi/icon.png index 1a3f49cc1b30f6b656b560d44aefbb4d3ecb4300..0978e7886c605a7a31808c54545265e113cd38e6 100644 GIT binary patch delta 97 zcmeywcz|(&;Y3G^a3@a}#}JF&w`UB67!){|4@wyR`+q#?rN*tG8IvOU{uzmvv4FO#s`A BA=Ur@ delta 145 zcmV;C0B--l0rCNmF%1M~K}|sb0I`n?{9y%=E<1S%a7bBm000id000id0mpBsWB>pF zPf0{UR5(xVjKL0oAPhsxgzo?U*pYFt3h`)6c$cNiYvC_!A=yImf$%8k1I5ZskqEQH ztd5ji1vJJ2o0i7yRH8$f5FsWQ1507b4+QrU09+eR<{agB00000NkvXXu0mjf)|oi) diff --git a/Resources/Textures/Clothing/Head/Hardhats/yellow.rsi/light-icon.png b/Resources/Textures/Clothing/Head/Hardhats/yellow.rsi/light-icon.png index 3a850ef0d89953c939f371809f8b31c012e41ea9..f385d0187d3475fbbaa1244ba2ba89f9f7a7b2ab 100644 GIT binary patch delta 176 zcmV;h08jsb0?YxBB!2;OQb$4nuFf3k0001nNkl60x&w?%HUJuEjTQbo6co zvf7vKRX8F0Z1-W#xX<=Wd@BBEaXAznQz_<9XkdtC0+CFcn7f|%=KCxO5iH-xyWjl5 zz0iJt^$XYLYcWhPF_bCiaOgQbuZr2Bih0%F1grREuYW9McpB};z{v81Z4b~5|Nk>H YTvV-`eDAP>9gxf5>FVdQ&MBb@0QJvOBme*a From 795ecc3b30f6bbee75500937e8bf339239082f65 Mon Sep 17 00:00:00 2001 From: PJBot Date: Fri, 12 Jul 2024 15:01:46 +0000 Subject: [PATCH 178/765] Automatic changelog update --- Resources/Changelog/Changelog.yml | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index e51638b71e9..1dfa17c2b06 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,12 +1,4 @@ Entries: -- author: SpeltIncorrectyl - changes: - - message: Security Officers, Head of Security, and Warden can now choose to start - with a security webbing instead of a belt in their loadout menu. - type: Add - id: 6411 - time: '2024-04-21T06:19:20.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/27189 - author: ElectroJr changes: - message: Fixed the nukie station not getting properly initialized. @@ -3824,3 +3816,10 @@ id: 6910 time: '2024-07-12T11:38:59.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/29917 +- author: jonathanargo + changes: + - message: Hard hat icon sprites are now centered correctly. + type: Fix + id: 6911 + time: '2024-07-12T15:00:40.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/29953 From 702a73c32ee8b9393d05a4e52501b176d903d74f Mon Sep 17 00:00:00 2001 From: Plykiya <58439124+Plykiya@users.noreply.github.com> Date: Fri, 12 Jul 2024 20:00:34 -0700 Subject: [PATCH 179/765] Update UtensilSystem.cs to not use Component.Owner (#29971) Update UtensilSystem.cs Co-authored-by: plykiya --- .../Nutrition/EntitySystems/UtensilSystem.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Content.Server/Nutrition/EntitySystems/UtensilSystem.cs b/Content.Server/Nutrition/EntitySystems/UtensilSystem.cs index 43087214a45..d40288183fc 100644 --- a/Content.Server/Nutrition/EntitySystems/UtensilSystem.cs +++ b/Content.Server/Nutrition/EntitySystems/UtensilSystem.cs @@ -31,24 +31,24 @@ public override void Initialize() /// /// Clicked with utensil /// - private void OnAfterInteract(EntityUid uid, UtensilComponent component, AfterInteractEvent ev) + private void OnAfterInteract(Entity entity, ref AfterInteractEvent ev) { if (ev.Handled || ev.Target == null || !ev.CanReach) return; - var result = TryUseUtensil(ev.User, ev.Target.Value, component); + var result = TryUseUtensil(ev.User, ev.Target.Value, entity); ev.Handled = result.Handled; } - public (bool Success, bool Handled) TryUseUtensil(EntityUid user, EntityUid target, UtensilComponent component) + public (bool Success, bool Handled) TryUseUtensil(EntityUid user, EntityUid target, Entity utensil) { if (!EntityManager.TryGetComponent(target, out FoodComponent? food)) return (false, true); //Prevents food usage with a wrong utensil - if ((food.Utensil & component.Types) == 0) + if ((food.Utensil & utensil.Comp.Types) == 0) { - _popupSystem.PopupEntity(Loc.GetString("food-system-wrong-utensil", ("food", target), ("utensil", component.Owner)), user, user); + _popupSystem.PopupEntity(Loc.GetString("food-system-wrong-utensil", ("food", target), ("utensil", utensil.Owner)), user, user); return (false, true); } From 13bfc144aef4af28208b5aca0d5d797cf16b7b1f Mon Sep 17 00:00:00 2001 From: Plykiya <58439124+Plykiya@users.noreply.github.com> Date: Fri, 12 Jul 2024 20:12:46 -0700 Subject: [PATCH 180/765] Update TriggerSystem.TimedCollide.cs to not use Component.Owner (#29970) Update TriggerSystem.TimedCollide.cs Co-authored-by: plykiya --- .../Explosion/EntitySystems/TriggerSystem.TimedCollide.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Content.Server/Explosion/EntitySystems/TriggerSystem.TimedCollide.cs b/Content.Server/Explosion/EntitySystems/TriggerSystem.TimedCollide.cs index 29b81deb32c..ea10b7c69b3 100644 --- a/Content.Server/Explosion/EntitySystems/TriggerSystem.TimedCollide.cs +++ b/Content.Server/Explosion/EntitySystems/TriggerSystem.TimedCollide.cs @@ -1,4 +1,4 @@ -using System.Linq; +using System.Linq; using Content.Server.Explosion.Components; using Content.Server.Explosion.EntitySystems; using Robust.Shared.Physics.Dynamics; @@ -42,14 +42,15 @@ private void OnComponentRemove(EntityUid uid, TriggerOnTimedCollideComponent com private void UpdateTimedCollide(float frameTime) { - foreach (var (activeTrigger, triggerOnTimedCollide) in EntityQuery()) + var query = EntityQueryEnumerator(); + while (query.MoveNext(out var uid, out _, out var triggerOnTimedCollide)) { foreach (var (collidingEntity, collidingTimer) in triggerOnTimedCollide.Colliding) { triggerOnTimedCollide.Colliding[collidingEntity] += frameTime; if (collidingTimer > triggerOnTimedCollide.Threshold) { - RaiseLocalEvent(activeTrigger.Owner, new TriggerEvent(activeTrigger.Owner, collidingEntity), true); + RaiseLocalEvent(uid, new TriggerEvent(uid, collidingEntity), true); triggerOnTimedCollide.Colliding[collidingEntity] -= triggerOnTimedCollide.Threshold; } } From 7b2b2ef7d9557ba764e03d8fc9c7ec073c5045ac Mon Sep 17 00:00:00 2001 From: ShadowCommander <10494922+ShadowCommander@users.noreply.github.com> Date: Fri, 12 Jul 2024 20:43:07 -0700 Subject: [PATCH 181/765] Change whitelist to pass when null (#29981) --- Content.Shared/Storage/EntitySystems/SharedItemMapperSystem.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Content.Shared/Storage/EntitySystems/SharedItemMapperSystem.cs b/Content.Shared/Storage/EntitySystems/SharedItemMapperSystem.cs index cfa082a9eeb..eb20c65a116 100644 --- a/Content.Shared/Storage/EntitySystems/SharedItemMapperSystem.cs +++ b/Content.Shared/Storage/EntitySystems/SharedItemMapperSystem.cs @@ -95,7 +95,8 @@ private bool TryGetLayers(EntityUid uid, var list = new List(); foreach (var mapLayerData in itemMapper.MapLayers.Values) { - var count = containedLayers.Count(ent => _whitelistSystem.IsWhitelistPass(mapLayerData.Whitelist, ent)); + var count = containedLayers.Count(ent => _whitelistSystem.IsWhitelistPassOrNull(mapLayerData.Whitelist, + ent)); if (count >= mapLayerData.MinCount && count <= mapLayerData.MaxCount) { list.Add(mapLayerData.Layer); From 5f0b47e32405f1b0d753c3080596f53cb17a1d98 Mon Sep 17 00:00:00 2001 From: lzk <124214523+lzk228@users.noreply.github.com> Date: Sat, 13 Jul 2024 06:03:16 +0200 Subject: [PATCH 182/765] Use reinforced glass damage modifier for secure windoors (#29941) * Use Rglass damage modifier for reinforced windoors * i actually can remove this line since inherited --- .../Structures/Doors/Windoors/base_structurewindoors.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Resources/Prototypes/Entities/Structures/Doors/Windoors/base_structurewindoors.yml b/Resources/Prototypes/Entities/Structures/Doors/Windoors/base_structurewindoors.yml index 1ec6c04ffe7..d15294cc467 100644 --- a/Resources/Prototypes/Entities/Structures/Doors/Windoors/base_structurewindoors.yml +++ b/Resources/Prototypes/Entities/Structures/Doors/Windoors/base_structurewindoors.yml @@ -172,6 +172,8 @@ - state: panel_open map: [ "enum.WiresVisualLayers.MaintenancePanel" ] visible: false + - type: Damageable + damageModifierSet: RGlass - type: Destructible thresholds: - trigger: @@ -257,7 +259,7 @@ - type: entity id: BaseSecurePlasmaWindoor - parent: BaseWindoor + parent: BaseSecureWindoor abstract: true components: - type: Sprite @@ -367,7 +369,7 @@ - type: entity id: BaseSecureUraniumWindoor - parent: BaseWindoor + parent: BaseSecureWindoor abstract: true components: - type: Sprite From eba6b45684766f8db59f98dac4940c7d091cd53d Mon Sep 17 00:00:00 2001 From: PJBot Date: Sat, 13 Jul 2024 04:04:22 +0000 Subject: [PATCH 183/765] Automatic changelog update --- Resources/Changelog/Changelog.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 1dfa17c2b06..4e0604242e3 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,11 +1,4 @@ Entries: -- author: ElectroJr - changes: - - message: Fixed the nukie station not getting properly initialized. - type: Fix - id: 6412 - time: '2024-04-21T06:52:45.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/27201 - author: Blackern5000 changes: - message: '"Experienced" passengers can now wear a rainbow jumpsuit using loadouts.' @@ -3823,3 +3816,10 @@ id: 6911 time: '2024-07-12T15:00:40.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/29953 +- author: lzk228 + changes: + - message: Secure windoors now use reinforced glass damage modifier. + type: Fix + id: 6912 + time: '2024-07-13T04:03:16.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/29941 From 2759539d9b0551b50a9b62693154a68365f6665b Mon Sep 17 00:00:00 2001 From: ShadowCommander <10494922+ShadowCommander@users.noreply.github.com> Date: Fri, 12 Jul 2024 21:04:53 -0700 Subject: [PATCH 184/765] Add doc comments to target action components (#29982) --- Content.Shared/Actions/EntityTargetActionComponent.cs | 10 ++++++++++ Content.Shared/Actions/WorldTargetActionComponent.cs | 3 +++ 2 files changed, 13 insertions(+) diff --git a/Content.Shared/Actions/EntityTargetActionComponent.cs b/Content.Shared/Actions/EntityTargetActionComponent.cs index 9024f42e0e7..7217794b23b 100644 --- a/Content.Shared/Actions/EntityTargetActionComponent.cs +++ b/Content.Shared/Actions/EntityTargetActionComponent.cs @@ -4,6 +4,9 @@ namespace Content.Shared.Actions; +/// +/// Used on action entities to define an action that triggers when targeting an entity. +/// [RegisterComponent, NetworkedComponent] public sealed partial class EntityTargetActionComponent : BaseTargetActionComponent { @@ -16,8 +19,15 @@ public sealed partial class EntityTargetActionComponent : BaseTargetActionCompon [NonSerialized] public EntityTargetActionEvent? Event; + /// + /// Determines which entities are valid targets for this action. + /// + /// No whitelist check when null. [DataField("whitelist")] public EntityWhitelist? Whitelist; + /// + /// Whether this action considers the user as a valid target entity when using this action. + /// [DataField("canTargetSelf")] public bool CanTargetSelf = true; } diff --git a/Content.Shared/Actions/WorldTargetActionComponent.cs b/Content.Shared/Actions/WorldTargetActionComponent.cs index 4974b4478db..8066a640349 100644 --- a/Content.Shared/Actions/WorldTargetActionComponent.cs +++ b/Content.Shared/Actions/WorldTargetActionComponent.cs @@ -3,6 +3,9 @@ namespace Content.Shared.Actions; +/// +/// Used on action entities to define an action that triggers when targeting an entity coordinate. +/// [RegisterComponent, NetworkedComponent] public sealed partial class WorldTargetActionComponent : BaseTargetActionComponent { From b0829df086c353b74d3fefd3b0a24720e50e74e7 Mon Sep 17 00:00:00 2001 From: Plykiya <58439124+Plykiya@users.noreply.github.com> Date: Fri, 12 Jul 2024 21:05:31 -0700 Subject: [PATCH 185/765] Update ShuttleDockControl.xaml.cs to not use Component.Owner (#29966) Update ShuttleDockControl.xaml.cs Co-authored-by: plykiya --- Content.Client/Shuttles/UI/ShuttleDockControl.xaml.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Content.Client/Shuttles/UI/ShuttleDockControl.xaml.cs b/Content.Client/Shuttles/UI/ShuttleDockControl.xaml.cs index 31f0eecad79..61ae0699266 100644 --- a/Content.Client/Shuttles/UI/ShuttleDockControl.xaml.cs +++ b/Content.Client/Shuttles/UI/ShuttleDockControl.xaml.cs @@ -107,7 +107,7 @@ protected override void Draw(DrawingHandleScreen handle) DrawCircles(handle); var gridNent = EntManager.GetNetEntity(GridEntity); var mapPos = _xformSystem.ToMapCoordinates(_coordinates.Value); - var ourGridMatrix = _xformSystem.GetWorldMatrix(gridXform.Owner); + var ourGridMatrix = _xformSystem.GetWorldMatrix(GridEntity.Value); var dockMatrix = Matrix3Helpers.CreateTransform(_coordinates.Value.Position, Angle.Zero); var worldFromDock = Matrix3x2.Multiply(dockMatrix, ourGridMatrix); From 53b057b8c7d216dde79665d88c3c1c48788a9d6b Mon Sep 17 00:00:00 2001 From: Winkarst <74284083+Winkarst-cpu@users.noreply.github.com> Date: Sat, 13 Jul 2024 07:05:51 +0300 Subject: [PATCH 186/765] Update ActionAlertTooltip.cs to use TryFromMarkup (#29975) --- .../Actions/UI/ActionAlertTooltip.cs | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/Content.Client/Actions/UI/ActionAlertTooltip.cs b/Content.Client/Actions/UI/ActionAlertTooltip.cs index ddc498b6e91..f805f6643d2 100644 --- a/Content.Client/Actions/UI/ActionAlertTooltip.cs +++ b/Content.Client/Actions/UI/ActionAlertTooltip.cs @@ -1,4 +1,4 @@ -using Content.Client.Stylesheets; +using Content.Client.Stylesheets; using Robust.Client.UserInterface.Controls; using Robust.Shared.Timing; using Robust.Shared.Utility; @@ -77,9 +77,12 @@ public ActionAlertTooltip(FormattedMessage name, FormattedMessage? desc, string? MaxWidth = TooltipTextMaxWidth, StyleClasses = {StyleNano.StyleClassTooltipActionRequirements} }; - requiresLabel.SetMessage(FormattedMessage.FromMarkup("[color=#635c5c]" + - requires + - "[/color]")); + + if (!FormattedMessage.TryFromMarkup("[color=#635c5c]" + requires + "[/color]", out var markup)) + return; + + requiresLabel.SetMessage(markup); + vbox.AddChild(requiresLabel); } } @@ -97,8 +100,11 @@ protected override void FrameUpdate(FrameEventArgs args) if (timeLeft > TimeSpan.Zero) { var duration = Cooldown.Value.End - Cooldown.Value.Start; - _cooldownLabel.SetMessage(FormattedMessage.FromMarkup( - $"[color=#a10505]{(int) duration.TotalSeconds} sec cooldown ({(int) timeLeft.TotalSeconds + 1} sec remaining)[/color]")); + + if (!FormattedMessage.TryFromMarkup($"[color=#a10505]{(int) duration.TotalSeconds} sec cooldown ({(int) timeLeft.TotalSeconds + 1} sec remaining)[/color]", out var markup)) + return; + + _cooldownLabel.SetMessage(markup); _cooldownLabel.Visible = true; } else From f52add98e319e9ee0871e44ede849df87bebcdfe Mon Sep 17 00:00:00 2001 From: Plykiya <58439124+Plykiya@users.noreply.github.com> Date: Fri, 12 Jul 2024 21:06:54 -0700 Subject: [PATCH 187/765] Update SmokingSystem.SmokingPipe.cs to not use Component.Owner (#29967) Update SmokingSystem.SmokingPipe.cs Co-authored-by: plykiya --- .../EntitySystems/SmokingSystem.SmokingPipe.cs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Content.Server/Nutrition/EntitySystems/SmokingSystem.SmokingPipe.cs b/Content.Server/Nutrition/EntitySystems/SmokingSystem.SmokingPipe.cs index 3950c73eb43..26d86acd545 100644 --- a/Content.Server/Nutrition/EntitySystems/SmokingSystem.SmokingPipe.cs +++ b/Content.Server/Nutrition/EntitySystems/SmokingSystem.SmokingPipe.cs @@ -42,7 +42,7 @@ private void OnPipeInteractUsingEvent(Entity entity, ref I if (!isHotEvent.IsHot) return; - if (TryTransferReagents(entity.Comp, smokable)) + if (TryTransferReagents(entity, (entity.Owner, smokable))) SetSmokableState(entity, SmokableState.Lit, smokable); args.Handled = true; } @@ -62,7 +62,7 @@ public void OnPipeAfterInteract(Entity entity, ref AfterIn if (!isHotEvent.IsHot) return; - if (TryTransferReagents(entity.Comp, smokable)) + if (TryTransferReagents(entity, (entity.Owner, smokable))) SetSmokableState(entity, SmokableState.Lit, smokable); args.Handled = true; } @@ -74,15 +74,15 @@ private void OnPipeSolutionEmptyEvent(Entity entity, ref S } // Convert smokable item into reagents to be smoked - private bool TryTransferReagents(SmokingPipeComponent component, SmokableComponent smokable) + private bool TryTransferReagents(Entity entity, Entity smokable) { - if (component.BowlSlot.Item == null) + if (entity.Comp.BowlSlot.Item == null) return false; - EntityUid contents = component.BowlSlot.Item.Value; + EntityUid contents = entity.Comp.BowlSlot.Item.Value; if (!TryComp(contents, out var reagents) || - !_solutionContainerSystem.TryGetSolution(smokable.Owner, smokable.Solution, out var pipeSolution, out _)) + !_solutionContainerSystem.TryGetSolution(smokable.Owner, smokable.Comp.Solution, out var pipeSolution, out _)) return false; foreach (var (_, soln) in _solutionContainerSystem.EnumerateSolutions((contents, reagents))) @@ -93,7 +93,7 @@ private bool TryTransferReagents(SmokingPipeComponent component, SmokableCompone EntityManager.DeleteEntity(contents); - _itemSlotsSystem.SetLock(component.Owner, component.BowlSlot, true); //no inserting more until current runs out + _itemSlotsSystem.SetLock(entity.Owner, entity.Comp.BowlSlot, true); //no inserting more until current runs out return true; } From bf813ccc63b2d1cee63f91c8e65a91dce94b7fec Mon Sep 17 00:00:00 2001 From: Tayrtahn Date: Sat, 13 Jul 2024 00:14:30 -0400 Subject: [PATCH 188/765] Fix antag objectives always overshooting MaxDifficulty (and kill tries20) (#29830) * The death of try20 * Add integration test for traitor gamerule * Fix max difficulty being overshot * Check at least one objective is assigned * EntProtoId --- .../Tests/GameRules/TraitorRuleTest.cs | 133 ++++++++++++++++++ .../Antag/AntagRandomObjectivesSystem.cs | 3 +- Content.Server/Objectives/ObjectivesSystem.cs | 28 ++-- .../Systems/SharedObjectivesSystem.cs | 17 ++- .../Random/Helpers/SharedRandomExtensions.cs | 21 +++ 5 files changed, 184 insertions(+), 18 deletions(-) create mode 100644 Content.IntegrationTests/Tests/GameRules/TraitorRuleTest.cs diff --git a/Content.IntegrationTests/Tests/GameRules/TraitorRuleTest.cs b/Content.IntegrationTests/Tests/GameRules/TraitorRuleTest.cs new file mode 100644 index 00000000000..31d33ba6174 --- /dev/null +++ b/Content.IntegrationTests/Tests/GameRules/TraitorRuleTest.cs @@ -0,0 +1,133 @@ +using System.Linq; +using Content.Server.Antag.Components; +using Content.Server.GameTicking; +using Content.Server.GameTicking.Rules; +using Content.Server.GameTicking.Rules.Components; +using Content.Server.Mind; +using Content.Server.Roles; +using Content.Shared.GameTicking; +using Content.Shared.GameTicking.Components; +using Content.Shared.Mind; +using Content.Shared.NPC.Systems; +using Content.Shared.Objectives.Components; +using Robust.Shared.GameObjects; +using Robust.Shared.Prototypes; + +namespace Content.IntegrationTests.Tests.GameRules; + +[TestFixture] +public sealed class TraitorRuleTest +{ + private const string TraitorGameRuleProtoId = "Traitor"; + private const string TraitorAntagRoleName = "Traitor"; + + [Test] + public async Task TestTraitorObjectives() + { + await using var pair = await PoolManager.GetServerClient(new PoolSettings() + { + Dirty = true, + DummyTicker = false, + Connected = true, + InLobby = true, + }); + var server = pair.Server; + var client = pair.Client; + var entMan = server.EntMan; + var protoMan = server.ProtoMan; + var compFact = server.ResolveDependency(); + var ticker = server.System(); + var mindSys = server.System(); + var roleSys = server.System(); + var factionSys = server.System(); + var traitorRuleSys = server.System(); + + // Look up the minimum player count and max total objective difficulty for the game rule + var minPlayers = 1; + var maxDifficulty = 0f; + await server.WaitAssertion(() => + { + Assert.That(protoMan.TryIndex(TraitorGameRuleProtoId, out var gameRuleEnt), + $"Failed to lookup traitor game rule entity prototype with ID \"{TraitorGameRuleProtoId}\"!"); + + Assert.That(gameRuleEnt.TryGetComponent(out var gameRule, compFact), + $"Game rule entity {TraitorGameRuleProtoId} does not have a GameRuleComponent!"); + + Assert.That(gameRuleEnt.TryGetComponent(out var randomObjectives, compFact), + $"Game rule entity {TraitorGameRuleProtoId} does not have an AntagRandomObjectivesComponent!"); + + minPlayers = gameRule.MinPlayers; + maxDifficulty = randomObjectives.MaxDifficulty; + }); + + // Initially in the lobby + Assert.That(ticker.RunLevel, Is.EqualTo(GameRunLevel.PreRoundLobby)); + Assert.That(client.AttachedEntity, Is.Null); + Assert.That(ticker.PlayerGameStatuses[client.User!.Value], Is.EqualTo(PlayerGameStatus.NotReadyToPlay)); + + // Add enough dummy players for the game rule + var dummies = await pair.Server.AddDummySessions(minPlayers); + await pair.RunTicksSync(5); + + // Initially, the players have no attached entities + Assert.That(pair.Player?.AttachedEntity, Is.Null); + Assert.That(dummies.All(x => x.AttachedEntity == null)); + + // Opt-in the player for the traitor role + await pair.SetAntagPreference(TraitorAntagRoleName, true); + + // Add the game rule + var gameRuleEnt = ticker.AddGameRule(TraitorGameRuleProtoId); + Assert.That(entMan.TryGetComponent(gameRuleEnt, out var traitorRule)); + + // Ready up + ticker.ToggleReadyAll(true); + Assert.That(ticker.PlayerGameStatuses.Values.All(x => x == PlayerGameStatus.ReadyToPlay)); + + // Start the round + await server.WaitPost(() => + { + ticker.StartRound(); + // Force traitor mode to start (skip the delay) + ticker.StartGameRule(gameRuleEnt); + }); + await pair.RunTicksSync(10); + + // Game should have started + Assert.That(ticker.RunLevel, Is.EqualTo(GameRunLevel.InRound)); + Assert.That(ticker.PlayerGameStatuses.Values.All(x => x == PlayerGameStatus.JoinedGame)); + Assert.That(client.EntMan.EntityExists(client.AttachedEntity)); + + // Check the player and dummies are spawned + var dummyEnts = dummies.Select(x => x.AttachedEntity ?? default).ToArray(); + var player = pair.Player!.AttachedEntity!.Value; + Assert.That(entMan.EntityExists(player)); + Assert.That(dummyEnts.All(entMan.EntityExists)); + + // Make sure the player is a traitor. + var mind = mindSys.GetMind(player)!.Value; + Assert.That(roleSys.MindIsAntagonist(mind)); + Assert.That(factionSys.IsMember(player, "Syndicate"), Is.True); + Assert.That(factionSys.IsMember(player, "NanoTrasen"), Is.False); + Assert.That(traitorRule.TotalTraitors, Is.EqualTo(1)); + Assert.That(traitorRule.TraitorMinds[0], Is.EqualTo(mind)); + + // Check total objective difficulty + Assert.That(entMan.TryGetComponent(mind, out var mindComp)); + var totalDifficulty = mindComp.Objectives.Sum(o => entMan.GetComponent(o).Difficulty); + Assert.That(totalDifficulty, Is.AtMost(maxDifficulty), + $"MaxDifficulty exceeded! Objectives: {string.Join(", ", mindComp.Objectives.Select(o => FormatObjective(o, entMan)))}"); + Assert.That(mindComp.Objectives, Is.Not.Empty, + $"No objectives assigned!"); + + + await pair.CleanReturnAsync(); + } + + private static string FormatObjective(Entity entity, IEntityManager entMan) + { + var meta = entMan.GetComponent(entity); + var objective = entMan.GetComponent(entity); + return $"{meta.EntityName} ({objective.Difficulty})"; + } +} diff --git a/Content.Server/Antag/AntagRandomObjectivesSystem.cs b/Content.Server/Antag/AntagRandomObjectivesSystem.cs index c935b8c0648..b60759a3d5c 100644 --- a/Content.Server/Antag/AntagRandomObjectivesSystem.cs +++ b/Content.Server/Antag/AntagRandomObjectivesSystem.cs @@ -39,7 +39,8 @@ private void OnAntagSelected(Entity ent, ref Aft for (var pick = 0; pick < set.MaxPicks && ent.Comp.MaxDifficulty > difficulty; pick++) { - if (_objectives.GetRandomObjective(mindId, mind, set.Groups) is not {} objective) + var remainingDifficulty = ent.Comp.MaxDifficulty - difficulty; + if (_objectives.GetRandomObjective(mindId, mind, set.Groups, remainingDifficulty) is not { } objective) continue; _mind.AddObjective(mindId, mind, objective); diff --git a/Content.Server/Objectives/ObjectivesSystem.cs b/Content.Server/Objectives/ObjectivesSystem.cs index f8ecc22828e..9144a6ae57a 100644 --- a/Content.Server/Objectives/ObjectivesSystem.cs +++ b/Content.Server/Objectives/ObjectivesSystem.cs @@ -12,6 +12,7 @@ using Content.Server.GameTicking.Components; using System.Text; using Robust.Server.Player; +using Robust.Shared.Utility; namespace Content.Server.Objectives; @@ -180,33 +181,32 @@ private void AddSummary(StringBuilder result, string agent, List<(EntityUid, str } } - public EntityUid? GetRandomObjective(EntityUid mindId, MindComponent mind, string objectiveGroupProto) + public EntityUid? GetRandomObjective(EntityUid mindId, MindComponent mind, ProtoId objectiveGroupProto, float maxDifficulty) { - if (!_prototypeManager.TryIndex(objectiveGroupProto, out var groups)) + if (!_prototypeManager.TryIndex(objectiveGroupProto, out var groupsProto)) { Log.Error($"Tried to get a random objective, but can't index WeightedRandomPrototype {objectiveGroupProto}"); return null; } - // TODO replace whatever the fuck this is with a proper objective selection system - // yeah the old 'preventing infinite loops' thing wasn't super elegant either and it mislead people on what exactly it did - var tries = 0; - while (tries < 20) - { - var groupName = groups.Pick(_random); + // Make a copy of the weights so we don't trash the prototype by removing entries + var groups = groupsProto.Weights.ShallowClone(); + while (_random.TryPickAndTake(groups, out var groupName)) + { if (!_prototypeManager.TryIndex(groupName, out var group)) { Log.Error($"Couldn't index objective group prototype {groupName}"); return null; } - var proto = group.Pick(_random); - var objective = TryCreateObjective(mindId, mind, proto); - if (objective != null) - return objective; - - tries++; + var objectives = group.Weights.ShallowClone(); + while (_random.TryPickAndTake(objectives, out var objectiveProto)) + { + if (TryCreateObjective((mindId, mind), objectiveProto, out var objective) + && Comp(objective.Value).Difficulty <= maxDifficulty) + return objective; + } } return null; diff --git a/Content.Shared/Objectives/Systems/SharedObjectivesSystem.cs b/Content.Shared/Objectives/Systems/SharedObjectivesSystem.cs index 8d2c4dcfebe..35fa501398f 100644 --- a/Content.Shared/Objectives/Systems/SharedObjectivesSystem.cs +++ b/Content.Shared/Objectives/Systems/SharedObjectivesSystem.cs @@ -1,5 +1,5 @@ +using System.Diagnostics.CodeAnalysis; using Content.Shared.Mind; -using Content.Shared.Objectives; using Content.Shared.Objectives.Components; using Robust.Shared.Prototypes; using Robust.Shared.Utility; @@ -40,7 +40,7 @@ public bool CanBeAssigned(EntityUid uid, EntityUid mindId, MindComponent mind, O if (comp.Unique) { var proto = _metaQuery.GetComponent(uid).EntityPrototype?.ID; - foreach (var objective in mind.AllObjectives) + foreach (var objective in mind.Objectives) { if (_metaQuery.GetComponent(objective).EntityPrototype?.ID == proto) return false; @@ -92,7 +92,18 @@ public bool CanBeAssigned(EntityUid uid, EntityUid mindId, MindComponent mind, O } /// - /// Get the title, description, icon and progress of an objective using . + /// Spawns and assigns an objective for a mind. + /// The objective is not added to the mind's objectives, mind system does that in TryAddObjective. + /// If the objective could not be assigned the objective is deleted and false is returned. + /// + public bool TryCreateObjective(Entity mind, EntProtoId proto, [NotNullWhen(true)] out EntityUid? objective) + { + objective = TryCreateObjective(mind.Owner, mind.Comp, proto); + return objective != null; + } + + /// + /// Get the title, description, icon and progress of an objective using . /// If any of them are null it is logged and null is returned. /// /// ID of the condition entity diff --git a/Content.Shared/Random/Helpers/SharedRandomExtensions.cs b/Content.Shared/Random/Helpers/SharedRandomExtensions.cs index 0b618a262db..376e91743d0 100644 --- a/Content.Shared/Random/Helpers/SharedRandomExtensions.cs +++ b/Content.Shared/Random/Helpers/SharedRandomExtensions.cs @@ -1,3 +1,4 @@ +using System.Diagnostics.CodeAnalysis; using System.Linq; using Content.Shared.Dataset; using Content.Shared.FixedPoint; @@ -87,6 +88,26 @@ public static T Pick(this IRobustRandom random, Dictionary weights) throw new InvalidOperationException("Invalid weighted pick"); } + public static T PickAndTake(this IRobustRandom random, Dictionary weights) + where T : notnull + { + var pick = Pick(random, weights); + weights.Remove(pick); + return pick; + } + + public static bool TryPickAndTake(this IRobustRandom random, Dictionary weights, [NotNullWhen(true)] out T? pick) + where T : notnull + { + if (weights.Count == 0) + { + pick = default; + return false; + } + pick = PickAndTake(random, weights); + return true; + } + public static (string reagent, FixedPoint2 quantity) Pick(this WeightedRandomFillSolutionPrototype prototype, IRobustRandom? random = null) { var randomFill = prototype.PickRandomFill(random); From 69b2a660ff4b2d521f14c3403af8ce5891183b39 Mon Sep 17 00:00:00 2001 From: PJBot Date: Sat, 13 Jul 2024 04:15:36 +0000 Subject: [PATCH 189/765] Automatic changelog update --- Resources/Changelog/Changelog.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 4e0604242e3..eb495bc316d 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,11 +1,4 @@ Entries: -- author: Blackern5000 - changes: - - message: '"Experienced" passengers can now wear a rainbow jumpsuit using loadouts.' - type: Add - id: 6413 - time: '2024-04-21T11:53:08.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/27211 - author: PJB3005 changes: - message: The item status menu has been moved to the side of the hands. There is @@ -3823,3 +3816,10 @@ id: 6912 time: '2024-07-13T04:03:16.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/29941 +- author: Tayrtahn + changes: + - message: Antag objective total difficulty is now properly capped. + type: Fix + id: 6913 + time: '2024-07-13T04:14:30.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/29830 From aa043d43eb15022f2bcd6735ce77792427da8c8b Mon Sep 17 00:00:00 2001 From: deltanedas <39013340+deltanedas@users.noreply.github.com> Date: Sat, 13 Jul 2024 04:17:10 +0000 Subject: [PATCH 190/765] fire extinguisher using item toggle (#29906) * move SprayAttemptEvent to shared * add SolutionTransferredEvent * replace FireExtinguisher with SpraySafety * update fire extinguisher yml * invert visuals * always handle event in solution transfer, it makes popups * instantly fill it * untroll --------- Co-authored-by: deltanedas <@deltanedas:kde.org> --- .../Extinguisher/FireExtinguisherComponent.cs | 7 - .../Extinguisher/FireExtinguisherComponent.cs | 10 -- .../Extinguisher/FireExtinguisherSystem.cs | 139 ------------------ .../Fluids/EntitySystems/SpraySystem.cs | 16 +- .../EntitySystems/SolutionTransferSystem.cs | 16 +- .../SharedFireExtinguisherComponent.cs | 25 ---- .../Fluids/Components/SpraySafetyComponent.cs | 24 +++ Content.Shared/Fluids/Events.cs | 12 ++ Content.Shared/Fluids/SpraySafetySystem.cs | 44 ++++++ .../Objects/Misc/fire_extinguisher.yml | 34 +++-- 10 files changed, 118 insertions(+), 209 deletions(-) delete mode 100644 Content.Client/Extinguisher/FireExtinguisherComponent.cs delete mode 100644 Content.Server/Extinguisher/FireExtinguisherComponent.cs delete mode 100644 Content.Server/Extinguisher/FireExtinguisherSystem.cs delete mode 100644 Content.Shared/Extinguisher/SharedFireExtinguisherComponent.cs create mode 100644 Content.Shared/Fluids/Components/SpraySafetyComponent.cs create mode 100644 Content.Shared/Fluids/SpraySafetySystem.cs diff --git a/Content.Client/Extinguisher/FireExtinguisherComponent.cs b/Content.Client/Extinguisher/FireExtinguisherComponent.cs deleted file mode 100644 index 324b05a93d4..00000000000 --- a/Content.Client/Extinguisher/FireExtinguisherComponent.cs +++ /dev/null @@ -1,7 +0,0 @@ -using Content.Shared.Extinguisher; -using Robust.Shared.GameStates; - -namespace Content.Client.Extinguisher; - -[RegisterComponent] -public sealed partial class FireExtinguisherComponent : SharedFireExtinguisherComponent; diff --git a/Content.Server/Extinguisher/FireExtinguisherComponent.cs b/Content.Server/Extinguisher/FireExtinguisherComponent.cs deleted file mode 100644 index 991fc76c62e..00000000000 --- a/Content.Server/Extinguisher/FireExtinguisherComponent.cs +++ /dev/null @@ -1,10 +0,0 @@ -using Content.Shared.Extinguisher; -using Robust.Shared.GameStates; - -namespace Content.Server.Extinguisher; - -[RegisterComponent] -[Access(typeof(FireExtinguisherSystem))] -public sealed partial class FireExtinguisherComponent : SharedFireExtinguisherComponent -{ -} diff --git a/Content.Server/Extinguisher/FireExtinguisherSystem.cs b/Content.Server/Extinguisher/FireExtinguisherSystem.cs deleted file mode 100644 index b33a1af157f..00000000000 --- a/Content.Server/Extinguisher/FireExtinguisherSystem.cs +++ /dev/null @@ -1,139 +0,0 @@ -using Content.Server.Chemistry.Containers.EntitySystems; -using Content.Server.Fluids.EntitySystems; -using Content.Server.Popups; -using Content.Shared.Chemistry.Components; -using Content.Shared.Extinguisher; -using Content.Shared.FixedPoint; -using Content.Shared.Interaction; -using Content.Shared.Interaction.Events; -using Content.Shared.Verbs; -using Robust.Shared.Audio; -using Robust.Shared.Audio.Systems; - -namespace Content.Server.Extinguisher; - -public sealed class FireExtinguisherSystem : EntitySystem -{ - [Dependency] private readonly SolutionContainerSystem _solutionContainerSystem = default!; - [Dependency] private readonly PopupSystem _popupSystem = default!; - [Dependency] private readonly SharedAppearanceSystem _appearance = default!; - [Dependency] private readonly SharedAudioSystem _audio = default!; - - public override void Initialize() - { - base.Initialize(); - - SubscribeLocalEvent(OnFireExtinguisherInit); - SubscribeLocalEvent(OnUseInHand); - SubscribeLocalEvent(OnAfterInteract); - SubscribeLocalEvent>(OnGetInteractionVerbs); - SubscribeLocalEvent(OnSprayAttempt); - } - - private void OnFireExtinguisherInit(Entity entity, ref ComponentInit args) - { - if (entity.Comp.HasSafety) - { - UpdateAppearance((entity.Owner, entity.Comp)); - } - } - - private void OnUseInHand(Entity entity, ref UseInHandEvent args) - { - if (args.Handled) - return; - - ToggleSafety((entity.Owner, entity.Comp), args.User); - - args.Handled = true; - } - - private void OnAfterInteract(Entity entity, ref AfterInteractEvent args) - { - if (args.Target == null || !args.CanReach) - { - return; - } - - if (args.Handled) - return; - - if (entity.Comp.HasSafety && entity.Comp.Safety) - { - _popupSystem.PopupEntity(Loc.GetString("fire-extinguisher-component-safety-on-message"), entity.Owner, args.User); - return; - } - - if (args.Target is not { Valid: true } target || - !_solutionContainerSystem.TryGetDrainableSolution(target, out var targetSoln, out var targetSolution) || - !_solutionContainerSystem.TryGetRefillableSolution(entity.Owner, out var containerSoln, out var containerSolution)) - { - return; - } - - args.Handled = true; - - // TODO: why is this copy paste shit here just have fire extinguisher cancel transfer when safety is on - var transfer = containerSolution.AvailableVolume; - if (TryComp(entity.Owner, out var solTrans)) - { - transfer = solTrans.TransferAmount; - } - transfer = FixedPoint2.Min(transfer, targetSolution.Volume); - - if (transfer > 0) - { - var drained = _solutionContainerSystem.Drain(target, targetSoln.Value, transfer); - _solutionContainerSystem.TryAddSolution(containerSoln.Value, drained); - - _audio.PlayPvs(entity.Comp.RefillSound, entity.Owner); - _popupSystem.PopupEntity(Loc.GetString("fire-extinguisher-component-after-interact-refilled-message", ("owner", entity.Owner)), - entity.Owner, args.Target.Value); - } - } - - private void OnGetInteractionVerbs(Entity entity, ref GetVerbsEvent args) - { - if (!args.CanAccess || !args.CanInteract) - return; - - var user = args.User; - var verb = new InteractionVerb - { - Act = () => ToggleSafety((entity.Owner, entity.Comp), user), - Text = Loc.GetString("fire-extinguisher-component-verb-text"), - }; - - args.Verbs.Add(verb); - } - - private void OnSprayAttempt(Entity entity, ref SprayAttemptEvent args) - { - if (entity.Comp.HasSafety && entity.Comp.Safety) - { - _popupSystem.PopupEntity(Loc.GetString("fire-extinguisher-component-safety-on-message"), entity, args.User); - args.Cancel(); - } - } - - private void UpdateAppearance(Entity entity) - { - if (!Resolve(entity, ref entity.Comp2, false)) - return; - - if (entity.Comp1.HasSafety) - { - _appearance.SetData(entity, FireExtinguisherVisuals.Safety, entity.Comp1.Safety, entity.Comp2); - } - } - - public void ToggleSafety(Entity extinguisher, EntityUid user) - { - if (!Resolve(extinguisher, ref extinguisher.Comp)) - return; - - extinguisher.Comp.Safety = !extinguisher.Comp.Safety; - _audio.PlayPvs(extinguisher.Comp.SafetySound, extinguisher, AudioParams.Default.WithVariation(0.125f).WithVolume(-4f)); - UpdateAppearance((extinguisher.Owner, extinguisher.Comp)); - } -} diff --git a/Content.Server/Fluids/EntitySystems/SpraySystem.cs b/Content.Server/Fluids/EntitySystems/SpraySystem.cs index 5499070738f..215ed7c33ff 100644 --- a/Content.Server/Fluids/EntitySystems/SpraySystem.cs +++ b/Content.Server/Fluids/EntitySystems/SpraySystem.cs @@ -1,11 +1,11 @@ using Content.Server.Chemistry.Components; using Content.Server.Chemistry.Containers.EntitySystems; using Content.Server.Chemistry.EntitySystems; -using Content.Server.Extinguisher; using Content.Server.Fluids.Components; using Content.Server.Gravity; using Content.Server.Popups; using Content.Shared.FixedPoint; +using Content.Shared.Fluids; using Content.Shared.Interaction; using Content.Shared.Timing; using Content.Shared.Vapor; @@ -34,7 +34,7 @@ public override void Initialize() { base.Initialize(); - SubscribeLocalEvent(OnAfterInteract, after: new[] { typeof(FireExtinguisherSystem) }); + SubscribeLocalEvent(OnAfterInteract); } private void OnAfterInteract(Entity entity, ref AfterInteractEvent args) @@ -48,7 +48,7 @@ private void OnAfterInteract(Entity entity, ref AfterInteractEve return; var ev = new SprayAttemptEvent(args.User); - RaiseLocalEvent(entity, ev); + RaiseLocalEvent(entity, ref ev); if (ev.Cancelled) return; @@ -148,13 +148,3 @@ private void OnAfterInteract(Entity entity, ref AfterInteractEve _useDelay.TryResetDelay((entity, useDelay)); } } - -public sealed class SprayAttemptEvent : CancellableEntityEventArgs -{ - public EntityUid User; - - public SprayAttemptEvent(EntityUid user) - { - User = user; - } -} diff --git a/Content.Shared/Chemistry/EntitySystems/SolutionTransferSystem.cs b/Content.Shared/Chemistry/EntitySystems/SolutionTransferSystem.cs index 3b753925088..e5d8cc5f597 100644 --- a/Content.Shared/Chemistry/EntitySystems/SolutionTransferSystem.cs +++ b/Content.Shared/Chemistry/EntitySystems/SolutionTransferSystem.cs @@ -117,6 +117,7 @@ private void OnAfterInteract(Entity ent, ref AfterInt transferAmount = FixedPoint2.Min(transferAmount, maxRefill); var transferred = Transfer(args.User, target, targetSoln.Value, uid, ownerSoln.Value, transferAmount); + args.Handled = true; if (transferred > 0) { var toTheBrim = ownerRefill.AvailableVolume == 0; @@ -125,8 +126,6 @@ private void OnAfterInteract(Entity ent, ref AfterInt : "comp-solution-transfer-fill-normal"; _popup.PopupClient(Loc.GetString(msg, ("owner", args.Target), ("amount", transferred), ("target", uid)), uid, args.User); - - args.Handled = true; return; } } @@ -143,13 +142,11 @@ private void OnAfterInteract(Entity ent, ref AfterInt transferAmount = FixedPoint2.Min(transferAmount, maxRefill); var transferred = Transfer(args.User, uid, ownerSoln.Value, target, targetSoln.Value, transferAmount); - + args.Handled = true; if (transferred > 0) { var message = Loc.GetString("comp-solution-transfer-transfer-solution", ("amount", transferred), ("target", target)); _popup.PopupClient(message, uid, args.User); - - args.Handled = true; } } } @@ -202,6 +199,9 @@ public FixedPoint2 Transfer(EntityUid user, var solution = _solution.SplitSolution(source, actualAmount); _solution.AddSolution(target, solution); + var ev = new SolutionTransferredEvent(sourceEntity, targetEntity, user, actualAmount); + RaiseLocalEvent(targetEntity, ref ev); + _adminLogger.Add(LogType.Action, LogImpact.Medium, $"{ToPrettyString(user):player} transferred {SharedSolutionContainerSystem.ToPrettyString(solution)} to {ToPrettyString(targetEntity):target}, which now contains {SharedSolutionContainerSystem.ToPrettyString(targetSolution)}"); @@ -225,3 +225,9 @@ public void Cancel(string reason) CancelReason = reason; } } + +/// +/// Raised on the target entity when a non-zero amount of solution gets transferred. +/// +[ByRefEvent] +public record struct SolutionTransferredEvent(EntityUid From, EntityUid To, EntityUid User, FixedPoint2 Amount); diff --git a/Content.Shared/Extinguisher/SharedFireExtinguisherComponent.cs b/Content.Shared/Extinguisher/SharedFireExtinguisherComponent.cs deleted file mode 100644 index dbb1f6f2c4d..00000000000 --- a/Content.Shared/Extinguisher/SharedFireExtinguisherComponent.cs +++ /dev/null @@ -1,25 +0,0 @@ -using Robust.Shared.Audio; -using Robust.Shared.GameStates; -using Robust.Shared.Serialization; - -namespace Content.Shared.Extinguisher; - -[NetworkedComponent] -public abstract partial class SharedFireExtinguisherComponent : Component -{ - [DataField("refillSound")] public SoundSpecifier RefillSound = new SoundPathSpecifier("/Audio/Effects/refill.ogg"); - - [DataField("hasSafety")] public bool HasSafety = true; - - [DataField("safety")] public bool Safety = true; - - [DataField("safetySound")] - public SoundSpecifier SafetySound { get; private set; } = new SoundPathSpecifier("/Audio/Machines/button.ogg"); -} - - -[Serializable, NetSerializable] -public enum FireExtinguisherVisuals : byte -{ - Safety -} diff --git a/Content.Shared/Fluids/Components/SpraySafetyComponent.cs b/Content.Shared/Fluids/Components/SpraySafetyComponent.cs new file mode 100644 index 00000000000..30827d4fd1c --- /dev/null +++ b/Content.Shared/Fluids/Components/SpraySafetyComponent.cs @@ -0,0 +1,24 @@ +using Robust.Shared.Audio; +using Robust.Shared.GameStates; + +namespace Content.Shared.Fluids.Components; + +/// +/// Uses ItemToggle to control safety for a spray item. +/// You can't spray or refill it while safety is on. +/// +[RegisterComponent, NetworkedComponent, Access(typeof(SpraySafetySystem))] +public sealed partial class SpraySafetyComponent : Component +{ + /// + /// Popup shown when trying to spray or refill with safety on. + /// + [DataField] + public LocId Popup = "fire-extinguisher-component-safety-on-message"; + + /// + /// Sound to play after refilling. + /// + [DataField] + public SoundSpecifier RefillSound = new SoundPathSpecifier("/Audio/Effects/refill.ogg"); +} diff --git a/Content.Shared/Fluids/Events.cs b/Content.Shared/Fluids/Events.cs index e281de91377..198e8887742 100644 --- a/Content.Shared/Fluids/Events.cs +++ b/Content.Shared/Fluids/Events.cs @@ -34,3 +34,15 @@ public AbsorbantDoAfterEvent(string targetSolution, string message, SoundSpecifi public override DoAfterEvent Clone() => this; } + +/// +/// Raised when trying to spray something, for example a fire extinguisher. +/// +[ByRefEvent] +public record struct SprayAttemptEvent(EntityUid User, bool Cancelled = false) +{ + public void Cancel() + { + Cancelled = true; + } +} diff --git a/Content.Shared/Fluids/SpraySafetySystem.cs b/Content.Shared/Fluids/SpraySafetySystem.cs new file mode 100644 index 00000000000..82006a995b9 --- /dev/null +++ b/Content.Shared/Fluids/SpraySafetySystem.cs @@ -0,0 +1,44 @@ +using Content.Shared.Chemistry.EntitySystems; +using Content.Shared.Fluids.Components; +using Content.Shared.Item.ItemToggle; +using Content.Shared.Popups; +using Robust.Shared.Audio.Systems; + +namespace Content.Shared.Fluids; + +public sealed class SpraySafetySystem : EntitySystem +{ + [Dependency] private readonly ItemToggleSystem _toggle = default!; + [Dependency] private readonly SharedAudioSystem _audio = default!; + [Dependency] private readonly SharedPopupSystem _popup = default!; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnTransferAttempt); + SubscribeLocalEvent(OnTransferred); + SubscribeLocalEvent(OnSprayAttempt); + } + + private void OnTransferAttempt(Entity ent, ref SolutionTransferAttemptEvent args) + { + var (uid, comp) = ent; + if (uid == args.To && !_toggle.IsActivated(uid)) + args.Cancel(Loc.GetString(comp.Popup)); + } + + private void OnTransferred(Entity ent, ref SolutionTransferredEvent args) + { + _audio.PlayPredicted(ent.Comp.RefillSound, ent, args.User); + } + + private void OnSprayAttempt(Entity ent, ref SprayAttemptEvent args) + { + if (!_toggle.IsActivated(ent.Owner)) + { + _popup.PopupEntity(Loc.GetString(ent.Comp.Popup), ent, args.User); + args.Cancel(); + } + } +} diff --git a/Resources/Prototypes/Entities/Objects/Misc/fire_extinguisher.yml b/Resources/Prototypes/Entities/Objects/Misc/fire_extinguisher.yml index 5aaa58dbbee..89b421c97d4 100644 --- a/Resources/Prototypes/Entities/Objects/Misc/fire_extinguisher.yml +++ b/Resources/Prototypes/Entities/Objects/Misc/fire_extinguisher.yml @@ -7,8 +7,8 @@ - type: Sprite sprite: Objects/Misc/fire_extinguisher.rsi layers: - - state: fire_extinguisher_closed - map: [ "enabled" ] + - state: fire_extinguisher_closed + map: [ "enum.ToggleVisuals.Layer" ] - type: Item sprite: Objects/Misc/fire_extinguisher.rsi size: Normal @@ -24,6 +24,8 @@ - type: DrainableSolution solution: spray - type: SolutionTransfer + maxTransferAmount: 100 + transferAmount: 100 - type: UseDelay - type: Spray transferAmount: 10 @@ -34,8 +36,20 @@ vaporAmount: 3 vaporSpread: 90 sprayVelocity: 2.0 - - type: FireExtinguisher - hasSafety: true + - type: ItemToggle + soundActivate: + path: /Audio/Machines/button.ogg + params: + variation: 0.125 + volume: -4 + soundDeactivate: + path: /Audio/Machines/button.ogg + params: + variation: 0.125 + volume: -4 + - type: ToggleVerb + text: fire-extinguisher-component-verb-text + - type: SpraySafety - type: MeleeWeapon wideAnimationRotation: 180 damage: @@ -46,14 +60,14 @@ - type: Tool qualities: - Rolling - speedModifier: 0.5 # its very big, akward to use + speedModifier: 0.5 # its very big, awkward to use - type: Appearance - type: GenericVisualizer visuals: - enum.FireExtinguisherVisuals.Safety: - enabled: - True: { state: fire_extinguisher_closed } - False: { state: fire_extinguisher_open } + enum.ToggleVisuals.Toggled: + enum.ToggleVisuals.Layer: + True: { state: fire_extinguisher_open } + False: { state: fire_extinguisher_closed } - type: PhysicalComposition materialComposition: Steel: 100 @@ -107,4 +121,4 @@ - type: PhysicalComposition materialComposition: Steel: 50 - Glass: 40 \ No newline at end of file + Glass: 40 From 767be16963fa8d582e899e6d45771fa33d890369 Mon Sep 17 00:00:00 2001 From: Plykiya <58439124+Plykiya@users.noreply.github.com> Date: Fri, 12 Jul 2024 21:20:17 -0700 Subject: [PATCH 191/765] Update SalvageSystem.Magnet to not use Component.Owner (#29961) * Update SalvageSystem.Magnet.cs * Update SalvageSystem.Magnet.cs the right way --------- Co-authored-by: plykiya --- .../Salvage/SalvageSystem.Magnet.cs | 31 ++++++++++++------- 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/Content.Server/Salvage/SalvageSystem.Magnet.cs b/Content.Server/Salvage/SalvageSystem.Magnet.cs index 3fe4baca8b6..5e85fdb573a 100644 --- a/Content.Server/Salvage/SalvageSystem.Magnet.cs +++ b/Content.Server/Salvage/SalvageSystem.Magnet.cs @@ -8,6 +8,7 @@ using Content.Shared.Salvage.Magnet; using Robust.Server.Maps; using Robust.Shared.Map; +using Robust.Shared.Map.Components; namespace Content.Server.Salvage; @@ -253,7 +254,8 @@ private async Task TakeMagnetOffer(Entity data, int var seed = data.Comp.Offered[index]; var offering = GetSalvageOffering(seed); - var salvMap = _mapManager.CreateMap(); + var salvMap = _mapSystem.CreateMap(); + var salvMapXform = Transform(salvMap); // Set values while awaiting asteroid dungeon if relevant so we can't double-take offers. data.Comp.ActiveSeed = seed; @@ -264,8 +266,8 @@ private async Task TakeMagnetOffer(Entity data, int switch (offering) { case AsteroidOffering asteroid: - var grid = _mapManager.CreateGrid(salvMap); - await _dungeon.GenerateDungeonAsync(asteroid.DungeonConfig, grid.Owner, grid, Vector2i.Zero, seed); + var grid = _mapManager.CreateGridEntity(salvMap); + await _dungeon.GenerateDungeonAsync(asteroid.DungeonConfig, grid.Owner, grid.Comp, Vector2i.Zero, seed); break; case SalvageOffering wreck: var salvageProto = wreck.SalvageMap; @@ -275,10 +277,10 @@ private async Task TakeMagnetOffer(Entity data, int Offset = new Vector2(0, 0) }; - if (!_map.TryLoad(salvMap, salvageProto.MapPath.ToString(), out var roots, opts)) + if (!_map.TryLoad(salvMapXform.MapID, salvageProto.MapPath.ToString(), out _, opts)) { Report(magnet, MagnetChannel, "salvage-system-announcement-spawn-debris-disintegrated"); - _mapManager.DeleteMap(salvMap); + _mapManager.DeleteMap(salvMapXform.MapID); return; } @@ -288,15 +290,14 @@ private async Task TakeMagnetOffer(Entity data, int } Box2? bounds = null; - var mapXform = _xformQuery.GetComponent(_mapManager.GetMapEntityId(salvMap)); - if (mapXform.ChildCount == 0) + if (salvMapXform.ChildCount == 0) { Report(magnet.Owner, MagnetChannel, "salvage-system-announcement-spawn-no-debris-available"); return; } - var mapChildren = mapXform.ChildEnumerator; + var mapChildren = salvMapXform.ChildEnumerator; while (mapChildren.MoveNext(out var mapChild)) { @@ -340,19 +341,25 @@ private async Task TakeMagnetOffer(Entity data, int if (!TryGetSalvagePlacementLocation(mapId, attachedBounds, bounds!.Value, worldAngle, out var spawnLocation, out var spawnAngle)) { Report(magnet.Owner, MagnetChannel, "salvage-system-announcement-spawn-no-debris-available"); - _mapManager.DeleteMap(salvMap); + _mapManager.DeleteMap(salvMapXform.MapID); return; } + // I have no idea if we want to return on failure or not + // but I assume trying to set the parent with a null value wouldn't have worked out anyways + if (!_mapSystem.TryGetMap(spawnLocation.MapId, out var spawnUid)) + return; + data.Comp.ActiveEntities = null; - mapChildren = mapXform.ChildEnumerator; + mapChildren = salvMapXform.ChildEnumerator; // It worked, move it into position and cleanup values. while (mapChildren.MoveNext(out var mapChild)) { var salvXForm = _xformQuery.GetComponent(mapChild); var localPos = salvXForm.LocalPosition; - _transform.SetParent(mapChild, salvXForm, _mapManager.GetMapEntityId(spawnLocation.MapId)); + + _transform.SetParent(mapChild, salvXForm, spawnUid.Value); _transform.SetWorldPositionRotation(mapChild, spawnLocation.Position + localPos, spawnAngle, salvXForm); data.Comp.ActiveEntities ??= new List(); @@ -371,7 +378,7 @@ private async Task TakeMagnetOffer(Entity data, int } Report(magnet.Owner, MagnetChannel, "salvage-system-announcement-arrived", ("timeLeft", data.Comp.ActiveTime.TotalSeconds)); - _mapManager.DeleteMap(salvMap); + _mapManager.DeleteMap(salvMapXform.MapID); data.Comp.Announced = false; From cce45366701eeca70d1d5c4799c70dbf2b72ffa5 Mon Sep 17 00:00:00 2001 From: Errant <35878406+Errant-4@users.noreply.github.com> Date: Sat, 13 Jul 2024 08:05:57 +0200 Subject: [PATCH 192/765] Dummy vox deserves a proper vox name (#29789) SKREEEEEeeeeeeee --- Resources/Prototypes/Entities/Mobs/Player/vox.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Resources/Prototypes/Entities/Mobs/Player/vox.yml b/Resources/Prototypes/Entities/Mobs/Player/vox.yml index d88732bafa6..28906584cb9 100644 --- a/Resources/Prototypes/Entities/Mobs/Player/vox.yml +++ b/Resources/Prototypes/Entities/Mobs/Player/vox.yml @@ -1,5 +1,5 @@ - type: entity save: false - name: Urist McVox + name: Uristititi McVox parent: BaseMobVox id: MobVox From a319fca68a7f4bc66d16891a80331c8445849a6e Mon Sep 17 00:00:00 2001 From: Nemanja <98561806+EmoGarbage404@users.noreply.github.com> Date: Sat, 13 Jul 2024 02:09:19 -0400 Subject: [PATCH 193/765] Watches (#29550) * watches * rename * add it into loot pools --- Content.Client/Clock/ClockSystem.cs | 26 +++++ Content.Server/Clock/ClockSystem.cs | 42 ++++++++ Content.Shared/Clock/ClockComponent.cs | 42 ++++++++ .../Clock/GlobalTimeManagerComponent.cs | 16 +++ Content.Shared/Clock/SharedClockSystem.cs | 66 ++++++++++++ Resources/Locale/en-US/devices/clock.ftl | 1 + .../Prototypes/Catalog/Fills/Lockers/misc.yml | 2 + .../Markers/Spawners/Random/maintenance.yml | 2 + .../Entities/Objects/Devices/wristwatch.yml | 59 +++++++++++ .../Devices/goldwatch.rsi/equipped-HAND.png | Bin 0 -> 295 bytes .../Devices/goldwatch.rsi/goldwatch.png | Bin 0 -> 1180 bytes .../Objects/Devices/goldwatch.rsi/hours_0.png | Bin 0 -> 145 bytes .../Objects/Devices/goldwatch.rsi/hours_1.png | Bin 0 -> 148 bytes .../Devices/goldwatch.rsi/hours_10.png | Bin 0 -> 150 bytes .../Devices/goldwatch.rsi/hours_11.png | Bin 0 -> 146 bytes .../Objects/Devices/goldwatch.rsi/hours_2.png | Bin 0 -> 149 bytes .../Objects/Devices/goldwatch.rsi/hours_3.png | Bin 0 -> 143 bytes .../Objects/Devices/goldwatch.rsi/hours_4.png | Bin 0 -> 151 bytes .../Objects/Devices/goldwatch.rsi/hours_5.png | Bin 0 -> 149 bytes .../Objects/Devices/goldwatch.rsi/hours_6.png | Bin 0 -> 145 bytes .../Objects/Devices/goldwatch.rsi/hours_7.png | Bin 0 -> 148 bytes .../Objects/Devices/goldwatch.rsi/hours_8.png | Bin 0 -> 149 bytes .../Objects/Devices/goldwatch.rsi/hours_9.png | Bin 0 -> 142 bytes .../Devices/goldwatch.rsi/inhand-left.png | Bin 0 -> 271 bytes .../Devices/goldwatch.rsi/inhand-right.png | Bin 0 -> 273 bytes .../Objects/Devices/goldwatch.rsi/meta.json | 98 ++++++++++++++++++ .../Devices/goldwatch.rsi/minutes_0.png | Bin 0 -> 144 bytes .../Devices/goldwatch.rsi/minutes_1.png | Bin 0 -> 150 bytes .../Devices/goldwatch.rsi/minutes_10.png | Bin 0 -> 151 bytes .../Devices/goldwatch.rsi/minutes_11.png | Bin 0 -> 150 bytes .../Devices/goldwatch.rsi/minutes_2.png | Bin 0 -> 148 bytes .../Devices/goldwatch.rsi/minutes_3.png | Bin 0 -> 142 bytes .../Devices/goldwatch.rsi/minutes_4.png | Bin 0 -> 148 bytes .../Devices/goldwatch.rsi/minutes_5.png | Bin 0 -> 150 bytes .../Devices/goldwatch.rsi/minutes_6.png | Bin 0 -> 143 bytes .../Devices/goldwatch.rsi/minutes_7.png | Bin 0 -> 149 bytes .../Devices/goldwatch.rsi/minutes_8.png | Bin 0 -> 146 bytes .../Devices/goldwatch.rsi/minutes_9.png | Bin 0 -> 143 bytes .../Devices/wristwatch.rsi/equipped-HAND.png | Bin 0 -> 292 bytes .../Devices/wristwatch.rsi/hours_0.png | Bin 0 -> 151 bytes .../Devices/wristwatch.rsi/hours_1.png | Bin 0 -> 152 bytes .../Devices/wristwatch.rsi/hours_10.png | Bin 0 -> 156 bytes .../Devices/wristwatch.rsi/hours_11.png | Bin 0 -> 153 bytes .../Devices/wristwatch.rsi/hours_2.png | Bin 0 -> 152 bytes .../Devices/wristwatch.rsi/hours_3.png | Bin 0 -> 153 bytes .../Devices/wristwatch.rsi/hours_4.png | Bin 0 -> 155 bytes .../Devices/wristwatch.rsi/hours_5.png | Bin 0 -> 155 bytes .../Devices/wristwatch.rsi/hours_6.png | Bin 0 -> 152 bytes .../Devices/wristwatch.rsi/hours_7.png | Bin 0 -> 153 bytes .../Devices/wristwatch.rsi/hours_8.png | Bin 0 -> 152 bytes .../Devices/wristwatch.rsi/hours_9.png | Bin 0 -> 150 bytes .../Devices/wristwatch.rsi/inhand-left.png | Bin 0 -> 252 bytes .../Devices/wristwatch.rsi/inhand-right.png | Bin 0 -> 254 bytes .../Objects/Devices/wristwatch.rsi/meta.json | 98 ++++++++++++++++++ .../Devices/wristwatch.rsi/minutes_0.png | Bin 0 -> 152 bytes .../Devices/wristwatch.rsi/minutes_1.png | Bin 0 -> 158 bytes .../Devices/wristwatch.rsi/minutes_10.png | Bin 0 -> 159 bytes .../Devices/wristwatch.rsi/minutes_11.png | Bin 0 -> 160 bytes .../Devices/wristwatch.rsi/minutes_2.png | Bin 0 -> 157 bytes .../Devices/wristwatch.rsi/minutes_3.png | Bin 0 -> 151 bytes .../Devices/wristwatch.rsi/minutes_4.png | Bin 0 -> 160 bytes .../Devices/wristwatch.rsi/minutes_5.png | Bin 0 -> 159 bytes .../Devices/wristwatch.rsi/minutes_6.png | Bin 0 -> 153 bytes .../Devices/wristwatch.rsi/minutes_7.png | Bin 0 -> 157 bytes .../Devices/wristwatch.rsi/minutes_8.png | Bin 0 -> 155 bytes .../Devices/wristwatch.rsi/minutes_9.png | Bin 0 -> 150 bytes .../Devices/wristwatch.rsi/wristwatch.png | Bin 0 -> 887 bytes 67 files changed, 452 insertions(+) create mode 100644 Content.Client/Clock/ClockSystem.cs create mode 100644 Content.Server/Clock/ClockSystem.cs create mode 100644 Content.Shared/Clock/ClockComponent.cs create mode 100644 Content.Shared/Clock/GlobalTimeManagerComponent.cs create mode 100644 Content.Shared/Clock/SharedClockSystem.cs create mode 100644 Resources/Locale/en-US/devices/clock.ftl create mode 100644 Resources/Prototypes/Entities/Objects/Devices/wristwatch.yml create mode 100644 Resources/Textures/Objects/Devices/goldwatch.rsi/equipped-HAND.png create mode 100644 Resources/Textures/Objects/Devices/goldwatch.rsi/goldwatch.png create mode 100644 Resources/Textures/Objects/Devices/goldwatch.rsi/hours_0.png create mode 100644 Resources/Textures/Objects/Devices/goldwatch.rsi/hours_1.png create mode 100644 Resources/Textures/Objects/Devices/goldwatch.rsi/hours_10.png create mode 100644 Resources/Textures/Objects/Devices/goldwatch.rsi/hours_11.png create mode 100644 Resources/Textures/Objects/Devices/goldwatch.rsi/hours_2.png create mode 100644 Resources/Textures/Objects/Devices/goldwatch.rsi/hours_3.png create mode 100644 Resources/Textures/Objects/Devices/goldwatch.rsi/hours_4.png create mode 100644 Resources/Textures/Objects/Devices/goldwatch.rsi/hours_5.png create mode 100644 Resources/Textures/Objects/Devices/goldwatch.rsi/hours_6.png create mode 100644 Resources/Textures/Objects/Devices/goldwatch.rsi/hours_7.png create mode 100644 Resources/Textures/Objects/Devices/goldwatch.rsi/hours_8.png create mode 100644 Resources/Textures/Objects/Devices/goldwatch.rsi/hours_9.png create mode 100644 Resources/Textures/Objects/Devices/goldwatch.rsi/inhand-left.png create mode 100644 Resources/Textures/Objects/Devices/goldwatch.rsi/inhand-right.png create mode 100644 Resources/Textures/Objects/Devices/goldwatch.rsi/meta.json create mode 100644 Resources/Textures/Objects/Devices/goldwatch.rsi/minutes_0.png create mode 100644 Resources/Textures/Objects/Devices/goldwatch.rsi/minutes_1.png create mode 100644 Resources/Textures/Objects/Devices/goldwatch.rsi/minutes_10.png create mode 100644 Resources/Textures/Objects/Devices/goldwatch.rsi/minutes_11.png create mode 100644 Resources/Textures/Objects/Devices/goldwatch.rsi/minutes_2.png create mode 100644 Resources/Textures/Objects/Devices/goldwatch.rsi/minutes_3.png create mode 100644 Resources/Textures/Objects/Devices/goldwatch.rsi/minutes_4.png create mode 100644 Resources/Textures/Objects/Devices/goldwatch.rsi/minutes_5.png create mode 100644 Resources/Textures/Objects/Devices/goldwatch.rsi/minutes_6.png create mode 100644 Resources/Textures/Objects/Devices/goldwatch.rsi/minutes_7.png create mode 100644 Resources/Textures/Objects/Devices/goldwatch.rsi/minutes_8.png create mode 100644 Resources/Textures/Objects/Devices/goldwatch.rsi/minutes_9.png create mode 100644 Resources/Textures/Objects/Devices/wristwatch.rsi/equipped-HAND.png create mode 100644 Resources/Textures/Objects/Devices/wristwatch.rsi/hours_0.png create mode 100644 Resources/Textures/Objects/Devices/wristwatch.rsi/hours_1.png create mode 100644 Resources/Textures/Objects/Devices/wristwatch.rsi/hours_10.png create mode 100644 Resources/Textures/Objects/Devices/wristwatch.rsi/hours_11.png create mode 100644 Resources/Textures/Objects/Devices/wristwatch.rsi/hours_2.png create mode 100644 Resources/Textures/Objects/Devices/wristwatch.rsi/hours_3.png create mode 100644 Resources/Textures/Objects/Devices/wristwatch.rsi/hours_4.png create mode 100644 Resources/Textures/Objects/Devices/wristwatch.rsi/hours_5.png create mode 100644 Resources/Textures/Objects/Devices/wristwatch.rsi/hours_6.png create mode 100644 Resources/Textures/Objects/Devices/wristwatch.rsi/hours_7.png create mode 100644 Resources/Textures/Objects/Devices/wristwatch.rsi/hours_8.png create mode 100644 Resources/Textures/Objects/Devices/wristwatch.rsi/hours_9.png create mode 100644 Resources/Textures/Objects/Devices/wristwatch.rsi/inhand-left.png create mode 100644 Resources/Textures/Objects/Devices/wristwatch.rsi/inhand-right.png create mode 100644 Resources/Textures/Objects/Devices/wristwatch.rsi/meta.json create mode 100644 Resources/Textures/Objects/Devices/wristwatch.rsi/minutes_0.png create mode 100644 Resources/Textures/Objects/Devices/wristwatch.rsi/minutes_1.png create mode 100644 Resources/Textures/Objects/Devices/wristwatch.rsi/minutes_10.png create mode 100644 Resources/Textures/Objects/Devices/wristwatch.rsi/minutes_11.png create mode 100644 Resources/Textures/Objects/Devices/wristwatch.rsi/minutes_2.png create mode 100644 Resources/Textures/Objects/Devices/wristwatch.rsi/minutes_3.png create mode 100644 Resources/Textures/Objects/Devices/wristwatch.rsi/minutes_4.png create mode 100644 Resources/Textures/Objects/Devices/wristwatch.rsi/minutes_5.png create mode 100644 Resources/Textures/Objects/Devices/wristwatch.rsi/minutes_6.png create mode 100644 Resources/Textures/Objects/Devices/wristwatch.rsi/minutes_7.png create mode 100644 Resources/Textures/Objects/Devices/wristwatch.rsi/minutes_8.png create mode 100644 Resources/Textures/Objects/Devices/wristwatch.rsi/minutes_9.png create mode 100644 Resources/Textures/Objects/Devices/wristwatch.rsi/wristwatch.png diff --git a/Content.Client/Clock/ClockSystem.cs b/Content.Client/Clock/ClockSystem.cs new file mode 100644 index 00000000000..7097ada9df6 --- /dev/null +++ b/Content.Client/Clock/ClockSystem.cs @@ -0,0 +1,26 @@ +using Content.Shared.Clock; +using Robust.Client.GameObjects; + +namespace Content.Client.Clock; + +public sealed class ClockSystem : SharedClockSystem +{ + public override void Update(float frameTime) + { + base.Update(frameTime); + + var query = EntityQueryEnumerator(); + while (query.MoveNext(out var uid, out var comp, out var sprite)) + { + if (!sprite.LayerMapTryGet(ClockVisualLayers.HourHand, out var hourLayer) || + !sprite.LayerMapTryGet(ClockVisualLayers.MinuteHand, out var minuteLayer)) + continue; + + var time = GetClockTime((uid, comp)); + var hourState = $"{comp.HoursBase}{time.Hours % 12}"; + var minuteState = $"{comp.MinutesBase}{time.Minutes / 5}"; + sprite.LayerSetState(hourLayer, hourState); + sprite.LayerSetState(minuteLayer, minuteState); + } + } +} diff --git a/Content.Server/Clock/ClockSystem.cs b/Content.Server/Clock/ClockSystem.cs new file mode 100644 index 00000000000..29400a59f7b --- /dev/null +++ b/Content.Server/Clock/ClockSystem.cs @@ -0,0 +1,42 @@ +using Content.Server.GameTicking.Events; +using Content.Shared.Clock; +using Content.Shared.Destructible; +using Robust.Server.GameStates; +using Robust.Shared.Random; + +namespace Content.Server.Clock; + +public sealed class ClockSystem : SharedClockSystem +{ + [Dependency] private readonly PvsOverrideSystem _pvsOverride = default!; + [Dependency] private readonly IRobustRandom _robustRandom = default!; + + /// + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnRoundStart); + SubscribeLocalEvent(OnMapInit); + SubscribeLocalEvent(OnBreak); + } + + private void OnRoundStart(RoundStartingEvent ev) + { + var manager = Spawn(); + AddComp(manager); + } + + private void OnMapInit(Entity ent, ref MapInitEvent args) + { + ent.Comp.TimeOffset = TimeSpan.FromHours(_robustRandom.NextFloat(0, 24)); + _pvsOverride.AddGlobalOverride(ent); + Dirty(ent); + } + + private void OnBreak(Entity ent, ref BreakageEventArgs args) + { + ent.Comp.StuckTime = GetClockTime(ent); + Dirty(ent, ent.Comp); + } +} diff --git a/Content.Shared/Clock/ClockComponent.cs b/Content.Shared/Clock/ClockComponent.cs new file mode 100644 index 00000000000..3a1027d8136 --- /dev/null +++ b/Content.Shared/Clock/ClockComponent.cs @@ -0,0 +1,42 @@ +using Robust.Shared.GameStates; +using Robust.Shared.Serialization; + +namespace Content.Shared.Clock; + +[RegisterComponent, NetworkedComponent] +[Access(typeof(SharedClockSystem))] +[AutoGenerateComponentState] +public sealed partial class ClockComponent : Component +{ + /// + /// If not null, this time will be permanently shown. + /// + [DataField, AutoNetworkedField] + public TimeSpan? StuckTime; + + /// + /// The format in which time is displayed. + /// + [DataField, AutoNetworkedField] + public ClockType ClockType = ClockType.TwelveHour; + + [DataField] + public string HoursBase = "hours_"; + + [DataField] + public string MinutesBase = "minutes_"; +} + +[Serializable, NetSerializable] +public enum ClockType : byte +{ + TwelveHour, + TwentyFourHour +} + +[Serializable, NetSerializable] +public enum ClockVisualLayers : byte +{ + HourHand, + MinuteHand +} diff --git a/Content.Shared/Clock/GlobalTimeManagerComponent.cs b/Content.Shared/Clock/GlobalTimeManagerComponent.cs new file mode 100644 index 00000000000..764b578b250 --- /dev/null +++ b/Content.Shared/Clock/GlobalTimeManagerComponent.cs @@ -0,0 +1,16 @@ +using Robust.Shared.GameStates; + +namespace Content.Shared.Clock; + +/// +/// This is used for globally managing the time on-station +/// +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState, AutoGenerateComponentPause, Access(typeof(SharedClockSystem))] +public sealed partial class GlobalTimeManagerComponent : Component +{ + /// + /// A fixed random offset, used to fuzz the time between shifts. + /// + [DataField, AutoPausedField, AutoNetworkedField] + public TimeSpan TimeOffset; +} diff --git a/Content.Shared/Clock/SharedClockSystem.cs b/Content.Shared/Clock/SharedClockSystem.cs new file mode 100644 index 00000000000..0a7c1b01b2c --- /dev/null +++ b/Content.Shared/Clock/SharedClockSystem.cs @@ -0,0 +1,66 @@ +using System.Linq; +using Content.Shared.Examine; +using Content.Shared.GameTicking; + +namespace Content.Shared.Clock; + +public abstract class SharedClockSystem : EntitySystem +{ + [Dependency] private readonly SharedGameTicker _ticker = default!; + + /// + public override void Initialize() + { + SubscribeLocalEvent(OnExamined); + } + + private void OnExamined(Entity ent, ref ExaminedEvent args) + { + if (!args.IsInDetailsRange) + return; + + args.PushMarkup(Loc.GetString("clock-examine", ("time", GetClockTimeText(ent)))); + } + + public string GetClockTimeText(Entity ent) + { + var time = GetClockTime(ent); + switch (ent.Comp.ClockType) + { + case ClockType.TwelveHour: + return time.ToString(@"h\:mm"); + case ClockType.TwentyFourHour: + return time.ToString(@"hh\:mm"); + default: + throw new ArgumentOutOfRangeException(); + } + } + + private TimeSpan GetGlobalTime() + { + return (EntityQuery().FirstOrDefault()?.TimeOffset ?? TimeSpan.Zero) + _ticker.RoundDuration(); + } + + public TimeSpan GetClockTime(Entity ent) + { + var comp = ent.Comp; + + if (comp.StuckTime != null) + return comp.StuckTime.Value; + + var time = GetGlobalTime(); + + switch (comp.ClockType) + { + case ClockType.TwelveHour: + var adjustedHours = time.Hours % 12; + if (adjustedHours == 0) + adjustedHours = 12; + return new TimeSpan(adjustedHours, time.Minutes, time.Seconds); + case ClockType.TwentyFourHour: + return time; + default: + throw new ArgumentOutOfRangeException(); + } + } +} diff --git a/Resources/Locale/en-US/devices/clock.ftl b/Resources/Locale/en-US/devices/clock.ftl new file mode 100644 index 00000000000..6d0aef1eb76 --- /dev/null +++ b/Resources/Locale/en-US/devices/clock.ftl @@ -0,0 +1 @@ +clock-examine = The time reads: [color=white]{$time}[/color] diff --git a/Resources/Prototypes/Catalog/Fills/Lockers/misc.yml b/Resources/Prototypes/Catalog/Fills/Lockers/misc.yml index fac36ba710c..b49fa383bce 100644 --- a/Resources/Prototypes/Catalog/Fills/Lockers/misc.yml +++ b/Resources/Prototypes/Catalog/Fills/Lockers/misc.yml @@ -170,6 +170,8 @@ prob: 0.20 - id: BarberScissors prob: 0.05 + - id: Wristwatch + prob: 0.05 - id: BookRandomStory prob: 0.1 # Syndicate loot diff --git a/Resources/Prototypes/Entities/Markers/Spawners/Random/maintenance.yml b/Resources/Prototypes/Entities/Markers/Spawners/Random/maintenance.yml index 4c820998ea2..014b525fc1a 100644 --- a/Resources/Prototypes/Entities/Markers/Spawners/Random/maintenance.yml +++ b/Resources/Prototypes/Entities/Markers/Spawners/Random/maintenance.yml @@ -68,6 +68,7 @@ - ClothingHeadHatCowboyBountyHunter - ClothingNeckAutismPin - ClothingNeckGoldAutismPin + - WristwatchGold rareChance: 0.01 prototypes: - Lighter @@ -129,6 +130,7 @@ - ClothingShoesTourist - ClothingUniformJumpsuitLoungewear - ClothingHeadHatCowboyRed + - Wristwatch chance: 0.6 offset: 0.0 diff --git a/Resources/Prototypes/Entities/Objects/Devices/wristwatch.yml b/Resources/Prototypes/Entities/Objects/Devices/wristwatch.yml new file mode 100644 index 00000000000..7fbb4aecf61 --- /dev/null +++ b/Resources/Prototypes/Entities/Objects/Devices/wristwatch.yml @@ -0,0 +1,59 @@ +- type: entity + id: Wristwatch + parent: BaseItem + name: wristwatch + description: A cheap watch for telling time. How much did you waste playing Space Station 14? + components: + - type: Sprite + sprite: Objects/Devices/wristwatch.rsi + layers: + - state: wristwatch + - map: [ "enum.ClockVisualLayers.MinuteHand"] + - map: [ "enum.ClockVisualLayers.HourHand"] + - type: Clock + - type: Item + sprite: Objects/Devices/wristwatch.rsi + size: Small + - type: Clothing + sprite: Objects/Devices/wristwatch.rsi + slots: + - gloves + - type: Appearance + - type: Damageable + damageContainer: Inorganic + - type: StaticPrice + price: 50 + - type: Destructible + thresholds: + - trigger: + !type:DamageTrigger + damage: 100 + behaviors: + - !type:DoActsBehavior + acts: [ "Destruction" ] + - trigger: + !type:DamageGroupTrigger + damageGroup: Brute + damage: 25 + behaviors: + - !type:DoActsBehavior + acts: [ "Breakage" ] + +- type: entity + id: WristwatchGold + parent: Wristwatch + name: gold watch + description: A fancy watch worth more than your kidney. It was owned by the notorious Syndicate mobster Vunibaldo "200 Pound Horse Meat Grinder" Frediani. + components: + - type: Sprite + sprite: Objects/Devices/goldwatch.rsi + layers: + - state: goldwatch + - map: [ "enum.ClockVisualLayers.MinuteHand"] + - map: [ "enum.ClockVisualLayers.HourHand"] + - type: Item + sprite: Objects/Devices/goldwatch.rsi + - type: Clothing + sprite: Objects/Devices/goldwatch.rsi + - type: StaticPrice + price: 500 #if you ever increase the price of kidneys, increase this too. diff --git a/Resources/Textures/Objects/Devices/goldwatch.rsi/equipped-HAND.png b/Resources/Textures/Objects/Devices/goldwatch.rsi/equipped-HAND.png new file mode 100644 index 0000000000000000000000000000000000000000..59522f6c12e86f2b7a6364c89a0d9a25bb3e8fef GIT binary patch literal 295 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=oCO|{#S9F5M?jcysy3fAQ1GUw zi(^Q|oVT|O`4|I5+#V_iZsP7_4OlsqYcB7K(y)cWw;S@fmPVP1DQx8aB^dakWoE{+ zKk1C-?`u!4zV}v1pWy^I!zZSOJq!v+%=h{Xx4&+g)l>b2-MDRW>hgDUPFIHCUB~YC zbnew>5!L6G|6}@Kmvb@0Pk2xMX<>&rh6&;fPgof$8Syf=GA+1se)V&`L&eh*_Gr}o t3d(0a@cPo%GQlXu3rkS!2RfyiLA^yGryYJmM^L^(#=bn3K5&dQS7w~ThxPPf3CF6+Up_QedvgYyZ#HELMe?$PtS8Y2? zljE;xbl?T;Y;UK@@I4xhk5E}%1NA+4$M0P^y*(9=#^~~`K}SLy3FtVxE)`9h6uo_g zKF^k_CmxD)by2>{;Q2_J9K@}`5;dw)LaI_u+{h`wid;q8_i{={u3SLG{t`Fa4k5## z8QQ#Ujv`SH`TP-bO?&CozM51nCu{|P9QHDyB5&HU+9J=)KgfOlDoP{_788%IOwS~9 z#h2Rw$t?&o#}awI%j9PgHJ)RfNEA_ZU@_N(T`J}kfV|_!U^#%u%QEIMPJ|;IZFRt) zr#(o)7@PsSi>AV}qlG2#EQb z0$rF35}?V?S;WYFam^Mgtyn>!-kTI?K0t3rh$aS~P*Z(^-$5~Al>k^JND=P!iunl# z1c*A&tclldXr_>Qw%8qKaxG-YasxmiB4VF^PSsx#3yDV;ARse(L=JLq`Envf27uIE z;8s^33xO+ry>OyJ&5o$3bzhJaL=1@X*!F~Z9f0kK9ONZS-TVwrG6D;1UiD|%J!upZID_PNGp5Of2y$5+NY&($!mJ+^a_J3@1suQlCa;4i)!4F?n+(>uG@#(#BQ(%`oxI9+ zSskz*tvcM(nNjUA-VZe7>aYgB1)2=jIc!GM0CFx%R1PHo$aNE{%GrKx1&9l1uYhhc zx+Xx3sF8Enj>rMo839}&LXhip^g{<&gxU?Yr6c@oY5EF;d&nXdQk)5pd)bbGpWY2c z1P&xZg1-Lfd6J`(adkkaMaXs0dH7u5qyTLN2;@A_tCTlncbivZne%7J(~1eJ{y6mffknI@wr8A+3=s0Wg|ABlL zF|hz7h#Ixx^OH(TjGaMxoRB*b07yNQ`6~FH52*EMK84m8SJVeYIQ>uHSOB2Y(U5k+ ur2YZJ+GhI)hS(k4FNAzS0z?G;W_$tEs%t8vJoi2T0000mdKI;Vst0Pf`}!2kdN literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Devices/goldwatch.rsi/hours_11.png b/Resources/Textures/Objects/Devices/goldwatch.rsi/hours_11.png new file mode 100644 index 0000000000000000000000000000000000000000..e364438e4ecd35612f8d36bd0210b081e8e5aee1 GIT binary patch literal 146 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz&H|6fVg?4jBOuH;Rhv&5DCpwp z;uumf=k3LdoD2pW%on-JTHe_&Q2vov$iaE&E>op|{Ue|%AZU=!YC-eXS literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Devices/goldwatch.rsi/hours_2.png b/Resources/Textures/Objects/Devices/goldwatch.rsi/hours_2.png new file mode 100644 index 0000000000000000000000000000000000000000..87c642239fe1370c4a14745d559d81fdb8716ed6 GIT binary patch literal 149 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz&H|6fVg?4jBOuH;Rhv&5DCq9# z;uumf=k2+TybKCF%#KP2Io{YSC+ ihVTfs9qbT^EzEK^4LRmc+hjH!B;e`l=d#Wzp$P!(2__T( literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Devices/goldwatch.rsi/hours_3.png b/Resources/Textures/Objects/Devices/goldwatch.rsi/hours_3.png new file mode 100644 index 0000000000000000000000000000000000000000..107b210ff4f3c9e0d121ec590091b896ba2918bd GIT binary patch literal 143 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz&H|6fVg?4jBOuH;Rhv&5DCp?v z;uumf=k2+Tf(!y8E{S@5QFulkC`m%0QriXU5|5dy8{_S}HvH e!X+RJ7CgX|&A~F4?KMLLi0kR<=d#Wzp$PzNDkZr9 literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Devices/goldwatch.rsi/hours_4.png b/Resources/Textures/Objects/Devices/goldwatch.rsi/hours_4.png new file mode 100644 index 0000000000000000000000000000000000000000..c03f799fcce9cb94ff51072e22083ab1511e0e34 GIT binary patch literal 151 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz&H|6fVg?4jBOuH;Rhv&5DCp_w z;uumf=k3LfoD2#)E`iL2EZ^k~lp|b%b~Lc?J&Z3-l@phL1XKtCf7nmRM&=gJWGUbm jU&8$H57SMiyNqBdc6T$5ojc=SOMrNuu6{1-oD!M<`(-7z literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Devices/goldwatch.rsi/hours_5.png b/Resources/Textures/Objects/Devices/goldwatch.rsi/hours_5.png new file mode 100644 index 0000000000000000000000000000000000000000..2835fadd249d0a84532950f44f547515a74f29d6 GIT binary patch literal 149 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz&H|6fVg?4jBOuH;Rhv&5DCq9# z;uumf=k3LdoIusC7g?ki{$(#|vFmZukn<>c&vJbE_D4Wv5O9zANzWF$H9QO6No-gj izOG>Ff&2PknNn`^0~|XKYR3KtaXnrAT-G@yGywp`$15cO literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Devices/goldwatch.rsi/hours_6.png b/Resources/Textures/Objects/Devices/goldwatch.rsi/hours_6.png new file mode 100644 index 0000000000000000000000000000000000000000..55df41a9ce9fa78ca7b747f8b4a7369bde2092ca GIT binary patch literal 145 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz&H|6fVg?4jBOuH;Rhv&5DCq3z z;uumf=k0}qoD2pWM=x-_<+xjapzp!Ka|#;riZdTf+&L6GPPMtR?7EOWm%Ouh`_db;|#taD0e0swhmDyIMd literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Devices/goldwatch.rsi/hours_7.png b/Resources/Textures/Objects/Devices/goldwatch.rsi/hours_7.png new file mode 100644 index 0000000000000000000000000000000000000000..890650474dfcf2593d48c0df4977ffc49a687cfb GIT binary patch literal 148 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz&H|6fVg?4jBOuH;Rhv&5DCp+t z;uumf=k0k%UIqmLW=B0n&L83(EOPCwb+g)1t~)F*Zea#01A`yz7rvLQjWul0=6q14 i&m8mE=zt_h;s_)E*YzB8*#ms5B literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Devices/goldwatch.rsi/inhand-left.png b/Resources/Textures/Objects/Devices/goldwatch.rsi/inhand-left.png new file mode 100644 index 0000000000000000000000000000000000000000..ec40991d4ecf42b62c9e4bfa358a24a938dface4 GIT binary patch literal 271 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=oCO|{#S9F5M?jcysy3fAQ1GCq zi(^Q|oVPdkaxyuJFgz6G*~)#8$;8NP3s17~YJ<%}+#Ag6t8Q3Zq^aE~kgw61y~p$u zlS3TC32uf;Mg@I_C#(&77$%4_fCZKHtM8qkfBW&?Bu8FW3t4lWwF?<;-+fxXFCxg9 z@mu@rMf3jew{t|%g4LYh7^~~EYL3kDWOx=exqpT+=Yg2)PlCm2j5D%*?UMZFE5Myl a)u10&EMok2KPwB+GYp=telF{r5}E*wty!l4 literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Devices/goldwatch.rsi/inhand-right.png b/Resources/Textures/Objects/Devices/goldwatch.rsi/inhand-right.png new file mode 100644 index 0000000000000000000000000000000000000000..aac69417e32f8656e2f87d013ae5b462f43879e4 GIT binary patch literal 273 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=oCO|{#S9F5M?jcysy3fAQ1Gy) zi(^Q|oVPc3^B!^#V7Tb0)S@>*gFz|D>6C)nVlE@Cg$z}XgPT%sHm0lXII(N$yfxls zy?YoYh%R{O_Nif2&v@5zx%wcbwNdTi`%h`Omrf z)2=8q{C&7<#r^;B{R-H$qL|mPQT)tSqxo6qG8%SK(L`hB}_edZJv0j59y g&3%q>5@G#$kEboFyt=akR{01#^=T>t<8 literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Devices/goldwatch.rsi/minutes_1.png b/Resources/Textures/Objects/Devices/goldwatch.rsi/minutes_1.png new file mode 100644 index 0000000000000000000000000000000000000000..0ef2c831f4d7d9a213a9a7a9c20360607b94a848 GIT binary patch literal 150 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz&H|6fVg?4jBOuH;Rhv&5DCpto z;uumf=k0k%UIqmo7ROl)EPuFNoa9}d^{0Q?ygH$5{X?KC5a0~>sdcW`uwk>=fl7VG kJ6jpgRdYVzgUCs+*L?lWG50GM{~3^gr>mdKI;Vst0C#vP6951J literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Devices/goldwatch.rsi/minutes_10.png b/Resources/Textures/Objects/Devices/goldwatch.rsi/minutes_10.png new file mode 100644 index 0000000000000000000000000000000000000000..3019a20a9ba454202f8ed338bcdfaafcc25aed05 GIT binary patch literal 151 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz&H|6fVg?4jBOuH;Rhv&5DCp_w z;uumf=k3Lfyg=11fu1ES-{mI=Y8Z%ZJL0zf=k=JAr!UU704fB52B8TLciui`!udd^ lj&o;KV@{(yBShv&18c-Yj-3}@i&TIFJYD@<);T3K0RSQ!D?R`K literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Devices/goldwatch.rsi/minutes_11.png b/Resources/Textures/Objects/Devices/goldwatch.rsi/minutes_11.png new file mode 100644 index 0000000000000000000000000000000000000000..fcbf039b6ffdc5668c29a95790386bf6c26e691f GIT binary patch literal 150 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz&H|6fVg?4jBOuH;Rhv&5DCpto z;uumf=k29~yg=0~j-Fdse(PTlsz`XzaK2TdTw6l#%taZXIv@yOYMH-b>ssCgYgkUa l4%ObX(c#;7euxyqDLtp@96P_~zHkBwc)I$ztaD0e0s!chD@FhS literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Devices/goldwatch.rsi/minutes_2.png b/Resources/Textures/Objects/Devices/goldwatch.rsi/minutes_2.png new file mode 100644 index 0000000000000000000000000000000000000000..1304f56e757368d4d5d02aa54f405f34fa1b3259 GIT binary patch literal 148 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz&H|6fVg?4jBOuH;Rhv&5DCp+t z;uumf=k2+TybKCF%#KP2Io{YSC@ig3`BA%{(F6*2UngBb^DJB2_ literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Devices/goldwatch.rsi/minutes_3.png b/Resources/Textures/Objects/Devices/goldwatch.rsi/minutes_3.png new file mode 100644 index 0000000000000000000000000000000000000000..8f58881dbda93e25a21ab56f6ab0baeea8616a4b GIT binary patch literal 142 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz&H|6fVg?4jBOuH;Rhv&5DCpqn z;uumf=k2+Tf(!y8E{rVMPU3*p+{=*Ho b8Ns4DSugTe~DWM4f6_Y3a literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Devices/goldwatch.rsi/minutes_5.png b/Resources/Textures/Objects/Devices/goldwatch.rsi/minutes_5.png new file mode 100644 index 0000000000000000000000000000000000000000..1d71f45c4791977ae15c34eea85bb396938222a4 GIT binary patch literal 150 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz&H|6fVg?4jBOuH;Rhv&5DCpto z;uumf=k2A7oIusC7g?ki{$oz?nOXl5b%|uY}?70No*bOBp+ON lUl)+i`2M{-P|Csj0ITK_j-Bsp%Jzd)db;|#taD0e0s!UED|!F` literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Devices/goldwatch.rsi/minutes_6.png b/Resources/Textures/Objects/Devices/goldwatch.rsi/minutes_6.png new file mode 100644 index 0000000000000000000000000000000000000000..5e1070e3a80454ab5edd53e2b7850b6c4fdfdc85 GIT binary patch literal 143 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz&H|6fVg?4jBOuH;Rhv&5DCp?v z;uumf=j}yDP6h=521kCAroYTm2iwyGrZ~^=HQ2CKg&n901U`r-oZYzSs|WKQjt3kC fzyBLPa0LlV+n-{Y%b>)p1>$(R`njxgN@xNA9D^j} literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Devices/goldwatch.rsi/minutes_7.png b/Resources/Textures/Objects/Devices/goldwatch.rsi/minutes_7.png new file mode 100644 index 0000000000000000000000000000000000000000..4af1070d216a1a25590a53b6aa3f5a91b6413b18 GIT binary patch literal 149 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz&H|6fVg?4jBOuH;Rhv&5DCq9# z;uumf=k0k%UIqmo7ROm4oIk`nSmcf#s@3zI9Lu_S=PYKRGBB9IyrNwDTc=rrHs^y~ k(;3gHG`x;uvj9mq@IRl-F?X-$@-rZXp00i_>zopr00p@y8~^|S literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Devices/goldwatch.rsi/minutes_8.png b/Resources/Textures/Objects/Devices/goldwatch.rsi/minutes_8.png new file mode 100644 index 0000000000000000000000000000000000000000..39b252688a78299da0303e13de4000e038bb8339 GIT binary patch literal 146 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz&H|6fVg?4jBOuH;Rhv&5DCpwp z;uumf=k2+JybJ;&E{;N87wQ|m3KXmgKDruJ-+VlKk{mx!83;V!KOj^4?)=uL0SC^0 i5PXpKgG0a&B;LSk{)1y~>B1A-AfBhIpUXO@geCw@bSf_Z literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Devices/goldwatch.rsi/minutes_9.png b/Resources/Textures/Objects/Devices/goldwatch.rsi/minutes_9.png new file mode 100644 index 0000000000000000000000000000000000000000..b9614ed80f52a6292f44f8548ded905f170b710e GIT binary patch literal 143 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz&H|6fVg?4jBOuH;Rhv&5DCp?v z;uumf=k2+Tf(!y8E{p=fS?83{1OQ`3CdB{% literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Devices/wristwatch.rsi/equipped-HAND.png b/Resources/Textures/Objects/Devices/wristwatch.rsi/equipped-HAND.png new file mode 100644 index 0000000000000000000000000000000000000000..b12afe6d4eec194bee8911634e1060ccaa43b517 GIT binary patch literal 292 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=oCO|{#S9F5M?jcysy3fAQ1F_k zi(^Q|oVT|&avlm0aeJsNwV{|RI3mKjO?XG+EiKzjZxu4<9Ggo8nV{7=-Pi>MZof{k)S{$Rl^IG|~>AOD9 z@&C*Ep!UYB=WnaezHI)UTgilJ0Cr;?8QzFrUUt_tqny+1`ECFBSIrC+vAZ7Y9a3QU oCBpE8m7$W+A&y~!IGD*Ft0Yr#`1X`lKp!%Ay85}Sb4q9e08OoHO#lD@ literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Devices/wristwatch.rsi/hours_0.png b/Resources/Textures/Objects/Devices/wristwatch.rsi/hours_0.png new file mode 100644 index 0000000000000000000000000000000000000000..3af9ca46343c1cc46a95181236029f45ffc7fcf1 GIT binary patch literal 151 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz&H|6fVg?4jBOuH;Rhv&5DCp_w z;uumf=j}yCP6h)G)AZ&ZIon oZP=CWkap_cc7|6F$%euMtesytPYVh}Tm*@Dy85}Sb4q9e0JbwN@c;k- literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Devices/wristwatch.rsi/hours_10.png b/Resources/Textures/Objects/Devices/wristwatch.rsi/hours_10.png new file mode 100644 index 0000000000000000000000000000000000000000..aeac86265673b1c55070ac1237c027112df89691 GIT binary patch literal 156 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz&H|6fVg?4jBOuH;Rhv&5DCp&lJK6k>0|rH=Th;al2?&AV|Q|)z4*}Q$iB}{GTY9 literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Devices/wristwatch.rsi/hours_2.png b/Resources/Textures/Objects/Devices/wristwatch.rsi/hours_2.png new file mode 100644 index 0000000000000000000000000000000000000000..386166cabdd3578c61abb30fad6364611cdebaa7 GIT binary patch literal 152 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz&H|6fVg?4jBOuH;Rhv&5DCp(s z;uumf=j}O1UIqgWmV=Y7h{R237f-o(g-P+l&EI#5pU->B2vi3Gry5MW3#S)0ta|pp nuYyxRQ1_wHf@+A=0jmd$pXYF%-o3Xn4J6{}>gTe~DWM4f#O*FS literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Devices/wristwatch.rsi/hours_3.png b/Resources/Textures/Objects/Devices/wristwatch.rsi/hours_3.png new file mode 100644 index 0000000000000000000000000000000000000000..2f5300928f2e1fb8cd3ff0242ab69c5200ab4a26 GIT binary patch literal 153 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz&H|6fVg?4jBOuH;Rhv&5DCq6! z;uumf=k3LVoD2#)&KJe*9MRmhe)EitB6l4GTz~F-GK1Z-%o3;&0!}w{WGv1;_iX8p n!iFW5uO_`cQ7sOZX?V{dYd?b{?UiYaGf2SG)z4*}Q$iB}9d#~_ literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Devices/wristwatch.rsi/hours_4.png b/Resources/Textures/Objects/Devices/wristwatch.rsi/hours_4.png new file mode 100644 index 0000000000000000000000000000000000000000..c994c0568591ca8dac03794872c2421335f69bcc GIT binary patch literal 155 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz&H|6fVg?4jBOuH;Rhv&5DCq0y z;uumf=k3LVoD2#)&Vj7cU+KxN-(9k%i(Py}tJ0sCqBG5FF3JE^f#cos8I85sQF77&b{w4G6F7t^>bP0l+XkKs;?;e literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Devices/wristwatch.rsi/hours_7.png b/Resources/Textures/Objects/Devices/wristwatch.rsi/hours_7.png new file mode 100644 index 0000000000000000000000000000000000000000..fa7af8e5cca4735e331a30cfa96e4bd7aba03ac4 GIT binary patch literal 153 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz&H|6fVg?4jBOuH;Rhv&5DCq6! z;uumf=k0k%UIqgWmV=Y7h{R237f%V~w(;UPxvp{c?sN;FGB9YcWe7dnF~QIwT-9OL p(jE2n@oXi%(;4S70%Z?aJYaO?=RE!C&gP9E#h$KyF6*2UngH6@Dn$SQ literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Devices/wristwatch.rsi/hours_8.png b/Resources/Textures/Objects/Devices/wristwatch.rsi/hours_8.png new file mode 100644 index 0000000000000000000000000000000000000000..83caf8c8e170e619de757651e787ddb190f0e2bb GIT binary patch literal 152 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz&H|6fVg?4jBOuH;Rhv&5DCp(s z;uumf=k2+Jyg=0~j-EMPaT@(`8r;e3HZIAVzVCc~PNtt7s1OW3usehn*Snl3b(pnu lhdlpu#p=fS?83{1OTP2D8c{$ literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Devices/wristwatch.rsi/hours_9.png b/Resources/Textures/Objects/Devices/wristwatch.rsi/hours_9.png new file mode 100644 index 0000000000000000000000000000000000000000..6334bb72fdc1733bc48f6078d32126779a1e23a4 GIT binary patch literal 150 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz&H|6fVg?4jBOuH;Rhv&5DCpto z;uumf=k2+Jyg=0~j-G2yMQQZMt!Roe*vOdN^y_Br-S^A3pJxOr1%n*Mm9vzSa?7Vb iXE4;Zw`ID+2N9p~=QhXbc(L6vAg-sYpUXO@geCy%Dk<{- literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Devices/wristwatch.rsi/inhand-left.png b/Resources/Textures/Objects/Devices/wristwatch.rsi/inhand-left.png new file mode 100644 index 0000000000000000000000000000000000000000..76ca3c491159bfbe14fc4bbe0712376d010e8e9c GIT binary patch literal 252 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=oCO|{#S9F5M?jcysy3fAP;i~6 zi(^Q|oVPbO@;Vs`90*VjH1On7OOR?yW=dO_AZ8_C{lvZNjroDODXLfJPSj>7Vs%)@ za6*(}CzC=r!xOHC7{&=8!5Nls3isB$e}BHS_X|@R-)`G@12*fKQVBg9uYUgjnj1we zRs$@OUaT_y*<-u6LAh<6)#URxiai=a(?3a8|6+pM_Jy&ou2dxFroeASpvxINUHx3v IIVCg!0CAvI4gdfE literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Devices/wristwatch.rsi/inhand-right.png b/Resources/Textures/Objects/Devices/wristwatch.rsi/inhand-right.png new file mode 100644 index 0000000000000000000000000000000000000000..f9ab9c67d492e6bcbab2032582b09efd6aa0eb53 GIT binary patch literal 254 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=oCO|{#S9F5M?jcysy3fAP;i5% zi(^Q|oVPbO@-i8U90*VjH1On7OOR?yW=dO_AZ8_?JjZXR(zn%%T{hLNs&`w*a6*(} zCzC=r!xOHC7{&?O3`MLCAi;#w508KSw0FO~y4WR_9Lt*OeF;2an=}tdB(MDV|1~$J z26R(yR38k~{v7$4H7R#yo2B5A_ZY@B z;uumf=k0k%UIqo8qXE+rvQ9Wkl&LXVIy0a4FUu6&bMB%HP#s7q)0;CkY1i0xWb=mJ tXDC14G2za1hFAL-PyH5hkcB9@z*lkX7LO7~v2YVez|+;wWt~$(695Z$EL8vi literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Devices/wristwatch.rsi/minutes_10.png b/Resources/Textures/Objects/Devices/wristwatch.rsi/minutes_10.png new file mode 100644 index 0000000000000000000000000000000000000000..9dad0d83cbe85a64b02d8ee9a552d191ae753355 GIT binary patch literal 159 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz&H|6fVg?4jBOuH;Rhv&5C>ZGJ z;uumf=k3Lfyg=11fgUkj#|sUvC$bzr_=4e>TjoF0@J~e|o_s*1An<@AL(niwwEVh= sL-^hHvpQk>8)Eh<Z4F z;uumf=k588yg=2gfgUkj#|sUvC$bzrxPwuw<=MKQZ+|<_Vg{-NDQ*xIj1IlcknXoq vi?yKKbaTaRrWHE8D=Pl8t^ipL1R3lxKg0McPTV$f0C7EC{an^LB{Ts5menmb literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Devices/wristwatch.rsi/minutes_2.png b/Resources/Textures/Objects/Devices/wristwatch.rsi/minutes_2.png new file mode 100644 index 0000000000000000000000000000000000000000..a4c3bbe7179bc4ac528d3d1c5c8ed342b7529a29 GIT binary patch literal 157 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz&H|6fVg?4jBOuH;Rhv&5DCqC$ z;uumf=k2A9yg=2gfgUl(1S75$Cg|{LYh0XhCtu^es7a*_P$38$FgtK2t$g~zRpE@1 q=cEOt(%;%Tv@I?8{|_R~5U`ciU50ys$SWy#kcg+NpUXO@geCy3Eh>os literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Devices/wristwatch.rsi/minutes_3.png b/Resources/Textures/Objects/Devices/wristwatch.rsi/minutes_3.png new file mode 100644 index 0000000000000000000000000000000000000000..6bfdc405c790914479d3f4582acb23b3840585cd GIT binary patch literal 151 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz&H|6fVg?4jBOuH;Rhv&5DCp_w z;uumf=k2-OybKCF%z;W9d6ZKkk98hz;;OQ1dKR;D_w>up8G#DHK!^Fx-rjhnAk)pu k89a?wZ2l(q;2T7yf$!Zf_626eGc!SaPgg&ebxsLQ0QvkX`2YX_ literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Devices/wristwatch.rsi/minutes_4.png b/Resources/Textures/Objects/Devices/wristwatch.rsi/minutes_4.png new file mode 100644 index 0000000000000000000000000000000000000000..89c08f3396f0ff1bbfe620de16cadeda888989c7 GIT binary patch literal 160 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz&H|6fVg?4jBOuH;Rhv&5C>Z4F z;uumf=k2A9yg=11fgUl(1S75$Cg||Ca%UtO%x{}C{qZatIiN}~XsBW^p1o7qX+FcZ uhb<-LlB>ceJQi0``C`{nB@0r}@ScJD`byq!byDHkAik%opUXO@geCw@EiDoN literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Devices/wristwatch.rsi/minutes_5.png b/Resources/Textures/Objects/Devices/wristwatch.rsi/minutes_5.png new file mode 100644 index 0000000000000000000000000000000000000000..4cbaa00d14b3d50aba0fe36ec3ee2468db228850 GIT binary patch literal 159 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz&H|6fVg?4jBOuH;Rhv&5C>ZGJ z;uumf=j|m%UZ851z#BTrET^R0lV0{HBp1Kh&(i<6ONI}q4h#;|G8jw0TX&q{=1sOW vuZ^QQOarRLug}qMVetL>m=~zzf#m^~R||N*ZKyx9AEd+6)z4*}Q$iB}N<1$? literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Devices/wristwatch.rsi/minutes_6.png b/Resources/Textures/Objects/Devices/wristwatch.rsi/minutes_6.png new file mode 100644 index 0000000000000000000000000000000000000000..e834c52d8cd5aaaa10bbbd97c159e1cd82a8bafb GIT binary patch literal 153 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz&H|6fVg?4jBOuH;Rhv&5DCq6! z;uumf=k29NP6h=Y=7SxHEcf$AXO4|Boy*)z@9UU+d{ t*t(DBhM-sW%k_+Xrdz!qwE|ItM6yeoWith n_j|*jLy8B4Jh|H$M47>|>_umJlzhUS9)ftDu6{1-oD!MIP)^@RCt{2S4(IUQ53yN%tErLXj|+;TN*N56cJn$>xT%{T|qa& zjkKbz6~RqFanVx62GlOQiK0TqjXMkOO2I*^;3A;XLK7Mq3#L>TQ-c)g=Q-zPUiv1P zU(<*PUKsA3_dDmF_n9}l=r7xU0^24q774P()`+QWb|FLcn?%<$Yra25V7M*F;2T>a z^lLF|OAdZJL_87TSsTE}78VW!Xk~4K$MyR2-A@$K;dirQd#@y12?)tW)&PdhZ|LCu zVjBR5STSDJVSjF8A{+?-ye=51C`ab?Ml3RYpafZYUoR@SDlo~`iN2&Qdv&aDjej$} z<^u_24>eXjs^ChXFF8ezuXb6Mf9gAJDib8cI~MMpIcF7Y2_zB;_CxngO-(d3F>Bf8 z?Zw-4L(|yk=x7N9B*cyhF>*Ca0sxQ2Vm!|0^R}Hun?j+$lF1||@ofAlTS^R++TgvX z_mZs&6$Avh0RH&uF71h&fpEr za&xaqiS|-j9jD{x2WeUdZ9fvF=@%os9QDm@r%ZjK(Wp;VRfYuM@$Q*`oINrJNW=aE z`l!9UUXeU6HxxQ-C?QmE1NEc;q(fyw^c(ju=HQ&O!tP61@MGmvP|>t|9be?QuJ zf5$G_~!uQ1Zs9Cr2E&X`=DaF3FAtJ>;Q@s2@?gXM3=6po>$c~sA|TAmimt}~y??`6+iz=%nuRh`+1LO8 N002ovPDHLkV1f$6lfVD~ literal 0 HcmV?d00001 From 0b11619df338c0f908cede7f46bae5d5009f05b2 Mon Sep 17 00:00:00 2001 From: slarticodefast <161409025+slarticodefast@users.noreply.github.com> Date: Sat, 13 Jul 2024 08:10:04 +0200 Subject: [PATCH 194/765] Remove imagesharp and StatusEffectAddedEvent from FlashOverlay (#28930) remove imagesharp and StatusEffectAddedEvent from FlashOverlay --- Content.Client/Flash/FlashOverlay.cs | 27 ++++++--------------------- Content.Client/Flash/FlashSystem.cs | 14 +++----------- 2 files changed, 9 insertions(+), 32 deletions(-) diff --git a/Content.Client/Flash/FlashOverlay.cs b/Content.Client/Flash/FlashOverlay.cs index 9ea00275e84..046be2aa621 100644 --- a/Content.Client/Flash/FlashOverlay.cs +++ b/Content.Client/Flash/FlashOverlay.cs @@ -1,27 +1,22 @@ using Content.Shared.Flash; using Content.Shared.Flash.Components; using Content.Shared.StatusEffect; -using Content.Client.Viewport; using Robust.Client.Graphics; -using Robust.Client.State; using Robust.Client.Player; using Robust.Shared.Enums; using Robust.Shared.Prototypes; using Robust.Shared.Timing; -using SixLabors.ImageSharp.PixelFormats; namespace Content.Client.Flash { public sealed class FlashOverlay : Overlay { [Dependency] private readonly IPrototypeManager _prototypeManager = default!; - [Dependency] private readonly IClyde _displayManager = default!; - [Dependency] private readonly IStateManager _stateManager = default!; [Dependency] private readonly IEntityManager _entityManager = default!; [Dependency] private readonly IPlayerManager _playerManager = default!; [Dependency] private readonly IGameTiming _timing = default!; - private readonly StatusEffectsSystem _statusSys; + private readonly StatusEffectsSystem _statusSys; public override OverlaySpace Space => OverlaySpace.WorldSpace; private readonly ShaderInstance _shader; @@ -56,20 +51,6 @@ protected override void FrameUpdate(FrameEventArgs args) PercentComplete = timeDone / lastsFor; } - public void ReceiveFlash() - { - if (_stateManager.CurrentState is IMainViewportState state) - { - // take a screenshot - // note that the callback takes a while and ScreenshotTexture will be null the first few Draws - state.Viewport.Viewport.Screenshot(image => - { - var rgba32Image = image.CloneAs(SixLabors.ImageSharp.Configuration.Default); - ScreenshotTexture = _displayManager.LoadTextureFromImage(rgba32Image); - }); - } - } - protected override bool BeforeDraw(in OverlayDrawArgs args) { if (!_entityManager.TryGetComponent(_playerManager.LocalEntity, out EyeComponent? eyeComp)) @@ -82,6 +63,11 @@ protected override bool BeforeDraw(in OverlayDrawArgs args) protected override void Draw(in OverlayDrawArgs args) { + if (RequestScreenTexture && ScreenTexture != null) + { + ScreenshotTexture = ScreenTexture; + RequestScreenTexture = false; // we only need the first frame, so we can stop the request now for performance reasons + } if (ScreenshotTexture == null) return; @@ -96,7 +82,6 @@ protected override void DisposeBehavior() { base.DisposeBehavior(); ScreenshotTexture = null; - PercentComplete = 1.0f; } } } diff --git a/Content.Client/Flash/FlashSystem.cs b/Content.Client/Flash/FlashSystem.cs index 9a0579f6aa3..146d84b990f 100644 --- a/Content.Client/Flash/FlashSystem.cs +++ b/Content.Client/Flash/FlashSystem.cs @@ -22,7 +22,6 @@ public override void Initialize() SubscribeLocalEvent(OnShutdown); SubscribeLocalEvent(OnPlayerAttached); SubscribeLocalEvent(OnPlayerDetached); - SubscribeLocalEvent(OnStatusAdded); _overlay = new(); } @@ -34,8 +33,8 @@ private void OnPlayerAttached(EntityUid uid, FlashedComponent component, LocalPl private void OnPlayerDetached(EntityUid uid, FlashedComponent component, LocalPlayerDetachedEvent args) { - _overlay.PercentComplete = 1.0f; _overlay.ScreenshotTexture = null; + _overlay.RequestScreenTexture = false; _overlayMan.RemoveOverlay(_overlay); } @@ -43,6 +42,7 @@ private void OnInit(EntityUid uid, FlashedComponent component, ComponentInit arg { if (_player.LocalEntity == uid) { + _overlay.RequestScreenTexture = true; _overlayMan.AddOverlay(_overlay); } } @@ -51,17 +51,9 @@ private void OnShutdown(EntityUid uid, FlashedComponent component, ComponentShut { if (_player.LocalEntity == uid) { - _overlay.PercentComplete = 1.0f; _overlay.ScreenshotTexture = null; + _overlay.RequestScreenTexture = false; _overlayMan.RemoveOverlay(_overlay); } } - - private void OnStatusAdded(EntityUid uid, FlashedComponent component, StatusEffectAddedEvent args) - { - if (_player.LocalEntity == uid && args.Key == FlashedKey) - { - _overlay.ReceiveFlash(); - } - } } From 939923951803cbe6c4510ca0fc4b1be0b92a5c56 Mon Sep 17 00:00:00 2001 From: PJBot Date: Sat, 13 Jul 2024 06:10:25 +0000 Subject: [PATCH 195/765] Automatic changelog update --- Resources/Changelog/Changelog.yml | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index eb495bc316d..ca549b51fb3 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,16 +1,4 @@ Entries: -- author: PJB3005 - changes: - - message: The item status menu has been moved to the side of the hands. There is - now one for each hand. - type: Add - - message: The item status menu fits with the rest of the HUD theme now. - type: Add - - message: Improved, fixed and otherwise added a bunch of item status menus. - type: Add - id: 6414 - time: '2024-04-21T13:16:23.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/22986 - author: FairlySadPanda changes: - message: Xenoarchaeology Traversal Distorters have been rolled into the Artifact @@ -3823,3 +3811,10 @@ id: 6913 time: '2024-07-13T04:14:30.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/29830 +- author: EmoGarbage404 + changes: + - message: Added wristwatches for telling time. + type: Add + id: 6914 + time: '2024-07-13T06:09:19.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/29550 From ad00038233b7faaa603d0c5c28e3756870c95c6e Mon Sep 17 00:00:00 2001 From: deltanedas <39013340+deltanedas@users.noreply.github.com> Date: Sat, 13 Jul 2024 06:11:14 +0000 Subject: [PATCH 196/765] make cargo balance ui updating its own component (#28295) * add BankClientComponent and event * query BankClient instead of hardcoded CargoOrderConsole for updating * add BankClient to all ordering consoles * :trollface: * add Balance field to BankClient * forgor Co-authored-by: ShadowCommander <10494922+ShadowCommander@users.noreply.github.com> * m --------- Co-authored-by: deltanedas <@deltanedas:kde.org> Co-authored-by: ShadowCommander <10494922+ShadowCommander@users.noreply.github.com> --- .../Cargo/Systems/CargoSystem.Orders.cs | 10 +++++++ Content.Server/Cargo/Systems/CargoSystem.cs | 14 +++++----- .../Cargo/Components/BankClientComponent.cs | 26 +++++++++++++++++++ .../Entities/Mobs/Player/admin_ghost.yml | 1 + .../Entities/Objects/Misc/paper.yml | 1 + .../Machines/Computers/computers.yml | 1 + 6 files changed, 46 insertions(+), 7 deletions(-) create mode 100644 Content.Shared/Cargo/Components/BankClientComponent.cs diff --git a/Content.Server/Cargo/Systems/CargoSystem.Orders.cs b/Content.Server/Cargo/Systems/CargoSystem.Orders.cs index 06738a2deb0..7abe9061525 100644 --- a/Content.Server/Cargo/Systems/CargoSystem.Orders.cs +++ b/Content.Server/Cargo/Systems/CargoSystem.Orders.cs @@ -40,6 +40,7 @@ private void InitializeConsole() SubscribeLocalEvent(OnOrderUIOpened); SubscribeLocalEvent(OnInit); SubscribeLocalEvent(OnInteractUsing); + SubscribeLocalEvent(OnOrderBalanceUpdated); Reset(); } @@ -317,6 +318,15 @@ private void OnOrderUIOpened(EntityUid uid, CargoOrderConsoleComponent component #endregion + + private void OnOrderBalanceUpdated(Entity ent, ref BankBalanceUpdatedEvent args) + { + if (!_uiSystem.IsUiOpen(ent.Owner, CargoConsoleUiKey.Orders)) + return; + + UpdateOrderState(ent, args.Station); + } + private void UpdateOrderState(EntityUid consoleUid, EntityUid? station) { if (station == null || diff --git a/Content.Server/Cargo/Systems/CargoSystem.cs b/Content.Server/Cargo/Systems/CargoSystem.cs index 62cd8f49f6d..cb36088c45b 100644 --- a/Content.Server/Cargo/Systems/CargoSystem.cs +++ b/Content.Server/Cargo/Systems/CargoSystem.cs @@ -89,18 +89,18 @@ public override void Update(float frameTime) public void UpdateBankAccount(EntityUid uid, StationBankAccountComponent component, int balanceAdded) { component.Balance += balanceAdded; - var query = EntityQueryEnumerator(); + var query = EntityQueryEnumerator(); - while (query.MoveNext(out var oUid, out var _)) + var ev = new BankBalanceUpdatedEvent(uid, component.Balance); + while (query.MoveNext(out var client, out var comp, out var xform)) { - if (!_uiSystem.IsUiOpen(oUid, CargoConsoleUiKey.Orders)) - continue; - - var station = _station.GetOwningStation(oUid); + var station = _station.GetOwningStation(client, xform); if (station != uid) continue; - UpdateOrderState(oUid, station); + comp.Balance = component.Balance; + Dirty(client, comp); + RaiseLocalEvent(client, ref ev); } } } diff --git a/Content.Shared/Cargo/Components/BankClientComponent.cs b/Content.Shared/Cargo/Components/BankClientComponent.cs new file mode 100644 index 00000000000..4fd70855034 --- /dev/null +++ b/Content.Shared/Cargo/Components/BankClientComponent.cs @@ -0,0 +1,26 @@ +using Content.Shared.Cargo; +using Robust.Shared.GameStates; + +namespace Content.Shared.Cargo.Components; + +/// +/// Makes an entity a client of the station's bank account. +/// When its balance changes it will have raised on it. +/// Other systems can then use this for logic or to update ui states. +/// +[RegisterComponent, NetworkedComponent, Access(typeof(SharedCargoSystem))] +[AutoGenerateComponentState] +public sealed partial class BankClientComponent : Component +{ + /// + /// The balance updated for the last station this entity was a part of. + /// + [DataField, AutoNetworkedField] + public int Balance; +} + +/// +/// Raised on an entity with when the bank's balance is updated. +/// +[ByRefEvent] +public record struct BankBalanceUpdatedEvent(EntityUid Station, int Balance); diff --git a/Resources/Prototypes/Entities/Mobs/Player/admin_ghost.yml b/Resources/Prototypes/Entities/Mobs/Player/admin_ghost.yml index fd62544b610..f206f246cdb 100644 --- a/Resources/Prototypes/Entities/Mobs/Player/admin_ghost.yml +++ b/Resources/Prototypes/Entities/Mobs/Player/admin_ghost.yml @@ -75,6 +75,7 @@ - type: RadarConsole followEntity: true - type: CargoOrderConsole + - type: BankClient - type: CrewMonitoringConsole - type: GeneralStationRecordConsole canDeleteEntries: true diff --git a/Resources/Prototypes/Entities/Objects/Misc/paper.yml b/Resources/Prototypes/Entities/Objects/Misc/paper.yml index 1c8d8754884..5dbafa6416a 100644 --- a/Resources/Prototypes/Entities/Objects/Misc/paper.yml +++ b/Resources/Prototypes/Entities/Objects/Misc/paper.yml @@ -548,6 +548,7 @@ tags: - Write - type: CargoOrderConsole + - type: BankClient - type: ActivatableUI verbText: qm-clipboard-computer-verb-text key: enum.CargoConsoleUiKey.Orders diff --git a/Resources/Prototypes/Entities/Structures/Machines/Computers/computers.yml b/Resources/Prototypes/Entities/Structures/Machines/Computers/computers.yml index b91d568344b..e6ec6bbf20b 100644 --- a/Resources/Prototypes/Entities/Structures/Machines/Computers/computers.yml +++ b/Resources/Prototypes/Entities/Structures/Machines/Computers/computers.yml @@ -738,6 +738,7 @@ - map: ["computerLayerKeys"] state: tech_key - type: CargoOrderConsole + - type: BankClient - type: ActiveRadio channels: - Supply From a97f4ac9fd40ae3bd9cdd4bec2c86a67367b00e9 Mon Sep 17 00:00:00 2001 From: CaasGit <87243814+CaasGit@users.noreply.github.com> Date: Fri, 12 Jul 2024 23:12:57 -0700 Subject: [PATCH 197/765] fix(SharedGunSystem): Return and debug log on CreateEffect. (#29656) Sometimes CreateEffect is called on a Invalid Entity. This now causes that to check, thus returning out and printing some hopefully helpful logs to try to track down the real source of this issue. --- Content.Client/Weapons/Ranged/Systems/GunSystem.cs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Content.Client/Weapons/Ranged/Systems/GunSystem.cs b/Content.Client/Weapons/Ranged/Systems/GunSystem.cs index ac5914d47c0..71342277674 100644 --- a/Content.Client/Weapons/Ranged/Systems/GunSystem.cs +++ b/Content.Client/Weapons/Ranged/Systems/GunSystem.cs @@ -276,6 +276,14 @@ protected override void CreateEffect(EntityUid gunUid, MuzzleFlashEvent message, if (!Timing.IsFirstTimePredicted) return; + // EntityUid check added to stop throwing exceptions due to https://github.com/space-wizards/space-station-14/issues/28252 + // TODO: Check to see why invalid entities are firing effects. + if (gunUid == EntityUid.Invalid) + { + Log.Debug($"Invalid Entity sent MuzzleFlashEvent (proto: {message.Prototype}, user: {user})"); + return; + } + var gunXform = Transform(gunUid); var gridUid = gunXform.GridUid; EntityCoordinates coordinates; From 4dd3fa17e925a036a0450f9a79fcd13f7ce65c68 Mon Sep 17 00:00:00 2001 From: Plykiya <58439124+Plykiya@users.noreply.github.com> Date: Sat, 13 Jul 2024 03:59:33 -0700 Subject: [PATCH 198/765] Replace DetachParentToNull() with DetachEntity() (#29992) DETACH PARENT TO ENTITY Co-authored-by: plykiya --- Content.Client/Materials/MaterialStorageSystem.cs | 4 ++-- Content.Client/Stack/StackSystem.cs | 2 +- Content.Shared/Actions/ActionContainerSystem.cs | 2 +- Content.Shared/Follower/FollowerSystem.cs | 2 +- .../Inventory/VirtualItem/SharedVirtualItemSystem.cs | 2 +- .../Weapons/Ranged/Systems/SharedGunSystem.ChamberMagazine.cs | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Content.Client/Materials/MaterialStorageSystem.cs b/Content.Client/Materials/MaterialStorageSystem.cs index edd07391f7b..592471d6736 100644 --- a/Content.Client/Materials/MaterialStorageSystem.cs +++ b/Content.Client/Materials/MaterialStorageSystem.cs @@ -1,4 +1,4 @@ -using Content.Shared.Materials; +using Content.Shared.Materials; using Robust.Client.GameObjects; namespace Content.Client.Materials; @@ -49,7 +49,7 @@ public override bool TryInsertMaterialEntity(EntityUid user, { if (!base.TryInsertMaterialEntity(user, toInsert, receiver, storage, material, composition)) return false; - _transform.DetachParentToNull(toInsert, Transform(toInsert)); + _transform.DetachEntity(toInsert, Transform(toInsert)); return true; } } diff --git a/Content.Client/Stack/StackSystem.cs b/Content.Client/Stack/StackSystem.cs index c081581338f..7e681aeba3e 100644 --- a/Content.Client/Stack/StackSystem.cs +++ b/Content.Client/Stack/StackSystem.cs @@ -44,7 +44,7 @@ public override void SetCount(EntityUid uid, int amount, StackComponent? compone // TODO PREDICT ENTITY DELETION: This should really just be a normal entity deletion call. if (component.Count <= 0 && !component.Lingering) { - Xform.DetachParentToNull(uid, Transform(uid)); + Xform.DetachEntity(uid, Transform(uid)); return; } diff --git a/Content.Shared/Actions/ActionContainerSystem.cs b/Content.Shared/Actions/ActionContainerSystem.cs index 1c5a3ba0d93..1a83cf38e51 100644 --- a/Content.Shared/Actions/ActionContainerSystem.cs +++ b/Content.Shared/Actions/ActionContainerSystem.cs @@ -261,7 +261,7 @@ public void RemoveAction(EntityUid actionId, BaseActionComponent? action = null) if (action.Container == null) return; - _transform.DetachParentToNull(actionId, Transform(actionId)); + _transform.DetachEntity(actionId, Transform(actionId)); // Container removal events should have removed the action from the action container. // However, just in case the container was already deleted we will still manually clear the container field diff --git a/Content.Shared/Follower/FollowerSystem.cs b/Content.Shared/Follower/FollowerSystem.cs index 8027ee449c4..8c35617e2c3 100644 --- a/Content.Shared/Follower/FollowerSystem.cs +++ b/Content.Shared/Follower/FollowerSystem.cs @@ -227,7 +227,7 @@ public void StopFollowingEntity(EntityUid uid, EntityUid target, FollowedCompone if (_netMan.IsClient) { - _transform.DetachParentToNull(uid, xform); + _transform.DetachEntity(uid, xform); return; } diff --git a/Content.Shared/Inventory/VirtualItem/SharedVirtualItemSystem.cs b/Content.Shared/Inventory/VirtualItem/SharedVirtualItemSystem.cs index 4a5894d8958..cd0863ec88d 100644 --- a/Content.Shared/Inventory/VirtualItem/SharedVirtualItemSystem.cs +++ b/Content.Shared/Inventory/VirtualItem/SharedVirtualItemSystem.cs @@ -244,7 +244,7 @@ public void DeleteVirtualItem(Entity item, EntityUid user) if (TerminatingOrDeleted(item)) return; - _transformSystem.DetachParentToNull(item, Transform(item)); + _transformSystem.DetachEntity(item, Transform(item)); if (_netManager.IsServer) QueueDel(item); } diff --git a/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.ChamberMagazine.cs b/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.ChamberMagazine.cs index adae26a223a..d6f45ba77df 100644 --- a/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.ChamberMagazine.cs +++ b/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.ChamberMagazine.cs @@ -108,7 +108,7 @@ private void UseChambered(EntityUid uid, ChamberMagazineAmmoProviderComponent co else { // Similar to below just due to prediction. - TransformSystem.DetachParentToNull(chamberEnt.Value, Transform(chamberEnt.Value)); + TransformSystem.DetachEntity(chamberEnt.Value, Transform(chamberEnt.Value)); } } From a289f0f9340e834a959ca524454e4332d161bb45 Mon Sep 17 00:00:00 2001 From: Plykiya <58439124+Plykiya@users.noreply.github.com> Date: Sat, 13 Jul 2024 04:50:21 -0700 Subject: [PATCH 199/765] Update SpawnAfterInteractSystem.cs to not use Component.Owner (#29968) * Update SpawnAfterInteractSystem.cs * what the fuck is that condition --------- Co-authored-by: plykiya --- .../Engineering/EntitySystems/SpawnAfterInteractSystem.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Content.Server/Engineering/EntitySystems/SpawnAfterInteractSystem.cs b/Content.Server/Engineering/EntitySystems/SpawnAfterInteractSystem.cs index 281bbc47211..8391e8faada 100644 --- a/Content.Server/Engineering/EntitySystems/SpawnAfterInteractSystem.cs +++ b/Content.Server/Engineering/EntitySystems/SpawnAfterInteractSystem.cs @@ -65,8 +65,8 @@ bool IsTileClear() EntityManager.SpawnEntity(component.Prototype, args.ClickLocation.SnapToGrid(grid)); - if (component.RemoveOnInteract && stackComp == null && !((!EntityManager.EntityExists(uid) ? EntityLifeStage.Deleted : EntityManager.GetComponent(component.Owner).EntityLifeStage) >= EntityLifeStage.Deleted)) - EntityManager.DeleteEntity(uid); + if (component.RemoveOnInteract && stackComp == null) + TryQueueDel(uid); } } } From d1233358228be69368505febb58a7319bf743e09 Mon Sep 17 00:00:00 2001 From: Ed <96445749+TheShuEd@users.noreply.github.com> Date: Sat, 13 Jul 2024 15:15:57 +0300 Subject: [PATCH 200/765] Shiny Diamonds (#25750) * shiny * add * reresprite * rereresprite * Add files via upload * Update ore.yml --- .../Locale/en-US/materials/materials.ftl | 2 + .../Locale/en-US/salvage/salvage-magnet.ftl | 1 + .../Entities/Objects/Materials/materials.yml | 13 ++ .../Entities/Objects/Materials/ore.yml | 31 ++++ .../Entities/Structures/Machines/lathe.yml | 1 + .../Entities/Structures/Walls/asteroid.yml | 155 +++++++++++++++++- .../Entities/World/Debris/asteroids.yml | 3 + .../Prototypes/Procedural/Magnet/asteroid.yml | 1 + .../Procedural/biome_ore_templates.yml | 14 ++ .../Prototypes/Procedural/salvage_loot.yml | 7 + .../Prototypes/Reagents/Materials/ores.yml | 9 + Resources/Prototypes/Recipes/Lathes/sheet.yml | 7 + Resources/Prototypes/Stacks/Materials/ore.yml | 7 + Resources/Prototypes/ore.yml | 6 + .../materials.rsi/diamond-inhand-left.png | Bin 223 -> 236 bytes .../materials.rsi/diamond-inhand-right.png | Bin 231 -> 244 bytes .../Materials/materials.rsi/diamond.png | Bin 297 -> 255 bytes .../Materials/materials.rsi/diamond_2.png | Bin 0 -> 345 bytes .../Materials/materials.rsi/diamond_3.png | Bin 0 -> 419 bytes .../Objects/Materials/materials.rsi/meta.json | 6 + .../Objects/Materials/ore.rsi/diamond.png | Bin 0 -> 390 bytes .../Objects/Materials/ore.rsi/meta.json | 5 +- .../Structures/Walls/rock.rsi/meta.json | 18 +- .../Walls/rock.rsi/rock_diamond.png | Bin 1307 -> 1916 bytes 24 files changed, 283 insertions(+), 3 deletions(-) create mode 100644 Resources/Textures/Objects/Materials/materials.rsi/diamond_2.png create mode 100644 Resources/Textures/Objects/Materials/materials.rsi/diamond_3.png create mode 100644 Resources/Textures/Objects/Materials/ore.rsi/diamond.png diff --git a/Resources/Locale/en-US/materials/materials.ftl b/Resources/Locale/en-US/materials/materials.ftl index a354423d2b7..0fc716bda53 100644 --- a/Resources/Locale/en-US/materials/materials.ftl +++ b/Resources/Locale/en-US/materials/materials.ftl @@ -25,6 +25,7 @@ materials-meat = meat materials-web = silk materials-bones = bone materials-coal = coal +materials-diamond = diamond materials-gunpowder = gunpowder # Ores @@ -36,3 +37,4 @@ materials-raw-plasma = raw plasma materials-raw-uranium = raw uranium materials-raw-bananium = raw bananium materials-raw-salt = raw salt +materials-raw-diamond = raw diamond diff --git a/Resources/Locale/en-US/salvage/salvage-magnet.ftl b/Resources/Locale/en-US/salvage/salvage-magnet.ftl index 7ce2a486de9..c60bafcc138 100644 --- a/Resources/Locale/en-US/salvage/salvage-magnet.ftl +++ b/Resources/Locale/en-US/salvage/salvage-magnet.ftl @@ -13,6 +13,7 @@ salvage-magnet-resources = {$resource -> [OreQuartz] Quartz [OreSalt] Salt [OreGold] Gold + [OreDiamond] Diamond [OreSilver] Silver [OrePlasma] Plasma [OreUranium] Uranium diff --git a/Resources/Prototypes/Entities/Objects/Materials/materials.yml b/Resources/Prototypes/Entities/Objects/Materials/materials.yml index 596adb9885f..3a5861055bc 100644 --- a/Resources/Prototypes/Entities/Objects/Materials/materials.yml +++ b/Resources/Prototypes/Entities/Objects/Materials/materials.yml @@ -350,8 +350,21 @@ components: - type: Stack stackType: Diamond + baseLayer: base + layerStates: + - diamond + - diamond_2 + - diamond_3 - type: Sprite state: diamond + layers: + - state: diamond + map: ["base"] + - type: StaticPrice + price: 0 + - type: StackPrice + price: 500 + - type: Appearance - type: Item heldPrefix: diamond - type: Extractable diff --git a/Resources/Prototypes/Entities/Objects/Materials/ore.yml b/Resources/Prototypes/Entities/Objects/Materials/ore.yml index bf7dbfad5a3..136d20cc81b 100644 --- a/Resources/Prototypes/Entities/Objects/Materials/ore.yml +++ b/Resources/Prototypes/Entities/Objects/Materials/ore.yml @@ -66,6 +66,37 @@ - type: Stack count: 1 +- type: entity + parent: OreBase + id: DiamondOre + name: diamond ore + suffix: Full + components: + - type: Stack + stackType: DiamondOre + - type: Sprite + state: diamond + - type: Material + - type: PhysicalComposition + materialComposition: + RawDiamond: 500 + - type: Extractable + grindableSolutionName: diamondore + - type: SolutionContainerManager + solutions: + diamondore: + reagents: + - ReagentId: Carbon + Quantity: 20 + +- type: entity + parent: DiamondOre + id: DiamondOre1 + suffix: Single + components: + - type: Stack + count: 1 + - type: entity parent: OreBase id: SteelOre diff --git a/Resources/Prototypes/Entities/Structures/Machines/lathe.yml b/Resources/Prototypes/Entities/Structures/Machines/lathe.yml index 50f1b0e6c1d..4559c7caf49 100644 --- a/Resources/Prototypes/Entities/Structures/Machines/lathe.yml +++ b/Resources/Prototypes/Entities/Structures/Machines/lathe.yml @@ -1258,6 +1258,7 @@ - IngotGold30 - IngotSilver30 - MaterialBananium10 + - MaterialDiamond - type: MaterialStorageMagnetPickup # Delta V - Summary: Adds magnet pull from Frontier magnetEnabled: True range: 0.30 # Delta V - End Magnet Pull diff --git a/Resources/Prototypes/Entities/Structures/Walls/asteroid.yml b/Resources/Prototypes/Entities/Structures/Walls/asteroid.yml index e14bf26e0db..c0a30e76694 100644 --- a/Resources/Prototypes/Entities/Structures/Walls/asteroid.yml +++ b/Resources/Prototypes/Entities/Structures/Walls/asteroid.yml @@ -93,6 +93,28 @@ state: rock_asteroid_west - state: rock_gold +- type: entity + id: AsteroidRockDiamond + parent: AsteroidRock + description: An ore vein rich with diamonds. + suffix: Diamond + components: + - type: OreVein + oreChance: 1.0 + currentOre: OreDiamond + - type: Sprite + layers: + - state: rock_asteroid + - map: [ "enum.EdgeLayer.South" ] + state: rock_asteroid_south + - map: [ "enum.EdgeLayer.East" ] + state: rock_asteroid_east + - map: [ "enum.EdgeLayer.North" ] + state: rock_asteroid_north + - map: [ "enum.EdgeLayer.West" ] + state: rock_asteroid_west + - state: rock_diamond + - type: entity id: AsteroidRockPlasma parent: AsteroidRock @@ -693,6 +715,28 @@ state: rock_west - state: rock_gold +- type: entity + id: WallRockDiamond + parent: WallRock + description: An ore vein rich with diamonds. + suffix: Diamond + components: + - type: OreVein + oreChance: 1.0 + currentOre: OreDiamond + - type: Sprite + layers: + - state: rock + - map: [ "enum.EdgeLayer.South" ] + state: rock_south + - map: [ "enum.EdgeLayer.East" ] + state: rock_east + - map: [ "enum.EdgeLayer.North" ] + state: rock_north + - map: [ "enum.EdgeLayer.West" ] + state: rock_west + - state: rock_diamond + - type: entity id: WallRockPlasma parent: WallRock @@ -993,6 +1037,28 @@ state: rock_wall_west - state: rock_gold +- type: entity + id: WallRockBasaltDiamond + parent: WallRockBasalt + description: An ore vein rich with diamonds. + suffix: Diamond + components: + - type: OreVein + oreChance: 1.0 + currentOre: OreDiamond + - type: Sprite + layers: + - state: rock_wall + - map: [ "enum.EdgeLayer.South" ] + state: rock_wall_south + - map: [ "enum.EdgeLayer.East" ] + state: rock_wall_east + - map: [ "enum.EdgeLayer.North" ] + state: rock_wall_north + - map: [ "enum.EdgeLayer.West" ] + state: rock_wall_west + - state: rock_diamond + - type: entity id: WallRockBasaltPlasma parent: WallRockBasalt @@ -1236,6 +1302,28 @@ state: rock_snow_west - state: rock_gold +- type: entity + id: WallRockSnowDiamond + parent: WallRockSnow + description: An ore vein rich with diamonds. + suffix: Diamond + components: + - type: OreVein + oreChance: 1.0 + currentOre: OreDiamond + - type: Sprite + layers: + - state: rock_snow + - map: [ "enum.EdgeLayer.South" ] + state: rock_snow_south + - map: [ "enum.EdgeLayer.East" ] + state: rock_snow_east + - map: [ "enum.EdgeLayer.North" ] + state: rock_snow_north + - map: [ "enum.EdgeLayer.West" ] + state: rock_snow_west + - state: rock_diamond + - type: entity id: WallRockSnowPlasma parent: WallRockSnow @@ -1479,6 +1567,28 @@ state: rock_sand_west - state: rock_gold +- type: entity + id: WallRockSandDiamond + parent: WallRockSand + description: An ore vein rich with diamonds. + suffix: Diamond + components: + - type: OreVein + oreChance: 1.0 + currentOre: OreDiamond + - type: Sprite + layers: + - state: rock_sand + - map: [ "enum.EdgeLayer.South" ] + state: rock_sand_south + - map: [ "enum.EdgeLayer.East" ] + state: rock_sand_east + - map: [ "enum.EdgeLayer.North" ] + state: rock_sand_north + - map: [ "enum.EdgeLayer.West" ] + state: rock_sand_west + - state: rock_diamond + - type: entity id: WallRockSandPlasma parent: WallRockSand @@ -1589,7 +1699,6 @@ state: rock_sand_west - state: rock_uranium - - type: entity id: WallRockSandBananium parent: WallRockSand @@ -1722,6 +1831,28 @@ state: rock_chromite_west - state: rock_gold +- type: entity + id: WallRockChromiteDiamond + parent: WallRockChromite + description: An ore vein rich with diamonds. + suffix: Diamond + components: + - type: OreVein + oreChance: 1.0 + currentOre: OreDiamond + - type: Sprite + layers: + - state: rock_chromite + - map: [ "enum.EdgeLayer.South" ] + state: rock_chromite_south + - map: [ "enum.EdgeLayer.East" ] + state: rock_chromite_east + - map: [ "enum.EdgeLayer.North" ] + state: rock_chromite_north + - map: [ "enum.EdgeLayer.West" ] + state: rock_chromite_west + - state: rock_diamond + - type: entity id: WallRockChromitePlasma parent: WallRockChromite @@ -1965,6 +2096,28 @@ state: rock_andesite_west - state: rock_gold +- type: entity + id: WallRockAndesiteDiamond + parent: WallRockAndesite + description: An ore vein rich with diamonds. + suffix: Diamond + components: + - type: OreVein + oreChance: 1.0 + currentOre: OreDiamond + - type: Sprite + layers: + - state: rock_andesite + - map: [ "enum.EdgeLayer.South" ] + state: rock_andesite_south + - map: [ "enum.EdgeLayer.East" ] + state: rock_andesite_east + - map: [ "enum.EdgeLayer.North" ] + state: rock_andesite_north + - map: [ "enum.EdgeLayer.West" ] + state: rock_andesite_west + - state: rock_diamond + - type: entity id: WallRockAndesitePlasma parent: WallRockAndesite diff --git a/Resources/Prototypes/Entities/World/Debris/asteroids.yml b/Resources/Prototypes/Entities/World/Debris/asteroids.yml index 061288d010b..2817b083bed 100644 --- a/Resources/Prototypes/Entities/World/Debris/asteroids.yml +++ b/Resources/Prototypes/Entities/World/Debris/asteroids.yml @@ -32,6 +32,9 @@ - id: WallRockGold prob: 0.05 orGroup: rock + - id: WallRockDiamond + prob: 0.005 + orGroup: rock - id: WallRockSilver prob: 0.05 orGroup: rock diff --git a/Resources/Prototypes/Procedural/Magnet/asteroid.yml b/Resources/Prototypes/Procedural/Magnet/asteroid.yml index c20b80af55b..c380dfbc7cf 100644 --- a/Resources/Prototypes/Procedural/Magnet/asteroid.yml +++ b/Resources/Prototypes/Procedural/Magnet/asteroid.yml @@ -6,6 +6,7 @@ OreCoal: 1.0 OreSalt: 1.0 OreGold: 0.25 + OreDiamond: 0.05 OreSilver: 0.25 OrePlasma: 0.15 OreUranium: 0.15 diff --git a/Resources/Prototypes/Procedural/biome_ore_templates.yml b/Resources/Prototypes/Procedural/biome_ore_templates.yml index 4a60427e305..a6e5fac2d84 100644 --- a/Resources/Prototypes/Procedural/biome_ore_templates.yml +++ b/Resources/Prototypes/Procedural/biome_ore_templates.yml @@ -130,6 +130,20 @@ maxGroupSize: 10 radius: 4 +- type: biomeMarkerLayer + id: OreDiamond + entityMask: + AsteroidRock: AsteroidRockDiamond + WallRock: WallRockDiamond + WallRockBasalt: WallRockBasaltDiamond + WallRockChromite: WallRockChromiteDiamond + WallRockSand: WallRockSandDiamond + WallRockSnow: WallRockSnowDiamond + maxCount: 6 + minGroupSize: 1 + maxGroupSize: 2 + radius: 4 + # Artifact Fragment - type: biomeMarkerLayer id: OreArtifactFragment diff --git a/Resources/Prototypes/Procedural/salvage_loot.yml b/Resources/Prototypes/Procedural/salvage_loot.yml index e8783760ddc..da99da7c75b 100644 --- a/Resources/Prototypes/Procedural/salvage_loot.yml +++ b/Resources/Prototypes/Procedural/salvage_loot.yml @@ -178,6 +178,13 @@ - !type:BiomeMarkerLoot proto: OreBananium +- type: salvageLoot + id: OreDiamond + guaranteed: true + loots: + - !type:BiomeMarkerLoot + proto: OreDiamond + - type: salvageLoot id: OreArtifactFragment guaranteed: true diff --git a/Resources/Prototypes/Reagents/Materials/ores.yml b/Resources/Prototypes/Reagents/Materials/ores.yml index 18f1d9ebb3a..1555ab9e234 100644 --- a/Resources/Prototypes/Reagents/Materials/ores.yml +++ b/Resources/Prototypes/Reagents/Materials/ores.yml @@ -24,6 +24,15 @@ color: "#FFD700" price: 0.2 +- type: material + id: RawDiamond + stackEntity: DiamondOre1 + name: materials-raw-diamond + unit: materials-unit-piece + icon: { sprite: Objects/Materials/ore.rsi, state: diamond } + color: "#C9D8F2" + price: 0.5 + - type: material id: RawSilver stackEntity: SilverOre1 diff --git a/Resources/Prototypes/Recipes/Lathes/sheet.yml b/Resources/Prototypes/Recipes/Lathes/sheet.yml index 053715a1811..3efaac95a72 100644 --- a/Resources/Prototypes/Recipes/Lathes/sheet.yml +++ b/Resources/Prototypes/Recipes/Lathes/sheet.yml @@ -127,6 +127,13 @@ materials: RawBananium: 3000 +- type: latheRecipe + id: MaterialDiamond + result: MaterialDiamond1 + completetime: 3 + materials: + RawDiamond: 1000 + - type: latheRecipe id: SheetUranium1 result: SheetUranium1 diff --git a/Resources/Prototypes/Stacks/Materials/ore.yml b/Resources/Prototypes/Stacks/Materials/ore.yml index 51254b5a7a6..3aaa04601aa 100644 --- a/Resources/Prototypes/Stacks/Materials/ore.yml +++ b/Resources/Prototypes/Stacks/Materials/ore.yml @@ -4,6 +4,13 @@ icon: { sprite: /Textures/Objects/Materials/ore.rsi, state: gold } spawn: GoldOre1 maxCount: 30 + +- type: stack + id: DiamondOre + name: rough diamond + icon: { sprite: /Textures/Objects/Materials/ore.rsi, state: diamond } + spawn: DiamondOre1 + maxCount: 30 - type: stack id: SteelOre diff --git a/Resources/Prototypes/ore.yml b/Resources/Prototypes/ore.yml index 9f97ef2cf79..218f327ac58 100644 --- a/Resources/Prototypes/ore.yml +++ b/Resources/Prototypes/ore.yml @@ -58,6 +58,12 @@ minOreYield: 1 maxOreYield: 3 +- type: ore + id: OreDiamond + oreEntity: DiamondOre1 + minOreYield: 1 + maxOreYield: 2 + - type: ore id: OreQuartzCrab oreEntity: MobSpawnCrabQuartz diff --git a/Resources/Textures/Objects/Materials/materials.rsi/diamond-inhand-left.png b/Resources/Textures/Objects/Materials/materials.rsi/diamond-inhand-left.png index c9b55e9daa52ea2f352f43917ffa03611e0c5512..9eae45d039abc1b118d047edae3ca52f3b28bb1f 100644 GIT binary patch delta 59 zcmcc5_=a(U3KwH>kh>GZx^prwCn}2ZTki6(^2$hD_K{2WaO4v0iEeGe?YVjOf1)Nc O0D-5gpUXO@geCxoViiyT delta 48 zcmaFEc%N~C%0xq9ep@RKE3b^iWgod@4@)jFo*3LFoS&QbXX>LG1|aZs^>bP0l+XkK DuM!c9 diff --git a/Resources/Textures/Objects/Materials/materials.rsi/diamond-inhand-right.png b/Resources/Textures/Objects/Materials/materials.rsi/diamond-inhand-right.png index 295c2c4eca1dddeb5fb91200177af77b78a76710..3353eb6f7caea4fa57c518ff3ecf7cf12666714b 100644 GIT binary patch delta 198 zcmaFP_=RzT3KwH>kh>GZx^prwCn}27%jgKX6`nSk64_`t$2CGx_imuV5|LvZ4?QX` z{tw;Oy}bD0DRo8$2#9mredSv8x9n$Eq`pjOdwMf)mY(L^|0lNZTK)FvzvySq*%8x9 zrmJ~cc^+Qtd|+#8=^2|_soQLC_kCg6l_vLA=;^0?L1Sj9Squ!(!W)e*7=GF)A0WKd u_`;<(>{n8bzUC{8E3e3uG-+TMTV zR(fX6Tcg|aa^0(#VvW;xyX^cEeB=z&ECz-H*IeH4Y%$#PhW(1mTb?Z@zZp#zKPqM0 k)pbMiMc@B&h6D9Gn3pWeUD_Nmi4mm9)78&qol`;+04q0CTL1t6 diff --git a/Resources/Textures/Objects/Materials/materials.rsi/diamond.png b/Resources/Textures/Objects/Materials/materials.rsi/diamond.png index 5eb8aabf8796f2a3b5ffce29119ea1b73dbdbb9b..8b39437d0ac358f85f04f69f9a743c0325c6dbc9 100644 GIT binary patch delta 239 zcmV+v2VHk$7F-7iz zT59IzT#MrJ6M&|NsAn|Nr~{|9}7g|C#^)&;S2_|NsB_|Nj^K|L<^4gdeDmrzFTP znBl;G5CD@C)eo!&inn>XIEGZrNlvJjxYH0A5FpU1pOTZ)qN5}8v;Z{M6MdNaCi9S$K>qUP^%Twzu?oMZ=a4G?J8i*bPP;Q4t31j!H_&b>4K~m zhqGi$x`cGJk6Xm)0~uj)acvt|max1qU`%0jGY(;OP@T*gz$zhbw1APZgz*;>LyK^% W=;V3o>MMY5V(@hJb6Mw<&;$V4^l+vC diff --git a/Resources/Textures/Objects/Materials/materials.rsi/diamond_2.png b/Resources/Textures/Objects/Materials/materials.rsi/diamond_2.png new file mode 100644 index 0000000000000000000000000000000000000000..410d83f1c29f1e958fb38d3c0594d059846ffe0e GIT binary patch literal 345 zcmV-f0jBPx$6G=otR9J=Wlrc`jFcgNr07481b?b)8#)fYY#Kcv&1-Hm;Ah|&V3tL&cv_k6s zGuTE}sFY_y>45(wvJ>n3{GMYdDJl8yseZb!k=n6u9;)hgF9MC!uAr`g#g6yyKnKjB z8LgbnrVCF8^vQf2ci&b_5E$&@<_b6m*1%JkycPx$T}ebiR9J=Wls!(vKoo?(MF^#!h@hZD$pyeCz!nu(am5w5h3`Q{1@;XhXwoHZ znvfz5)lhg%R>t<)`B92^Bx}9veV*BQ?=AG`(c{!%whc_A)VC)#COU|KL`oMBhQO%e z`y9xC8_0Yj&UPUWELoX60775^q0g!Ft^x{Vb_{@tvtG=ze-T>>s5rs>7`OzMz&r3* z+7LKGrn?Aeo9i`j>yS_EGiXr*wF1hyo|Ht)$sHI2E8qvX243xakPlvXQ&5-dCGbUF zY!4N2a~Ni}2%B7J?1B(@w&aC~phUiFC)7F+8xz^Ua0Cq5IIys(5(|%-Gs3*(VKO2MgDRD+0!h&1O&fMX zBBd{q+@eaPbS7yg>08o=r1GA*gdL6C6>&839zA+&i(e?myS|8_8-D-* N002ovPDHLkV1hl2wF>|M literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Materials/materials.rsi/meta.json b/Resources/Textures/Objects/Materials/materials.rsi/meta.json index 78f497c0cda..3ae12dc14c0 100644 --- a/Resources/Textures/Objects/Materials/materials.rsi/meta.json +++ b/Resources/Textures/Objects/Materials/materials.rsi/meta.json @@ -78,6 +78,12 @@ { "name": "diamond" }, + { + "name": "diamond_2" + }, + { + "name": "diamond_3" + }, { "name": "diamond-inhand-left", "directions": 4 diff --git a/Resources/Textures/Objects/Materials/ore.rsi/diamond.png b/Resources/Textures/Objects/Materials/ore.rsi/diamond.png new file mode 100644 index 0000000000000000000000000000000000000000..b2a3c788d34c3190e6ff143d2b0cc324597bad94 GIT binary patch literal 390 zcmV;10eSw3P)Px$KuJVFR9J=Wl(9<0KoExih!1epam8)g%X$!NjkqZ+?Cllod<9=5*XJb!3wK2X zOD(eHL8=gtq_7{G+jTt1Og){h-5(|$7t;P6ifNlOA8?n z08s(T&Aa4z{;TGmj{z-&)I!*9F@SSGxVi0`oly`;MMNDD@ie2OvkT&BW@E+@x_@{f zQ#W)qUMq+J93P%wGMxbcCezus`1%1z_GZSeg1WK9_Qw!wU{#2uhKJPb!l3C0pyZ|(wP3GpU2GIZ9Ke6)0cT606jQbG zQRE{KAT|iZ_@G97B0gzCOpGRgkw7Q`%SZ6l2Oq$|gAhqffCr;S6MPb5jF`ZKsjL#K zk#Cfb3YCwP%k_G_?%nR*+}_MDxomE)z2EH2?0?MO&VOdXVzF4_!(I`w zev8E~n>stS))>?M7E6Wj>dBJ@pGsTq+zIXU)8!X&k|Iv(HRq&=I4Kb)8Kysxyet=sIk%a_htLt10Dw?fk9v(kytiZ3cu@~3`_&6fL@>-=o%{x ze*J+nIv?A*yMN`Qnwp{=K{6nyKf}EkSPHBL4g|!tc3PqiTMl{a#horGctC_x)P;^Mccm?e|>(ue^|AZ*A?c zf8Koi_NWE2p`#;cVGW|%`~yH&ZG9Clr*549_5lxo!3h1H`!K56>60Z{RYe>jR!gH9KA(@G;OzNPR%r761%oL^Z0-ACIc} z{}N&5XSuzLfF-DA=OA#3kTM_2ya1s1-vJ@Ii@pplDeG_C(0bD;O23Gc@Lpm2L%R&^ z>FMF!_I7QB5T!qnSSH>}hu>0;e64w8$SD68B7gE}d-1{@>2#pP8smTC^y!>`_@jud zY;E=RCA$LD4AcFVxbpsqeyyc$wEvx}SG69z>3&}v)Z8wb?zdPf2;G-iru!`xi^XCv zy5r+b_gmtI?)Z4q{T54wVCwvUlKb~$_43{X1revZkO>M$MdYh)ku{eu7nF!>f3d{X zKYt82^Xo*M#UjpfcU$MT5Vm!9YwdvI;2$;6NN0S$N#qO6(ixv08L{!ZZT@l*r&Ywc z^!tD3jc><|mY!Ki?UkGd_O=8s;aI#P6pMD0zIoN#qSr*BPI0 z3S-U>&>5d^DS%3z9}uPA&JU;%zopa|6@Q3&Px&>bIdy5C}{ z5R8e>*X`FGA8)!pRN@eyU&($;ITD-r{BrYGYJ7fN{QQukb1G$gzUh98#bPOE;(r>S zuiGEm{D5>%59{08rO+AmVWB%dzgT}Lk1&bVqdv-vqR#*?K0a$k{fodS?sfq%IjS?E zQsxKvDu7(^@v9y_aMPPnzXaG0%yhRyPn(M(K7Z9H4;&2?pC5uh7y10d3ShMO_{V`G z*M1r8JG`gPtpz6DU}8Nmk&LI!?SHDS_LbNo{X>X2vYVwN3ZYbf$Q`(q&mXuC5OGq# zJXEu@9hLb#z;56;a6XY()*sYUKzbyRSXTCr=kf^SDrn$?pBMdsdcfIk;EKCFh3be0 zLU80IGd^EO=4+oH5OiIkp#G>GDTPziX?)Z4q{T7SGVt+9h-SP32 z=8w%ilR}8oGHaoYh-KpbDxM(XRBh?(lv0k4WsFbE0~URFcSau(j!TS|2Jf!GSjQjw z8Q{vQP%G_D0PX`ff!?TVVb2^Ygf0rd%Q#e_&jhx9(_6n1weI#zMpjIFg?|*krBl;UwQ^{L zE<%42)$BC?#f%m6k`ws+)}$4v3NSvGdqe@W6foAAgF#fAzwsIVIeU%));xCaEU?kt zKW6(I(BF${^V3gq`&w7xKF?P7Ujx$a{@$_D5W?|40QN29>amM5z?)O=9V27C?d*RD zwG+H}uFY1oGvCCs_rcBq}O z`{iCt&}HCtcRQ5%5y$6up)$D@*n_(I*h5CqBO9i3(GRt(oC1m~wF?fKdtyPz}00000NkvXXu0mjfAd}HG literal 1307 zcmeAS@N?(olHy`uVBq!ia0vp^2|(Py!3HG1+{xJmq&N#aB8wRq_>O=u<5X=vX$A(C zvz{)FAr*7p&OPWI;wW=GUD3cNXrkAIv(0isO?=N(KP-`3Rb28ig`>11DCm>EfXS8@ z0RoaC0vC7gdanCfOybGWGXYK^1*-m+`wV}TeLs1wI{#Vi{p#O;n>Os;@q6aa+WY6; zoI5w&QcYt;21A4i!V>*DHOyyPq~y?guCr2bj6*2FYMJ`I;Jh@JD)y+&=;f)D*iuiw<< z*tmC(PW-m*()Qc0{SamAiJ0|ty-57?f9L!boKv5v|1^B&=~$CG-QazfEgvL0H*e)M z$Y9L*Bx>y=?ek-!{~_~f)1J&ecg~@eGnzrV=Ipn7{g>K`_HAV3xBEY}TKwA)pXB5v zOf98VB3#b_O+kfmzYiY+{^po^;%)(osU)h_wC-PDQ|B6+w94=U%P6m zp7}gcbSMoejrjQcsQJUUJF@qst-d{Lz5Mp0=4J^8(u=IP)}<`|5w%O;X?Uzm&DnS2 z-0a_TKLvkw)p>P8erj&=zmLILJPxO?vL>8uh|bRb6q&94M$1?G{w&5;Cr6&O>rOq- z&7GjMWNQA|hU>Dj7ebG3`Q$A9A31>g2Cq z7kbYc?LX4+y1V;RYKmAH8;@ndi4EY+#ap@ZC_`FSS?xMuXvp+m_iie2xhh88!e@!5Q|3pU8Ml%fTc&hBN6< zY%bR{;rHjmTD&#N%s@u2cIKZ|Yzp6>SGS&0-|;Nmlwqg+eeDptgQoX0IGo;{zwY!* zIObEYdg7CRe{{Ocp18XG8oK9#*+c1Zs zCoNne;CXL;{^b4Vo#x6f_ILaHq*M9azK&3iBEK44-F0vGH8~ANvg=4*z60a%#o&xh-ZP$=0XY zHGX_3TfUWv<>Bi`+W&kWPnv4Bq;dA(F^(@tY?vJ_x`KxT% z#SS;zrr3*J|MzDxmq5DRfhGTEo@4(Z+VHbs!mDIEh1tJ9U#wZz*5t~3068r@|H+tO zcOK~U$~s_td Date: Sat, 13 Jul 2024 12:17:05 +0000 Subject: [PATCH 201/765] Automatic changelog update --- Resources/Changelog/Changelog.yml | 23 +++++++++-------------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index ca549b51fb3..e4c8aa1b430 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,18 +1,4 @@ Entries: -- author: FairlySadPanda - changes: - - message: Xenoarchaeology Traversal Distorters have been rolled into the Artifact - Analyzers to make artifact gameplay a bit more controlled. - type: Tweak - - message: The T2 Abnormal Artifact Manipulation tech has been made cheaper to compensate - for losing an unlock. - type: Tweak - - message: The Xenoarchaeology guidebook entry has been rewritten to be more useful - and comprehensive for newbies. - type: Tweak - id: 6415 - time: '2024-04-21T16:09:26.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/26545 - author: deltanedas changes: - message: Flaming mice no longer completely engulf people they touch. @@ -3818,3 +3804,12 @@ id: 6914 time: '2024-07-13T06:09:19.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/29550 +- author: TheShuEd + changes: + - message: Added diamonds ore! + type: Add + - message: Diamonds can now be sold at a bargain price. + type: Add + id: 6915 + time: '2024-07-13T12:15:57.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/25750 From 6aa44e47ff00a6bb1600e29f43290df1843d9f82 Mon Sep 17 00:00:00 2001 From: Ed <96445749+TheShuEd@users.noreply.github.com> Date: Sat, 13 Jul 2024 15:45:35 +0300 Subject: [PATCH 202/765] Vgroid diamonds hotfix (#29999) vgroid diamonds --- .../Entities/Structures/Walls/asteroid.yml | 22 +++++++++++++++++++ Resources/Prototypes/Procedural/vgroid.yml | 6 +++++ 2 files changed, 28 insertions(+) diff --git a/Resources/Prototypes/Entities/Structures/Walls/asteroid.yml b/Resources/Prototypes/Entities/Structures/Walls/asteroid.yml index c0a30e76694..4673405e03f 100644 --- a/Resources/Prototypes/Entities/Structures/Walls/asteroid.yml +++ b/Resources/Prototypes/Entities/Structures/Walls/asteroid.yml @@ -611,6 +611,28 @@ state: ironrock_west - state: rock_artifact_fragment +- type: entity + id: IronRockDiamond + parent: IronRock + description: An ore vein rich with diamonds. + suffix: Diamond + components: + - type: OreVein + oreChance: 1.0 + currentOre: OreDiamond + - type: Sprite + layers: + - state: ironrock + - map: [ "enum.EdgeLayer.South" ] + state: ironrock_south + - map: [ "enum.EdgeLayer.East" ] + state: ironrock_east + - map: [ "enum.EdgeLayer.North" ] + state: ironrock_north + - map: [ "enum.EdgeLayer.West" ] + state: ironrock_west + - state: rock_diamond + # Rocks and ore veins - type: entity id: WallRock diff --git a/Resources/Prototypes/Procedural/vgroid.yml b/Resources/Prototypes/Procedural/vgroid.yml index 49e956e73f5..6e9fc6f3957 100644 --- a/Resources/Prototypes/Procedural/vgroid.yml +++ b/Resources/Prototypes/Procedural/vgroid.yml @@ -82,6 +82,12 @@ count: 50 minGroupSize: 2 maxGroupSize: 4 + - !type:OreDunGen + replacement: IronRock + entity: IronRockDiamond + count: 15 + minGroupSize: 1 + maxGroupSize: 2 # Configs - type: dungeonConfig From 00e712129ed389c97ee26b882826ade10cd1f1de Mon Sep 17 00:00:00 2001 From: Winkarst <74284083+Winkarst-cpu@users.noreply.github.com> Date: Sat, 13 Jul 2024 19:45:34 +0300 Subject: [PATCH 203/765] Update RadiationPulseOverlay.cs to have 0 warnings (#30004) --- Content.Client/Radiation/Overlays/RadiationPulseOverlay.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Content.Client/Radiation/Overlays/RadiationPulseOverlay.cs b/Content.Client/Radiation/Overlays/RadiationPulseOverlay.cs index 8d5607af2d0..9ec24fae0ef 100644 --- a/Content.Client/Radiation/Overlays/RadiationPulseOverlay.cs +++ b/Content.Client/Radiation/Overlays/RadiationPulseOverlay.cs @@ -116,7 +116,9 @@ private void RadiationQuery(IEye? currentEye) var shaderInstance = _pulses[pulseEntity]; shaderInstance.instance.CurrentMapCoords = _transform.GetMapCoordinates(pulseEntity); shaderInstance.instance.Range = pulse.VisualRange; - } else { + } + else + { _pulses[pulseEntity].shd.Dispose(); _pulses.Remove(pulseEntity); } @@ -129,7 +131,7 @@ private bool PulseQualifies(EntityUid pulseEntity, MapCoordinates currentEyeLoc) var transformComponent = _entityManager.GetComponent(pulseEntity); var transformSystem = _entityManager.System(); return transformComponent.MapID == currentEyeLoc.MapId - && transformComponent.Coordinates.InRange(_entityManager, transformSystem, EntityCoordinates.FromMap(transformComponent.ParentUid, currentEyeLoc, transformSystem, _entityManager), MaxDist); + && transformSystem.InRange(transformComponent.Coordinates, transformSystem.ToCoordinates(transformComponent.ParentUid, currentEyeLoc), MaxDist); } private sealed record RadiationShaderInstance(MapCoordinates CurrentMapCoords, float Range, TimeSpan Start, float Duration) From 5717bc407be4e6f7912ff69640cf5b2da837bd50 Mon Sep 17 00:00:00 2001 From: Pieter-Jan Briers Date: Sat, 13 Jul 2024 19:34:17 +0200 Subject: [PATCH 204/765] New CDN publish workflow (#30009) * LET'S SEE IF THIS WORKS * I forgot the chmod +x * I forgot the shebang --- .github/workflows/publish.yml | 2 +- SpaceStation14.sln | 1 - Tools/publish_github_artifact.py | 2 +- 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 3c2b00666a1..16cb5017d6a 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -72,4 +72,4 @@ jobs: - uses: geekyeggo/delete-artifact@v5 if: always() with: - name: build \ No newline at end of file + name: build diff --git a/SpaceStation14.sln b/SpaceStation14.sln index e0cb455a6db..bcd013b5981 100644 --- a/SpaceStation14.sln +++ b/SpaceStation14.sln @@ -62,7 +62,6 @@ EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Build", "Build", "{806ED41A-411B-4B3B-BEB6-DEC6DCA4C205}" ProjectSection(SolutionItems) = preProject Tools\generate_hashes.ps1 = Tools\generate_hashes.ps1 - Tools\gen_build_info.py = Tools\gen_build_info.py EndProjectSection EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Robust.Shared.Scripting", "RobustToolbox\Robust.Shared.Scripting\Robust.Shared.Scripting.csproj", "{41B450C0-A361-4CD7-8121-7072B8995CFC}" diff --git a/Tools/publish_github_artifact.py b/Tools/publish_github_artifact.py index 9daa12782c9..145dc69b228 100755 --- a/Tools/publish_github_artifact.py +++ b/Tools/publish_github_artifact.py @@ -53,4 +53,4 @@ def get_engine_version() -> str: if __name__ == '__main__': - main() \ No newline at end of file + main() From f1d3ed9efc72dd1df3edb83c03a19302ea6f62aa Mon Sep 17 00:00:00 2001 From: Pieter-Jan Briers Date: Sat, 13 Jul 2024 22:36:20 +0200 Subject: [PATCH 205/765] Remove outdated steps from Test Packaging workflow (#30018) gen build info was removed in 5e800e0ece7beadeb06bba901dd573e84fa4c133 but I didn't realize this workflow also tested it. Gone now. --- .github/workflows/test-packaging.yml | 5 ----- 1 file changed, 5 deletions(-) diff --git a/.github/workflows/test-packaging.yml b/.github/workflows/test-packaging.yml index 725eb2ef1e6..014cf3f5109 100644 --- a/.github/workflows/test-packaging.yml +++ b/.github/workflows/test-packaging.yml @@ -64,8 +64,3 @@ jobs: - name: Package client run: dotnet run --project Content.Packaging client --no-wipe-release - - - name: Shuffle files around - run: | - mkdir "release/${{ github.sha }}" - mv release/*.zip "release/${{ github.sha }}" From ae0a69d769ab4ba2e715deb166f7d567559e4ede Mon Sep 17 00:00:00 2001 From: Plykiya <58439124+Plykiya@users.noreply.github.com> Date: Sat, 13 Jul 2024 14:05:22 -0700 Subject: [PATCH 206/765] Replace obsolete xform.ToMap() with xformSystem.ToMapCoordinates() (#30010) * Get rid of a bunch of obsolete usages * position --------- Co-authored-by: plykiya --- .../Construction/ConstructionSystem.cs | 6 +++--- .../ContextMenu/UI/EntityMenuUIController.cs | 2 +- Content.Client/Gameplay/GameplayStateBase.cs | 3 ++- .../Movement/Systems/JetpackSystem.cs | 5 +++-- Content.Client/NPC/PathfindingSystem.cs | 18 +++++++++--------- Content.Client/Physics/JointVisualsOverlay.cs | 4 ++-- Content.Client/Pinpointer/UI/NavMapControl.cs | 14 +++++++------- Content.Client/RCD/AlignRCDConstruction.cs | 6 +++--- Content.Client/Sandbox/SandboxSystem.cs | 6 ++++-- .../Shuttles/Systems/ShuttleSystem.Console.cs | 4 ++-- .../Shuttles/UI/ShuttleMapControl.xaml.cs | 2 +- .../Storage/Systems/StorageSystem.cs | 4 ++-- .../Weapons/Melee/MeleeWeaponSystem.cs | 2 +- .../Weapons/Ranged/Systems/GunSystem.cs | 6 +++--- .../Pointing/EntitySystems/PointingSystem.cs | 5 ++--- Content.Shared/Actions/SharedActionsSystem.cs | 2 +- 16 files changed, 46 insertions(+), 43 deletions(-) diff --git a/Content.Client/Construction/ConstructionSystem.cs b/Content.Client/Construction/ConstructionSystem.cs index 453658bebf9..889c992f7f6 100644 --- a/Content.Client/Construction/ConstructionSystem.cs +++ b/Content.Client/Construction/ConstructionSystem.cs @@ -48,11 +48,11 @@ public override void Initialize() CommandBinds.Builder .Bind(ContentKeyFunctions.OpenCraftingMenu, - new PointerInputCmdHandler(HandleOpenCraftingMenu, outsidePrediction:true)) + new PointerInputCmdHandler(HandleOpenCraftingMenu, outsidePrediction: true)) .Bind(EngineKeyFunctions.Use, new PointerInputCmdHandler(HandleUse, outsidePrediction: true)) .Bind(ContentKeyFunctions.EditorFlipObject, - new PointerInputCmdHandler(HandleFlip, outsidePrediction:true)) + new PointerInputCmdHandler(HandleFlip, outsidePrediction: true)) .Register(); SubscribeLocalEvent(HandleConstructionGhostExamined); @@ -196,7 +196,7 @@ public bool TrySpawnGhost( if (GhostPresent(loc)) return false; - var predicate = GetPredicate(prototype.CanBuildInImpassable, loc.ToMap(EntityManager, _transformSystem)); + var predicate = GetPredicate(prototype.CanBuildInImpassable, _transformSystem.ToMapCoordinates(loc)); if (!_examineSystem.InRangeUnOccluded(user, loc, 20f, predicate: predicate)) return false; diff --git a/Content.Client/ContextMenu/UI/EntityMenuUIController.cs b/Content.Client/ContextMenu/UI/EntityMenuUIController.cs index a60619baa35..0462c095ba8 100644 --- a/Content.Client/ContextMenu/UI/EntityMenuUIController.cs +++ b/Content.Client/ContextMenu/UI/EntityMenuUIController.cs @@ -170,7 +170,7 @@ private bool HandleOpenEntityMenu(in PointerInputCmdHandler.PointerInputCmdArgs if (_combatMode.IsInCombatMode(args.Session?.AttachedEntity)) return false; - var coords = args.Coordinates.ToMap(_entityManager, _xform); + var coords = _xform.ToMapCoordinates(args.Coordinates); if (_verbSystem.TryGetEntityMenuEntities(coords, out var entities)) OpenRootMenu(entities); diff --git a/Content.Client/Gameplay/GameplayStateBase.cs b/Content.Client/Gameplay/GameplayStateBase.cs index 6236cd8e958..63cbfdb09c6 100644 --- a/Content.Client/Gameplay/GameplayStateBase.cs +++ b/Content.Client/Gameplay/GameplayStateBase.cs @@ -104,7 +104,8 @@ private bool HandleInspect(ICommonSession? session, EntityCoordinates coords, En public IEnumerable GetClickableEntities(EntityCoordinates coordinates) { - return GetClickableEntities(coordinates.ToMap(_entityManager, _entitySystemManager.GetEntitySystem())); + var transformSystem = _entitySystemManager.GetEntitySystem(); + return GetClickableEntities(transformSystem.ToMapCoordinates(coordinates)); } public IEnumerable GetClickableEntities(MapCoordinates coordinates) diff --git a/Content.Client/Movement/Systems/JetpackSystem.cs b/Content.Client/Movement/Systems/JetpackSystem.cs index b7f5e48821f..e25300d44c5 100644 --- a/Content.Client/Movement/Systems/JetpackSystem.cs +++ b/Content.Client/Movement/Systems/JetpackSystem.cs @@ -15,6 +15,7 @@ public sealed class JetpackSystem : SharedJetpackSystem [Dependency] private readonly IGameTiming _timing = default!; [Dependency] private readonly ClothingSystem _clothing = default!; [Dependency] private readonly SharedTransformSystem _transform = default!; + [Dependency] private readonly SharedMapSystem _mapSystem = default!; public override void Initialize() { @@ -73,11 +74,11 @@ private void CreateParticles(EntityUid uid) var uidXform = Transform(uid); var coordinates = uidXform.Coordinates; - var gridUid = coordinates.GetGridUid(EntityManager); + var gridUid = _transform.GetGrid(coordinates); if (TryComp(gridUid, out var grid)) { - coordinates = new EntityCoordinates(gridUid.Value, grid.WorldToLocal(coordinates.ToMapPos(EntityManager, _transform))); + coordinates = new EntityCoordinates(gridUid.Value, _mapSystem.WorldToLocal(gridUid.Value, grid, _transform.ToMapCoordinates(coordinates).Position)); } else if (uidXform.MapUid != null) { diff --git a/Content.Client/NPC/PathfindingSystem.cs b/Content.Client/NPC/PathfindingSystem.cs index d3ae5091528..0c72a8f99ff 100644 --- a/Content.Client/NPC/PathfindingSystem.cs +++ b/Content.Client/NPC/PathfindingSystem.cs @@ -203,7 +203,7 @@ private void DrawScreen(OverlayDrawArgs args, DrawingHandleScreen screenHandle) if (found || !_system.Breadcrumbs.TryGetValue(netGrid, out var crumbs) || !xformQuery.TryGetComponent(grid, out var gridXform)) continue; - var (_, _, worldMatrix, invWorldMatrix) = gridXform.GetWorldPositionRotationMatrixWithInv(); + var (_, _, worldMatrix, invWorldMatrix) = _transformSystem.GetWorldPositionRotationMatrixWithInv(gridXform); var localAABB = invWorldMatrix.TransformBox(aabb.Enlarged(float.Epsilon - SharedPathfindingSystem.ChunkSize)); foreach (var chunk in crumbs) @@ -287,7 +287,7 @@ private void DrawScreen(OverlayDrawArgs args, DrawingHandleScreen screenHandle) return; } - var invGridMatrix = gridXform.InvWorldMatrix; + var invGridMatrix = _transformSystem.GetInvWorldMatrix(gridXform); DebugPathPoly? nearest = null; foreach (var poly in tile) @@ -359,7 +359,7 @@ private void DrawWorld(OverlayDrawArgs args, DrawingHandleWorld worldHandle) continue; } - var (_, _, worldMatrix, invWorldMatrix) = gridXform.GetWorldPositionRotationMatrixWithInv(); + var (_, _, worldMatrix, invWorldMatrix) = _transformSystem.GetWorldPositionRotationMatrixWithInv(gridXform); worldHandle.SetTransform(worldMatrix); var localAABB = invWorldMatrix.TransformBox(aabb); @@ -419,7 +419,7 @@ private void DrawWorld(OverlayDrawArgs args, DrawingHandleWorld worldHandle) !xformQuery.TryGetComponent(grid, out var gridXform)) continue; - var (_, _, worldMatrix, invWorldMatrix) = gridXform.GetWorldPositionRotationMatrixWithInv(); + var (_, _, worldMatrix, invWorldMatrix) = _transformSystem.GetWorldPositionRotationMatrixWithInv(gridXform); worldHandle.SetTransform(worldMatrix); var localAABB = invWorldMatrix.TransformBox(aabb); @@ -458,7 +458,7 @@ private void DrawWorld(OverlayDrawArgs args, DrawingHandleWorld worldHandle) !xformQuery.TryGetComponent(grid, out var gridXform)) continue; - var (_, _, worldMatrix, invMatrix) = gridXform.GetWorldPositionRotationMatrixWithInv(); + var (_, _, worldMatrix, invMatrix) = _transformSystem.GetWorldPositionRotationMatrixWithInv(gridXform); worldHandle.SetTransform(worldMatrix); var localAABB = invMatrix.TransformBox(aabb); @@ -483,7 +483,7 @@ private void DrawWorld(OverlayDrawArgs args, DrawingHandleWorld worldHandle) if (neighborPoly.NetEntity != poly.GraphUid) { color = Color.Green; - var neighborMap = _entManager.GetCoordinates(neighborPoly).ToMap(_entManager, _transformSystem); + var neighborMap = _transformSystem.ToMapCoordinates(_entManager.GetCoordinates(neighborPoly)); if (neighborMap.MapId != args.MapId) continue; @@ -517,7 +517,7 @@ private void DrawWorld(OverlayDrawArgs args, DrawingHandleWorld worldHandle) !xformQuery.TryGetComponent(grid, out var gridXform)) continue; - var (_, _, worldMatrix, invWorldMatrix) = gridXform.GetWorldPositionRotationMatrixWithInv(); + var (_, _, worldMatrix, invWorldMatrix) = _transformSystem.GetWorldPositionRotationMatrixWithInv(gridXform); worldHandle.SetTransform(worldMatrix); var localAABB = invWorldMatrix.TransformBox(args.WorldBounds); @@ -544,7 +544,7 @@ private void DrawWorld(OverlayDrawArgs args, DrawingHandleWorld worldHandle) if (!_entManager.TryGetComponent(_entManager.GetEntity(node.GraphUid), out var graphXform)) continue; - worldHandle.SetTransform(graphXform.WorldMatrix); + worldHandle.SetTransform(_transformSystem.GetWorldMatrix(graphXform)); worldHandle.DrawRect(node.Box, Color.Orange.WithAlpha(0.10f)); } } @@ -568,7 +568,7 @@ private void DrawWorld(OverlayDrawArgs args, DrawingHandleWorld worldHandle) continue; matrix = graph; - worldHandle.SetTransform(graphXform.WorldMatrix); + worldHandle.SetTransform(_transformSystem.GetWorldMatrix(graphXform)); } worldHandle.DrawRect(node.Box, new Color(0f, cost / highestGScore, 1f - (cost / highestGScore), 0.10f)); diff --git a/Content.Client/Physics/JointVisualsOverlay.cs b/Content.Client/Physics/JointVisualsOverlay.cs index 09c02746e2e..e0b3499a974 100644 --- a/Content.Client/Physics/JointVisualsOverlay.cs +++ b/Content.Client/Physics/JointVisualsOverlay.cs @@ -58,8 +58,8 @@ protected override void Draw(in OverlayDrawArgs args) coordsA = coordsA.Offset(rotA.RotateVec(visuals.OffsetA)); coordsB = coordsB.Offset(rotB.RotateVec(visuals.OffsetB)); - var posA = coordsA.ToMapPos(_entManager, xformSystem); - var posB = coordsB.ToMapPos(_entManager, xformSystem); + var posA = xformSystem.ToMapCoordinates(coordsA).Position; + var posB = xformSystem.ToMapCoordinates(coordsB).Position; var diff = (posB - posA); var length = diff.Length(); diff --git a/Content.Client/Pinpointer/UI/NavMapControl.cs b/Content.Client/Pinpointer/UI/NavMapControl.cs index 3c99a188181..413b41c36a6 100644 --- a/Content.Client/Pinpointer/UI/NavMapControl.cs +++ b/Content.Client/Pinpointer/UI/NavMapControl.cs @@ -228,8 +228,8 @@ protected override void KeyBindUp(GUIBoundKeyEventArgs args) { if (!blip.Selectable) continue; - - var currentDistance = (blip.Coordinates.ToMapPos(EntManager, _transformSystem) - worldPosition).Length(); + + var currentDistance = (_transformSystem.ToMapCoordinates(blip.Coordinates).Position - worldPosition).Length(); if (closestDistance < currentDistance || currentDistance * MinimapScale > MaxSelectableDistance) continue; @@ -397,7 +397,7 @@ protected override void Draw(DrawingHandleScreen handle) { if (lit && value.Visible) { - var mapPos = coord.ToMap(EntManager, _transformSystem); + var mapPos = _transformSystem.ToMapCoordinates(coord); if (mapPos.MapId != MapId.Nullspace) { @@ -418,7 +418,7 @@ protected override void Draw(DrawingHandleScreen handle) if (blip.Texture == null) continue; - var mapPos = blip.Coordinates.ToMap(EntManager, _transformSystem); + var mapPos = _transformSystem.ToMapCoordinates(blip.Coordinates); if (mapPos.MapId != MapId.Nullspace) { @@ -535,7 +535,7 @@ private void UpdateNavMapWallLines() // East edge neighborData = 0; if (relativeTile.X != SharedNavMapSystem.ChunkSize - 1) - neighborData = chunk.TileData[i+SharedNavMapSystem.ChunkSize]; + neighborData = chunk.TileData[i + SharedNavMapSystem.ChunkSize]; else if (_navMap.Chunks.TryGetValue(chunkOrigin + Vector2i.Right, out neighborChunk)) neighborData = neighborChunk.TileData[i + SharedNavMapSystem.ChunkSize - SharedNavMapSystem.ArraySize]; @@ -548,7 +548,7 @@ private void UpdateNavMapWallLines() // South edge neighborData = 0; if (relativeTile.Y != 0) - neighborData = chunk.TileData[i-1]; + neighborData = chunk.TileData[i - 1]; else if (_navMap.Chunks.TryGetValue(chunkOrigin + Vector2i.Down, out neighborChunk)) neighborData = neighborChunk.TileData[i - 1 + SharedNavMapSystem.ChunkSize]; @@ -561,7 +561,7 @@ private void UpdateNavMapWallLines() // West edge neighborData = 0; if (relativeTile.X != 0) - neighborData = chunk.TileData[i-SharedNavMapSystem.ChunkSize]; + neighborData = chunk.TileData[i - SharedNavMapSystem.ChunkSize]; else if (_navMap.Chunks.TryGetValue(chunkOrigin + Vector2i.Left, out neighborChunk)) neighborData = neighborChunk.TileData[i - SharedNavMapSystem.ChunkSize + SharedNavMapSystem.ArraySize]; diff --git a/Content.Client/RCD/AlignRCDConstruction.cs b/Content.Client/RCD/AlignRCDConstruction.cs index d5425425a76..fcbe408a382 100644 --- a/Content.Client/RCD/AlignRCDConstruction.cs +++ b/Content.Client/RCD/AlignRCDConstruction.cs @@ -45,7 +45,7 @@ public override void AlignPlacementMode(ScreenCoordinates mouseScreen) _unalignedMouseCoords = ScreenToCursorGrid(mouseScreen); MouseCoords = _unalignedMouseCoords.AlignWithClosestGridTile(SearchBoxSize, _entityManager, _mapManager); - var gridId = MouseCoords.GetGridUid(_entityManager); + var gridId = _transformSystem.GetGrid(MouseCoords); if (!_entityManager.TryGetComponent(gridId, out var mapGrid)) return; @@ -105,8 +105,8 @@ public override bool IsValidPosition(EntityCoordinates position) if (currentState is not GameplayStateBase screen) return false; - - var target = screen.GetClickedEntity(_unalignedMouseCoords.ToMap(_entityManager, _transformSystem)); + + var target = screen.GetClickedEntity(_transformSystem.ToMapCoordinates(_unalignedMouseCoords)); // Determine if the RCD operation is valid or not if (!_rcdSystem.IsRCDOperationStillValid(heldEntity.Value, rcd, mapGridData.Value, target, player.Value, false)) diff --git a/Content.Client/Sandbox/SandboxSystem.cs b/Content.Client/Sandbox/SandboxSystem.cs index 6a1129bb75d..8a4c93fa354 100644 --- a/Content.Client/Sandbox/SandboxSystem.cs +++ b/Content.Client/Sandbox/SandboxSystem.cs @@ -17,6 +17,7 @@ public sealed class SandboxSystem : SharedSandboxSystem [Dependency] private readonly IPlacementManager _placement = default!; [Dependency] private readonly ContentEyeSystem _contentEye = default!; [Dependency] private readonly SharedTransformSystem _transform = default!; + [Dependency] private readonly SharedMapSystem _mapSystem = default!; private bool _sandboxEnabled; public bool SandboxAllowed { get; private set; } @@ -92,7 +93,7 @@ public bool Copy(ICommonSession? session, EntityCoordinates coords, EntityUid ui && EntityManager.TryGetComponent(uid, out MetaDataComponent? comp) && !comp.EntityDeleted) { - if (comp.EntityPrototype == null || comp.EntityPrototype.NoSpawn || comp.EntityPrototype.Abstract) + if (comp.EntityPrototype == null || comp.EntityPrototype.HideSpawnMenu || comp.EntityPrototype.Abstract) return false; if (_placement.Eraser) @@ -109,7 +110,8 @@ public bool Copy(ICommonSession? session, EntityCoordinates coords, EntityUid ui } // Try copy tile. - if (!_map.TryFindGridAt(coords.ToMap(EntityManager, _transform), out _, out var grid) || !grid.TryGetTileRef(coords, out var tileRef)) + + if (!_map.TryFindGridAt(_transform.ToMapCoordinates(coords), out var gridUid, out var grid) || !_mapSystem.TryGetTileRef(gridUid, grid, coords, out var tileRef)) return false; if (_placement.Eraser) diff --git a/Content.Client/Shuttles/Systems/ShuttleSystem.Console.cs b/Content.Client/Shuttles/Systems/ShuttleSystem.Console.cs index c134b7157c4..eb9ec285f8c 100644 --- a/Content.Client/Shuttles/Systems/ShuttleSystem.Console.cs +++ b/Content.Client/Shuttles/Systems/ShuttleSystem.Console.cs @@ -35,9 +35,9 @@ public MapCoordinates GetMapCoordinates(IMapObject mapObj) switch (mapObj) { case ShuttleBeaconObject beacon: - return GetCoordinates(beacon.Coordinates).ToMap(EntityManager, XformSystem); + return XformSystem.ToMapCoordinates(GetCoordinates(beacon.Coordinates)); case ShuttleExclusionObject exclusion: - return GetCoordinates(exclusion.Coordinates).ToMap(EntityManager, XformSystem); + return XformSystem.ToMapCoordinates(GetCoordinates(exclusion.Coordinates)); case GridMapObject grid: var gridXform = Transform(grid.Entity); diff --git a/Content.Client/Shuttles/UI/ShuttleMapControl.xaml.cs b/Content.Client/Shuttles/UI/ShuttleMapControl.xaml.cs index 8bd4a338cb0..53ad4a0b23a 100644 --- a/Content.Client/Shuttles/UI/ShuttleMapControl.xaml.cs +++ b/Content.Client/Shuttles/UI/ShuttleMapControl.xaml.cs @@ -519,7 +519,7 @@ private void AddMapObject(List edges, List verts, ValueList(gunUid); _animPlayer.Stop(gunUid, uidPlayer, "muzzle-flash-light"); - _animPlayer.Play((gunUid, uidPlayer), animTwo,"muzzle-flash-light"); + _animPlayer.Play((gunUid, uidPlayer), animTwo, "muzzle-flash-light"); } } diff --git a/Content.Server/Pointing/EntitySystems/PointingSystem.cs b/Content.Server/Pointing/EntitySystems/PointingSystem.cs index 9dc3b5e1e67..ca7791fb68a 100644 --- a/Content.Server/Pointing/EntitySystems/PointingSystem.cs +++ b/Content.Server/Pointing/EntitySystems/PointingSystem.cs @@ -145,8 +145,7 @@ public bool TryPoint(ICommonSession? session, EntityCoordinates coordsPointed, E _popup.PopupEntity(Loc.GetString("pointing-system-try-point-cannot-reach"), player, player); return false; } - - var mapCoordsPointed = coordsPointed.ToMap(EntityManager, _transform); + var mapCoordsPointed = _transform.ToMapCoordinates(coordsPointed); _rotateToFaceSystem.TryFaceCoordinates(player, mapCoordsPointed.Position); var arrow = EntityManager.SpawnEntity("PointingArrow", coordsPointed); @@ -154,7 +153,7 @@ public bool TryPoint(ICommonSession? session, EntityCoordinates coordsPointed, E if (TryComp(arrow, out var pointing)) { if (TryComp(player, out TransformComponent? xformPlayer)) - pointing.StartPosition = EntityCoordinates.FromMap(arrow, xformPlayer.Coordinates.ToMap(EntityManager, _transform), _transform).Position; + pointing.StartPosition = _transform.ToCoordinates((player, xformPlayer), _transform.ToMapCoordinates(xformPlayer.Coordinates)).Position; pointing.EndTime = _gameTiming.CurTime + PointDuration; diff --git a/Content.Shared/Actions/SharedActionsSystem.cs b/Content.Shared/Actions/SharedActionsSystem.cs index 0e302f1e028..49c137468e4 100644 --- a/Content.Shared/Actions/SharedActionsSystem.cs +++ b/Content.Shared/Actions/SharedActionsSystem.cs @@ -427,7 +427,7 @@ private void OnActionRequest(RequestPerformActionEvent ev, EntitySessionEventArg } var entityCoordinatesTarget = GetCoordinates(netCoordinatesTarget); - _rotateToFaceSystem.TryFaceCoordinates(user, entityCoordinatesTarget.ToMapPos(EntityManager, _transformSystem)); + _rotateToFaceSystem.TryFaceCoordinates(user, _transformSystem.ToMapCoordinates(entityCoordinatesTarget).Position); if (!ValidateWorldTarget(user, entityCoordinatesTarget, (actionEnt, worldAction))) return; From 1f8b8180e5c3827ff1a4ea0724644c3477a45f76 Mon Sep 17 00:00:00 2001 From: Plykiya <58439124+Plykiya@users.noreply.github.com> Date: Sat, 13 Jul 2024 14:25:51 -0700 Subject: [PATCH 207/765] Replace obsolete EntityCoordiates.InRange() with TransformSystem.InRange() (#29993) * Replace EntityCoordiates.InRange() with TransformSystem.InRange() * nullspace * I figured it out * man I have no clue how client side sutff works * please have mercy * remove RadiationPulseOverlay changes * nullspace --------- Co-authored-by: plykiya --- Content.Client/RCD/AlignRCDConstruction.cs | 2 +- Content.Client/Storage/Systems/StorageSystem.cs | 4 ++-- Content.Server/Atmos/EntitySystems/GasAnalyzerSystem.cs | 2 +- Content.Server/Dragon/DragonSystem.cs | 2 +- Content.Server/Guardian/GuardianSystem.cs | 2 +- Content.Server/Instruments/InstrumentSystem.cs | 3 ++- Content.Server/Medical/HealthAnalyzerSystem.cs | 2 +- Content.Server/Movement/Systems/PullController.cs | 5 +++-- .../HTN/Preconditions/CoordinatesInRangePrecondition.cs | 9 ++++++++- .../Preconditions/CoordinatesNotInRangePrecondition.cs | 9 ++++++++- .../NPC/HTN/Preconditions/TargetInRangePrecondition.cs | 9 ++++++++- Content.Server/Pointing/EntitySystems/PointingSystem.cs | 2 +- Content.Shared/Actions/SharedActionsSystem.cs | 2 +- Content.Shared/DoAfter/SharedDoAfterSystem.Update.cs | 2 +- 14 files changed, 39 insertions(+), 16 deletions(-) diff --git a/Content.Client/RCD/AlignRCDConstruction.cs b/Content.Client/RCD/AlignRCDConstruction.cs index fcbe408a382..ef99b01855c 100644 --- a/Content.Client/RCD/AlignRCDConstruction.cs +++ b/Content.Client/RCD/AlignRCDConstruction.cs @@ -75,7 +75,7 @@ public override bool IsValidPosition(EntityCoordinates position) if (!_entityManager.TryGetComponent(player, out var xform)) return false; - if (!xform.Coordinates.InRange(_entityManager, _transformSystem, position, SharedInteractionSystem.InteractionRange)) + if (!_transformSystem.InRange(xform.Coordinates, position, SharedInteractionSystem.InteractionRange)) { InvalidPlaceColor = InvalidPlaceColor.WithAlpha(0); return false; diff --git a/Content.Client/Storage/Systems/StorageSystem.cs b/Content.Client/Storage/Systems/StorageSystem.cs index 1e011f08f0e..eea7b9ec797 100644 --- a/Content.Client/Storage/Systems/StorageSystem.cs +++ b/Content.Client/Storage/Systems/StorageSystem.cs @@ -142,8 +142,8 @@ public void PickupAnimation(EntityUid item, EntityCoordinates initialCoords, Ent { if (!_timing.IsFirstTimePredicted) return; - - if (finalCoords.InRange(EntityManager, TransformSystem, initialCoords, 0.1f) || + + if (TransformSystem.InRange(finalCoords, initialCoords, 0.1f) || !Exists(initialCoords.EntityId) || !Exists(finalCoords.EntityId)) { return; diff --git a/Content.Server/Atmos/EntitySystems/GasAnalyzerSystem.cs b/Content.Server/Atmos/EntitySystems/GasAnalyzerSystem.cs index c2cdd4a1072..0f4490cd7eb 100644 --- a/Content.Server/Atmos/EntitySystems/GasAnalyzerSystem.cs +++ b/Content.Server/Atmos/EntitySystems/GasAnalyzerSystem.cs @@ -162,7 +162,7 @@ private bool UpdateAnalyzer(EntityUid uid, GasAnalyzerComponent? component = nul if (component.LastPosition.HasValue) { // Check if position is out of range => don't update and disable - if (!component.LastPosition.Value.InRange(EntityManager, _transform, userPos, SharedInteractionSystem.InteractionRange)) + if (!_transform.InRange(component.LastPosition.Value, userPos, SharedInteractionSystem.InteractionRange)) { if (component.User is { } userId && component.Enabled) _popup.PopupEntity(Loc.GetString("gas-analyzer-shutoff"), userId, userId); diff --git a/Content.Server/Dragon/DragonSystem.cs b/Content.Server/Dragon/DragonSystem.cs index 62d1f61a35b..96ca8d3614a 100644 --- a/Content.Server/Dragon/DragonSystem.cs +++ b/Content.Server/Dragon/DragonSystem.cs @@ -146,7 +146,7 @@ private void OnSpawnRift(EntityUid uid, DragonComponent component, DragonSpawnRi // cant stack rifts near eachother foreach (var (_, riftXform) in EntityQuery(true)) { - if (riftXform.Coordinates.InRange(EntityManager, _transform, xform.Coordinates, RiftRange)) + if (_transform.InRange(riftXform.Coordinates, xform.Coordinates, RiftRange)) { _popup.PopupEntity(Loc.GetString("carp-rift-proximity", ("proximity", RiftRange)), uid, uid); return; diff --git a/Content.Server/Guardian/GuardianSystem.cs b/Content.Server/Guardian/GuardianSystem.cs index 203882ed9ef..ae4d0ca2b8c 100644 --- a/Content.Server/Guardian/GuardianSystem.cs +++ b/Content.Server/Guardian/GuardianSystem.cs @@ -325,7 +325,7 @@ private void CheckGuardianMove( if (!guardianComponent.GuardianLoose) return; - if (!guardianXform.Coordinates.InRange(EntityManager, _transform, hostXform.Coordinates, guardianComponent.DistanceAllowed)) + if (!_transform.InRange(guardianXform.Coordinates, hostXform.Coordinates, guardianComponent.DistanceAllowed)) RetractGuardian(hostUid, hostComponent, guardianUid, guardianComponent); } diff --git a/Content.Server/Instruments/InstrumentSystem.cs b/Content.Server/Instruments/InstrumentSystem.cs index 582bf7fa67b..6814b596dc5 100644 --- a/Content.Server/Instruments/InstrumentSystem.cs +++ b/Content.Server/Instruments/InstrumentSystem.cs @@ -402,7 +402,8 @@ public override void Update(float frameTime) var trans = transformQuery.GetComponent(uid); var masterTrans = transformQuery.GetComponent(master); - if (!masterTrans.Coordinates.InRange(EntityManager, _transform, trans.Coordinates, 10f)) + if (!_transform.InRange(masterTrans.Coordinates, trans.Coordinates, 10f) +) { Clean(uid, instrument); } diff --git a/Content.Server/Medical/HealthAnalyzerSystem.cs b/Content.Server/Medical/HealthAnalyzerSystem.cs index 1d6e564a32d..98f4f00d899 100644 --- a/Content.Server/Medical/HealthAnalyzerSystem.cs +++ b/Content.Server/Medical/HealthAnalyzerSystem.cs @@ -65,7 +65,7 @@ public override void Update(float frameTime) //Get distance between health analyzer and the scanned entity var patientCoordinates = Transform(patient).Coordinates; - if (!patientCoordinates.InRange(EntityManager, _transformSystem, transform.Coordinates, component.MaxScanRange)) + if (!_transformSystem.InRange(patientCoordinates, transform.Coordinates, component.MaxScanRange)) { //Range too far, disable updates StopAnalyzingEntity((uid, component), patient); diff --git a/Content.Server/Movement/Systems/PullController.cs b/Content.Server/Movement/Systems/PullController.cs index 340dc5654e8..4bd4b603714 100644 --- a/Content.Server/Movement/Systems/PullController.cs +++ b/Content.Server/Movement/Systems/PullController.cs @@ -58,6 +58,7 @@ public sealed class PullController : VirtualController [Dependency] private readonly ActionBlockerSystem _actionBlockerSystem = default!; [Dependency] private readonly SharedContainerSystem _container = default!; [Dependency] private readonly SharedGravitySystem _gravity = default!; + [Dependency] private readonly SharedTransformSystem _transformSystem = default!; /// /// If distance between puller and pulled entity lower that this threshold, @@ -133,8 +134,8 @@ private bool OnRequestMovePulledObject(ICommonSession? session, EntityCoordinate var range = 2f; var fromUserCoords = coords.WithEntityId(player, EntityManager); var userCoords = new EntityCoordinates(player, Vector2.Zero); - - if (!coords.InRange(EntityManager, TransformSystem, userCoords, range)) + + if (!_transformSystem.InRange(coords, userCoords, range)) { var direction = fromUserCoords.Position - userCoords.Position; diff --git a/Content.Server/NPC/HTN/Preconditions/CoordinatesInRangePrecondition.cs b/Content.Server/NPC/HTN/Preconditions/CoordinatesInRangePrecondition.cs index 3485bd2a18c..452bf327f25 100644 --- a/Content.Server/NPC/HTN/Preconditions/CoordinatesInRangePrecondition.cs +++ b/Content.Server/NPC/HTN/Preconditions/CoordinatesInRangePrecondition.cs @@ -8,12 +8,19 @@ namespace Content.Server.NPC.HTN.Preconditions; public sealed partial class CoordinatesInRangePrecondition : HTNPrecondition { [Dependency] private readonly IEntityManager _entManager = default!; + private SharedTransformSystem _transformSystem = default!; [DataField("targetKey", required: true)] public string TargetKey = default!; [DataField("rangeKey", required: true)] public string RangeKey = default!; + public override void Initialize(IEntitySystemManager sysManager) + { + base.Initialize(sysManager); + _transformSystem = sysManager.GetEntitySystem(); + } + public override bool IsMet(NPCBlackboard blackboard) { if (!blackboard.TryGetValue(NPCBlackboard.OwnerCoordinates, out var coordinates, _entManager)) @@ -22,6 +29,6 @@ public override bool IsMet(NPCBlackboard blackboard) if (!blackboard.TryGetValue(TargetKey, out var target, _entManager)) return false; - return coordinates.InRange(_entManager, _entManager.System(), target, blackboard.GetValueOrDefault(RangeKey, _entManager)); + return _transformSystem.InRange(coordinates, target, blackboard.GetValueOrDefault(RangeKey, _entManager)); } } diff --git a/Content.Server/NPC/HTN/Preconditions/CoordinatesNotInRangePrecondition.cs b/Content.Server/NPC/HTN/Preconditions/CoordinatesNotInRangePrecondition.cs index 9d000ca2eb8..901831679e8 100644 --- a/Content.Server/NPC/HTN/Preconditions/CoordinatesNotInRangePrecondition.cs +++ b/Content.Server/NPC/HTN/Preconditions/CoordinatesNotInRangePrecondition.cs @@ -8,12 +8,19 @@ namespace Content.Server.NPC.HTN.Preconditions; public sealed partial class CoordinatesNotInRangePrecondition : HTNPrecondition { [Dependency] private readonly IEntityManager _entManager = default!; + private SharedTransformSystem _transformSystem = default!; [DataField("targetKey", required: true)] public string TargetKey = default!; [DataField("rangeKey", required: true)] public string RangeKey = default!; + public override void Initialize(IEntitySystemManager sysManager) + { + base.Initialize(sysManager); + _transformSystem = sysManager.GetEntitySystem(); + } + public override bool IsMet(NPCBlackboard blackboard) { if (!blackboard.TryGetValue(NPCBlackboard.OwnerCoordinates, out var coordinates, _entManager)) @@ -22,7 +29,7 @@ public override bool IsMet(NPCBlackboard blackboard) if (!blackboard.TryGetValue(TargetKey, out var target, _entManager)) return false; - return !coordinates.InRange(_entManager, _entManager.System(), target, blackboard.GetValueOrDefault(RangeKey, _entManager)); + return !_transformSystem.InRange(coordinates, target, blackboard.GetValueOrDefault(RangeKey, _entManager)); } } diff --git a/Content.Server/NPC/HTN/Preconditions/TargetInRangePrecondition.cs b/Content.Server/NPC/HTN/Preconditions/TargetInRangePrecondition.cs index aaccb426d71..921b5ffa226 100644 --- a/Content.Server/NPC/HTN/Preconditions/TargetInRangePrecondition.cs +++ b/Content.Server/NPC/HTN/Preconditions/TargetInRangePrecondition.cs @@ -8,11 +8,17 @@ namespace Content.Server.NPC.HTN.Preconditions; public sealed partial class TargetInRangePrecondition : HTNPrecondition { [Dependency] private readonly IEntityManager _entManager = default!; + private SharedTransformSystem _transformSystem = default!; [DataField("targetKey", required: true)] public string TargetKey = default!; [DataField("rangeKey", required: true)] public string RangeKey = default!; + public override void Initialize(IEntitySystemManager sysManager) + { + base.Initialize(sysManager); + _transformSystem = sysManager.GetEntitySystem(); + } public override bool IsMet(NPCBlackboard blackboard) { @@ -23,6 +29,7 @@ public override bool IsMet(NPCBlackboard blackboard) !_entManager.TryGetComponent(target, out var targetXform)) return false; - return coordinates.InRange(_entManager, _entManager.System(), targetXform.Coordinates, blackboard.GetValueOrDefault(RangeKey, _entManager)); + var transformSystem = _entManager.System; + return _transformSystem.InRange(coordinates, targetXform.Coordinates, blackboard.GetValueOrDefault(RangeKey, _entManager)); } } diff --git a/Content.Server/Pointing/EntitySystems/PointingSystem.cs b/Content.Server/Pointing/EntitySystems/PointingSystem.cs index ca7791fb68a..4b7f50fb86c 100644 --- a/Content.Server/Pointing/EntitySystems/PointingSystem.cs +++ b/Content.Server/Pointing/EntitySystems/PointingSystem.cs @@ -101,7 +101,7 @@ public bool InRange(EntityUid pointer, EntityCoordinates coordinates) { if (HasComp(pointer)) { - return Transform(pointer).Coordinates.InRange(EntityManager, _transform, coordinates, 15); + return _transform.InRange(Transform(pointer).Coordinates, coordinates, 15); } else { diff --git a/Content.Shared/Actions/SharedActionsSystem.cs b/Content.Shared/Actions/SharedActionsSystem.cs index 49c137468e4..013348eb4f7 100644 --- a/Content.Shared/Actions/SharedActionsSystem.cs +++ b/Content.Shared/Actions/SharedActionsSystem.cs @@ -533,7 +533,7 @@ private bool ValidateWorldTargetBase(EntityUid user, EntityCoordinates coords, W if (action.Range <= 0) return true; - return coords.InRange(EntityManager, _transformSystem, Transform(user).Coordinates, action.Range); + return _transformSystem.InRange(coords, Transform(user).Coordinates, action.Range); } return _interactionSystem.InRangeUnobstructed(user, coords, range: action.Range); diff --git a/Content.Shared/DoAfter/SharedDoAfterSystem.Update.cs b/Content.Shared/DoAfter/SharedDoAfterSystem.Update.cs index 4f77a271b37..ad94f3b9408 100644 --- a/Content.Shared/DoAfter/SharedDoAfterSystem.Update.cs +++ b/Content.Shared/DoAfter/SharedDoAfterSystem.Update.cs @@ -170,7 +170,7 @@ private bool ShouldCancel(DoAfter doAfter, if (args.BreakOnMove && !(!args.BreakOnWeightlessMove && _gravity.IsWeightless(args.User, xform: userXform))) { // Whether the user has moved too much from their original position. - if (!userXform.Coordinates.InRange(EntityManager, _transform, doAfter.UserPosition, args.MovementThreshold)) + if (!_transform.InRange(userXform.Coordinates, doAfter.UserPosition, args.MovementThreshold)) return true; // Whether the distance between the user and target(if any) has changed too much. From cfb490c6e9100c8cf32be0ab988a9fc1cd715271 Mon Sep 17 00:00:00 2001 From: Winkarst <74284083+Winkarst-cpu@users.noreply.github.com> Date: Sun, 14 Jul 2024 02:17:15 +0300 Subject: [PATCH 208/765] Update IdExaminableSystem.cs to use TryFromMarkup (#29957) * Change FromMarkup to TryFromMarkup method in IdExaminableSystem.cs * Update --- Content.Shared/Access/Systems/IdExaminableSystem.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Content.Shared/Access/Systems/IdExaminableSystem.cs b/Content.Shared/Access/Systems/IdExaminableSystem.cs index 333272e27ac..13359adcba2 100644 --- a/Content.Shared/Access/Systems/IdExaminableSystem.cs +++ b/Content.Shared/Access/Systems/IdExaminableSystem.cs @@ -27,7 +27,8 @@ private void OnGetExamineVerbs(EntityUid uid, IdExaminableComponent component, G { Act = () => { - var markup = FormattedMessage.FromMarkup(info); + var markup = FormattedMessage.FromMarkupOrThrow(info); + _examineSystem.SendExamineTooltip(args.User, uid, markup, false, false); }, Text = Loc.GetString("id-examinable-component-verb-text"), From bdb19299898c5ffba6e076295585f9dc94a13e24 Mon Sep 17 00:00:00 2001 From: Pieter-Jan Briers Date: Sun, 14 Jul 2024 01:18:12 +0200 Subject: [PATCH 209/765] Update changelog RSS configuration (#30024) New server --- Tools/actions_changelog_rss.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tools/actions_changelog_rss.py b/Tools/actions_changelog_rss.py index 5e42a030bde..01ca7852ccb 100755 --- a/Tools/actions_changelog_rss.py +++ b/Tools/actions_changelog_rss.py @@ -29,7 +29,7 @@ # Change these to suit your server settings # https://docs.fabfile.org/en/stable/getting-started.html#run-commands-via-connections-and-run -SSH_HOST = "centcomm.spacestation14.io" +SSH_HOST = "moon.spacestation14.com" SSH_USER = "changelog-rss" SSH_PORT = 22 RSS_FILE = "changelog.xml" From dc2a6780e165ba052f8e24625ad00832fa111fe2 Mon Sep 17 00:00:00 2001 From: Luiz Costa <33888056+luizwritescode@users.noreply.github.com> Date: Sat, 13 Jul 2024 23:59:45 -0300 Subject: [PATCH 210/765] Fix lizards losing snouts when equipping a head bandana (#29979) * say goodbye to no-snout lizards * remove snout from plague doctor hat HideLayerClothing component --- .../Components/FoldableClothingComponent.cs | 13 +++++++++++++ .../EntitySystems/FoldableClothingSystem.cs | 7 +++++++ .../Prototypes/Entities/Clothing/Head/bandanas.yml | 2 ++ .../Prototypes/Entities/Clothing/Head/hats.yml | 1 - .../Prototypes/Entities/Clothing/Masks/bandanas.yml | 3 +++ 5 files changed, 25 insertions(+), 1 deletion(-) diff --git a/Content.Shared/Clothing/Components/FoldableClothingComponent.cs b/Content.Shared/Clothing/Components/FoldableClothingComponent.cs index 1a40d1dca12..ffcb52b4576 100644 --- a/Content.Shared/Clothing/Components/FoldableClothingComponent.cs +++ b/Content.Shared/Clothing/Components/FoldableClothingComponent.cs @@ -1,3 +1,4 @@ +using Content.Shared.Humanoid; using Content.Shared.Inventory; using Robust.Shared.GameStates; @@ -30,4 +31,16 @@ public sealed partial class FoldableClothingComponent : Component /// [DataField] public string? FoldedHeldPrefix; + + /// + /// Which layers does this hide when Unfolded? See and + /// + [DataField] + public HashSet UnfoldedHideLayers = new(); + + /// + /// Which layers does this hide when folded? See and + /// + [DataField] + public HashSet FoldedHideLayers = new(); } diff --git a/Content.Shared/Clothing/EntitySystems/FoldableClothingSystem.cs b/Content.Shared/Clothing/EntitySystems/FoldableClothingSystem.cs index be55588ddd5..603af4099c8 100644 --- a/Content.Shared/Clothing/EntitySystems/FoldableClothingSystem.cs +++ b/Content.Shared/Clothing/EntitySystems/FoldableClothingSystem.cs @@ -47,6 +47,10 @@ private void OnFolded(Entity ent, ref FoldedEvent arg if (ent.Comp.FoldedHeldPrefix != null) _itemSystem.SetHeldPrefix(ent.Owner, ent.Comp.FoldedHeldPrefix, false, itemComp); + + if (TryComp(ent.Owner, out var hideLayerComp)) + hideLayerComp.Slots = ent.Comp.FoldedHideLayers; + } else { @@ -59,6 +63,9 @@ private void OnFolded(Entity ent, ref FoldedEvent arg if (ent.Comp.FoldedHeldPrefix != null) _itemSystem.SetHeldPrefix(ent.Owner, null, false, itemComp); + if (TryComp(ent.Owner, out var hideLayerComp)) + hideLayerComp.Slots = ent.Comp.UnfoldedHideLayers; + } } } diff --git a/Resources/Prototypes/Entities/Clothing/Head/bandanas.yml b/Resources/Prototypes/Entities/Clothing/Head/bandanas.yml index 51a56f1f1d6..da56194f715 100644 --- a/Resources/Prototypes/Entities/Clothing/Head/bandanas.yml +++ b/Resources/Prototypes/Entities/Clothing/Head/bandanas.yml @@ -20,6 +20,8 @@ - state: icon_mask map: [ "unfoldedLayer" ] visible: false + - type: HideLayerClothing # needed since head bandana inherits from mask bandana + slots: [] - type: Tag tags: - Bandana diff --git a/Resources/Prototypes/Entities/Clothing/Head/hats.yml b/Resources/Prototypes/Entities/Clothing/Head/hats.yml index 992b9073846..b2c3151469e 100644 --- a/Resources/Prototypes/Entities/Clothing/Head/hats.yml +++ b/Resources/Prototypes/Entities/Clothing/Head/hats.yml @@ -393,7 +393,6 @@ - type: HideLayerClothing slots: - Hair - - Snout - HeadTop - HeadSide diff --git a/Resources/Prototypes/Entities/Clothing/Masks/bandanas.yml b/Resources/Prototypes/Entities/Clothing/Masks/bandanas.yml index f5ad2fb6c83..80210300953 100644 --- a/Resources/Prototypes/Entities/Clothing/Masks/bandanas.yml +++ b/Resources/Prototypes/Entities/Clothing/Masks/bandanas.yml @@ -11,6 +11,9 @@ - HEAD unfoldedSlots: - MASK + foldedHideLayers: [] + unfoldedHideLayers: + - Snout - type: Mask - type: IngestionBlocker - type: IdentityBlocker From e0b06928ed224ffca3c18196dc3db7b2f70b298d Mon Sep 17 00:00:00 2001 From: PJBot Date: Sun, 14 Jul 2024 03:00:52 +0000 Subject: [PATCH 211/765] Automatic changelog update --- Resources/Changelog/Changelog.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index e4c8aa1b430..0a41c2e2e9c 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,11 +1,4 @@ Entries: -- author: deltanedas - changes: - - message: Flaming mice no longer completely engulf people they touch. - type: Tweak - id: 6416 - time: '2024-04-22T08:42:26.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/27202 - author: Weax changes: - message: The CLF3 reaction now requires heating first before you can engulf chemistry @@ -3813,3 +3806,10 @@ id: 6915 time: '2024-07-13T12:15:57.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/25750 +- author: coffeeware + changes: + - message: Lizards will no longer lose their snouts when equipping head bandanas + type: Fix + id: 6916 + time: '2024-07-14T02:59:45.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/29979 From d545d4f108e35ad277f2836608ecd1ab26e046bc Mon Sep 17 00:00:00 2001 From: Winkarst <74284083+Winkarst-cpu@users.noreply.github.com> Date: Sun, 14 Jul 2024 06:05:39 +0300 Subject: [PATCH 212/765] Update MainMenu.cs to use ISawmill (#29988) * Update MainMenu.cs to use ISawmill * Update * Error --- Content.Client/MainMenu/MainMenu.cs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Content.Client/MainMenu/MainMenu.cs b/Content.Client/MainMenu/MainMenu.cs index 43c5bfe5674..3c709d2d15b 100644 --- a/Content.Client/MainMenu/MainMenu.cs +++ b/Content.Client/MainMenu/MainMenu.cs @@ -25,6 +25,9 @@ public sealed class MainScreen : Robust.Client.State.State [Dependency] private readonly IGameController _controllerProxy = default!; [Dependency] private readonly IResourceCache _resourceCache = default!; [Dependency] private readonly IUserInterfaceManager _userInterfaceManager = default!; + [Dependency] private readonly ILogManager _logManager = default!; + + private ISawmill _sawmill = default!; private MainMenuControl _mainMenuControl = default!; private bool _isConnecting; @@ -35,6 +38,8 @@ public sealed class MainScreen : Robust.Client.State.State /// protected override void Startup() { + _sawmill = _logManager.GetSawmill("mainmenu"); + _mainMenuControl = new MainMenuControl(_resourceCache, _configurationManager); _userInterfaceManager.StateRoot.AddChild(_mainMenuControl); @@ -116,7 +121,7 @@ private void TryConnect(string address) catch (ArgumentException e) { _userInterfaceManager.Popup($"Unable to connect: {e.Message}", "Connection error."); - Logger.Warning(e.ToString()); + _sawmill.Warning(e.ToString()); _netManager.ConnectFailed -= _onConnectFailed; _setConnectingState(false); } From 2c27f5557091cef32ffda82ff16ca188db15c0f6 Mon Sep 17 00:00:00 2001 From: osjarw <62134478+osjarw@users.noreply.github.com> Date: Sun, 14 Jul 2024 06:26:38 +0300 Subject: [PATCH 213/765] NPC exits MeleeOperator on invalid EntityUid (#30005) EntityUid 0 problem fix --- .../HTN/PrimitiveTasks/Operators/Combat/Melee/MeleeOperator.cs | 3 ++- Content.Server/NPC/Systems/NPCJukeSystem.cs | 3 +++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/Content.Server/NPC/HTN/PrimitiveTasks/Operators/Combat/Melee/MeleeOperator.cs b/Content.Server/NPC/HTN/PrimitiveTasks/Operators/Combat/Melee/MeleeOperator.cs index 32be027ec43..5a02b86201b 100644 --- a/Content.Server/NPC/HTN/PrimitiveTasks/Operators/Combat/Melee/MeleeOperator.cs +++ b/Content.Server/NPC/HTN/PrimitiveTasks/Operators/Combat/Melee/MeleeOperator.cs @@ -89,7 +89,8 @@ public override HTNOperatorStatus Update(NPCBlackboard blackboard, float frameTi HTNOperatorStatus status; if (_entManager.TryGetComponent(owner, out var combat) && - blackboard.TryGetValue(TargetKey, out var target, _entManager)) + blackboard.TryGetValue(TargetKey, out var target, _entManager) && + target != EntityUid.Invalid) { combat.Target = target; diff --git a/Content.Server/NPC/Systems/NPCJukeSystem.cs b/Content.Server/NPC/Systems/NPCJukeSystem.cs index da9fa1f7615..94a30feb0cb 100644 --- a/Content.Server/NPC/Systems/NPCJukeSystem.cs +++ b/Content.Server/NPC/Systems/NPCJukeSystem.cs @@ -143,6 +143,9 @@ private void OnJukeSteering(EntityUid uid, NPCJukeComponent component, ref NPCSt if (!_melee.TryGetWeapon(uid, out var weaponUid, out var weapon)) return; + if (!HasComp(melee.Target)) + return; + var cdRemaining = weapon.NextAttack - _timing.CurTime; var attackCooldown = TimeSpan.FromSeconds(1f / _melee.GetAttackRate(weaponUid, uid, weapon)); From edde7e4a20c393ae73454d21950b697932354e36 Mon Sep 17 00:00:00 2001 From: ShadowCommander <10494922+ShadowCommander@users.noreply.github.com> Date: Sat, 13 Jul 2024 20:27:39 -0700 Subject: [PATCH 214/765] Clean itemmapper (#29983) * File scoped namespace * Format file * Fix param name in doc comment * Reflow doc comment --------- Co-authored-by: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com> --- .../EntitySystems/SharedItemMapperSystem.cs | 164 +++++++++--------- 1 file changed, 83 insertions(+), 81 deletions(-) diff --git a/Content.Shared/Storage/EntitySystems/SharedItemMapperSystem.cs b/Content.Shared/Storage/EntitySystems/SharedItemMapperSystem.cs index eb20c65a116..7ae821d8d91 100644 --- a/Content.Shared/Storage/EntitySystems/SharedItemMapperSystem.cs +++ b/Content.Shared/Storage/EntitySystems/SharedItemMapperSystem.cs @@ -4,107 +4,109 @@ using JetBrains.Annotations; using Robust.Shared.Containers; -namespace Content.Shared.Storage.EntitySystems +namespace Content.Shared.Storage.EntitySystems; + +/// +/// ItemMapperSystem is a system that on each initialization, insertion, removal of an entity from +/// given (with appropriate storage attached) will check each stored item to see +/// if its tags/component, and overall quantity match . +/// +[UsedImplicitly] +public abstract class SharedItemMapperSystem : EntitySystem { - /// - /// ItemMapperSystem is a system that on each initialization, insertion, removal of an entity from - /// given (with appropriate storage attached) will check each stored item to see - /// if its tags/component, and overall quantity match . - /// - [UsedImplicitly] - public abstract class SharedItemMapperSystem : EntitySystem + [Dependency] private readonly SharedAppearanceSystem _appearance = default!; + [Dependency] private readonly SharedContainerSystem _container = default!; + [Dependency] private readonly EntityWhitelistSystem _whitelistSystem = default!; + + /// + public override void Initialize() { - [Dependency] private readonly SharedAppearanceSystem _appearance = default!; - [Dependency] private readonly SharedContainerSystem _container = default!; - [Dependency] private readonly EntityWhitelistSystem _whitelistSystem = default!; + base.Initialize(); + SubscribeLocalEvent(InitLayers); + SubscribeLocalEvent(MapperEntityInserted); + SubscribeLocalEvent(MapperEntityRemoved); + } - /// - public override void Initialize() + private void InitLayers(EntityUid uid, ItemMapperComponent component, ComponentInit args) + { + foreach (var (layerName, val) in component.MapLayers) { - base.Initialize(); - SubscribeLocalEvent(InitLayers); - SubscribeLocalEvent(MapperEntityInserted); - SubscribeLocalEvent(MapperEntityRemoved); + val.Layer = layerName; } - private void InitLayers(EntityUid uid, ItemMapperComponent component, ComponentInit args) + if (EntityManager.TryGetComponent(uid, out AppearanceComponent? appearanceComponent)) { - foreach (var (layerName, val) in component.MapLayers) - { - val.Layer = layerName; - } + var list = new List(component.MapLayers.Keys); + _appearance.SetData(uid, StorageMapVisuals.InitLayers, new ShowLayerData(list), appearanceComponent); + } - if (EntityManager.TryGetComponent(uid, out AppearanceComponent? appearanceComponent)) - { - var list = new List(component.MapLayers.Keys); - _appearance.SetData(uid, StorageMapVisuals.InitLayers, new ShowLayerData(list), appearanceComponent); - } + // Ensure appearance is correct with current contained entities. + UpdateAppearance(uid, component); + } - // Ensure appearance is correct with current contained entities. - UpdateAppearance(uid, component); - } + private void MapperEntityRemoved(EntityUid uid, ItemMapperComponent itemMapper, EntRemovedFromContainerMessage args) + { + if (itemMapper.ContainerWhitelist != null && !itemMapper.ContainerWhitelist.Contains(args.Container.ID)) + return; - private void MapperEntityRemoved(EntityUid uid, ItemMapperComponent itemMapper, - EntRemovedFromContainerMessage args) - { - if (itemMapper.ContainerWhitelist != null && !itemMapper.ContainerWhitelist.Contains(args.Container.ID)) - return; + UpdateAppearance(uid, itemMapper); + } - UpdateAppearance(uid, itemMapper); - } + private void MapperEntityInserted(EntityUid uid, + ItemMapperComponent itemMapper, + EntInsertedIntoContainerMessage args) + { + if (itemMapper.ContainerWhitelist != null && !itemMapper.ContainerWhitelist.Contains(args.Container.ID)) + return; - private void MapperEntityInserted(EntityUid uid, ItemMapperComponent itemMapper, - EntInsertedIntoContainerMessage args) - { - if (itemMapper.ContainerWhitelist != null && !itemMapper.ContainerWhitelist.Contains(args.Container.ID)) - return; + UpdateAppearance(uid, itemMapper); + } - UpdateAppearance(uid, itemMapper); - } + private void UpdateAppearance(EntityUid uid, ItemMapperComponent? itemMapper = null) + { + if (!Resolve(uid, ref itemMapper)) + return; - private void UpdateAppearance(EntityUid uid, ItemMapperComponent? itemMapper = null) + if (EntityManager.TryGetComponent(uid, out AppearanceComponent? appearanceComponent) + && TryGetLayers(uid, itemMapper, out var containedLayers)) { - if(!Resolve(uid, ref itemMapper)) - return; - - if (EntityManager.TryGetComponent(uid, out AppearanceComponent? appearanceComponent) - && TryGetLayers(uid, itemMapper, out var containedLayers)) - { - _appearance.SetData(uid, StorageMapVisuals.LayerChanged, new ShowLayerData(containedLayers), appearanceComponent); - } + _appearance.SetData(uid, + StorageMapVisuals.LayerChanged, + new ShowLayerData(containedLayers), + appearanceComponent); } + } - /// - /// Method that iterates over storage of the entity in and sets according to - /// definition. It will have O(n*m) time behavior (n - number of entities in container, and m - number of - /// definitions in . - /// - /// EntityUid used to search the storage - /// component that contains definition used to map whitelist in - /// mapLayers to string. - /// - /// list of layers that should be visible - /// false if msg.Container.Owner is not a storage, true otherwise. - private bool TryGetLayers(EntityUid uid, - ItemMapperComponent itemMapper, - out List showLayers) - { - var containedLayers = _container.GetAllContainers(uid) - .Where(c => itemMapper.ContainerWhitelist?.Contains(c.ID) ?? true).SelectMany(cont => cont.ContainedEntities).ToArray(); + /// + /// Method that iterates over storage of the entity in and sets + /// according to definition. It will have O(n*m) time behavior + /// (n - number of entities in container, and m - number of definitions in ). + /// + /// EntityUid used to search the storage + /// component that contains definition used to map + /// Whitelist in to string. + /// + /// list of layers that should be visible + /// false if msg.Container.Owner is not a storage, true otherwise. + private bool TryGetLayers(EntityUid uid, ItemMapperComponent itemMapper, out List showLayers) + { + var containedLayers = _container.GetAllContainers(uid) + .Where(c => itemMapper.ContainerWhitelist?.Contains(c.ID) ?? true) + .SelectMany(cont => cont.ContainedEntities) + .ToArray(); - var list = new List(); - foreach (var mapLayerData in itemMapper.MapLayers.Values) + var list = new List(); + foreach (var mapLayerData in itemMapper.MapLayers.Values) + { + var count = containedLayers.Count(ent => _whitelistSystem.IsWhitelistPassOrNull(mapLayerData.Whitelist, + ent)); + if (count >= mapLayerData.MinCount && count <= mapLayerData.MaxCount) { - var count = containedLayers.Count(ent => _whitelistSystem.IsWhitelistPassOrNull(mapLayerData.Whitelist, - ent)); - if (count >= mapLayerData.MinCount && count <= mapLayerData.MaxCount) - { - list.Add(mapLayerData.Layer); - } + list.Add(mapLayerData.Layer); } - - showLayers = list; - return true; } + + showLayers = list; + return true; } } From ce252a52ad82fea169c515c3bbe32686b867ef00 Mon Sep 17 00:00:00 2001 From: Winkarst <74284083+Winkarst-cpu@users.noreply.github.com> Date: Sun, 14 Jul 2024 13:24:26 +0300 Subject: [PATCH 215/765] Update AccessLevelControl.xaml.cs to use ISawmill (#29987) * Update AccessLevelControl.xaml.cs to use ISawmill * Update * Silly me * Update --- Content.Client/Access/UI/AccessLevelControl.xaml.cs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/Content.Client/Access/UI/AccessLevelControl.xaml.cs b/Content.Client/Access/UI/AccessLevelControl.xaml.cs index 34db80b7af9..9f09eceec06 100644 --- a/Content.Client/Access/UI/AccessLevelControl.xaml.cs +++ b/Content.Client/Access/UI/AccessLevelControl.xaml.cs @@ -12,11 +12,17 @@ namespace Content.Client.Access.UI; [GenerateTypedNameReferences] public sealed partial class AccessLevelControl : GridContainer { + [Dependency] private readonly ILogManager _logManager = default!; + + private ISawmill _sawmill = default!; + public readonly Dictionary, Button> ButtonsList = new(); public AccessLevelControl() { RobustXamlLoader.Load(this); + + _sawmill = _logManager.GetSawmill("accesslevelcontrol"); } public void Populate(List> accessLevels, IPrototypeManager prototypeManager) @@ -25,7 +31,7 @@ public void Populate(List> accessLevels, IPrototyp { if (!prototypeManager.TryIndex(access, out var accessLevel)) { - Logger.Error($"Unable to find accesslevel for {access}"); + _sawmill.Error($"Unable to find accesslevel for {access}"); continue; } From 73f663433e2519bcf95c0391c94df50769ad6ec7 Mon Sep 17 00:00:00 2001 From: lzk <124214523+lzk228@users.noreply.github.com> Date: Sun, 14 Jul 2024 12:25:18 +0200 Subject: [PATCH 216/765] Fix AGhostCommand naming (#29945) --- .../Administration/Commands/{AGhost.cs => AGhostCommand.cs} | 3 +-- Resources/Locale/en-US/administration/commands/aghost.ftl | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) rename Content.Server/Administration/Commands/{AGhost.cs => AGhostCommand.cs} (97%) diff --git a/Content.Server/Administration/Commands/AGhost.cs b/Content.Server/Administration/Commands/AGhostCommand.cs similarity index 97% rename from Content.Server/Administration/Commands/AGhost.cs rename to Content.Server/Administration/Commands/AGhostCommand.cs index 935114e7a68..b24dbbc018c 100644 --- a/Content.Server/Administration/Commands/AGhost.cs +++ b/Content.Server/Administration/Commands/AGhostCommand.cs @@ -12,13 +12,12 @@ namespace Content.Server.Administration.Commands; [AdminCommand(AdminFlags.Admin)] -public sealed class AGhost : LocalizedCommands +public sealed class AGhostCommand : LocalizedCommands { [Dependency] private readonly IEntityManager _entities = default!; [Dependency] private readonly IPlayerManager _playerManager = default!; public override string Command => "aghost"; - public override string Description => LocalizationManager.GetString("aghost-description"); public override string Help => "aghost"; public override CompletionResult GetCompletion(IConsoleShell shell, string[] args) diff --git a/Resources/Locale/en-US/administration/commands/aghost.ftl b/Resources/Locale/en-US/administration/commands/aghost.ftl index 4de0639981e..30cd893dc8f 100644 --- a/Resources/Locale/en-US/administration/commands/aghost.ftl +++ b/Resources/Locale/en-US/administration/commands/aghost.ftl @@ -1,3 +1,3 @@ -aghost-description = Makes you an admin ghost. +cmd-aghost-desc = Makes you or others an admin ghost. aghost-no-mind-self = You can't ghost here! aghost-no-mind-other = They can't ghost here! From c4c68f15670f77e4d0b788041dd7f2fe202528dc Mon Sep 17 00:00:00 2001 From: lzk <124214523+lzk228@users.noreply.github.com> Date: Sun, 14 Jul 2024 12:25:57 +0200 Subject: [PATCH 217/765] Change wristwatch meta description (#30036) --- Resources/Prototypes/Entities/Objects/Devices/wristwatch.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Resources/Prototypes/Entities/Objects/Devices/wristwatch.yml b/Resources/Prototypes/Entities/Objects/Devices/wristwatch.yml index 7fbb4aecf61..6359f659b57 100644 --- a/Resources/Prototypes/Entities/Objects/Devices/wristwatch.yml +++ b/Resources/Prototypes/Entities/Objects/Devices/wristwatch.yml @@ -2,7 +2,7 @@ id: Wristwatch parent: BaseItem name: wristwatch - description: A cheap watch for telling time. How much did you waste playing Space Station 14? + description: A cheap watch for telling time. How much did you waste working on this shift? components: - type: Sprite sprite: Objects/Devices/wristwatch.rsi From 2faf4c849a3667a100746a3b4f66c888f558755d Mon Sep 17 00:00:00 2001 From: SlamBamActionman <83650252+SlamBamActionman@users.noreply.github.com> Date: Sun, 14 Jul 2024 12:26:34 +0200 Subject: [PATCH 218/765] Fix RGB toys color when worn/in-hand (#30023) rgbeeeeeeee --- .../Prototypes/Entities/Objects/Fun/toys.yml | 22 ++++++++++++++++++ .../Textures/Objects/Fun/toys.rsi/meta.json | 8 +++++++ .../toys.rsi/rainbowcarpplush-inhand-left.png | Bin 0 -> 15498 bytes .../rainbowcarpplush-inhand-right.png | Bin 0 -> 15496 bytes 4 files changed, 30 insertions(+) create mode 100644 Resources/Textures/Objects/Fun/toys.rsi/rainbowcarpplush-inhand-left.png create mode 100644 Resources/Textures/Objects/Fun/toys.rsi/rainbowcarpplush-inhand-right.png diff --git a/Resources/Prototypes/Entities/Objects/Fun/toys.yml b/Resources/Prototypes/Entities/Objects/Fun/toys.yml index 16c96b2a150..496b79531eb 100644 --- a/Resources/Prototypes/Entities/Objects/Fun/toys.yml +++ b/Resources/Prototypes/Entities/Objects/Fun/toys.yml @@ -184,6 +184,19 @@ energy: 2 - type: RgbLightController layers: [ 0 ] + - type: Item + inhandVisuals: + left: + - state: bee-inhand-left + shader: unshaded + right: + - state: bee-inhand-right + shader: unshaded + - type: Clothing + clothingVisuals: + head: + - state: bee-equipped-HELMET + shader: unshaded - type: entity parent: BasePlushie @@ -546,6 +559,15 @@ energy: 2 - type: RgbLightController layers: [ 0 ] + - type: Item + heldPrefix: rainbowcarpplush + inhandVisuals: + left: + - state: rainbowcarpplush-inhand-left + shader: unshaded + right: + - state: rainbowcarpplush-inhand-right + shader: unshaded - type: entity parent: PlushieCarp diff --git a/Resources/Textures/Objects/Fun/toys.rsi/meta.json b/Resources/Textures/Objects/Fun/toys.rsi/meta.json index fc92a479367..fa118695c20 100644 --- a/Resources/Textures/Objects/Fun/toys.rsi/meta.json +++ b/Resources/Textures/Objects/Fun/toys.rsi/meta.json @@ -53,6 +53,14 @@ { "name": "rainbowcarpplush" }, + { + "name": "rainbowcarpplush-inhand-left", + "directions": 4 + }, + { + "name": "rainbowcarpplush-inhand-right", + "directions": 4 + }, { "name": "narplush" }, diff --git a/Resources/Textures/Objects/Fun/toys.rsi/rainbowcarpplush-inhand-left.png b/Resources/Textures/Objects/Fun/toys.rsi/rainbowcarpplush-inhand-left.png new file mode 100644 index 0000000000000000000000000000000000000000..8f28f41fd8513829dc0f926f9bd0fa46f67c05c4 GIT binary patch literal 15498 zcmeI3XHXkS7RSeHT)WHOZtd2s?{2rY>U3J1k!F+-$dUjfFxVExfK6~>B#mH+av{Zsto5kBM&o zz3;ES2!ebc6{(2@zah-uH;q9#Ytz6o@bj%TGRcl0-~FBWYlKXn`7Z)&<6+c0y#kAHiB8`m9wh?jJ z(ee81bbXM4AFTFOx)dOQnV@l=%WSgP6)qLu9ajNtrW)n*+!8un#SdjV$c-#1e%RQ%J?Us)w)k1(wogFe+j-5mnuR zHx)mPrmYGTbvm6wr$k8EQc+P*P!NiVQL$J66asseg~nY1i~V;`kk4^6gk5hVtu#ql zcuZVeM>%K}pU-sUeX8bVwt73V*sIt9il_^>q9P%N*5_oR6~xVe{tCqqgwS4EhOz-h`BPf;edXO+c# zM#u{bbFV61%LLM5pq%zrO0>31b-t^k5gME()M8956<~6KNE(lU#TW#ZWE)JZz%VF? zM_DU|mNJmWta@U|Ko}Vu15(zG0rrmpr|~}&1=d1w40?r;vYByOO`7pk0<~IFm1uP( zr1Y*TMHpqGY+zVm`bxCEYRJpI(iBk^JB?fPM3hDiDug6yP!NPptP2PT5Xdo|P5>}U z1c72gE-(b>3;`0UL@W#NK-6ks_d209l-|MYma5Q(KN%WwuM@hnjRYqhZh|z-=>KdN z^@OR@RU~N#>oW^lw_x?U&$2ioqh{^r1{3K%ldQPSPB1%8#s9qJyoZ?gjADG;J6D10 znbS# z)Z}pMe?PLq>C^mYDlnu?aZnSkXHHBZm8EWsUb(Gp~}&dD(K(2JCmMT@UZ~CQ&8`R zO3fsDH^N_RRL|%y4h)CmI)Q1h+8i!cM6iIv1=C=)Ib5uWU;&2dA8hl>>vEZ}g#G+1p87b_xI zz~O>vu-Y6hRz$FX!v)h|wK-g@h+qMS3#P$pbGTR$!2%8!OoP?taIqqS1spDz2CL2C zVnqZCI9xCdR-41ciU<~PxL_KrHiwH95iH=XafWrmT zV6{11tcYL%hYO~`YIC?)5y1iu7fgfI{vs~l>Z^Z*1>E;@f{T3>%igX4mjZeE$XG3c zWH&>QoIwauQ3-w@AczA)kcTMsFW+o7Ta`526 zptRfVp!D~fj}q}q9_WkQiwz%u~;mT zNTgD!OeO}m0GP14h{|p2?-4iZP%_{SXh`wqX`cW zkBEq9-@bihWMouSREG{7I(F>XsZ%GdRvR51-MMq;n3$L@UAn}^#>U0P#mC2Y?b@|l zw{8gu35kh`Nl8h`$;sWjckj`oN6(%;d-dwoyLa!DloTAtbvm71uQwPB1VI>$#?;i* zw6rvmB>VK~lb)V#GMUU~v&CYeC<@Ta$jAT?z?5m4b~qeh;^3mA%jL?-$^yjt_U+rR zUq1k6z<>b&S58jOz<~pEb8`m`8U$Dk88T$((4l#GdBcVc8$Nvah!G<|3Pz0@1^AC1 zJsNNxJ9g~2apT61A3tHj1dxbHlO|1`JbB8LDO0CT1=y!gpFU&8jF~fM&YCrA_Uzen z=FFKpckaA-^XAW=zhJ?Fg$oxhTC`~K;>AmrECCr`wrtt*<;z#BSg~^D%2lgYtzNyl zprByQnl)?Ju3fio-TL+GH*DBYSXj7mK79Ddkt0Ws z9zAyK*zx1XPnAmsE?vHS`O1|m zSFc{ZcJ12r>(_7GxN-C5&0Du_-M)SM&Ye4V@7}$4@813U_a8iX@bKZoM~@zrm6bhy z{P@X}Cr_U~efI3x^XJcBym$eY=*yQcU%h(u`t|EKZ{ECp`?jK@;@!J<@87@w@ZrP9 zj~_pM`czq2nb6yK5A1bZ{a@`I!c>nT>Dh{ z?|V%n2Ki0MdX#0lzR*7k)%%40_>XOQzrIm9Lw|hH_ouI%jUqC}KOF6!x-!H$uw|R# z>S0?>rY>_nf!qxgNKiY(&M9%%l-Ah6oZ6lpsPBun)10yswmX3uL9{L1PQsK*vZ7=%g>nRopKRG77E$J4ae~T#8JuCHm5R)Ak?~nE zMpIU*Nn;kb)cI-MI0#@TSwiHt+Z+t;4iO4>*}>0lY) zC#%%YX{A}3vC>rx>Fcg?V2~4o!8dlL^R?S69hzao(*c4~q?LLy#!M%P#*qx2<}#7t z>0l`hDqB5ES;~@AE)v&M<=ja(RfQYZ<8||tf;U52uvR?GMG`FSGSak7=dH5XF9=0p zVVlE6SECLw}M zYDthH$YL>RuFOOw_8d>oBv{H$o;F(?OYT%=?EL7;b#9=ho~gX zS3^Zo45-gcsBS^^dd{+VvRC=mFC8|@b0#?n7ejJ8E?E3!%lQs5-xDu&mh-05$l$|u6xT0TEtD)#GqYPmxV2ekm^MR;-`)1qIsm5uDxCvrKprFryf zIR-9N#@$O@;qHpAN#AybyDPeud3JD6EVs)&6Rpq;d2uJN_gIJrFA1bBP^D6+v}ncV ziXO3)o3thBDX@PTt||kSr9KrqDs@b%$`R@)b@ZkR`giWhq_-8kEP(eE)c2xNKFPj~ z@HZP}EBc!Q!{LNMU>dx(fQuIqED&(PGl*Hj^Z2u~<@4Qmj@h zMNvI__DoGpwb^WTyWQb%&@>I`_3G6NEFY|wW!bc}G_ZE?p`+XF&dkgN#CrGc-KS3< z0Hi9f=&)hKh7TV;V#J7%BS(Tnj2=B2@E<#N zEFe5?+_>@M$7g3}Pna+PZ{EE5^XD&EuwdcBg^Ly~TD*8MNcYmEOP4KMmYbWqeEISfD^{#rxpLL2 zRjXI8UbALRUS8hXwQJX{Tep7w`VAX4Y}~kU)223T%hs)1w{6?Def#zu zJ9ZQl6ztr&bJwn2yLa#2vu96XVd37rd-v_zw}1cs0|yQqJb3WXp+kocA3k#A$kC%m zj~zQ!R8(~Q`0*1bPMkb>^3&d2uy4LDNzs{*v^h1LrEJk!~%MZ`|P{{vh2vnK!m literal 0 HcmV?d00001 From 7fc567d9d0e4feeee036ea926ca53ffee50a88fd Mon Sep 17 00:00:00 2001 From: Winkarst <74284083+Winkarst-cpu@users.noreply.github.com> Date: Sun, 14 Jul 2024 13:26:56 +0300 Subject: [PATCH 219/765] Clumsy proof grappling gun (#29904) Make grappling gun clumsy proof --- .../Entities/Objects/Weapons/Guns/Launchers/launchers.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Launchers/launchers.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Launchers/launchers.yml index 0f94825ad0e..b351bad293d 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Launchers/launchers.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Launchers/launchers.yml @@ -251,6 +251,7 @@ - type: Gun soundGunshot: /Audio/Weapons/Guns/Gunshots/harpoon.ogg fireRate: 0.5 + clumsyProof: true - type: BasicEntityAmmoProvider proto: GrapplingHook capacity: 1 From 5b71d7d5e7451375ff5819c317fcb79f3bc8bbfa Mon Sep 17 00:00:00 2001 From: PJBot Date: Sun, 14 Jul 2024 10:28:02 +0000 Subject: [PATCH 220/765] Automatic changelog update --- Resources/Changelog/Changelog.yml | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 0a41c2e2e9c..d06bda3324f 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,19 +1,4 @@ Entries: -- author: Weax - changes: - - message: The CLF3 reaction now requires heating first before you can engulf chemistry - in fiery death. - type: Tweak - id: 6417 - time: '2024-04-22T08:44:14.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/27187 -- author: Potato1234_x - changes: - - message: Added Psicodine, Mannitol, Lipolicide and Happiness. - type: Add - id: 6418 - time: '2024-04-22T08:45:39.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/27134 - author: Terraspark4941 changes: - message: Updated the engineering section of the guidebook! @@ -3813,3 +3798,17 @@ id: 6916 time: '2024-07-14T02:59:45.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/29979 +- author: SlamBamActionman + changes: + - message: RGBee and Rainbow Carp plushies now cycle color when held/worn. + type: Fix + id: 6917 + time: '2024-07-14T10:26:34.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/30023 +- author: Winkarst-cpu + changes: + - message: Now grappling gun is clumsy proof. + type: Tweak + id: 6918 + time: '2024-07-14T10:26:56.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/29904 From a71417125e218a5342f270c8170269612aace89d Mon Sep 17 00:00:00 2001 From: osjarw <62134478+osjarw@users.noreply.github.com> Date: Sun, 14 Jul 2024 13:28:46 +0300 Subject: [PATCH 221/765] Fix HTN/NPC better plan selection (#30017) * recording commit * Remove debugging/recording content --- Content.Server/NPC/HTN/HTNPlanJob.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Content.Server/NPC/HTN/HTNPlanJob.cs b/Content.Server/NPC/HTN/HTNPlanJob.cs index d6d10ad311f..8158303524a 100644 --- a/Content.Server/NPC/HTN/HTNPlanJob.cs +++ b/Content.Server/NPC/HTN/HTNPlanJob.cs @@ -160,9 +160,9 @@ private bool TryFindSatisfiedMethod(HTNCompoundTask compoundId, Queue t { var compound = _protoManager.Index(compoundId.Task); - for (var i = mtrIndex; i < compound.Branches.Count; i++) + for (; mtrIndex < compound.Branches.Count; mtrIndex++) { - var branch = compound.Branches[i]; + var branch = compound.Branches[mtrIndex]; var isValid = true; foreach (var con in branch.Preconditions) From cf7668f957b4d9ece50b654c5c4646aa43211030 Mon Sep 17 00:00:00 2001 From: Ed <96445749+TheShuEd@users.noreply.github.com> Date: Sun, 14 Jul 2024 16:58:48 +0300 Subject: [PATCH 222/765] Ambient music rules refactor (#29921) * refactor * dutypo --- .../Audio/ContentAudioSystem.AmbientMusic.cs | 1 + Content.Shared/Audio/AmbientMusicPrototype.cs | 1 + Content.Shared/Random/Rules/AlwaysTrue.cs | 12 + Content.Shared/Random/Rules/GridInRange.cs | 39 +++ Content.Shared/Random/Rules/InSpace.cs | 18 ++ Content.Shared/Random/Rules/NearbyAccess.cs | 77 ++++++ .../Random/Rules/NearbyComponents.cs | 71 +++++ Content.Shared/Random/Rules/NearbyEntities.cs | 58 ++++ .../Random/Rules/NearbyTilesPercent.cs | 79 ++++++ Content.Shared/Random/Rules/OnMapGrid.cs | 19 ++ Content.Shared/Random/Rules/RulesSystem.cs | 39 +++ Content.Shared/Random/RulesPrototype.cs | 141 ---------- Content.Shared/Random/RulesSystem.cs | 247 ------------------ 13 files changed, 414 insertions(+), 388 deletions(-) create mode 100644 Content.Shared/Random/Rules/AlwaysTrue.cs create mode 100644 Content.Shared/Random/Rules/GridInRange.cs create mode 100644 Content.Shared/Random/Rules/InSpace.cs create mode 100644 Content.Shared/Random/Rules/NearbyAccess.cs create mode 100644 Content.Shared/Random/Rules/NearbyComponents.cs create mode 100644 Content.Shared/Random/Rules/NearbyEntities.cs create mode 100644 Content.Shared/Random/Rules/NearbyTilesPercent.cs create mode 100644 Content.Shared/Random/Rules/OnMapGrid.cs create mode 100644 Content.Shared/Random/Rules/RulesSystem.cs delete mode 100644 Content.Shared/Random/RulesPrototype.cs delete mode 100644 Content.Shared/Random/RulesSystem.cs diff --git a/Content.Client/Audio/ContentAudioSystem.AmbientMusic.cs b/Content.Client/Audio/ContentAudioSystem.AmbientMusic.cs index 84b787a4ec9..d60c978ccf5 100644 --- a/Content.Client/Audio/ContentAudioSystem.AmbientMusic.cs +++ b/Content.Client/Audio/ContentAudioSystem.AmbientMusic.cs @@ -4,6 +4,7 @@ using Content.Shared.CCVar; using Content.Shared.GameTicking; using Content.Shared.Random; +using Content.Shared.Random.Rules; using Robust.Client.GameObjects; using Robust.Client.Player; using Robust.Client.ResourceManagement; diff --git a/Content.Shared/Audio/AmbientMusicPrototype.cs b/Content.Shared/Audio/AmbientMusicPrototype.cs index 54f70f57280..219c41527d1 100644 --- a/Content.Shared/Audio/AmbientMusicPrototype.cs +++ b/Content.Shared/Audio/AmbientMusicPrototype.cs @@ -1,4 +1,5 @@ using Content.Shared.Random; +using Content.Shared.Random.Rules; using Robust.Shared.Audio; using Robust.Shared.Prototypes; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; diff --git a/Content.Shared/Random/Rules/AlwaysTrue.cs b/Content.Shared/Random/Rules/AlwaysTrue.cs new file mode 100644 index 00000000000..98b81fae793 --- /dev/null +++ b/Content.Shared/Random/Rules/AlwaysTrue.cs @@ -0,0 +1,12 @@ +namespace Content.Shared.Random.Rules; + +/// +/// Always returns true. Used for fallbacks. +/// +public sealed partial class AlwaysTrueRule : RulesRule +{ + public override bool Check(EntityManager entManager, EntityUid uid) + { + return !Inverted; + } +} diff --git a/Content.Shared/Random/Rules/GridInRange.cs b/Content.Shared/Random/Rules/GridInRange.cs new file mode 100644 index 00000000000..8cbbef1cdc2 --- /dev/null +++ b/Content.Shared/Random/Rules/GridInRange.cs @@ -0,0 +1,39 @@ +using System.Numerics; +using Robust.Shared.Map; + +namespace Content.Shared.Random.Rules; + +/// +/// Returns true if on a grid or in range of one. +/// +public sealed partial class GridInRangeRule : RulesRule +{ + [DataField] + public float Range = 10f; + + public override bool Check(EntityManager entManager, EntityUid uid) + { + if (!entManager.TryGetComponent(uid, out TransformComponent? xform)) + { + return false; + } + + if (xform.GridUid != null) + { + return !Inverted; + } + + var transform = entManager.System(); + var mapManager = IoCManager.Resolve(); + + var worldPos = transform.GetWorldPosition(xform); + var gridRange = new Vector2(Range, Range); + + foreach (var _ in mapManager.FindGridsIntersecting(xform.MapID, new Box2(worldPos - gridRange, worldPos + gridRange))) + { + return !Inverted; + } + + return false; + } +} diff --git a/Content.Shared/Random/Rules/InSpace.cs b/Content.Shared/Random/Rules/InSpace.cs new file mode 100644 index 00000000000..8163e1f6be9 --- /dev/null +++ b/Content.Shared/Random/Rules/InSpace.cs @@ -0,0 +1,18 @@ +namespace Content.Shared.Random.Rules; + +/// +/// Returns true if the attached entity is in space. +/// +public sealed partial class InSpaceRule : RulesRule +{ + public override bool Check(EntityManager entManager, EntityUid uid) + { + if (!entManager.TryGetComponent(uid, out TransformComponent? xform) || + xform.GridUid != null) + { + return Inverted; + } + + return !Inverted; + } +} diff --git a/Content.Shared/Random/Rules/NearbyAccess.cs b/Content.Shared/Random/Rules/NearbyAccess.cs new file mode 100644 index 00000000000..2a8ad077c6e --- /dev/null +++ b/Content.Shared/Random/Rules/NearbyAccess.cs @@ -0,0 +1,77 @@ +using Content.Shared.Access; +using Content.Shared.Access.Components; +using Content.Shared.Access.Systems; +using Robust.Shared.Prototypes; + +namespace Content.Shared.Random.Rules; + +/// +/// Checks for an entity nearby with the specified access. +/// +public sealed partial class NearbyAccessRule : RulesRule +{ + // This exists because of door electronics contained inside doors. + /// + /// Does the access entity need to be anchored. + /// + [DataField] + public bool Anchored = true; + + /// + /// Count of entities that need to be nearby. + /// + [DataField] + public int Count = 1; + + [DataField(required: true)] + public List> Access = new(); + + [DataField] + public float Range = 10f; + + public override bool Check(EntityManager entManager, EntityUid uid) + { + var xformQuery = entManager.GetEntityQuery(); + + if (!xformQuery.TryGetComponent(uid, out var xform) || + xform.MapUid == null) + { + return false; + } + + var transform = entManager.System(); + var lookup = entManager.System(); + var reader = entManager.System(); + + var found = false; + var worldPos = transform.GetWorldPosition(xform, xformQuery); + var count = 0; + + // TODO: Update this when we get the callback version + var entities = new HashSet>(); + lookup.GetEntitiesInRange(xform.MapID, worldPos, Range, entities); + foreach (var comp in entities) + { + if (!reader.AreAccessTagsAllowed(Access, comp) || + Anchored && + (!xformQuery.TryGetComponent(comp, out var compXform) || + !compXform.Anchored)) + { + continue; + } + + count++; + + if (count < Count) + continue; + + found = true; + break; + } + + if (!found) + return Inverted; + + return !Inverted; + } +} diff --git a/Content.Shared/Random/Rules/NearbyComponents.cs b/Content.Shared/Random/Rules/NearbyComponents.cs new file mode 100644 index 00000000000..13108e88d6c --- /dev/null +++ b/Content.Shared/Random/Rules/NearbyComponents.cs @@ -0,0 +1,71 @@ +using Robust.Shared.Prototypes; + +namespace Content.Shared.Random.Rules; + +public sealed partial class NearbyComponentsRule : RulesRule +{ + /// + /// Does the entity need to be anchored. + /// + [DataField] + public bool Anchored; + + [DataField] + public int Count; + + [DataField(required: true)] + public ComponentRegistry Components = default!; + + [DataField] + public float Range = 10f; + + public override bool Check(EntityManager entManager, EntityUid uid) + { + var inRange = new HashSet>(); + var xformQuery = entManager.GetEntityQuery(); + + if (!xformQuery.TryGetComponent(uid, out var xform) || + xform.MapUid == null) + { + return false; + } + + var transform = entManager.System(); + var lookup = entManager.System(); + + var found = false; + var worldPos = transform.GetWorldPosition(xform); + var count = 0; + + foreach (var compType in Components.Values) + { + inRange.Clear(); + lookup.GetEntitiesInRange(compType.Component.GetType(), xform.MapID, worldPos, Range, inRange); + foreach (var comp in inRange) + { + if (Anchored && + (!xformQuery.TryGetComponent(comp, out var compXform) || + !compXform.Anchored)) + { + continue; + } + + count++; + + if (count < Count) + continue; + + found = true; + break; + } + + if (found) + break; + } + + if (!found) + return Inverted; + + return !Inverted; + } +} diff --git a/Content.Shared/Random/Rules/NearbyEntities.cs b/Content.Shared/Random/Rules/NearbyEntities.cs new file mode 100644 index 00000000000..0754750bc47 --- /dev/null +++ b/Content.Shared/Random/Rules/NearbyEntities.cs @@ -0,0 +1,58 @@ +using Content.Shared.Whitelist; + +namespace Content.Shared.Random.Rules; + +/// +/// Checks for entities matching the whitelist in range. +/// This is more expensive than so prefer that! +/// +public sealed partial class NearbyEntitiesRule : RulesRule +{ + /// + /// How many of the entity need to be nearby. + /// + [DataField] + public int Count = 1; + + [DataField(required: true)] + public EntityWhitelist Whitelist = new(); + + [DataField] + public float Range = 10f; + + public override bool Check(EntityManager entManager, EntityUid uid) + { + if (!entManager.TryGetComponent(uid, out TransformComponent? xform) || + xform.MapUid == null) + { + return false; + } + + var transform = entManager.System(); + var lookup = entManager.System(); + var whitelistSystem = entManager.System(); + + var found = false; + var worldPos = transform.GetWorldPosition(xform); + var count = 0; + + foreach (var ent in lookup.GetEntitiesInRange(xform.MapID, worldPos, Range)) + { + if (whitelistSystem.IsWhitelistFail(Whitelist, ent)) + continue; + + count++; + + if (count < Count) + continue; + + found = true; + break; + } + + if (!found) + return Inverted; + + return !Inverted; + } +} diff --git a/Content.Shared/Random/Rules/NearbyTilesPercent.cs b/Content.Shared/Random/Rules/NearbyTilesPercent.cs new file mode 100644 index 00000000000..465ac8dc5c6 --- /dev/null +++ b/Content.Shared/Random/Rules/NearbyTilesPercent.cs @@ -0,0 +1,79 @@ +using Content.Shared.Maps; +using Robust.Shared.Map; +using Robust.Shared.Map.Components; +using Robust.Shared.Physics.Components; +using Robust.Shared.Prototypes; + +namespace Content.Shared.Random.Rules; + +public sealed partial class NearbyTilesPercentRule : RulesRule +{ + /// + /// If there are anchored entities on the tile do we ignore the tile. + /// + [DataField] + public bool IgnoreAnchored; + + [DataField(required: true)] + public float Percent; + + [DataField(required: true)] + public List> Tiles = new(); + + [DataField] + public float Range = 10f; + + public override bool Check(EntityManager entManager, EntityUid uid) + { + if (!entManager.TryGetComponent(uid, out TransformComponent? xform) || + !entManager.TryGetComponent(xform.GridUid, out var grid)) + { + return false; + } + + var transform = entManager.System(); + var tileDef = IoCManager.Resolve(); + + var physicsQuery = entManager.GetEntityQuery(); + var tileCount = 0; + var matchingTileCount = 0; + + foreach (var tile in grid.GetTilesIntersecting(new Circle(transform.GetWorldPosition(xform), + Range))) + { + // Only consider collidable anchored (for reasons some subfloor stuff has physics but non-collidable) + if (IgnoreAnchored) + { + var gridEnum = grid.GetAnchoredEntitiesEnumerator(tile.GridIndices); + var found = false; + + while (gridEnum.MoveNext(out var ancUid)) + { + if (!physicsQuery.TryGetComponent(ancUid, out var physics) || + !physics.CanCollide) + { + continue; + } + + found = true; + break; + } + + if (found) + continue; + } + + tileCount++; + + if (!Tiles.Contains(tileDef[tile.Tile.TypeId].ID)) + continue; + + matchingTileCount++; + } + + if (tileCount == 0 || matchingTileCount / (float) tileCount < Percent) + return Inverted; + + return !Inverted; + } +} diff --git a/Content.Shared/Random/Rules/OnMapGrid.cs b/Content.Shared/Random/Rules/OnMapGrid.cs new file mode 100644 index 00000000000..bea841872eb --- /dev/null +++ b/Content.Shared/Random/Rules/OnMapGrid.cs @@ -0,0 +1,19 @@ +namespace Content.Shared.Random.Rules; + +/// +/// Returns true if griduid and mapuid match (AKA on 'planet'). +/// +public sealed partial class OnMapGridRule : RulesRule +{ + public override bool Check(EntityManager entManager, EntityUid uid) + { + if (!entManager.TryGetComponent(uid, out TransformComponent? xform) || + xform.GridUid != xform.MapUid || + xform.MapUid == null) + { + return Inverted; + } + + return !Inverted; + } +} diff --git a/Content.Shared/Random/Rules/RulesSystem.cs b/Content.Shared/Random/Rules/RulesSystem.cs new file mode 100644 index 00000000000..1957beab510 --- /dev/null +++ b/Content.Shared/Random/Rules/RulesSystem.cs @@ -0,0 +1,39 @@ +using Robust.Shared.Prototypes; + +namespace Content.Shared.Random.Rules; + +/// +/// Rules-based item selection. Can be used for any sort of conditional selection +/// Every single condition needs to be true for this to be selected. +/// e.g. "choose maintenance audio if 90% of tiles nearby are maintenance tiles" +/// +[Prototype("rules")] +public sealed partial class RulesPrototype : IPrototype +{ + [IdDataField] public string ID { get; } = string.Empty; + + [DataField("rules", required: true)] + public List Rules = new(); +} + +[ImplicitDataDefinitionForInheritors] +public abstract partial class RulesRule +{ + [DataField] + public bool Inverted; + public abstract bool Check(EntityManager entManager, EntityUid uid); +} + +public sealed class RulesSystem : EntitySystem +{ + public bool IsTrue(EntityUid uid, RulesPrototype rules) + { + foreach (var rule in rules.Rules) + { + if (!rule.Check(EntityManager, uid)) + return false; + } + + return true; + } +} diff --git a/Content.Shared/Random/RulesPrototype.cs b/Content.Shared/Random/RulesPrototype.cs deleted file mode 100644 index 20961af8e72..00000000000 --- a/Content.Shared/Random/RulesPrototype.cs +++ /dev/null @@ -1,141 +0,0 @@ -using Content.Shared.Access; -using Content.Shared.Maps; -using Content.Shared.Whitelist; -using Robust.Shared.Prototypes; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.List; - -namespace Content.Shared.Random; - -/// -/// Rules-based item selection. Can be used for any sort of conditional selection -/// Every single condition needs to be true for this to be selected. -/// e.g. "choose maintenance audio if 90% of tiles nearby are maintenance tiles" -/// -[Prototype("rules")] -public sealed partial class RulesPrototype : IPrototype -{ - [IdDataField] public string ID { get; } = string.Empty; - - [DataField("rules", required: true)] - public List Rules = new(); -} - -[ImplicitDataDefinitionForInheritors] -public abstract partial class RulesRule -{ - -} - -/// -/// Returns true if the attached entity is in space. -/// -public sealed partial class InSpaceRule : RulesRule -{ - -} - -/// -/// Checks for entities matching the whitelist in range. -/// This is more expensive than so prefer that! -/// -public sealed partial class NearbyEntitiesRule : RulesRule -{ - /// - /// How many of the entity need to be nearby. - /// - [DataField("count")] - public int Count = 1; - - [DataField("whitelist", required: true)] - public EntityWhitelist Whitelist = new(); - - [DataField("range")] - public float Range = 10f; -} - -public sealed partial class NearbyTilesPercentRule : RulesRule -{ - /// - /// If there are anchored entities on the tile do we ignore the tile. - /// - [DataField("ignoreAnchored")] public bool IgnoreAnchored; - - [DataField("percent", required: true)] - public float Percent; - - [DataField("tiles", required: true, customTypeSerializer:typeof(PrototypeIdListSerializer))] - public List Tiles = new(); - - [DataField("range")] - public float Range = 10f; -} - -/// -/// Always returns true. Used for fallbacks. -/// -public sealed partial class AlwaysTrueRule : RulesRule -{ - -} - -/// -/// Returns true if on a grid or in range of one. -/// -public sealed partial class GridInRangeRule : RulesRule -{ - [DataField("range")] - public float Range = 10f; - - [DataField("inverted")] - public bool Inverted = false; -} - -/// -/// Returns true if griduid and mapuid match (AKA on 'planet'). -/// -public sealed partial class OnMapGridRule : RulesRule -{ - -} - -/// -/// Checks for an entity nearby with the specified access. -/// -public sealed partial class NearbyAccessRule : RulesRule -{ - // This exists because of doorelectronics contained inside doors. - /// - /// Does the access entity need to be anchored. - /// - [DataField("anchored")] - public bool Anchored = true; - - /// - /// Count of entities that need to be nearby. - /// - [DataField("count")] - public int Count = 1; - - [DataField("access", required: true)] - public List> Access = new(); - - [DataField("range")] - public float Range = 10f; -} - -public sealed partial class NearbyComponentsRule : RulesRule -{ - /// - /// Does the entity need to be anchored. - /// - [DataField("anchored")] - public bool Anchored; - - [DataField("count")] public int Count; - - [DataField("components", required: true)] - public ComponentRegistry Components = default!; - - [DataField("range")] - public float Range = 10f; -} diff --git a/Content.Shared/Random/RulesSystem.cs b/Content.Shared/Random/RulesSystem.cs deleted file mode 100644 index 58d67c268e3..00000000000 --- a/Content.Shared/Random/RulesSystem.cs +++ /dev/null @@ -1,247 +0,0 @@ -using System.Numerics; -using Content.Shared.Access.Components; -using Content.Shared.Access.Systems; -using Content.Shared.Whitelist; -using Robust.Shared.Map; -using Robust.Shared.Map.Components; -using Robust.Shared.Physics.Components; - -namespace Content.Shared.Random; - -public sealed class RulesSystem : EntitySystem -{ - [Dependency] private readonly IMapManager _mapManager = default!; - [Dependency] private readonly ITileDefinitionManager _tileDef = default!; - [Dependency] private readonly AccessReaderSystem _reader = default!; - [Dependency] private readonly EntityLookupSystem _lookup = default!; - [Dependency] private readonly SharedTransformSystem _transform = default!; - [Dependency] private readonly EntityWhitelistSystem _whitelistSystem = default!; - public bool IsTrue(EntityUid uid, RulesPrototype rules) - { - var inRange = new HashSet>(); - foreach (var rule in rules.Rules) - { - switch (rule) - { - case AlwaysTrueRule: - break; - case GridInRangeRule griddy: - { - if (!TryComp(uid, out TransformComponent? xform)) - { - return false; - } - - if (xform.GridUid != null) - { - return !griddy.Inverted; - } - - var worldPos = _transform.GetWorldPosition(xform); - var gridRange = new Vector2(griddy.Range, griddy.Range); - - foreach (var _ in _mapManager.FindGridsIntersecting( - xform.MapID, - new Box2(worldPos - gridRange, worldPos + gridRange))) - { - return !griddy.Inverted; - } - - break; - } - case InSpaceRule: - { - if (!TryComp(uid, out TransformComponent? xform) || - xform.GridUid != null) - { - return false; - } - - break; - } - case NearbyAccessRule access: - { - var xformQuery = GetEntityQuery(); - - if (!xformQuery.TryGetComponent(uid, out var xform) || - xform.MapUid == null) - { - return false; - } - - var found = false; - var worldPos = _transform.GetWorldPosition(xform, xformQuery); - var count = 0; - - // TODO: Update this when we get the callback version - var entities = new HashSet>(); - _lookup.GetEntitiesInRange(xform.MapID, worldPos, access.Range, entities); - foreach (var comp in entities) - { - if (!_reader.AreAccessTagsAllowed(access.Access, comp) || - access.Anchored && - (!xformQuery.TryGetComponent(comp, out var compXform) || - !compXform.Anchored)) - { - continue; - } - - count++; - - if (count < access.Count) - continue; - - found = true; - break; - } - - if (!found) - return false; - - break; - } - case NearbyComponentsRule nearbyComps: - { - var xformQuery = GetEntityQuery(); - - if (!xformQuery.TryGetComponent(uid, out var xform) || - xform.MapUid == null) - { - return false; - } - - var found = false; - var worldPos = _transform.GetWorldPosition(xform); - var count = 0; - - foreach (var compType in nearbyComps.Components.Values) - { - inRange.Clear(); - _lookup.GetEntitiesInRange(compType.Component.GetType(), xform.MapID, worldPos, nearbyComps.Range, inRange); - foreach (var comp in inRange) - { - if (nearbyComps.Anchored && - (!xformQuery.TryGetComponent(comp, out var compXform) || - !compXform.Anchored)) - { - continue; - } - - count++; - - if (count < nearbyComps.Count) - continue; - - found = true; - break; - } - - if (found) - break; - } - - if (!found) - return false; - - break; - } - case NearbyEntitiesRule entity: - { - if (!TryComp(uid, out TransformComponent? xform) || - xform.MapUid == null) - { - return false; - } - - var found = false; - var worldPos = _transform.GetWorldPosition(xform); - var count = 0; - - foreach (var ent in _lookup.GetEntitiesInRange(xform.MapID, worldPos, entity.Range)) - { - if (_whitelistSystem.IsWhitelistFail(entity.Whitelist, ent)) - continue; - - count++; - - if (count < entity.Count) - continue; - - found = true; - break; - } - - if (!found) - return false; - - break; - } - case NearbyTilesPercentRule tiles: - { - if (!TryComp(uid, out TransformComponent? xform) || - !TryComp(xform.GridUid, out var grid)) - { - return false; - } - - var physicsQuery = GetEntityQuery(); - var tileCount = 0; - var matchingTileCount = 0; - - foreach (var tile in grid.GetTilesIntersecting(new Circle(_transform.GetWorldPosition(xform), - tiles.Range))) - { - // Only consider collidable anchored (for reasons some subfloor stuff has physics but non-collidable) - if (tiles.IgnoreAnchored) - { - var gridEnum = grid.GetAnchoredEntitiesEnumerator(tile.GridIndices); - var found = false; - - while (gridEnum.MoveNext(out var ancUid)) - { - if (!physicsQuery.TryGetComponent(ancUid, out var physics) || - !physics.CanCollide) - { - continue; - } - - found = true; - break; - } - - if (found) - continue; - } - - tileCount++; - - if (!tiles.Tiles.Contains(_tileDef[tile.Tile.TypeId].ID)) - continue; - - matchingTileCount++; - } - - if (tileCount == 0 || matchingTileCount / (float) tileCount < tiles.Percent) - return false; - - break; - } - case OnMapGridRule: - { - if (!TryComp(uid, out TransformComponent? xform) || - xform.GridUid != xform.MapUid || - xform.MapUid == null) - { - return false; - } - - break; - } - default: - throw new NotImplementedException(); - } - } - - return true; - } -} From 389683d14feefb56daed4d96ccc60afebe890d98 Mon Sep 17 00:00:00 2001 From: themias <89101928+themias@users.noreply.github.com> Date: Sun, 14 Jul 2024 10:08:39 -0400 Subject: [PATCH 223/765] Prevent virtual item storage and popups (#30020) * Prevent virtual item storage and popups * fix typo * add comment --- Content.Shared/Interaction/SmartEquipSystem.cs | 11 ++++++----- .../Inventory/VirtualItem/SharedVirtualItemSystem.cs | 8 ++++++++ .../Prototypes/Entities/Virtual/virtual_item.yml | 1 + 3 files changed, 15 insertions(+), 5 deletions(-) diff --git a/Content.Shared/Interaction/SmartEquipSystem.cs b/Content.Shared/Interaction/SmartEquipSystem.cs index bba294db28d..4feb0445f8f 100644 --- a/Content.Shared/Interaction/SmartEquipSystem.cs +++ b/Content.Shared/Interaction/SmartEquipSystem.cs @@ -62,21 +62,22 @@ private void HandleSmartEquip(ICommonSession? session, string equipmentSlot) if (playerSession.AttachedEntity is not { Valid: true } uid || !Exists(uid)) return; - if (!_actionBlocker.CanInteract(uid, null)) - return; - // early out if we don't have any hands or a valid inventory slot if (!TryComp(uid, out var hands) || hands.ActiveHand == null) return; + var handItem = hands.ActiveHand.HeldEntity; + + // can the user interact, and is the item interactable? e.g. virtual items + if (!_actionBlocker.CanInteract(uid, handItem)) + return; + if (!TryComp(uid, out var inventory) || !_inventory.HasSlot(uid, equipmentSlot, inventory)) { _popup.PopupClient(Loc.GetString("smart-equip-missing-equipment-slot", ("slotName", equipmentSlot)), uid, uid); return; } - var handItem = hands.ActiveHand.HeldEntity; - // early out if we have an item and cant drop it at all if (handItem != null && !_hands.CanDropHeld(uid, hands.ActiveHand)) { diff --git a/Content.Shared/Inventory/VirtualItem/SharedVirtualItemSystem.cs b/Content.Shared/Inventory/VirtualItem/SharedVirtualItemSystem.cs index cd0863ec88d..8b9c052c8d5 100644 --- a/Content.Shared/Inventory/VirtualItem/SharedVirtualItemSystem.cs +++ b/Content.Shared/Inventory/VirtualItem/SharedVirtualItemSystem.cs @@ -2,6 +2,7 @@ using Content.Shared.Hands; using Content.Shared.Hands.EntitySystems; using Content.Shared.Interaction; +using Content.Shared.Interaction.Events; using Content.Shared.Inventory.Events; using Content.Shared.Item; using Content.Shared.Popups; @@ -43,6 +44,7 @@ public override void Initialize() SubscribeLocalEvent(OnBeingUnequippedAttempt); SubscribeLocalEvent(OnBeforeRangedInteract); + SubscribeLocalEvent(OnGettingInteractedWithAttemptEvent); } /// @@ -72,6 +74,12 @@ private void OnBeforeRangedInteract(Entity ent, ref Before args.Handled = true; } + private void OnGettingInteractedWithAttemptEvent(Entity ent, ref GettingInteractedWithAttemptEvent args) + { + // No interactions with a virtual item, please. + args.Cancelled = true; + } + #region Hands /// diff --git a/Resources/Prototypes/Entities/Virtual/virtual_item.yml b/Resources/Prototypes/Entities/Virtual/virtual_item.yml index ed742435501..088de6a6da5 100644 --- a/Resources/Prototypes/Entities/Virtual/virtual_item.yml +++ b/Resources/Prototypes/Entities/Virtual/virtual_item.yml @@ -5,4 +5,5 @@ noSpawn: true components: - type: Item + size: Ginormous # no storage insertion visuals - type: VirtualItem From c0903b7aad1e3e36684f9df773197f1b09c82846 Mon Sep 17 00:00:00 2001 From: CookieMasterT <124045269+CookieMasterT@users.noreply.github.com> Date: Sun, 14 Jul 2024 16:09:41 +0200 Subject: [PATCH 224/765] Add petting cyborgs (#30037) added petting borgs, adjusted interactions --- .../interaction-popup-component.ftl | 14 ++++++ .../Mobs/Cyborgs/base_borg_chassis.yml | 1 + .../Entities/Mobs/Cyborgs/borg_chassis.yml | 48 +++++++++++++++++++ 3 files changed, 63 insertions(+) diff --git a/Resources/Locale/en-US/interaction/interaction-popup-component.ftl b/Resources/Locale/en-US/interaction/interaction-popup-component.ftl index 55be1fb3b97..10773d6de84 100644 --- a/Resources/Locale/en-US/interaction/interaction-popup-component.ftl +++ b/Resources/Locale/en-US/interaction/interaction-popup-component.ftl @@ -60,12 +60,26 @@ petting-success-honkbot = You pet {THE($target)} on {POSS-ADJ($target)} slippery petting-success-mimebot = You pet {THE($target)} on {POSS-ADJ($target)} cold metal head. petting-success-cleanbot = You pet {THE($target)} on {POSS-ADJ($target)} damp metal head. petting-success-medibot = You pet {THE($target)} on {POSS-ADJ($target)} sterile metal head. +petting-success-generic-cyborg = You pet {THE($target)} on {POSS-ADJ($target)} metal head. +petting-success-salvage-cyborg = You pet {THE($target)} on {POSS-ADJ($target)} dirty metal head. +petting-success-engineer-cyborg = You pet {THE($target)} on {POSS-ADJ($target)} reflective metal head. +petting-success-janitor-cyborg = You pet {THE($target)} on {POSS-ADJ($target)} damp metal head. +petting-success-medical-cyborg = You pet {THE($target)} on {POSS-ADJ($target)} sterile metal head. +petting-success-service-cyborg = You pet {THE($target)} on {POSS-ADJ($target)} dapper looking metal head. +petting-success-syndicate-cyborg = You pet {THE($target)} on {POSS-ADJ($target)} menacing metal head. petting-success-recycler = You pet {THE($target)} on {POSS-ADJ($target)} mildly threatening steel exterior. petting-failure-honkbot = You reach out to pet {THE($target)}, but {SUBJECT($target)} {CONJUGATE-BASIC($target, "honk", "honks")} in refusal! petting-failure-cleanbot = You reach out to pet {THE($target)}, but {SUBJECT($target)} {CONJUGATE-BE($target)} busy mopping! petting-failure-mimebot = You reach out to pet {THE($target)}, but {SUBJECT($target)} {CONJUGATE-BE($target)} busy miming! petting-failure-medibot = You reach out to pet {THE($target)}, but {POSS-ADJ($target)} syringe nearly stabs your hand! +petting-failure-generic-cyborg = You reach out to pet {THE($target)}, but {SUBJECT($target)} {CONJUGATE-BE($target)} busy stating laws! +petting-failure-salvage-cyborg = You reach out to pet {THE($target)}, but {SUBJECT($target)} {CONJUGATE-BE($target)} busy drilling! +petting-failure-engineer-cyborg = You reach out to pet {THE($target)}, but {SUBJECT($target)} {CONJUGATE-BE($target)} busy repairing! +petting-failure-janitor-cyborg = You reach out to pet {THE($target)}, but {SUBJECT($target)} {CONJUGATE-BE($target)} busy cleaning! +petting-failure-medical-cyborg = You reach out to pet {THE($target)}, but {SUBJECT($target)} {CONJUGATE-BE($target)} busy saving lives! +petting-failure-service-cyborg = You reach out to pet {THE($target)}, but {SUBJECT($target)} {CONJUGATE-BE($target)} busy serving others! +petting-failure-syndicate-cyborg = You reach out to pet {THE($target)}, but {POSS-ADJ($target)} treacherous affiliation makes you reconsider. ## Rattling fences diff --git a/Resources/Prototypes/Entities/Mobs/Cyborgs/base_borg_chassis.yml b/Resources/Prototypes/Entities/Mobs/Cyborgs/base_borg_chassis.yml index 128a56814ab..bfb1dd83a82 100644 --- a/Resources/Prototypes/Entities/Mobs/Cyborgs/base_borg_chassis.yml +++ b/Resources/Prototypes/Entities/Mobs/Cyborgs/base_borg_chassis.yml @@ -150,6 +150,7 @@ - type: Lock locked: true breakOnEmag: false + unlockOnClick: false - type: ActivatableUIRequiresLock - type: LockedWiresPanel - type: Damageable diff --git a/Resources/Prototypes/Entities/Mobs/Cyborgs/borg_chassis.yml b/Resources/Prototypes/Entities/Mobs/Cyborgs/borg_chassis.yml index 04d94469c1a..1c2f6e87682 100644 --- a/Resources/Prototypes/Entities/Mobs/Cyborgs/borg_chassis.yml +++ b/Resources/Prototypes/Entities/Mobs/Cyborgs/borg_chassis.yml @@ -29,6 +29,11 @@ node: cyborg - type: Speech speechVerb: Robotic + - type: InteractionPopup + interactSuccessString: petting-success-generic-cyborg + interactFailureString: petting-failure-generic-cyborg + interactSuccessSound: + path: /Audio/Ambience/Objects/periodic_beep.ogg - type: entity id: BorgChassisMining @@ -85,6 +90,11 @@ access: [["Cargo"], ["Salvage"], ["Command"], ["Research"]] - type: Inventory templateId: borgTall + - type: InteractionPopup + interactSuccessString: petting-success-salvage-cyborg + interactFailureString: petting-failure-salvage-cyborg + interactSuccessSound: + path: /Audio/Ambience/Objects/periodic_beep.ogg - type: entity id: BorgChassisEngineer @@ -133,6 +143,11 @@ access: [["Engineering"], ["Command"], ["Research"]] - type: Inventory templateId: borgShort + - type: InteractionPopup + interactSuccessString: petting-success-engineer-cyborg + interactFailureString: petting-failure-engineer-cyborg + interactSuccessSound: + path: /Audio/Ambience/Objects/periodic_beep.ogg - type: SiliconLawProvider # Delta-V - Adds custom lawset for Engineering Cyborg laws: Engineer @@ -191,8 +206,16 @@ access: [["Service"], ["Command"], ["Research"]] - type: Inventory templateId: borgShort +<<<<<<< HEAD - type: SiliconLawProvider # Delta-V Adds custom lawset for Janitor Cyborg laws: Janitor +======= + - type: InteractionPopup + interactSuccessString: petting-success-janitor-cyborg + interactFailureString: petting-failure-janitor-cyborg + interactSuccessSound: + path: /Audio/Ambience/Objects/periodic_beep.ogg +>>>>>>> b6115b672a (Add petting cyborgs (#30037)) - type: entity id: BorgChassisMedical @@ -255,6 +278,11 @@ - type: FootstepModifier footstepSoundCollection: collection: FootstepHoverBorg + - type: InteractionPopup + interactSuccessString: petting-success-medical-cyborg + interactFailureString: petting-failure-medical-cyborg + interactSuccessSound: + path: /Audio/Ambience/Objects/periodic_beep.ogg - type: entity id: BorgChassisService @@ -303,6 +331,11 @@ access: [["Service"], ["Command"], ["Research"]] - type: Inventory templateId: borgTall + - type: InteractionPopup + interactSuccessString: petting-success-service-cyborg + interactFailureString: petting-failure-service-cyborg + interactSuccessSound: + path: /Audio/Ambience/Objects/periodic_beep.ogg - type: entity id: BorgChassisSyndicateAssault @@ -332,6 +365,11 @@ noMindState: synd_sec - type: Construction node: syndicateassault + - type: InteractionPopup + interactSuccessString: petting-success-syndicate-cyborg + interactFailureString: petting-failure-syndicate-cyborg + interactSuccessSound: + path: /Audio/Ambience/Objects/periodic_beep.ogg - type: entity id: BorgChassisSyndicateMedical @@ -364,6 +402,11 @@ - type: ShowHealthBars damageContainers: - Biological + - type: InteractionPopup + interactSuccessString: petting-success-syndicate-cyborg + interactFailureString: petting-failure-syndicate-cyborg + interactSuccessSound: + path: /Audio/Ambience/Objects/periodic_beep.ogg - type: entity id: BorgChassisSyndicateSaboteur @@ -397,3 +440,8 @@ damageContainers: - Inorganic - Silicon + - type: InteractionPopup + interactSuccessString: petting-success-syndicate-cyborg + interactFailureString: petting-failure-syndicate-cyborg + interactSuccessSound: + path: /Audio/Ambience/Objects/periodic_beep.ogg From 5b021b0e8894bc8307d26f6621c135d485aa73b6 Mon Sep 17 00:00:00 2001 From: PJBot Date: Sun, 14 Jul 2024 14:10:48 +0000 Subject: [PATCH 225/765] Automatic changelog update --- Resources/Changelog/Changelog.yml | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index d06bda3324f..f0ef8806add 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,11 +1,4 @@ Entries: -- author: Terraspark4941 - changes: - - message: Updated the engineering section of the guidebook! - type: Tweak - id: 6419 - time: '2024-04-22T08:58:54.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/26851 - author: eclips_e changes: - message: Slimepeople can now morph into a "geras"--a smaller slime form that can @@ -3812,3 +3805,12 @@ id: 6918 time: '2024-07-14T10:26:56.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/29904 +- author: HahayesSiH + changes: + - message: It is now possible to pet cyborgs. + type: Add + - message: Clicking on cyborgs and opening the strip menu no longer unlocks them. + type: Tweak + id: 6919 + time: '2024-07-14T14:09:41.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/30037 From 3b6cf9ee7b3d8b89918c7aac5c93740cd60b7134 Mon Sep 17 00:00:00 2001 From: deltanedas <39013340+deltanedas@users.noreply.github.com> Date: Sun, 14 Jul 2024 15:11:40 +0000 Subject: [PATCH 226/765] make ninja shoes magboots (#28586) Co-authored-by: deltanedas <@deltanedas:kde.org> --- Resources/Prototypes/Entities/Clothing/Shoes/specific.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/Resources/Prototypes/Entities/Clothing/Shoes/specific.yml b/Resources/Prototypes/Entities/Clothing/Shoes/specific.yml index 4ae752345a7..80d5eab249b 100644 --- a/Resources/Prototypes/Entities/Clothing/Shoes/specific.yml +++ b/Resources/Prototypes/Entities/Clothing/Shoes/specific.yml @@ -121,6 +121,7 @@ - type: Clothing sprite: Clothing/Shoes/Specific/spaceninja.rsi - type: NoSlip + - type: Magboots # always have gravity because le suction cups - type: ClothingSpeedModifier # ninja are masters of sneaking around relatively quickly, won't break cloak walkModifier: 1.1 From eb7c5d99e2e1318c5813f46967f20e2f2c564a0a Mon Sep 17 00:00:00 2001 From: lzk <124214523+lzk228@users.noreply.github.com> Date: Sun, 14 Jul 2024 17:12:25 +0200 Subject: [PATCH 227/765] make scarves eatable again (#29959) --- .../Prototypes/Entities/Clothing/Neck/base_clothingneck.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/Resources/Prototypes/Entities/Clothing/Neck/base_clothingneck.yml b/Resources/Prototypes/Entities/Clothing/Neck/base_clothingneck.yml index d2fffb81537..d7f04f49bc3 100644 --- a/Resources/Prototypes/Entities/Clothing/Neck/base_clothingneck.yml +++ b/Resources/Prototypes/Entities/Clothing/Neck/base_clothingneck.yml @@ -38,3 +38,4 @@ - type: Tag tags: - Scarf + - ClothMade From fd052fa778de5fe5c55b9657bc28735703d650fe Mon Sep 17 00:00:00 2001 From: PJBot Date: Sun, 14 Jul 2024 15:13:31 +0000 Subject: [PATCH 228/765] Automatic changelog update --- Resources/Changelog/Changelog.yml | 37 ++++++++++++------------------- 1 file changed, 14 insertions(+), 23 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index f0ef8806add..0b965b19702 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,27 +1,4 @@ Entries: -- author: eclips_e - changes: - - message: Slimepeople can now morph into a "geras"--a smaller slime form that can - pass under grilles, at the cost of dropping all of their inventory. They can - also be picked up with two hands and placed into duffelbags. - type: Add - - message: Slimepeople now have an internal 2x2 storage that they (and anyone around - them) can access. It is not dropped when morphing into a geras! - type: Add - - message: Slimepeople now have slightly increased regeneration and a slightly meatier - punch, but slower attacks. - type: Add - id: 6420 - time: '2024-04-22T10:03:03.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/23425 -- author: FungiFellow - changes: - - message: Syndi-Cats are now 6TC, Insulated, Available to Syndies, Can Move in - Space, Open Doors, and Hit Harder - type: Tweak - id: 6421 - time: '2024-04-22T12:18:28.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/27222 - author: Tayrtahn changes: - message: Ghosts can no longer trigger artifacts by examining them. @@ -3814,3 +3791,17 @@ id: 6919 time: '2024-07-14T14:09:41.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/30037 +- author: deltanedas + changes: + - message: Fixed ninja shoes not working as magboots. + type: Fix + id: 6920 + time: '2024-07-14T15:11:40.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/28586 +- author: lzk228 + changes: + - message: Scarves are eatable again. + type: Fix + id: 6921 + time: '2024-07-14T15:12:25.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/29959 From 401379ee3a5ee4616f4a22e0a76955d59dcf2364 Mon Sep 17 00:00:00 2001 From: Pieter-Jan Briers Date: Mon, 15 Jul 2024 00:07:48 +0200 Subject: [PATCH 229/765] Fix AccessLevelControl breaking (#30045) #29987 did an oopsie This broke the ID computer, station records, and maybe some others too. --- Content.Client/Access/UI/AccessLevelControl.xaml.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/Content.Client/Access/UI/AccessLevelControl.xaml.cs b/Content.Client/Access/UI/AccessLevelControl.xaml.cs index 9f09eceec06..12487b2e5ce 100644 --- a/Content.Client/Access/UI/AccessLevelControl.xaml.cs +++ b/Content.Client/Access/UI/AccessLevelControl.xaml.cs @@ -21,6 +21,7 @@ public sealed partial class AccessLevelControl : GridContainer public AccessLevelControl() { RobustXamlLoader.Load(this); + IoCManager.InjectDependencies(this); _sawmill = _logManager.GetSawmill("accesslevelcontrol"); } From 33c3af9990c332584125609874bace970e67c9f6 Mon Sep 17 00:00:00 2001 From: Pieter-Jan Briers Date: Mon, 15 Jul 2024 16:32:12 +0200 Subject: [PATCH 230/765] Update host key for changelog RSS (#30068) --- Tools/actions_changelog_rss.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tools/actions_changelog_rss.py b/Tools/actions_changelog_rss.py index 01ca7852ccb..5c696f5b01a 100755 --- a/Tools/actions_changelog_rss.py +++ b/Tools/actions_changelog_rss.py @@ -35,7 +35,7 @@ RSS_FILE = "changelog.xml" XSL_FILE = "stylesheet.xsl" HOST_KEYS = [ - "AAAAC3NzaC1lZDI1NTE5AAAAIEE8EhnPjb3nIaAPTXAJHbjrwdGGxHoM0f1imCK0SygD" + "AAAAC3NzaC1lZDI1NTE5AAAAIOBpGO/Qc6X0YWuw7z+/WS/65+aewWI29oAyx+jJpCmh" ] # RSS feed parameters, change these From 8f95604f051443398f2b3c4c79dda18d4d386321 Mon Sep 17 00:00:00 2001 From: Pieter-Jan Briers Date: Mon, 15 Jul 2024 16:55:05 +0200 Subject: [PATCH 231/765] Fix invalid UI hover/click sounds breaking client (#30067) fixes #29561 --- Content.Client/Audio/AudioUIController.cs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/Content.Client/Audio/AudioUIController.cs b/Content.Client/Audio/AudioUIController.cs index ef903672fd0..16e1edd2523 100644 --- a/Content.Client/Audio/AudioUIController.cs +++ b/Content.Client/Audio/AudioUIController.cs @@ -54,7 +54,7 @@ private void SetClickSound(string value) { if (!string.IsNullOrEmpty(value)) { - var resource = _cache.GetResource(value); + var resource = GetSoundOrFallback(value, CCVars.UIClickSound.DefaultValue); var source = _audioManager.CreateAudioSource(resource); @@ -77,7 +77,7 @@ private void SetHoverSound(string value) { if (!string.IsNullOrEmpty(value)) { - var hoverResource = _cache.GetResource(value); + var hoverResource = GetSoundOrFallback(value, CCVars.UIHoverSound.DefaultValue); var hoverSource = _audioManager.CreateAudioSource(hoverResource); @@ -95,4 +95,12 @@ private void SetHoverSound(string value) UIManager.SetHoverSound(null); } } + + private AudioResource GetSoundOrFallback(string path, string fallback) + { + if (!_cache.TryGetResource(path, out AudioResource? resource)) + return _cache.GetResource(fallback); + + return resource; + } } From d4b81acbfe9c8eef6ce5bb5429dac77915115231 Mon Sep 17 00:00:00 2001 From: Simon <63975668+Simyon264@users.noreply.github.com> Date: Mon, 15 Jul 2024 21:14:37 +0200 Subject: [PATCH 232/765] Fix some markup related obsolete warnings in research and anomaly related systems (#30072) Fix some Markup related obsolete warnings in Research and Anomaly related systems --- .../UI/DiskConsoleBoundUserInterface.cs | 1 - .../UI/ResearchClientBoundUserInterface.cs | 1 - .../UI/ResearchConsoleBoundUserInterface.cs | 1 - .../Research/UI/ResearchConsoleMenu.xaml.cs | 4 +- .../Research/UI/TechnologyCardControl.xaml.cs | 2 +- .../Anomaly/AnomalySystem.Scanner.cs | 40 +++++++++---------- 6 files changed, 23 insertions(+), 26 deletions(-) diff --git a/Content.Client/Research/UI/DiskConsoleBoundUserInterface.cs b/Content.Client/Research/UI/DiskConsoleBoundUserInterface.cs index da008ca04c9..c14a8c5bd05 100644 --- a/Content.Client/Research/UI/DiskConsoleBoundUserInterface.cs +++ b/Content.Client/Research/UI/DiskConsoleBoundUserInterface.cs @@ -1,6 +1,5 @@ using Content.Shared.Research; using Content.Shared.Research.Components; -using Robust.Client.GameObjects; namespace Content.Client.Research.UI { diff --git a/Content.Client/Research/UI/ResearchClientBoundUserInterface.cs b/Content.Client/Research/UI/ResearchClientBoundUserInterface.cs index 07dd35a0056..a0a2b58e889 100644 --- a/Content.Client/Research/UI/ResearchClientBoundUserInterface.cs +++ b/Content.Client/Research/UI/ResearchClientBoundUserInterface.cs @@ -1,5 +1,4 @@ using Content.Shared.Research.Components; -using Robust.Client.GameObjects; namespace Content.Client.Research.UI { diff --git a/Content.Client/Research/UI/ResearchConsoleBoundUserInterface.cs b/Content.Client/Research/UI/ResearchConsoleBoundUserInterface.cs index f29e66baaeb..2a9782045b8 100644 --- a/Content.Client/Research/UI/ResearchConsoleBoundUserInterface.cs +++ b/Content.Client/Research/UI/ResearchConsoleBoundUserInterface.cs @@ -1,6 +1,5 @@ using Content.Shared.Research.Components; using JetBrains.Annotations; -using Robust.Client.GameObjects; namespace Content.Client.Research.UI; diff --git a/Content.Client/Research/UI/ResearchConsoleMenu.xaml.cs b/Content.Client/Research/UI/ResearchConsoleMenu.xaml.cs index b364b833124..77ebe6740c5 100644 --- a/Content.Client/Research/UI/ResearchConsoleMenu.xaml.cs +++ b/Content.Client/Research/UI/ResearchConsoleMenu.xaml.cs @@ -81,7 +81,7 @@ public void UpdatePanels(ResearchConsoleBoundInterfaceState state) public void UpdateInformationPanel(ResearchConsoleBoundInterfaceState state) { var amountMsg = new FormattedMessage(); - amountMsg.AddMarkup(Loc.GetString("research-console-menu-research-points-text", + amountMsg.AddMarkupOrThrow(Loc.GetString("research-console-menu-research-points-text", ("points", state.Points))); ResearchAmountLabel.SetMessage(amountMsg); @@ -98,7 +98,7 @@ public void UpdateInformationPanel(ResearchConsoleBoundInterfaceState state) } var msg = new FormattedMessage(); - msg.AddMarkup(Loc.GetString("research-console-menu-main-discipline", + msg.AddMarkupOrThrow(Loc.GetString("research-console-menu-main-discipline", ("name", disciplineText), ("color", disciplineColor))); MainDisciplineLabel.SetMessage(msg); diff --git a/Content.Client/Research/UI/TechnologyCardControl.xaml.cs b/Content.Client/Research/UI/TechnologyCardControl.xaml.cs index f547457203e..292ed0ebe0b 100644 --- a/Content.Client/Research/UI/TechnologyCardControl.xaml.cs +++ b/Content.Client/Research/UI/TechnologyCardControl.xaml.cs @@ -23,7 +23,7 @@ public TechnologyCardControl(TechnologyPrototype technology, IPrototypeManager p DisciplineTexture.Texture = spriteSys.Frame0(discipline.Icon); TechnologyNameLabel.Text = Loc.GetString(technology.Name); var message = new FormattedMessage(); - message.AddMarkup(Loc.GetString("research-console-tier-discipline-info", + message.AddMarkupOrThrow(Loc.GetString("research-console-tier-discipline-info", ("tier", technology.Tier), ("color", discipline.Color), ("discipline", Loc.GetString(discipline.Name)))); TierLabel.SetMessage(message); UnlocksLabel.SetMessage(description); diff --git a/Content.Server/Anomaly/AnomalySystem.Scanner.cs b/Content.Server/Anomaly/AnomalySystem.Scanner.cs index 39c0d08b55e..65d79de60c6 100644 --- a/Content.Server/Anomaly/AnomalySystem.Scanner.cs +++ b/Content.Server/Anomaly/AnomalySystem.Scanner.cs @@ -141,7 +141,7 @@ public FormattedMessage GetScannerMessage(AnomalyScannerComponent component) var msg = new FormattedMessage(); if (component.ScannedAnomaly is not { } anomaly || !TryComp(anomaly, out var anomalyComp)) { - msg.AddMarkup(Loc.GetString("anomaly-scanner-no-anomaly")); + msg.AddMarkupOrThrow(Loc.GetString("anomaly-scanner-no-anomaly")); return msg; } @@ -149,14 +149,14 @@ public FormattedMessage GetScannerMessage(AnomalyScannerComponent component) //Severity if (secret != null && secret.Secret.Contains(AnomalySecretData.Severity)) - msg.AddMarkup(Loc.GetString("anomaly-scanner-severity-percentage-unknown")); + msg.AddMarkupOrThrow(Loc.GetString("anomaly-scanner-severity-percentage-unknown")); else - msg.AddMarkup(Loc.GetString("anomaly-scanner-severity-percentage", ("percent", anomalyComp.Severity.ToString("P")))); + msg.AddMarkupOrThrow(Loc.GetString("anomaly-scanner-severity-percentage", ("percent", anomalyComp.Severity.ToString("P")))); msg.PushNewline(); //Stability if (secret != null && secret.Secret.Contains(AnomalySecretData.Stability)) - msg.AddMarkup(Loc.GetString("anomaly-scanner-stability-unknown")); + msg.AddMarkupOrThrow(Loc.GetString("anomaly-scanner-stability-unknown")); else { string stateLoc; @@ -166,54 +166,54 @@ public FormattedMessage GetScannerMessage(AnomalyScannerComponent component) stateLoc = Loc.GetString("anomaly-scanner-stability-high"); else stateLoc = Loc.GetString("anomaly-scanner-stability-medium"); - msg.AddMarkup(stateLoc); + msg.AddMarkupOrThrow(stateLoc); } msg.PushNewline(); //Point output if (secret != null && secret.Secret.Contains(AnomalySecretData.OutputPoint)) - msg.AddMarkup(Loc.GetString("anomaly-scanner-point-output-unknown")); + msg.AddMarkupOrThrow(Loc.GetString("anomaly-scanner-point-output-unknown")); else - msg.AddMarkup(Loc.GetString("anomaly-scanner-point-output", ("point", GetAnomalyPointValue(anomaly, anomalyComp)))); + msg.AddMarkupOrThrow(Loc.GetString("anomaly-scanner-point-output", ("point", GetAnomalyPointValue(anomaly, anomalyComp)))); msg.PushNewline(); msg.PushNewline(); //Particles title - msg.AddMarkup(Loc.GetString("anomaly-scanner-particle-readout")); + msg.AddMarkupOrThrow(Loc.GetString("anomaly-scanner-particle-readout")); msg.PushNewline(); //Danger if (secret != null && secret.Secret.Contains(AnomalySecretData.ParticleDanger)) - msg.AddMarkup(Loc.GetString("anomaly-scanner-particle-danger-unknown")); + msg.AddMarkupOrThrow(Loc.GetString("anomaly-scanner-particle-danger-unknown")); else - msg.AddMarkup(Loc.GetString("anomaly-scanner-particle-danger", ("type", GetParticleLocale(anomalyComp.SeverityParticleType)))); + msg.AddMarkupOrThrow(Loc.GetString("anomaly-scanner-particle-danger", ("type", GetParticleLocale(anomalyComp.SeverityParticleType)))); msg.PushNewline(); //Unstable if (secret != null && secret.Secret.Contains(AnomalySecretData.ParticleUnstable)) - msg.AddMarkup(Loc.GetString("anomaly-scanner-particle-unstable-unknown")); + msg.AddMarkupOrThrow(Loc.GetString("anomaly-scanner-particle-unstable-unknown")); else - msg.AddMarkup(Loc.GetString("anomaly-scanner-particle-unstable", ("type", GetParticleLocale(anomalyComp.DestabilizingParticleType)))); + msg.AddMarkupOrThrow(Loc.GetString("anomaly-scanner-particle-unstable", ("type", GetParticleLocale(anomalyComp.DestabilizingParticleType)))); msg.PushNewline(); //Containment if (secret != null && secret.Secret.Contains(AnomalySecretData.ParticleContainment)) - msg.AddMarkup(Loc.GetString("anomaly-scanner-particle-containment-unknown")); + msg.AddMarkupOrThrow(Loc.GetString("anomaly-scanner-particle-containment-unknown")); else - msg.AddMarkup(Loc.GetString("anomaly-scanner-particle-containment", ("type", GetParticleLocale(anomalyComp.WeakeningParticleType)))); + msg.AddMarkupOrThrow(Loc.GetString("anomaly-scanner-particle-containment", ("type", GetParticleLocale(anomalyComp.WeakeningParticleType)))); msg.PushNewline(); //Transformation if (secret != null && secret.Secret.Contains(AnomalySecretData.ParticleTransformation)) - msg.AddMarkup(Loc.GetString("anomaly-scanner-particle-transformation-unknown")); + msg.AddMarkupOrThrow(Loc.GetString("anomaly-scanner-particle-transformation-unknown")); else - msg.AddMarkup(Loc.GetString("anomaly-scanner-particle-transformation", ("type", GetParticleLocale(anomalyComp.TransformationParticleType)))); + msg.AddMarkupOrThrow(Loc.GetString("anomaly-scanner-particle-transformation", ("type", GetParticleLocale(anomalyComp.TransformationParticleType)))); //Behavior msg.PushNewline(); msg.PushNewline(); - msg.AddMarkup(Loc.GetString("anomaly-behavior-title")); + msg.AddMarkupOrThrow(Loc.GetString("anomaly-behavior-title")); msg.PushNewline(); if (secret != null && secret.Secret.Contains(AnomalySecretData.Behavior)) @@ -224,14 +224,14 @@ public FormattedMessage GetScannerMessage(AnomalyScannerComponent component) { var behavior = _prototype.Index(anomalyComp.CurrentBehavior.Value); - msg.AddMarkup("- " + Loc.GetString(behavior.Description)); + msg.AddMarkupOrThrow("- " + Loc.GetString(behavior.Description)); msg.PushNewline(); var mod = Math.Floor((behavior.EarnPointModifier) * 100); - msg.AddMarkup("- " + Loc.GetString("anomaly-behavior-point", ("mod", mod))); + msg.AddMarkupOrThrow("- " + Loc.GetString("anomaly-behavior-point", ("mod", mod))); } else { - msg.AddMarkup(Loc.GetString("anomaly-behavior-balanced")); + msg.AddMarkupOrThrow(Loc.GetString("anomaly-behavior-balanced")); } } From c71f5258322a21954a59694f2e1c330ed257e1d2 Mon Sep 17 00:00:00 2001 From: Winkarst <74284083+Winkarst-cpu@users.noreply.github.com> Date: Mon, 15 Jul 2024 22:18:33 +0300 Subject: [PATCH 233/765] Make addgamerule command process only valid game rules (#29912) * addgamerule command processes only valid rules * Update * English moment --- Content.Server/GameTicking/GameTicker.GameRule.cs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Content.Server/GameTicking/GameTicker.GameRule.cs b/Content.Server/GameTicking/GameTicker.GameRule.cs index a6d0a4baf0a..e5bdb513c50 100644 --- a/Content.Server/GameTicking/GameTicker.GameRule.cs +++ b/Content.Server/GameTicking/GameTicker.GameRule.cs @@ -324,6 +324,13 @@ private void AddGameRuleCommand(IConsoleShell shell, string argstr, string[] arg foreach (var rule in args) { + if (!_prototypeManager.HasIndex(rule)) + { + shell.WriteError($"Invalid game rule {rule} was skipped."); + + continue; + } + if (shell.Player != null) { _adminLogger.Add(LogType.EventStarted, $"{shell.Player} tried to add game rule [{rule}] via command"); From b7f0c69ecbdc7a2d626cd64ad40d9309e708a097 Mon Sep 17 00:00:00 2001 From: PJBot Date: Mon, 15 Jul 2024 19:19:40 +0000 Subject: [PATCH 234/765] Automatic changelog update --- Resources/Changelog/Changelog.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 0b965b19702..b709a84f1fe 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,11 +1,4 @@ Entries: -- author: Tayrtahn - changes: - - message: Ghosts can no longer trigger artifacts by examining them. - type: Fix - id: 6422 - time: '2024-04-22T22:46:22.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/27249 - author: Tyzemol changes: - message: Slimes no longer absorb all items used on them @@ -3805,3 +3798,10 @@ id: 6921 time: '2024-07-14T15:12:25.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/29959 +- author: Winkarst-cpu + changes: + - message: Now addgamerule command processes only valid game rules. + type: Fix + id: 6922 + time: '2024-07-15T19:18:33.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/29912 From 96a7d5188a82107ef6870ce030a097767b22b538 Mon Sep 17 00:00:00 2001 From: Simon <63975668+Simyon264@users.noreply.github.com> Date: Tue, 16 Jul 2024 03:04:31 +0200 Subject: [PATCH 235/765] Add missing command description to replay_toggleui (#30071) --- Resources/Locale/en-US/replays/replays.ftl | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Resources/Locale/en-US/replays/replays.ftl b/Resources/Locale/en-US/replays/replays.ftl index 7a7e551b3e9..4722f4c56b9 100644 --- a/Resources/Locale/en-US/replays/replays.ftl +++ b/Resources/Locale/en-US/replays/replays.ftl @@ -41,3 +41,5 @@ replay-verb-spectate = Spectate cmd-replay-spectate-help = replay_spectate [optional entity] cmd-replay-spectate-desc = Attaches or detaches the local player to a given entity uid. cmd-replay-spectate-hint = Optional EntityUid + +cmd-replay-toggleui-desc = Toggles the replay control UI. From 6d877d0be7c4c20a766a74ff646c9d0fce0b254d Mon Sep 17 00:00:00 2001 From: Cojoke <83733158+Cojoke-dot@users.noreply.github.com> Date: Tue, 16 Jul 2024 02:17:18 -0500 Subject: [PATCH 236/765] Remove uses of AllObjectives (#30077) Remove the uses of AllObjectives --- Content.Server/CharacterInfo/CharacterInfoSystem.cs | 2 +- Content.Server/Dragon/DragonSystem.cs | 4 ++-- Content.Server/Objectives/Commands/ListObjectivesCommand.cs | 2 +- .../Objectives/Systems/HelpProgressConditionSystem.cs | 4 ++-- .../Objectives/Systems/ObjectiveBlacklistRequirementSystem.cs | 2 +- Content.Shared/Mind/SharedMindSystem.cs | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Content.Server/CharacterInfo/CharacterInfoSystem.cs b/Content.Server/CharacterInfo/CharacterInfoSystem.cs index df8718a022e..cb2216b5e3b 100644 --- a/Content.Server/CharacterInfo/CharacterInfoSystem.cs +++ b/Content.Server/CharacterInfo/CharacterInfoSystem.cs @@ -36,7 +36,7 @@ private void OnRequestCharacterInfoEvent(RequestCharacterInfoEvent msg, EntitySe if (_minds.TryGetMind(entity, out var mindId, out var mind)) { // Get objectives - foreach (var objective in mind.AllObjectives) + foreach (var objective in mind.Objectives) { var info = _objectives.GetInfo(objective, mindId, mind); if (info == null) diff --git a/Content.Server/Dragon/DragonSystem.cs b/Content.Server/Dragon/DragonSystem.cs index 96ca8d3614a..e626edeb269 100644 --- a/Content.Server/Dragon/DragonSystem.cs +++ b/Content.Server/Dragon/DragonSystem.cs @@ -225,7 +225,7 @@ public void DeleteRifts(EntityUid uid, bool resetRole, DragonComponent? comp = n return; var mind = Comp(mindContainer.Mind.Value); - foreach (var objId in mind.AllObjectives) + foreach (var objId in mind.Objectives) { if (_objQuery.TryGetComponent(objId, out var obj)) { @@ -247,7 +247,7 @@ public void RiftCharged(EntityUid uid, DragonComponent? comp = null) return; var mind = Comp(mindContainer.Mind.Value); - foreach (var objId in mind.AllObjectives) + foreach (var objId in mind.Objectives) { if (_objQuery.TryGetComponent(objId, out var obj)) { diff --git a/Content.Server/Objectives/Commands/ListObjectivesCommand.cs b/Content.Server/Objectives/Commands/ListObjectivesCommand.cs index 97fc943269a..88dcdcedf65 100644 --- a/Content.Server/Objectives/Commands/ListObjectivesCommand.cs +++ b/Content.Server/Objectives/Commands/ListObjectivesCommand.cs @@ -33,7 +33,7 @@ public override void Execute(IConsoleShell shell, string argStr, string[] args) } shell.WriteLine($"Objectives for player {player.UserId}:"); - var objectives = mind.AllObjectives.ToList(); + var objectives = mind.Objectives.ToList(); if (objectives.Count == 0) { shell.WriteLine("None."); diff --git a/Content.Server/Objectives/Systems/HelpProgressConditionSystem.cs b/Content.Server/Objectives/Systems/HelpProgressConditionSystem.cs index e4455c03813..e0a56149b3e 100644 --- a/Content.Server/Objectives/Systems/HelpProgressConditionSystem.cs +++ b/Content.Server/Objectives/Systems/HelpProgressConditionSystem.cs @@ -59,7 +59,7 @@ private void OnTraitorAssigned(EntityUid uid, RandomTraitorProgressComponent com if (!TryComp(traitor, out var mind)) continue; - foreach (var objective in mind.AllObjectives) + foreach (var objective in mind.Objectives) { if (HasComp(objective)) removeList.Add(traitor); @@ -88,7 +88,7 @@ private float GetProgress(EntityUid target) if (TryComp(target, out var mind)) { - foreach (var objective in mind.AllObjectives) + foreach (var objective in mind.Objectives) { // this has the potential to loop forever, anything setting target has to check that there is no HelpProgressCondition. var info = _objectives.GetInfo(objective, target, mind); diff --git a/Content.Server/Objectives/Systems/ObjectiveBlacklistRequirementSystem.cs b/Content.Server/Objectives/Systems/ObjectiveBlacklistRequirementSystem.cs index 8fe7e7e2031..0671c6b67e4 100644 --- a/Content.Server/Objectives/Systems/ObjectiveBlacklistRequirementSystem.cs +++ b/Content.Server/Objectives/Systems/ObjectiveBlacklistRequirementSystem.cs @@ -23,7 +23,7 @@ private void OnCheck(EntityUid uid, ObjectiveBlacklistRequirementComponent comp, if (args.Cancelled) return; - foreach (var objective in args.Mind.AllObjectives) + foreach (var objective in args.Mind.Objectives) { if (_whitelistSystem.IsBlacklistPass(comp.Blacklist, objective)) { diff --git a/Content.Shared/Mind/SharedMindSystem.cs b/Content.Shared/Mind/SharedMindSystem.cs index bf1065c1b1d..ba365daf15c 100644 --- a/Content.Shared/Mind/SharedMindSystem.cs +++ b/Content.Shared/Mind/SharedMindSystem.cs @@ -370,7 +370,7 @@ public bool TryGetObjectiveComp(EntityUid mindId, [NotNullWhen(true)] out T? if (Resolve(mindId, ref mind)) { var query = GetEntityQuery(); - foreach (var uid in mind.AllObjectives) + foreach (var uid in mind.Objectives) { if (query.TryGetComponent(uid, out objective)) { From 80c8ae2960b45aa2d78ad7860d8b0efa5ff1067e Mon Sep 17 00:00:00 2001 From: Nemanja <98561806+EmoGarbage404@users.noreply.github.com> Date: Tue, 16 Jul 2024 10:27:37 -0400 Subject: [PATCH 237/765] Revert "Change wristwatch meta description" (#30070) Revert "Change wristwatch meta description (#30036)" This reverts commit 919b3ac9e64a18990bd8dbf21eceae782e2b3f77. --- Resources/Prototypes/Entities/Objects/Devices/wristwatch.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Resources/Prototypes/Entities/Objects/Devices/wristwatch.yml b/Resources/Prototypes/Entities/Objects/Devices/wristwatch.yml index 6359f659b57..7fbb4aecf61 100644 --- a/Resources/Prototypes/Entities/Objects/Devices/wristwatch.yml +++ b/Resources/Prototypes/Entities/Objects/Devices/wristwatch.yml @@ -2,7 +2,7 @@ id: Wristwatch parent: BaseItem name: wristwatch - description: A cheap watch for telling time. How much did you waste working on this shift? + description: A cheap watch for telling time. How much did you waste playing Space Station 14? components: - type: Sprite sprite: Objects/Devices/wristwatch.rsi From 84470154e3dac15cdf56fd921c875751094f5ff8 Mon Sep 17 00:00:00 2001 From: Plykiya <58439124+Plykiya@users.noreply.github.com> Date: Tue, 16 Jul 2024 07:29:31 -0700 Subject: [PATCH 238/765] Replace EntityPrototype.NoSpawn with EntityPrototype.HideSpawnMenu (#30082) NoSpawn Co-authored-by: plykiya --- Content.Server/Holiday/Christmas/RandomGiftSystem.cs | 2 +- .../Clothing/EntitySystems/SharedChameleonClothingSystem.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Content.Server/Holiday/Christmas/RandomGiftSystem.cs b/Content.Server/Holiday/Christmas/RandomGiftSystem.cs index ee542572d7e..4603f45ed81 100644 --- a/Content.Server/Holiday/Christmas/RandomGiftSystem.cs +++ b/Content.Server/Holiday/Christmas/RandomGiftSystem.cs @@ -95,7 +95,7 @@ private void BuildIndex() foreach (var proto in _prototype.EnumeratePrototypes()) { - if (proto.Abstract || proto.NoSpawn || proto.Components.ContainsKey(mapGridCompName) || !proto.Components.ContainsKey(physicsCompName)) + if (proto.Abstract || proto.HideSpawnMenu || proto.Components.ContainsKey(mapGridCompName) || !proto.Components.ContainsKey(physicsCompName)) continue; _possibleGiftsUnsafe.Add(proto.ID); diff --git a/Content.Shared/Clothing/EntitySystems/SharedChameleonClothingSystem.cs b/Content.Shared/Clothing/EntitySystems/SharedChameleonClothingSystem.cs index fced03bfabf..f5df04037ee 100644 --- a/Content.Shared/Clothing/EntitySystems/SharedChameleonClothingSystem.cs +++ b/Content.Shared/Clothing/EntitySystems/SharedChameleonClothingSystem.cs @@ -78,7 +78,7 @@ protected virtual void UpdateSprite(EntityUid uid, EntityPrototype proto) { } public bool IsValidTarget(EntityPrototype proto, SlotFlags chameleonSlot = SlotFlags.NONE) { // check if entity is valid - if (proto.Abstract || proto.NoSpawn) + if (proto.Abstract || proto.HideSpawnMenu) return false; // check if it is marked as valid chameleon target From a369710d805ae1bf2addb6e51d222b453c79b944 Mon Sep 17 00:00:00 2001 From: Jezithyr Date: Tue, 16 Jul 2024 15:50:17 -0700 Subject: [PATCH 239/765] Remove Geras from Slimes to address combat balance (#29731) Removed Geras Removed Geras --- Resources/Prototypes/Entities/Mobs/Species/slime.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/Resources/Prototypes/Entities/Mobs/Species/slime.yml b/Resources/Prototypes/Entities/Mobs/Species/slime.yml index 31db778a00d..e83bec4f1f8 100644 --- a/Resources/Prototypes/Entities/Mobs/Species/slime.yml +++ b/Resources/Prototypes/Entities/Mobs/Species/slime.yml @@ -54,7 +54,6 @@ - type: Damageable damageContainer: Biological damageModifierSet: Slime - - type: Geras - type: PassiveDamage # Around 8 damage a minute healed allowedStates: - Alive From 62c946cfde0b222b727698123b81226e45be92e7 Mon Sep 17 00:00:00 2001 From: PJBot Date: Tue, 16 Jul 2024 22:51:25 +0000 Subject: [PATCH 240/765] Automatic changelog update --- Resources/Changelog/Changelog.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index b709a84f1fe..c7c2a9731b1 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,11 +1,4 @@ Entries: -- author: Tyzemol - changes: - - message: Slimes no longer absorb all items used on them - type: Fix - id: 6423 - time: '2024-04-23T08:48:26.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/27260 - author: Rainbeon changes: - message: Suit sensor vitals now function again. @@ -3805,3 +3798,10 @@ id: 6922 time: '2024-07-15T19:18:33.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/29912 +- author: Jezithyr + changes: + - message: Removed the Geras ability from Slimes + type: Remove + id: 6923 + time: '2024-07-16T22:50:17.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/29731 From a19c54ac26c5b8f512203613dc65c22c063ee1b5 Mon Sep 17 00:00:00 2001 From: K-Dynamic <20566341+K-Dynamic@users.noreply.github.com> Date: Wed, 17 Jul 2024 11:26:02 +1200 Subject: [PATCH 241/765] Nerf & standardised slip times (#27879) * standardised slip times * puddle and gib soap * banana peels * cleaned yaml by shifting to component * error slip * error slip intersect * intersect ratio return * error and omega soap changes * SlipocalypseClusterSoap 2 tc cost --- Content.Shared/Slippery/SlipperyComponent.cs | 4 ++-- Resources/Prototypes/Catalog/uplink_catalog.yml | 2 +- Resources/Prototypes/Entities/Effects/puddle.yml | 1 - .../Entities/Objects/Consumable/Food/produce.yml | 4 ---- .../Prototypes/Entities/Objects/Devices/pda.yml | 4 +--- .../Objects/Fun/Instruments/instruments_misc.yml | 2 -- .../Prototypes/Entities/Objects/Fun/error.yml | 7 ++++--- .../Entities/Objects/Misc/spider_web.yml | 2 -- .../Entities/Objects/Specific/Janitorial/soap.yml | 15 ++++++--------- Resources/Prototypes/Entities/Tiles/bananium.yml | 2 -- Resources/Prototypes/Reagents/cleaning.yml | 2 -- 11 files changed, 14 insertions(+), 31 deletions(-) diff --git a/Content.Shared/Slippery/SlipperyComponent.cs b/Content.Shared/Slippery/SlipperyComponent.cs index b80a9b57e4d..154ca6c51a4 100644 --- a/Content.Shared/Slippery/SlipperyComponent.cs +++ b/Content.Shared/Slippery/SlipperyComponent.cs @@ -25,14 +25,14 @@ public sealed partial class SlipperyComponent : Component /// [DataField, AutoNetworkedField] [Access(Other = AccessPermissions.ReadWrite)] - public float ParalyzeTime = 3f; + public float ParalyzeTime = 1.5f; /// /// The entity's speed will be multiplied by this to slip it forwards. /// [DataField, AutoNetworkedField] [Access(Other = AccessPermissions.ReadWrite)] - public float LaunchForwardsMultiplier = 1f; + public float LaunchForwardsMultiplier = 1.5f; /// /// If this is true, any slipping entity loses its friction until diff --git a/Resources/Prototypes/Catalog/uplink_catalog.yml b/Resources/Prototypes/Catalog/uplink_catalog.yml index 59c72e8cc16..8f6f0f2ce31 100644 --- a/Resources/Prototypes/Catalog/uplink_catalog.yml +++ b/Resources/Prototypes/Catalog/uplink_catalog.yml @@ -785,7 +785,7 @@ description: uplink-slipocalypse-clustersoap-desc productEntity: SlipocalypseClusterSoap cost: - Telecrystal: 3 + Telecrystal: 2 categories: - UplinkDisruption diff --git a/Resources/Prototypes/Entities/Effects/puddle.yml b/Resources/Prototypes/Entities/Effects/puddle.yml index fecf9f19a47..62bb923a61b 100644 --- a/Resources/Prototypes/Entities/Effects/puddle.yml +++ b/Resources/Prototypes/Entities/Effects/puddle.yml @@ -113,7 +113,6 @@ components: - type: Clickable - type: Slippery - launchForwardsMultiplier: 2.0 - type: Transform noRot: true anchored: true diff --git a/Resources/Prototypes/Entities/Objects/Consumable/Food/produce.yml b/Resources/Prototypes/Entities/Objects/Consumable/Food/produce.yml index a74e3450e94..b2375a2dbf9 100644 --- a/Resources/Prototypes/Entities/Objects/Consumable/Food/produce.yml +++ b/Resources/Prototypes/Entities/Objects/Consumable/Food/produce.yml @@ -311,7 +311,6 @@ sprite: Objects/Specific/Hydroponics/banana.rsi heldPrefix: peel - type: Slippery - launchForwardsMultiplier: 1.5 - type: StepTrigger intersectRatio: 0.2 - type: CollisionWake @@ -388,7 +387,6 @@ path: /Audio/Effects/slip.ogg params: volume: -100 - launchForwardsMultiplier: 1.6 - type: entity name: bananium peel @@ -402,8 +400,6 @@ sprite: Objects/Materials/materials.rsi heldPrefix: peel - type: Slippery - paralyzeTime: 4 - launchForwardsMultiplier: 2 - type: entity name: carrot diff --git a/Resources/Prototypes/Entities/Objects/Devices/pda.yml b/Resources/Prototypes/Entities/Objects/Devices/pda.yml index eca1dbf5b63..4b794fd4804 100644 --- a/Resources/Prototypes/Entities/Objects/Devices/pda.yml +++ b/Resources/Prototypes/Entities/Objects/Devices/pda.yml @@ -269,9 +269,7 @@ borderColor: "#C18199" - type: Icon state: pda-clown - - type: Slippery - paralyzeTime: 4 - launchForwardsMultiplier: 1.5 + - type: Slippery # secretly made of bananium - type: StepTrigger - type: CollisionWake enabled: false diff --git a/Resources/Prototypes/Entities/Objects/Fun/Instruments/instruments_misc.yml b/Resources/Prototypes/Entities/Objects/Fun/Instruments/instruments_misc.yml index 8cb3d88ede2..243a816a478 100644 --- a/Resources/Prototypes/Entities/Objects/Fun/Instruments/instruments_misc.yml +++ b/Resources/Prototypes/Entities/Objects/Fun/Instruments/instruments_misc.yml @@ -162,8 +162,6 @@ sound: path: /Audio/Items/bikehorn.ogg - type: Slippery - paralyzeTime: 4 - launchForwardsMultiplier: 1.5 - type: StepTrigger - type: CollisionWake enabled: false diff --git a/Resources/Prototypes/Entities/Objects/Fun/error.yml b/Resources/Prototypes/Entities/Objects/Fun/error.yml index 8f3fc211378..e4b9af61e0a 100644 --- a/Resources/Prototypes/Entities/Objects/Fun/error.yml +++ b/Resources/Prototypes/Entities/Objects/Fun/error.yml @@ -16,7 +16,8 @@ - ReagentId: Nutriment Quantity: 5 - type: Slippery - launchForwardsMultiplier: 5 + paralyzeTime: 3 + launchForwardsMultiplier: 3 - type: StepTrigger intersectRatio: 0.2 - type: CollisionWake @@ -28,14 +29,14 @@ slips: shape: !type:PhysShapeAabb - bounds: "-0.2,-0.2,0.2,0.2" + bounds: "-0.4,-0.3,0.4,0.3" hard: false layer: - SlipLayer fix1: shape: !type:PhysShapeAabb - bounds: "-0.2,-0.2,0.2,0.2" + bounds: "-0.4,-0.3,0.4,0.3" density: 30 mask: - ItemMask diff --git a/Resources/Prototypes/Entities/Objects/Misc/spider_web.yml b/Resources/Prototypes/Entities/Objects/Misc/spider_web.yml index 9561fa3538f..02feda953f8 100644 --- a/Resources/Prototypes/Entities/Objects/Misc/spider_web.yml +++ b/Resources/Prototypes/Entities/Objects/Misc/spider_web.yml @@ -108,8 +108,6 @@ - type: Transform anchored: true - type: Slippery - paralyzeTime: 2 - launchForwardsMultiplier: 1.5 - type: StepTrigger intersectRatio: 0.2 - type: Physics diff --git a/Resources/Prototypes/Entities/Objects/Specific/Janitorial/soap.yml b/Resources/Prototypes/Entities/Objects/Specific/Janitorial/soap.yml index 5678de6bafc..efb93a88680 100644 --- a/Resources/Prototypes/Entities/Objects/Specific/Janitorial/soap.yml +++ b/Resources/Prototypes/Entities/Objects/Specific/Janitorial/soap.yml @@ -21,8 +21,6 @@ sprite: Objects/Specific/Janitorial/soap.rsi storedRotation: -90 - type: Slippery - paralyzeTime: 2 - launchForwardsMultiplier: 1.5 - type: StepTrigger intersectRatio: 0.2 - type: CollisionWake @@ -129,8 +127,8 @@ - type: SolutionContainerVisuals fillBaseName: syndie- - type: Slippery - paralyzeTime: 5 - launchForwardsMultiplier: 2.5 + paralyzeTime: 3 + launchForwardsMultiplier: 3 - type: Item heldPrefix: syndie - type: FlavorProfile @@ -154,8 +152,8 @@ layers: - state: syndie-soaplet - type: Slippery - paralyzeTime: 5 - launchForwardsMultiplier: 2.5 + paralyzeTime: 1.5 # these things are tiny + launchForwardsMultiplier: 1.5 - type: StepTrigger intersectRatio: 0.04 - type: Item @@ -196,7 +194,6 @@ - type: SolutionContainerVisuals fillBaseName: gibs- - type: Slippery - paralyzeTime: 2 - type: StepTrigger - type: Item heldPrefix: gibs @@ -221,8 +218,8 @@ - type: SolutionContainerVisuals fillBaseName: omega- - type: Slippery - paralyzeTime: 7 - launchForwardsMultiplier: 3 + paralyzeTime: 5.0 + launchForwardsMultiplier: 3.0 - type: Item heldPrefix: omega - type: SolutionContainerManager diff --git a/Resources/Prototypes/Entities/Tiles/bananium.yml b/Resources/Prototypes/Entities/Tiles/bananium.yml index c9a6ec28441..fa8cfdd001a 100644 --- a/Resources/Prototypes/Entities/Tiles/bananium.yml +++ b/Resources/Prototypes/Entities/Tiles/bananium.yml @@ -44,8 +44,6 @@ - !type:DoActsBehavior acts: [ "Destruction" ] - type: Slippery - paralyzeTime: 2 - launchForwardsMultiplier: 1.5 - type: StepTrigger intersectRatio: 0.2 - type: Physics diff --git a/Resources/Prototypes/Reagents/cleaning.yml b/Resources/Prototypes/Reagents/cleaning.yml index da02fc666d8..a6b53be6883 100644 --- a/Resources/Prototypes/Reagents/cleaning.yml +++ b/Resources/Prototypes/Reagents/cleaning.yml @@ -77,8 +77,6 @@ meltingPoint: 18.2 tileReactions: - !type:SpillTileReaction - paralyzeTime: 3 - launchForwardsMultiplier: 2 requiredSlipSpeed: 1 superSlippery: true From abde50dba62089c980bfb9633fd1342eb815c103 Mon Sep 17 00:00:00 2001 From: PJBot Date: Tue, 16 Jul 2024 23:27:09 +0000 Subject: [PATCH 242/765] Automatic changelog update --- Resources/Changelog/Changelog.yml | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index c7c2a9731b1..e0f8aef124b 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,11 +1,4 @@ Entries: -- author: Rainbeon - changes: - - message: Suit sensor vitals now function again. - type: Fix - id: 6424 - time: '2024-04-23T08:57:09.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/27259 - author: Ghagliiarghii changes: - message: Security can now find replacements for their trusty Combat Knife in the @@ -3805,3 +3798,11 @@ id: 6923 time: '2024-07-16T22:50:17.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/29731 +- author: K-Dynamic + changes: + - message: nerfed paraylze timer of all slippable objects (including soaps, water + puddles, and clown-related items) + type: Tweak + id: 6924 + time: '2024-07-16T23:26:02.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/27879 From 3bc0de2803cc053c8396c0c8167870773ad56e6f Mon Sep 17 00:00:00 2001 From: Nemanja <98561806+EmoGarbage404@users.noreply.github.com> Date: Wed, 17 Jul 2024 00:35:18 -0400 Subject: [PATCH 243/765] Sign Resprite (#29806) * Redone signage * Signs * ok this thing now * alright ig? * big data * cryo sign * new sign --- Resources/Migrations/deltaMigrations.yml | 5 + Resources/Migrations/migration.yml | 16 + .../Structures/Wallmounts/Signs/signs.yml | 192 +-- .../ServerInfo/Guidebook/Service/Chef.xml | 1 - .../Structures/Wallmounts/signs.rsi/ai.png | Bin 400 -> 406 bytes .../Wallmounts/signs.rsi/ai_upload.png | Bin 0 -> 513 bytes .../Wallmounts/signs.rsi/anomaly.png | Bin 399 -> 515 bytes .../Wallmounts/signs.rsi/anomaly2.png | Bin 454 -> 0 bytes .../Wallmounts/signs.rsi/arcade.png | Bin 3131 -> 3126 bytes .../Wallmounts/signs.rsi/armory.png | Bin 391 -> 423 bytes .../Structures/Wallmounts/signs.rsi/ass.png | Bin 385 -> 519 bytes .../Wallmounts/signs.rsi/atmominsky.png | Bin 626 -> 0 bytes .../Structures/Wallmounts/signs.rsi/atmos.png | Bin 486 -> 466 bytes .../Structures/Wallmounts/signs.rsi/bar.png | Bin 388 -> 398 bytes .../Wallmounts/signs.rsi/barbershop.png | Bin 444 -> 481 bytes .../Wallmounts/signs.rsi/biblio.png | Bin 339 -> 397 bytes .../Wallmounts/signs.rsi/bridge.png | Bin 484 -> 475 bytes .../Structures/Wallmounts/signs.rsi/cans.png | Bin 0 -> 445 bytes .../Structures/Wallmounts/signs.rsi/cargo.png | Bin 352 -> 445 bytes .../Wallmounts/signs.rsi/cargo_dock.png | Bin 407 -> 476 bytes .../Wallmounts/signs.rsi/chapel.png | Bin 354 -> 533 bytes .../Structures/Wallmounts/signs.rsi/chem.png | Bin 431 -> 461 bytes .../Wallmounts/signs.rsi/chemistry1.png | Bin 450 -> 0 bytes .../Wallmounts/signs.rsi/chemistry2.png | Bin 401 -> 0 bytes .../Wallmounts/signs.rsi/cloning.png | Bin 418 -> 446 bytes .../Wallmounts/signs.rsi/commander.png | Bin 370 -> 434 bytes .../Wallmounts/signs.rsi/conference_room.png | Bin 356 -> 406 bytes .../Structures/Wallmounts/signs.rsi/court.png | Bin 431 -> 0 bytes .../Structures/Wallmounts/signs.rsi/cryo.png | Bin 0 -> 3065 bytes .../Structures/Wallmounts/signs.rsi/data.png | Bin 0 -> 408 bytes .../Wallmounts/signs.rsi/deathsposal.png | Bin 461 -> 470 bytes .../Structures/Wallmounts/signs.rsi/dock.png | Bin 432 -> 477 bytes .../Structures/Wallmounts/signs.rsi/doors.png | Bin 467 -> 480 bytes .../Wallmounts/signs.rsi/drama1.png | Bin 0 -> 627 bytes .../Wallmounts/signs.rsi/drama2.png | Bin 0 -> 588 bytes .../Wallmounts/signs.rsi/drama3.png | Bin 0 -> 578 bytes .../Wallmounts/signs.rsi/drones.png | Bin 405 -> 0 bytes .../Structures/Wallmounts/signs.rsi/eng.png | Bin 432 -> 418 bytes .../Wallmounts/signs.rsi/engine.png | Bin 471 -> 446 bytes .../Structures/Wallmounts/signs.rsi/eva.png | Bin 387 -> 517 bytes .../Wallmounts/signs.rsi/examroom.png | Bin 494 -> 490 bytes .../Structures/Wallmounts/signs.rsi/gravi.png | Bin 458 -> 423 bytes .../Structures/Wallmounts/signs.rsi/hydro.png | Bin 0 -> 479 bytes .../Wallmounts/signs.rsi/hydro1.png | Bin 428 -> 0 bytes .../Wallmounts/signs.rsi/hydro2.png | Bin 421 -> 0 bytes .../Wallmounts/signs.rsi/hydro3.png | Bin 448 -> 0 bytes .../Wallmounts/signs.rsi/interrogation.png | Bin 395 -> 441 bytes .../Wallmounts/signs.rsi/janitor.png | Bin 552 -> 434 bytes .../Wallmounts/signs.rsi/kitchen.png | Bin 0 -> 486 bytes .../Wallmounts/signs.rsi/laundromat.png | Bin 397 -> 467 bytes .../Structures/Wallmounts/signs.rsi/law.png | Bin 367 -> 396 bytes .../Structures/Wallmounts/signs.rsi/mail.png | Bin 346 -> 418 bytes .../Structures/Wallmounts/signs.rsi/mats.png | Bin 0 -> 391 bytes .../Wallmounts/signs.rsi/medbay.png | Bin 313 -> 533 bytes .../Structures/Wallmounts/signs.rsi/meta.json | 1372 +++-------------- .../Wallmounts/signs.rsi/miner_dock.png | Bin 462 -> 0 bytes .../Wallmounts/signs.rsi/morgue.png | Bin 341 -> 535 bytes .../Structures/Wallmounts/signs.rsi/news.png | Bin 3095 -> 3096 bytes .../Wallmounts/signs.rsi/prison.png | Bin 320 -> 373 bytes .../Wallmounts/signs.rsi/psychology.png | Bin 582 -> 576 bytes .../Wallmounts/signs.rsi/reception.png | Bin 3103 -> 3069 bytes .../Wallmounts/signs.rsi/restroom.png | Bin 0 -> 515 bytes .../Structures/Wallmounts/signs.rsi/rnd.png | Bin 390 -> 448 bytes .../Structures/Wallmounts/signs.rsi/robo.png | Bin 413 -> 481 bytes .../Wallmounts/signs.rsi/salvage.png | Bin 3109 -> 3061 bytes .../Structures/Wallmounts/signs.rsi/sci.png | Bin 473 -> 570 bytes .../Wallmounts/signs.rsi/science1.png | Bin 516 -> 0 bytes .../Wallmounts/signs.rsi/science2.png | Bin 422 -> 0 bytes .../Wallmounts/signs.rsi/security.png | Bin 473 -> 426 bytes .../Wallmounts/signs.rsi/shield.png | Bin 402 -> 0 bytes .../Structures/Wallmounts/signs.rsi/space.png | Bin 515 -> 527 bytes .../Wallmounts/signs.rsi/surgery.png | Bin 428 -> 430 bytes .../Wallmounts/signs.rsi/telecoms.png | Bin 466 -> 431 bytes .../Wallmounts/signs.rsi/toxins.png | Bin 424 -> 541 bytes .../Wallmounts/signs.rsi/toxins2.png | Bin 433 -> 0 bytes .../Structures/Wallmounts/signs.rsi/vault.png | Bin 0 -> 458 bytes .../Wallmounts/signs.rsi/virology.png | Bin 468 -> 519 bytes .../Wallmounts/signs.rsi/xenoarch.png | Bin 0 -> 449 bytes .../Wallmounts/signs.rsi/xenobio.png | Bin 609 -> 490 bytes .../Wallmounts/signs.rsi/xenobio2.png | Bin 569 -> 0 bytes .../Wallmounts/signs.rsi/xenolab.png | Bin 408 -> 0 bytes .../Wallmounts/signs.rsi/zomlab.png | Bin 6115 -> 958 bytes Resources/Textures/Template/signs.png | Bin 0 -> 1013 bytes 83 files changed, 284 insertions(+), 1302 deletions(-) create mode 100644 Resources/Textures/Structures/Wallmounts/signs.rsi/ai_upload.png delete mode 100644 Resources/Textures/Structures/Wallmounts/signs.rsi/anomaly2.png delete mode 100644 Resources/Textures/Structures/Wallmounts/signs.rsi/atmominsky.png create mode 100644 Resources/Textures/Structures/Wallmounts/signs.rsi/cans.png delete mode 100644 Resources/Textures/Structures/Wallmounts/signs.rsi/chemistry1.png delete mode 100644 Resources/Textures/Structures/Wallmounts/signs.rsi/chemistry2.png delete mode 100644 Resources/Textures/Structures/Wallmounts/signs.rsi/court.png create mode 100644 Resources/Textures/Structures/Wallmounts/signs.rsi/cryo.png create mode 100644 Resources/Textures/Structures/Wallmounts/signs.rsi/data.png create mode 100644 Resources/Textures/Structures/Wallmounts/signs.rsi/drama1.png create mode 100644 Resources/Textures/Structures/Wallmounts/signs.rsi/drama2.png create mode 100644 Resources/Textures/Structures/Wallmounts/signs.rsi/drama3.png delete mode 100644 Resources/Textures/Structures/Wallmounts/signs.rsi/drones.png create mode 100644 Resources/Textures/Structures/Wallmounts/signs.rsi/hydro.png delete mode 100644 Resources/Textures/Structures/Wallmounts/signs.rsi/hydro1.png delete mode 100644 Resources/Textures/Structures/Wallmounts/signs.rsi/hydro2.png delete mode 100644 Resources/Textures/Structures/Wallmounts/signs.rsi/hydro3.png create mode 100644 Resources/Textures/Structures/Wallmounts/signs.rsi/kitchen.png create mode 100644 Resources/Textures/Structures/Wallmounts/signs.rsi/mats.png delete mode 100644 Resources/Textures/Structures/Wallmounts/signs.rsi/miner_dock.png create mode 100644 Resources/Textures/Structures/Wallmounts/signs.rsi/restroom.png delete mode 100644 Resources/Textures/Structures/Wallmounts/signs.rsi/science1.png delete mode 100644 Resources/Textures/Structures/Wallmounts/signs.rsi/science2.png delete mode 100644 Resources/Textures/Structures/Wallmounts/signs.rsi/shield.png delete mode 100644 Resources/Textures/Structures/Wallmounts/signs.rsi/toxins2.png create mode 100644 Resources/Textures/Structures/Wallmounts/signs.rsi/vault.png create mode 100644 Resources/Textures/Structures/Wallmounts/signs.rsi/xenoarch.png delete mode 100644 Resources/Textures/Structures/Wallmounts/signs.rsi/xenobio2.png delete mode 100644 Resources/Textures/Structures/Wallmounts/signs.rsi/xenolab.png create mode 100644 Resources/Textures/Template/signs.png diff --git a/Resources/Migrations/deltaMigrations.yml b/Resources/Migrations/deltaMigrations.yml index 3df0243ffa6..1dcdc4fe022 100644 --- a/Resources/Migrations/deltaMigrations.yml +++ b/Resources/Migrations/deltaMigrations.yml @@ -115,3 +115,8 @@ shuttle_manipulator: ShuttleManipulator MagazinePistolSubMachineGunEmpty: null MagazinePistolSubMachineGunTopMountedEmpty: null MagazineShotgunEmpty: null + +# 2024-08-09 +SignScience1: SignScience +SignScience2: SignScience +SignShield: SignConference diff --git a/Resources/Migrations/migration.yml b/Resources/Migrations/migration.yml index c7ce3215a89..f23a50715b7 100644 --- a/Resources/Migrations/migration.yml +++ b/Resources/Migrations/migration.yml @@ -345,3 +345,19 @@ BookChefGaming: BookHowToCookForFortySpaceman #2024-06-29 IntercomAssesmbly: IntercomAssembly + +# 2024-07-7 +SignScience1: SignScience +SignScience2: SignScience +SignXenobio2: SignXenobio +SignXenolab: SignXenobio +SignToxins2: SignToxins +SignMinerDock: SignShipDock +SignChemistry1: SignChem +SignChemistry2: SignChem +SignCourt: SignLawyer +SignAtmosMinsky: SignAtmos +SignDrones: SignMaterials +SignShield: null # what was this even for? +SignHydro2: SignHydro1 +SignHydro3: SignHydro1 diff --git a/Resources/Prototypes/Entities/Structures/Wallmounts/Signs/signs.yml b/Resources/Prototypes/Entities/Structures/Wallmounts/Signs/signs.yml index a3f69bb5f5c..98cf7ec39bc 100644 --- a/Resources/Prototypes/Entities/Structures/Wallmounts/Signs/signs.yml +++ b/Resources/Prototypes/Entities/Structures/Wallmounts/Signs/signs.yml @@ -244,6 +244,15 @@ - type: Sprite state: ai +- type: entity + parent: BaseSign + id: SignAiUpload + name: ai upload sign + description: A sign, indicating an AI is present. + components: + - type: Sprite + state: ai_upload + - type: entity parent: BaseSign id: SignArcade @@ -274,11 +283,11 @@ - type: entity parent: BaseSign id: SignAnomaly - name: xenoarchaeology lab sign + name: xenoarcheology lab sign description: A sign indicating the xenoarchaeology lab. components: - type: Sprite - state: anomaly + state: xenoarch - type: entity parent: BaseSign @@ -287,7 +296,7 @@ description: A sign indicating the anomalous research lab. components: - type: Sprite - state: anomaly2 + state: anomaly - type: entity parent: BaseSign @@ -300,21 +309,38 @@ - type: entity parent: BaseSign - id: SignAtmosMinsky - name: atmospherics sign - description: A sign indicating the atmospherics area. + id: SignBar + name: bar sign + description: A sign indicating the bar. components: - type: Sprite - state: atmominsky + state: bar - type: entity parent: BaseSign - id: SignBar - name: bar sign - description: A sign indicating the bar. + id: SignKitchen + name: kitchen sign + description: The heart of the home. And disease. components: - type: Sprite - state: bar + state: kitchen + +- type: entity + parent: BaseSign + id: SignTheater + name: theater sign + description: Would it even be Space Station without drama? + components: + - type: Sprite + layers: + - state: drama1 + map: [ "base" ] + - type: RandomSprite + available: + - base: + drama1: null + drama2: null + drama3: null - type: entity parent: BaseSign @@ -397,24 +423,6 @@ - type: Sprite state: chem -- type: entity - parent: BaseSign - id: SignChemistry1 - name: chemistry sign - description: A sign indicating the chemistry lab. - components: - - type: Sprite - state: chemistry1 - -- type: entity - parent: BaseSign - id: SignChemistry2 - name: chemistry sign - description: A sign indicating the chemistry lab. - components: - - type: Sprite - state: chemistry2 - - type: entity parent: BaseSign id: SignCloning @@ -428,19 +436,20 @@ parent: BaseSign id: SignConference name: conference room sign - description: A sign indicating the conference room. + description: Where work happens. components: - type: Sprite state: conference_room - type: entity parent: BaseSign - id: SignCourt - name: court sign - description: A sign labelling the courtroom. + id: SignCryo + name: cryosleep sign + description: Just like that? You're gonna chicken out? components: - type: Sprite - state: court + state: cryo + - type: entity parent: BaseSign @@ -462,18 +471,27 @@ - type: entity parent: BaseSign - id: SignDrones - name: drones sign - description: A sign indicating drones. + id: SignRestroom + name: restroom sign + description: A sign indicating where you go to... What do you do here again? + components: + - type: Sprite + state: restroom + +- type: entity + parent: BaseSign + id: SignMaterials + name: materials sign + description: An omen to the juicy vault of steel, glass, and plastic that lays before you. components: - type: Sprite - state: drones + state: mats - type: entity parent: BaseSign id: SignEngine - name: engine sign - description: A sign indicating the engine room. + name: power sign + description: Where the powa happens. components: - type: Sprite state: engine @@ -547,7 +565,7 @@ parent: BaseSign id: SignHead name: head sign - description: A sign with a hat on it. + description: An official sign indicating the dwellings of a Nanotrasen-certified head of department. components: - type: Sprite state: commander @@ -559,25 +577,7 @@ description: A sign indicating a hydroponics area. components: - type: Sprite - state: hydro1 - -- type: entity - parent: BaseSign - id: SignHydro2 - name: hydro sign - description: A sign indicating a hydroponics area. - components: - - type: Sprite - state: hydro2 - -- type: entity - parent: BaseSign - id: SignHydro3 - name: hydro sign - description: A sign indicating a hydroponics area. - components: - - type: Sprite - state: hydro3 + state: hydro - type: entity parent: BaseSign @@ -609,8 +609,8 @@ - type: entity parent: BaseSign id: SignLawyer - name: lawyer sign - description: A sign labelling an area where the Lawyers work. + name: law sign + description: A sign indicating the presence of the (typically absent) rule of law. components: - type: Sprite state: law @@ -642,15 +642,6 @@ - type: Sprite state: medbay -- type: entity - parent: BaseSign - id: SignMinerDock - name: miner dock sign - description: A sign indicating the miner dock. - components: - - type: Sprite - state: miner_dock - - type: entity parent: BaseSign id: SignMorgue @@ -743,38 +734,27 @@ - type: entity parent: BaseSign - id: SignScience1 - name: epistemics sign # DeltaV - Epistemics Department replacing Science - description: A sign indicating the epistemics area. # DeltaV - Epistemics Department replacing Science - components: - - type: Sprite - sprite: Nyanotrasen/Structures/Wallmounts/signs.rsi # Nyanotrasen - Signs read "Epi" instead of "Sci" - state: epi1 - -- type: entity - parent: BaseSign - id: SignScience2 - name: epistemics sign - description: A sign indicating the epistemics area. + id: SignServer + name: server sign + description: Ever heard of Big Data? This is it, chump. The biggest. components: - type: Sprite - sprite: Nyanotrasen/Structures/Wallmounts/signs.rsi # Nyanotrasen - Signs read "Epi" instead of "Sci" - state: epi2 + state: data - type: entity parent: BaseSign - id: SignShield - name: shield sign - description: A sign with a shield. + id: SignCans + name: canisters sign + description: A sign indicating the auspicious presence of gas canisters. components: - type: Sprite - state: shield + state: cans - type: entity parent: BaseSign id: SignShipDock - name: docking sign - description: A sign indicating the ship docking area. + name: evac sign + description: A sign indicating the where the evac shuttle will (likely) arrive. components: - type: Sprite state: dock @@ -819,12 +799,12 @@ - type: entity parent: BaseSign - id: SignToxins2 - name: toxins sign - description: A sign indicating the toxin lab. + id: SignVault + name: vault sign + description: A sign indicating the vault. Who knows what secrets lie inside? components: - type: Sprite - state: toxins2 + state: vault - type: entity parent: BaseSign @@ -971,29 +951,11 @@ - type: Sprite state: xenobio -- type: entity - parent: BaseSign - id: SignXenobio2 - name: xenobio sign - description: A sign indicating the xenobiology lab. - components: - - type: Sprite - state: xenobio2 - -- type: entity - parent: BaseSign - id: SignXenolab - name: xenolab sign - description: A sign indicating the xenobiology lab. - components: - - type: Sprite - state: xenolab - - type: entity parent: BaseSign id: SignZomlab name: zombie lab sign - description: A sign indicating the zombie lab. + description: The final remains of a shut-down Nanotrasen research project that aimed to harness the powers of Romerol. I wonder how that went... components: - type: Sprite state: zomlab diff --git a/Resources/ServerInfo/Guidebook/Service/Chef.xml b/Resources/ServerInfo/Guidebook/Service/Chef.xml index 7d077ca269b..370c1db5c3f 100644 --- a/Resources/ServerInfo/Guidebook/Service/Chef.xml +++ b/Resources/ServerInfo/Guidebook/Service/Chef.xml @@ -51,7 +51,6 @@ Ask Botany for what you need, without a botanist, you may need to grow more plan - ## Gathering Milk: Alt-Click on a Cow with a container in your hand. (Beakers, Buckets, Milk Jugs, ect.) diff --git a/Resources/Textures/Structures/Wallmounts/signs.rsi/ai.png b/Resources/Textures/Structures/Wallmounts/signs.rsi/ai.png index 6cee540a6b2b727d219e49585e6395cebeaf0f46..e532ec039e84e8d2b1b2fb7892852f9b98749e39 100644 GIT binary patch delta 380 zcmV-?0fYXK1C|4jBYyw^b5ch_0Itp)=>Px$P)S5VR9J;$U>NCu5uYTNvG;#!S@iAf zR;+g6bO4vJ_kS)SaRv@v0g5gE@%aP8w|6hGIs&T$V3zYq$Wd%L419X=2&*GlaA`pH z`Q1f6WLvBpw*_wAw|6fw2p|LHxGfBK7x}<_Lw^h)Ry|Q6KyDNeqmL*D zp!=jEEry{YEry`jkO%>i(f|x}%vyq>2AkNB2m!Lw05(8Q8XzhP(0$S|YYA3Iphp8S zS&^(XfXy;o`UrsmPXk1S0HqGW2Zl~vKr1jbLI4?5q{T3#+I(POU|?XFeMEqvW7ZOs zv_WcUksJc4Hgz8ul;gHAD93GqI|ODaIZ;J&2rw{EH#d-#24EpDU=BbBun-|9WN@~M zh2+&4*tq#9a~Tr&_4O0OyN5T4Zx#Re`~kxO#QG3h^!)hz0jt`<*)c(O1jV*P0j{pu aC;$Lc%#;2PWaqa400006vn?+s3+*ijKpB+p_~B;Eq-anyK=CnAGz+S>l!x77X+BHBVFdFm`$rOv(v~o@) zQ*8uo8&E1Mbi@8|ER5$VSj?us#!Oh(0FkKO`8knHS#9eafjVv{0(EW2jet`Z=t{4E z+XdDsSO$cN_iqRQIu%vAUCmjiA^Ri*ep;|jIk4{ny}LZbWxa-h@-f^dRt7G)j+=0* z0pR=6@xxfFE6xTYnSw}Y{c{6=`y1dKb{FL2busbW>ciRqk#NqjO=|xAS>Dm{1&N}Z UI1{IdNB{r;07*qoM6N<$f`aX^cK`qY diff --git a/Resources/Textures/Structures/Wallmounts/signs.rsi/ai_upload.png b/Resources/Textures/Structures/Wallmounts/signs.rsi/ai_upload.png new file mode 100644 index 0000000000000000000000000000000000000000..91256aa1df71351761153db05f3f6ef7c1ed1207 GIT binary patch literal 513 zcmV+c0{;DpP)Px$yGcYrR9J=WS36F_KoET(6rn^!Q5vYANWlTp`Ude4taSDne1x1KbQVVlH%Q9? zC|p1VO=Kk^ifBRsV|K^;nGHrlg4bBy-I@2^%-FJlzm6l*Vs|{*{}kc&{!Zg;2meh&zEb$U@ za*DU*Co}}8phT)0o|KD}#E1n@LK~Tl&=;fP#6`}DOk@%Rt{AHTX$kom6Ol`>xB{l$ za}wL&x!@E)iB(ctuU%^g3rM31v$?(&>JR|RA_f4ArVF`%vWPL7F6t{_c1OuSP$7-t z#u*p9Es((EOoc8|hxa`oO$2Px$y-7qtR9J=WSG`WdFc3ZvLs6yvEC?Z$ zy$@h{$==6k=4^SAZkdzEV9#RZ0kTsGAr?p^1Y21+%Q5HVj%26=-_q9S=KFm2-N^y? z>$vC(M(f>aDx&iBf#eDbh}OH)@_Gr2+qBSpG^7Yp0DqF--`$KRM?5~gkRmQa zf8d;4M;fv!1|8|ay`kp?1%%)dn$kd`axkUo2$JARvROwO5|!KU`@`18inIn(8ZgR$ zjhu|dK+-_hspLN!;_4?e6 zCiOk=_WlXS=Ocd-`f!aEs;z5MPW?p!u%2i#f8u3T+{q57{s6xyftv+t68ifPp%REj zF-|yl?D_(SJmN!?0Ut<6na;-~8Sp`6K??RHbSGX`#bX^4QgQclv;eHDYq~_`mVkE1djudBYy!_NklZq}6n(9_WbaamAr}A81Ucm&^BSQTphaz ze9k`_H5vyO%hmDu`+y?LS>mqmVLux+ns{m>DY6_^XWP7V-T@Nlf@PrGmMF6PLY!Nw)&`cW1I_|{)0Q{_XNM&*nx(z+YID{ll6`;RMWddj7sBxQ; zw5kFkrZy0vTD5*5r7|(*G(G~#LG)hV62>swdSe5w@3E`E^*!uc=KT3@`G5f@rCY6j T45emh00000NkvXXu0mjfsm!cw diff --git a/Resources/Textures/Structures/Wallmounts/signs.rsi/anomaly2.png b/Resources/Textures/Structures/Wallmounts/signs.rsi/anomaly2.png deleted file mode 100644 index 73d94ac95e45de566b4003a5605a00de2f3c55ea..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 454 zcmV;%0XhDOP)Px$fJsC_R9J=WmN9C>FcgOWmMq;1p`albkdW!nGuTk5x804vB49G9BuFQ4~G&e^1hr3=I13x@iiS%@+p~gSXe0T94Yn z*?e)hUw$J`vrgt*3hbtLwGgAGN%Azq^GDbTAn_wSOrL6F8UZe8A8#*D7L2v$(gIM8 zi%n4(V-73FbwIRNfQ+x53+6Db`EJ_=s@dmh1~>G;r2v-#Zs=8ju5FPK0C3En%+)O@ zHbn_>zBN_>R72pn+_dDn#zp`()d@h&T3wCa0hq(UrNBB`RScQKu#Q&XQfPy;F2hkU zE>AZ>kn%JGm!cAD9e{K#!>(JP1wfhY1hL}J9EFU!J2X6PK{}4FVF#rGn07*qoM6N<$g2_n27ytkO diff --git a/Resources/Textures/Structures/Wallmounts/signs.rsi/arcade.png b/Resources/Textures/Structures/Wallmounts/signs.rsi/arcade.png index 9f36d43776ffe216cb3fec73d7ba255228a107be..7cb18443529fbb6b7988d25d9e9bc151055e5cf0 100644 GIT binary patch delta 478 zcmV<40U`do7`7OYBe63>3V#8*NklO060@3NC8OR>yOC?qrinQPJgt&TOAvh6%n_b zYRU32P9O?gE%Iycu_2Iv)FP7kbH0T0AwbZ!#QuxGHJfAuxD{vnL?j=8p zk8}4WG%iD_1us{5$z!zzNQBaPn(ZNslTt@jA%*}gSgvv{aZ`97g%sN`2l8KiGFzNS zk59$F*~T~>caW}MD)RyBfx~tKR>!W@fK-HWg0n#d>}1sTV3L1-lGD+zk7ob)0jmA$ UD-)6l>;M1&07*qoM6N<$f*?ZN$N&HU delta 482 zcmV<80UiFf7`qsdBMtxrXF*Lt006O%3;baPu^~kYe*hq3NK#Dz0D2|>0Dy!50Qvv` z0D$NK0Cg|`0P0`>06Lfe02gqax=}m;000SaNLh0L01FZT01FZU(%pXi0000RbVXQn zQ*UN;cVTj607GSLb9r+hQ*?D?X>TA@Z*OeDr{R1600BoyL_t(oh3(ccYlA=(2k^gJ zhkS!Ne^~+<6!b$#>*5y7>e9V|4*3KQg}7&NO>lED!4Hu@G6pPe zPsfY(G)9QV0qgS@wx=VTXtzJWwQMeD$O>KtPhtR0=)<*a1aSmiQ@L8g1aZXGHwJJ* zpXFW41_1Uc3|RpH1aZV_=oujZT~oQGrhlUqK-snfz}2>>b>@4_iGy>@KQc8$Qv;Re{Yk3>d13Cx% Y0`B|4(ES~6X8-^I07*qoM6N<$g4z$qcmMzZ diff --git a/Resources/Textures/Structures/Wallmounts/signs.rsi/armory.png b/Resources/Textures/Structures/Wallmounts/signs.rsi/armory.png index 671e57aa5cf295495ae5f9c8f377b847a3f772cb..3f237ec04663cd1dce749f3c7705b3232cacfa80 100644 GIT binary patch delta 398 zcmV;90df9^1E&L!BYyw^b5ch_0Itp)=>Px$VM#gMU!!>bNB+(RMf60d;?R29TcIpc5MZif#2DZ^`F+eYZ>_KGE0L;V6J6! zX1rK{BQQ4r9x9km07eEP3qa;i70gMm48$GxK)Un&{9H6?oquEJagn?)uBwEfdBIrG zTrt4d^=M9qFZW`_<5CDQ04*Maq(C{SY5=tO;63&W#)J2_0Z7A1Fs*ZH(^za3ltkg* zV!jEWmR11-W7!OsmMTe=gutcQLhny9XA|13LhZo0tF88-N!m&I7UNJKs77;1d4yI+msvhya?? z0m0a-(n_z%RNIKeIgs0BoP=Z7uS!fYK-zlK2n^nfyWc7RiBfaP>-h01U_0UT0iaE) soPx2Kn6cmaV-iDD@CO+4e*wTdO#Gy)!DZ)300000Ne4wvM6N<$f>`so0ssI2 delta 365 zcmV-z0h0cw1BU~UBYy!-NklAP&|3{(x-WKOMLR2~pR%AYecfX_@U*SjdQ z_RfGzzM7Y3m0_(_2aN&{O=o2z*slQ`_gi@H;hY0A!+Q^7Oc>JwsR1Mq@Rk19oiYkw zIxB+@QtCe%pk{8uR3)1*Re$3wsP6k$0Z2KHF9IMs?zgbkf`~%tNncuRWvDz*56;Y? zZ;a7Q6$elaL_`5d;Hqt3sg^*zkh=M(0Ej5M3hEb_CSCnnK4{Pf7`T^%m5Zlq00000 LNkvXXu0mjfp|hf= diff --git a/Resources/Textures/Structures/Wallmounts/signs.rsi/ass.png b/Resources/Textures/Structures/Wallmounts/signs.rsi/ass.png index 0dfa8a04f5cd9b305f3aa331f0894bd8c2e3a9ec..9d57ebe7e9a44b6ff917562f4475bd464aa620c3 100644 GIT binary patch delta 494 zcmVPx$!AV3xR9J=WSFvitFc7_#u7N;sGCEtp zqcMRj#aq6>U9;y8{007l>|NV0$X2=(g7Ij`7LREN6#4<_P|lT4r?aIbbZFlaN$2=I zo$gLPfWM9#$vB%YPM0EjTR*Z~cM`cjnZjT+KAZfw-vI!eIDZkW03;tzrkX8VMy-VD zDsRkt{UHuD5k?PiJI|Jp_Hqu~bA!PFG#C~nJfm0nYk=T+0ICwxs z68rVeUE$;b1m-ZL zQywCC&g3x^Z(dyJL&RXO&6K=BhHUAi;-smhlS4zO|HYPc+0yGAC1*?h6@ z6X5mvNgG4EIGZo_AL9+`rgaJ~I776XXd!M*PU@z`+vAH9fPXA9ME4V|&5e`iGs>8O z-z1CdVC5Hq@R$0!ZV;%FYJV2>^gq2`IX*Ms(3V;M(a-x{eYY_x(Qy=yM&P z1polvx1Y$X5@2bZAg@XY&QLe)!8i1LEY~a28^U@IsGtg>8(fW5aEeHqF!cOyh*NM1 ziX!qcdybQaOnMou*2+Zs-^ZnkNH*Y3QS+V_ZfU~|# zmLYO}DYak#i0^OIrPHo2B%X{?k$yUb@)&^#%Q#%Jn6I>MKo$g zoZe%6ya)iiO{_56;}nJIB!zfVe0LpXCxFguA7f5XobzAq_Tm5r4)5m~la@eH0HG0} zF&~&ie;xtbL!Aprkq=P-dZOzzz_8~CJB}fbV_B^T0%#Sb81=wD4LZ@7^}P%-Z#T?b z)`#dVpy_I+ORpW;*$P>C1BV0HF#7T#h}ojd)3S>xItS)Ku#H<2``(iL`n9iSS2c`& zlDRG!pIguipuKr2>)S{2`Fty**9&w1)8H}R12pzI4~DtJ;Z+;}7NHOTT%sC|^Ee(2 z;A0v}L-^WU0G~y5M3xQ^;~DmybI^_kpl8~{sQ1j4gdfE diff --git a/Resources/Textures/Structures/Wallmounts/signs.rsi/atmos.png b/Resources/Textures/Structures/Wallmounts/signs.rsi/atmos.png index 9441b32827891b83ec11770bb1a94bba35f4739c..ae31db348b28b877966c3e870f97c66aae2efacf 100644 GIT binary patch delta 441 zcmV;q0Y?7j1JVPKBYyw^b5ch_0Itp)=>Px$j7da6R9J=WmoZL-KoEw1jVF-eC0OVI z+=if@g^EMazS5RMP;nNOyk_44v~UxO=M|m>8M3UiFf3b`=$}w5limN@8JGp&uj^ti zxG!*yW%S(gUS5EGf%EMRuuHd__Xha*EAWSbdXPtr{#i3Z>r_%!#B1_N-r_i2r>7(lxFP({rEDQXEqGN8&1NmhtJ z#EmFb6#&e>4S()ENkb9?&>~z5whirF>n4XPyIFvsMx@Ga%!n=OfLzQcaRyu?yUxBC zjiUoBExe{BM>z|&Xb~V))uiUC?8b}6wrK3m3kFECVsgAvdhIlGFz&oy0C!9C6vn?)y+9^bk4!MJWh)1$6eUtm(6v%` z58fkn%?T=jxB=PNm|*hgl?mkp=>T?trr<}ZIyB!BjIH;6`27oT(|^}$>cHXne))-m z*XO5EAETRx89T-{p~0BB-9w<5libqI8V1)L*o6H(_w93`Iz%LKdq7HVk# zpkD#N*DE)1mw&?ArZqquHDA_ss>7jkAZ@FpmKosM*(K$`ltRzxhvPQ@bg5nIka|!5 z+Q>Qt0WS~_x}X|3)}nMnQW6Hd0Fwf>%uve=3<7Mw?Oi){Zjfhza=A&cvvEr6|73t+ z`7J3cfVtz?2AmWECWRS1X<3;8)O|+cWh{$EA z&}97?K=6p(8tuD90Yc9)(~qjqb8wnC^XGrdZ@TFNV)L;JSxBqh00000NkvXXu0mjf DFuK!I diff --git a/Resources/Textures/Structures/Wallmounts/signs.rsi/bar.png b/Resources/Textures/Structures/Wallmounts/signs.rsi/bar.png index e5fb2ab766ec9d9bc20e1325ca743d06dcb87ad8..8fdc8016af35f04020fb2b985d2e33c5f3615d67 100644 GIT binary patch delta 372 zcmV-)0gL{G1C9fbBYyw^b5ch_0Itp)=>Px$NJ&INR9J=WmoaX_FcgOWR_(yhMqLUA zhy-U~L9vu8aE4qVTee(*yF^O1o&h8dP*|dpAp-*)Xj0=ooBG)U2>$KqIsQM#)_XQ^ z>v}LH!zm8FjMg8tmlhzL;_&mr6-%gWnN)XWPLmrGjd!KXAo)huQ{#$fJh@G@eyEAWJuzyk2&Vn z04jtkTXPnG3?Xj^#~iRc11dy!Cb;HK05SyE9AIvNPu&5o8=x!4E@hbwpqg?aoa%rN zUDp{X^9p5N^=(~nE@mgOn)eO>oHnDb1k26I)U3P!sCNSDFv@xF0Mv?2dG7$WD?BId zt@w2e1Vewf;;&7E-RkeHSX&3$8VH8JF{jYT+tb$cn9F>a$Pn)KN9mqscYOn5ErutI S6ZrxF0000n7dE*9lrr)-Mb#f7OXeBvrmHe z)tfbk_2qiAJ0G7vfD4IA&M1NSw6H=vjRoOCLYZz^X9X8=YCY!CZy^IS+^l(>d-2jD_Nk)(R8b|MPG3)pM?w*bS$ zzH$brvr^ZAsqJBZn<6wJhI1G_qP{W`GD^_Ny#S^X8bBR^>i?Sp}&r0T0U#mClb%cxc~qF07*qo IM6N<$f^({(`~Uy| diff --git a/Resources/Textures/Structures/Wallmounts/signs.rsi/barbershop.png b/Resources/Textures/Structures/Wallmounts/signs.rsi/barbershop.png index d196072a32b0e63fa87efd8d4abe329dc2e4701d..b01a82717f781ae49f7efa4628cc1d0b824c7884 100644 GIT binary patch delta 455 zcmV;&0XY7=1K|UZB!2;OQb$4nuFf3k0004-NklFfje>$=hzcl$%*%F*ldBkAi#=iJ|H;r4Dl+xg{u0sv?z2!9d)ov%0B_FWiwP?WW? zQ+fVkxx&{yi0h#R)SV}>4`JXLJ5OR?yWS`OB@+nBxlYCajEhkS**VU42B1Pvn(BNq zfGjl%rui`&fI14B&|3pg5Vp>(0c1_dc&7lk+hbmJ#y~Yxynha4X#~f-0>(ufcC7XIluDH-Pg;{viY8ocvk z_Spa?i#jhvVcn7t{ao;{f+F7e!VsO*Eb=?$G7bF+_eAz002ovPDHLkV1gC1-G%@F delta 418 zcmV;T0bTy#1H1!}B!3BTNLh0L01FZT01FZU(%pXi0000RbVXQnQ*UN;cVTj607GSL zb9r+hQ*?D?X>TA@Z*OeDr{R1600BoyL_t(oh3(d{Zo)7S2H-zi2i|~AMMw;Zls*Ik z7Pcy^EbJh4=o56PM0OTds%$Kz;vtBX3`i(U@CF&!(xqpa)_;IVoJ)nc#ThK!cRt&( zk)|oi4C4;?_ki(amPLi}IG&5w zdW#3(cDUKdNzQndIGTkPx$M@d9MR9J;$U>NCu5uc=r6~ljOS#;+Z zcDryoK*fsTKdTr61E(P6mVbZG!0`JOc1K`!0L*d;4PMG^hk_S3K4WzR6D|$Z@HsK& zv5;cOzV`h@shhF8fnn9YgG8w%$pH)u3=B?{jyUD^weM$`v46XPA;YzSVbwm|>L_vm z0|Ns?n3Fw*7|h43_8nx%a3$U>oN0hwV89(fRumAMz-Zj`Rz*!yhsWUL}i&L*U{`m4U!>5}h zRLArJL^}XI@oepD-w(&gd{Pr3*&zU{mXWJxr%FeX6CqWj0M;HDFbB{)1kmFgnTD}p zAwX>NZNRf3&VuOsdj(0uCCcA003&)fs->1 RdN2S0002ovPDHLkV1iYwqFn$0 delta 313 zcmV-90mlA~1JeSKBYy!JNklHz|%z&f;@O zXD3IIZY~Z!gn?vs(syvvsipNNY0?Gz8h@&j39u1BlBHmjAPPd9 zua~!a6ol9w4<;kgHR^UC58wfeW0)%n!ruUJA+2x5Rsa|!Uu!n^fYlMGwqFI<7+^nL zBFR$y5sYFt069dPss&Kz0dfk^c z;6fILPx$l}SWFR9J=WmoZMmFcgM=5UNlsqNoc@ zbjZK~y5E=JA>5!V2Vlqm6D*b0h$>jm@p?4R|7k8MK!wmT*MA0}46eIeWB{3YnuMr}0BI5$Ly!PO18yAq3|>?r_L&q!Y|BL2hTJGk zLc~4;z`kXJKOdovhm;qUsEYtuZUKM~E*gsxK`0^t=v1|CJPCjo)OzD0%S&bZv{Y&s zt%HaUs%rC^v3e4UUqIOxQP#&AfGPu~GS0xzdww@iWjhEU-Un<*`##V%43n8-eAnyB siz>8@e7Sz-k4YC|wEL&}e$D>%0qM}{g%`-a761SM07*qoM6N<$f}h&W761SM delta 459 zcmV;+0W|*G1LOmcBYy#_NklZrE5Ji8YC?{}9jpPDp5NEJtU%-fh!c`8C z0&xP1!Uu3gL4n``Sjri!jI>3h)G2*}G)`eJ!FB?>3s#DF8pQ5s=I!kK0pMo;-R`;^ zR_lD1gL6`-KB!4sl@S_ZqvDfNzZxp$a zV3~8D5PAT9lwq^o{kp%|?%+q67C`3}G>ynXT2=sN$LHaSd=^;D4{Jou^#J04umq5n z6^bOpGH1B9g{e1!A7vnN5C^0Mpxpz^0z}S9sbz8#wJ2Ah*=(+D!L==9q!8K8N(*MIkqi+#CP`zZn_UqO+C^*oTLC33Ks&%i9;+SY~Npa9Zjw>Og%Nr<$p zu$a$u!|ADDv)$EFlTFAhkd~(soq8kXm|7K($>V@fBw?-jA_)-()PPVotqOGAZ5)tt z^BDmQk-~N1P&6_Q2<~t2Sl2~2l$?VCJF!yD!?pG=D(Dt ztj5&=&ii5N9p4Sr&D4inpOZiTEx*~#z5v`)xJ$h>xeovU002ovPDHLkV1j#+ B*vS9@ diff --git a/Resources/Textures/Structures/Wallmounts/signs.rsi/cans.png b/Resources/Textures/Structures/Wallmounts/signs.rsi/cans.png new file mode 100644 index 0000000000000000000000000000000000000000..53cdbbb5c90e050ba1b4436e71db44fffdf2f450 GIT binary patch literal 445 zcmV;u0Yd(XP)Px$cS%G+R9J=WS20e+Fc2INFCfK9p@0XFCJNkJT;&nhUP+rrr1D#UD2?v{P@JU{ z;R{C*?aAb9pS=zO38sl+JK5RU@x}rEIxc*ZTYbi{s5|SpYAfe6t9&9bhm(L0V=tjq^JOeAHk?=S2xO%| zR*IAHIjIm_atHvE++!~>_R=f;IYcW!Qky;?HS%H;twJ<`tQ5|Si@J*@z%BtWWn9!9 z+kk8W6qKa58S+~RsJ22@3XHu3fa8?|);1())v&gni6jp!0k#KHWH-SoK}zG9>y=JO6{&e_%{6QKT2=A(PF1FE(<2Ar=?CSZdvJMu}$ zHzMgg;DT1oi9#*}nb358h^(|WWLG#(#g7lb-E|1PFuZ*LFRu}&;z3UYLY#aKs;w|+ n``qvRF)>M`ho9j3HT%aW%=??Ofo!l+00000NkvXXu0mjfD(Jv1 literal 0 HcmV?d00001 diff --git a/Resources/Textures/Structures/Wallmounts/signs.rsi/cargo.png b/Resources/Textures/Structures/Wallmounts/signs.rsi/cargo.png index bf0176ea97ecd8d2a47e095dba2082fae42236d8..0366a82ffa65b5fa94b2e2f5c7fa100be17d4169 100644 GIT binary patch delta 420 zcmV;V0bBmy0=)x}BYyw^b5ch_0Itp)=>Px$cS%G+R9J=WSG{V(Fc7|$%qb$6jDZdw zx_HSe6at2H%iuL$(-&|?`z<^hlD$t6FI_TZD0D2ri1r1pOBIZBO78sA6q*l=k#)ZB zlTNym0RB5}PIdYoU|U2luQZocfbRj`^#KM-H6|~#hR-ir1b->OkUzL?V{(J-Zbyo^ zwf)e>$T|M30)7iUj!~3mBBx0hv@0M91BlWL^7WGCG)gnJ2zCgPFo5waX4&TJC41Ja zyWoDLVCXnUeRad}vERenyFS_ltPqsRpPwE{VU#Tg><~!eDp@b0UBDd`mz*tta%vW& z?R)D2&IziE&VMrDcowtPOeX@kL>Wm+u2)OAS> zD9=c>O+kDfs0;CVpwJqIjw3#RP)Nc63a!b$zj-k!iydgp{sY_9?22#8>jhp_(5?;u O0000wIsxogL$v!7<9{71fF7`jIKV6b00`s6 zcz)PzSn=vyfU@;<0QM{3rnqzfB4Iq|wk#U}06N`XzQ3GL`Say`V#jg<(B)$61@K%4 zMB?)q(Cfe_1HadXu7jx*0N0`94N!Cly$!%;9G3#12Mpr`husE5BCiRxClUw-i^4J4 zU7(w*mXtC>7(XZMB4q<8bM^62E0J&-R9;;W%|Zi7Z3?tEqA{DTVAQs Y1IX`VC+9BnkpKVy07*qoM6N<$f|0b5xBvhE diff --git a/Resources/Textures/Structures/Wallmounts/signs.rsi/cargo_dock.png b/Resources/Textures/Structures/Wallmounts/signs.rsi/cargo_dock.png index df7ee4cf112dfcf787a8e68e4b007f2cf8eb35e6..4b07e410e29efd308e689ed7baa58261a4b0d6a1 100644 GIT binary patch delta 451 zcmV;!0X+Vf1Kb0UBYyw^b5ch_0Itp)=>Px$mPtfGR9J=WS37QlKoFfosS}|Hxr{{N zB8?l)0EK%BYHk4~+=7~dK7~00O_~%gkWxk#TG-xD7dOsOOqoZlbGyPH_019h08J#9>u+RjM6GkS zH|_VHD}Z7s9rV8ISS(*!0;Zr+Gg<;<`N#W6o&@8$N3d%^2KtyW_bTMt0&Fkt6&Tto z23*H#wHknY7vMPN z7UbYMwq6WanPx*icN=~k4p4mx{yL`E71iWc(*>&r!Zd?0&6>yRI+oN9)2um9ud@XJ zTqYc*0mp6ER-J-M0#p&E8B5UB1SEmKYzpWYF7rrgb36#UV71{AP;SFo2w0h>R#aUi tfe*FlzYzo6>W2vxF`NAdL!V~<_y+nJ*U2Bf#Bcxr delta 381 zcmV-@0fPSA1D6AkBYy#2Nkl%m0hK zU&wIz@&&Ri*VQ#(cq15(*AXm)47q&y0)ubfPO==Zd6GMWq+L8-H3S`iZXh-Qb0D%j zv5qF%0h=eeGk69h;*^6~sH6$c<2<{6O4uzkaPl(c|Nj95pLR1Tn91WWO-8WNU8 zX;vA*EQeVnqil%c7??aMl@UqV5S0%pXcXik;5h-Eriue}bq&bQ1-iNh3~vai8SrNL bC>R9*k|dwl&Ptjw00000NkvXXu0mjfPCc64 diff --git a/Resources/Textures/Structures/Wallmounts/signs.rsi/chapel.png b/Resources/Textures/Structures/Wallmounts/signs.rsi/chapel.png index 635f00ec536f7a9666c491dc4439f7cc9fbc3c86..a862131d76c7f6531e0dc2919cecfc912678e916 100644 GIT binary patch delta 508 zcmVPx$&q+i}^Juvrmap2(aj0ksC$(iX6?Zl63J0DtcfvIt24C*R&H+h_m8 z-T6=wF|QiTBJ#ZFrv#XS29dTciUqN=u>-%f2`sOcCOXFK8fRBGsdf@ZuWuMV0#CO% z1`1?AjWDErc*Fq!c*H?S`?>a6Fc#45`KbqUQjwg`b9-w7R3RMgrk^`+U4V#bHz1&? z18ciLr7G6}kAFBuk?L&Jz43fM#LGoa9nc}9{mj&=qeoW!RPY7MY@3(P$#GsaG(mfxFRqL0|tTVUe% zMrH=OJs&iPKss)c1=AwKeF1=U++1IyI$#q}9-#(6YeQ}+wAIEA$y1rO|Of#Te0(BP`h0dS%_YV&w+aG@mQW=N` yK&3j}8J`8xaS;#XvETJ$B8sq2KZg2i_Ky$f4^UjzPI6lS0000!Q-+@gBQ&L3>*W#Z+M*wU-$E^UU!31Yz?d7xYdI;mFT!H4$q%QDXuS^Ks zE}`J;ZvM;Z*g;ezfH00AI4ftrbU-Fe@)Nl;8keAA>BP~mZ2<_*jJrT^1{C@;U;i!d a)aeS&q;JawR0B2u0000Px$he<`QWLXw%uC+#gdbL7W0e_77mfuC28y(cM72?|U z0F`+mc4#U-3&1s>6M&N7J<3|mhDZX?R2*fk03Zp(%~EqSmWl!R3NpSY8Gy}v7%L){ z2*6}o2nOKN14gD4<7=qAJ#cx=u$sqeRuiT+4+1D_1;KmLybwEbOev@bd|8j-hCTpV znGk@|v_SztDu1A2jRu%zJRP^PgH#Ny?7VY%OE6?( zH=^Pp<^XXjzTZ9|U$25D3DN289mm7dw^On64QQ>AuPs+e4xVMLptZKfe&>(L7$VyJ eQ?6gLe|-R(2 zu1bN|=U!or!iU32vU`8}Ak(?1xT_rc>uw>$Ls^nc=PbOb2!Fs|M)V)Mg)yZ7KP86! z4uOM15>OEUKpcehwjBVHV9q$5iSmd57Ty#;jaVrSRC`Tg2LRrhF97&N;vDx?0P2tk zV6YjTSibP43^t?R1ITnv(wO5fBm8AV(wK{9g*CunGa?Scldpc9&WM9hU zsjBE{DRgMh63aL7Ial}iMi=<&xY7mYi)9y!Gg7s<|q9;s1S)?G8MHAsAV7;1xPzC_e zL@3_^8#!NBb$hzz5Wf>mfQp>2O)(c(OTaVDv*ctzkw7ekFS%8KxXr+~0b|11gqI+< z3LuoBEK(zRo+ZY$4OSD{vKGa0KQ!BevjFc#BtkZ5o+YU2)~i4C79bl`gpY`z9f$$v zPAH?QTa-m=j9*khvpsm3O$TcUc=r>#o%|`seg3koJK)lQj6qmjfnv+wzI?#Iz`*bymm@G70JB^{-Hc+( z85kHCcm>2@OstMz!lsEDJ}1^ZtPY?jz?ue#0qt2PaCYUiGxT*pdzJ}`rRaQ809jE` zIqeKQ1SqkbYzI&i3{3|ZX^GCMab;I*l$5(?bj(m0BYyw^b5ch_0Itp)=>Px$cu7P-R9J=WS3OR{FckhkoFGkyNDN)T zLnSVd1F(3^0W$OkS-3+$51V$HNtpOLR90UFZ+DU+EP*at={3&>+ zfEuL8Sp9S%)ql||1-}iuj?s(oD8P6gxSU@hnob5IT7P`vW%cZT9sqv!^{UF-)!yFs z+bg2opMrH2Q2%zyUSz;hY`<;aS-l6iR?6OMz&87X2yjKfngSt16j^hiYDQ@;YrBvk zfL$WJ|Mkri$uasWFh)Qrg=ji)=FkUeE}@hnZGZD(q8^Lr&HfG3)$E8bz6ZBo0hZ*D P00000NkvXXu0mjfdSbsk delta 393 zcmV;40e1er1EK?vBYy#DNkl}?q+=yeUx9_8>ckX9@(Xli>fWUc)=eEqo%kjx1363LANhVczP=97>%Z%)YQl8B z+&2mEbRTgIZlVPP7EPsG#onU-9^3FLAU39XY zvBr+6(t)2!O@;^wl#sZ&5&(eDFLT%?-7x@w!!&k1adNf+-_ac*EIlHKiSR-NvMQmL9iTn9z5C? z_ZR|*aH3;KE`O93qOJjykmU|&UMUW~3-aKBW5-m>0Zxf+6`;v=+zNoZ7!{z0+dI5` zy!|Rj^j;S_C(dkYF*rAwYWAlAcTe;WW) nVmVSm0vrFFKmRT7)$1Dw6PJ$WJEk500000Px$Y)M2xR9J=Wmpx9yKoEr=2t~*dmX!u7 zC|u+KX?=tE2$nnN3^_v15O-FNU~b@+1Eg>P6*SQ*7Li308a7&-{Yz#Okl;1;Xtg_^ zcV>3Hz+cyeZqOTzx2_y*o*t#XlmOmny!8gRxV{O<&fA7zvwwP%LP!C)bN}w1?3`=; z`XYt6R84U4bG=_b`hyn7GR5_J(HuL8{G3*($HEv>+mI{*NAwNITz4AV(swKy4I zHeZ|^LJM#X2qOT8kjVvv6@X4uh@$|y8BT%FmZ1qkEYmDv01^P~pmj(gknO~wBIkha zz_AGn89)bNlYbjd04Na7089`nDckYjVTfMecS8o?<9&_Q^U}T@pG#H%yx#e9I!RC$ z@t)0N&Bsnw1zE%prsXc?+!kZqwaEbDsb^!`${L`X;U?QTfT+9*zU6>S{P)eIA1^~? zH*6b*Uf(}DwxYtcMBB&{@^@ZLL;EO=)h1K^znLbbSdh@;; zpyxTB1mL<@Oi@E30%lI*VM^9QtD`vHe`W?EN~Xq`6huT+T~h@hA}RZ0B1Y3(I+j$u q1ykOA6+q7qN6p*t@Za)Tv%UeErgobM5?7`G0000v(JayEL4o+TND`K29jta$~~_fd`W(B!h53 z-)*N&sy_}~ILXTVtf6a*MBDD}8i{v$pBx_^E@IszWA;_VTH)$5=H{Y1Vik7||5#}z z{~&A1<823YT}s3KH!`1KT++gDac6^wgO{J81k>hzjs-tBj;WiS7v|!evo=YwvXsp% z&u)>9BHN!|zd9e@Jv>`tZPJ{;505{ygC!md$pf8m2*h7g)Vw*l=?zC$ZaY&Vr>mdKI;Vst0R3#IGynhq delta 330 zcmV-Q0k!^?1LOjbBYy!aNkl^wfOymL>3JWR^VBr}o zJb)F2g^>$TcnCM4FroGoHd=|Oxa__qF-E50x4aqNXBMEtzoXZ*V7=L0Z3q_gNXemm zxZdophtma8<}7j|fw4DKiWoEnkut}AHDd{wF1HwaBjuVtD}Qo@V7lDegs>CP1{zDC z0=G2Q0zRdkBZ!>=BJp(1ofPdJ&}}%=#$-34?>e>TrqC`yU483_P5Xe|14){3U$qy| z#`xXQIpJ?Op>3M21=wuItq7V!U5Bs# cmUrlI17y8!23K}i(*OVf07*qoM6N<$f_B4_)Bpeg diff --git a/Resources/Textures/Structures/Wallmounts/signs.rsi/court.png b/Resources/Textures/Structures/Wallmounts/signs.rsi/court.png deleted file mode 100644 index fbb8c50593e43a54c2f61f5a8d97fe98bdc090d1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 431 zcmV;g0Z{&lP)gv`SZXI&h7d?+=Mz}li!a~{=o{Fl z&J)<#1wu#}NT;QW&!GN?zYOci&F;?KWkAMtasTgTX7^@mNyYYm0p13qqm{_#^8LXJ z0OIZLYtm?SqQwu}HQezY#0>z&JLivuJ=UN2H4`E;0v1p1uDAL7%AAWT!slKy`T5<) zED;AV?6=V z5Z(X~DYXcTHuX^~3z2DH?m6#zGXU54x`j|>{eb%-Djk3kC=I}EJfxu(cplK30=S|a z)61>tTN9Z8=;hH)TZ9;pm%D)u;L^LNx1z~x7YzV$wB+iGiG;Y<%ln%5)hzE%mR9*u Zd;%Sq$86x@y|e%T002ovPDHLkV1gIT!BhYM diff --git a/Resources/Textures/Structures/Wallmounts/signs.rsi/cryo.png b/Resources/Textures/Structures/Wallmounts/signs.rsi/cryo.png new file mode 100644 index 0000000000000000000000000000000000000000..3a0fc6d71683852e419285e836efa71b6e34a3e1 GIT binary patch literal 3065 zcmVf6Xi@@54ZTQ_E-Enz5K6$1 z03tR-RB%L5k){YTDBysjLy@r}iiH7DvFijGMAUI`6dRUFWUU$Bym{}eS9UO(Z2>7`&z9wUXbV-Il z#&6`Y8GKGQ04S2&F6MJnWNa;Ck|;8QE#r9r;7G||@X{|>%+C|c55>;RS}qbKr-&IQ zTvLXPlM{>K&(BTgi^a?^4mXV>;xX8n8Ce|RasXz}{8imI52H3ZN4bf ze_i~WlJ|C&UW9+{8AKoW!}eExnGFE2re(F+`iE_46#!l90Z_aBhs|Iw0E)7{bq;-T z9=d#9QpDmcXDh4R++0fmpKB>E=%LdZt9g z$j;($`3&Zthxi`{{&gM}5&R^+h%b~yM9Zd3AWW9ETgVfL1(`yIK=_}U_z%PWq}jQa ziQ4!P(3V&Nr6C$XejWfQDiI(Fdt@un?|lo#M+5oIi_w{wo%_#%{(V=tO#a9gB!7-$ zM?^BX5>d|Vn*3S!?g~$*UQipUP zL&zMmg;!4Do9IA%up=Rh?=qPj=x&RGBx1dpI68aT- z2O}^EromdU5o`ssU{5#*j)WJ%$?!5bA1;Eoz?EiTr=n?cd`V|I)p<|3O zju?MT93~aB0<#&j8`F+Cg&D?-VWzQItUA^l>xvDRIYI4MQ`g1<+DyrL=EogS06Xii({|v`U^zjmmKqDIK93(F5q| z^fLNk`gQs{RV`IdRle#b)i%{Ds;|}NsClUI)k@Ub)kf6bsWa4l)YH_rsduU0(?DsM zX@qO!YV6TCtMPOWZH~(v?wpc2hv(eZgf-1HBQ#fN?$aF5oYvCT^3%%Fs?s{6^;Da# z?V+8jy+iwi_M{F~$4y6|vqR^k&SQoO!;_KDsATjprgSxR{dFa}^}2()GkV5)QF?`X z?Rxk03HmJkB>f%wz4}uIItC#I1qQ7Kw+-=zEW;GTU55RJuZ@h2VvIHzbs0S}Rx=JT z&Npr~zH34@aW`3J(qMAU6l2OVO*7qXdf5y%vo}jIt1%lghs_<#1?IcWhb_<+P8LFo z28$a^64R5J!)#@aTGB0pEekEXET35!SjAgyv+B3{Xl-wuZrx~o$A)4PXj5p@WAm%6 znJw40#`fA=@?77!tLJvleQsxN$G6*KchjC~A7a13zSsVPgQJ7Uq0M2^(ZDg$vDWbh zi^d9LZDyT!LOXdmt#&%*^w!zIS?qk+`4<X~g?%562@eae34a)26HyS+zks@6 z$%2*zuOhu7%OdYYnM6sVdZQJi6QY}=U&naIl*dS8tzuWkUW(I*6U24LW8oFzvR(TOpMEs5_rp_~TJ^wNN(wM(bC zZ0;`Z6P^ce2XB(^$}i_nB)KM)Cp}7bP2Qe7nc|*Ok@8f)7E}wKr~0SXrM^xJP1~RL zDLp2=Jp-4Km~m7{5vB?IGPN`FGKaIwvx>8%%bb_(Ts9>N5;bK**^9Ef#WdN^)PTf9 zvR*Qp{o-l7TcBI8wqSIn=gRt3(5j`Y zdRObOE?Pal#&6AmwS={4Ykw%TE-Wv6xh`g1Pmxy9nxe7we(PI{6^cd0H#WFzsN0Cz zDA+i-Y3`<~O&?2mB^OJrODjs>Z{}{k_?699m0x|@lC)*8%%N=0R?Jr6*6Z8cw;d=~ zF3&F?+a9vLa|dHb$&Qyhm+ZVyVOLSNi?B>BD~E ze(8aT1AWbo&CM;EEoH56tE6@EV8X%6-*|u1-NtOIZ>P7H9s-9XhaP{M`0e$>L5F*f zu#U8SXZT%h2eqT56Y5;vIn|ZYCGC#u9zGg)w718lr{jCe@An_mJyvsE<#^c%!il02 zpHAkVoIaIx>gnm^(__6$dheWxJ#(!uyl?Pq(Ao3ne9xWf_v}A;-u3*k3(gmgUSwVD zy5w-FbHIL};|Kd6ItCpEJBJ*Hx-UCj?irppeBz4xmD5+fub#UWaP88_{E^}7QP*$Y zNVp-r$-DXJR{E{yw{vdK+*xxMeYfPE(!GlNn)e%iH2tw%>L5Kn>ODH}V8MesW8ASP zKV|>)e!S=*`C-L`&P4Mg+egPHeJ3wJUif(YN!F8@r^P=j|6Kdbc>FRj6+1Ql zT=e|YubW?}zu5oM?q%DiJqyhfA?sPY& z^JVSI=wtmV^?J~mhocD|pN7`vr~M89Y8iwSfSC_R6Kit-@ce)^1&DjqLoOnxyiYj= zHoBY-jcYCgf|MDsk>>|m)7}Aq-z>C&SWQ7R9teHq_DD9j1}L{jEer*u6(CDuX@8m* zf;j`C&OhK_4P2X>sxH$7_9+j&Y-$R&5Jw**XFK70_e*eFx&-v+Z9Z2 zCm~hFyTG+>o&gd-G#(&J;-59Z+HCLh{rq^@@!SbuF$YR9YY8w1Fc zB{5c;3IMR$RE=vBbq3%gWG7;mlaU0#B2;}DRpTick^ZYs=gT^Jelhy2w&`*{pnQK5 z>I3CDaN6(S`2jgsK+B`hP+12 zBTN##?;L^{&t7t{X;%9xGa+?X!;?cD5nr9vrHu?OsA&i3N>Acuv*GF}IUx{DV#pMh$D7h61#zc!y<)!@{_hc`fVEcW5bKai!VNf6f#&TOi}3c-H>A45U@za z?4r!CbnQ`5^n;HxZq8Z&=R-dz+4Gd}qPgg&ebxsLQ00>{K Aj{pDw literal 0 HcmV?d00001 diff --git a/Resources/Textures/Structures/Wallmounts/signs.rsi/deathsposal.png b/Resources/Textures/Structures/Wallmounts/signs.rsi/deathsposal.png index 28975a1b12b7eb516409bfe62fd84cf92e4a0b63..1fa88f63afa4f524eba589a462e26b11a459faf4 100644 GIT binary patch delta 445 zcmV;u0Yd)G1J(nOBYyw^b5ch_0Itp)=>Px$kV!;AR9J=WS21gYKotI3x&{KpbTnJQ zQ6!M1xaAkvHM{f=+#hKEfqU1u7rIH8LJ>!yTO3mf6#4_~5T0DrJL7q^E$uhu<>`Ij zz4z{&5BTdilQ|d5RiTUM`SHGy>q16u&gQthn)W8&@3sI?G=GU`6hP$D*}Qe}weNrh zvGkeIctSsGBF;rG>Dc)x>j?!61!Vzi-+^rz007%Eu=br{1%y!s&ou!6o@*kEvS9@z zX!X{e*=;&Lz`ck z0zT)bfFef3ye+DM#&7k-a#h&ZH~iOZZ+yJJA$i)=<~9Ri1opcvM&pT=^Ui{pW`i1p nlacPhBzt{noQ}SIH2cRVKoGWbYj>5E00000NkvXXu0mjfr|Qy8 delta 436 zcmV;l0ZabY1I+`FBYy#uNklygFqg@6vv2Jch%c9CLx*1b=UpBnVsErfWK}hvX0ey zQw}Ba^l&THIg^Q-izUu4=Gx->-4*~!8AJns#OI4;=j5U9Ab*I`)-jXmj2?v$r=pLB z@VxJQLVz(%2_WkRuq^|j?~Dr&CpkRV1ORxhi8#r}1z=fGiN;9|mKDkX!fn`Q z6z(8OE8+UPF9!e)UQ-TGo0eo009CQU07Riy-3dwnyr9b3YXbyP3fnTYb^!2OPr@Gq zpc{TbF$Z+cet&HMos2&Uz_yI)zzL$X@|wgU`1cmTM*xj!DjbIpdgG%?GHs-JK3 zcZ4+ z%YnvU>T10y?aQnB->kO1zrBJz-U;giVFdQOEhf|1AT9enh*GKzgeEK&hAvFPx$mq|oHR9J=WS37FMKoETiX$^)Tr?fkR zN+AqxLOP!yY2E7vK7nrFK5cx0bRtc_7?lQhR_Pc+AO}#YG2{J6yE_UglGjMukKWsz z&+Y(!9al}A)7iZ4is=3I*~oR%L_Qo(aC0G@P+tjYV;@l7z^)u*$0o!me1+pHL0pFJNa-(Ix(!0Lpj!ydie9;q delta 407 zcmV;I0cif+1F!>-BYy#RNklZq}6n(9-bnj9rLoNWK>d-TQgh(23KZsy|8!1D165``;{2$N%e+*3c@3=8d*lc$v zp8#*KFM}}#oty3MbpP>#rmCHS2T_RQ>TZz4%(O^T)kyckiGM(zNj$8c2j>_GD15I! zwGv%Ic_y{ZC40-6+_!k1Nd!@-FG|J+)(Z4N1z)^B{SB_qROT1VI$)pogzRD|jpt9h{Sl)&xpf=&uBzZPkWLS+sn% zu-*bH=>qL+rPx$nn^@KR9J=WSFuWwFB^XcTz){(+nQdm z3pRorDFb$w@(c%pA8=M1a>?vwHd(RI*Cd-v=DpdOSu((1$ARkQbT;3aB6@v(Ai0iI z+^$<=SW2Ejwd)h9}OnoZq@+M zh(z=RF!IrOGMF3yj!(|mD=FfT`p8D)y8g%%Q1CrRo3JQrZCfn?j9kaD?>X>2M_UA$ z0)Ledo6r^zg|2iziG!aJ;Cl|D&_$M4Qu0N*+Dm}423X|XCnMy^b;KGA$nvUn+AS<9 za%KZvhNhUbXGjjhufsO@mPz0_uVjrOTQCRkfQGps@gx zD^?d;HBgjwd&TP7TNPmH)C9&gU>m{{V1K>MDw=OEYAvz{fScu$P=NFV7U^o|3YM)! z_NuP2nt~(_+BVGc3P~I&3)iXu{sfA$?wt??X%|otiPqG&%ua^hU+Q!=Z~TiZ{%>|L zzCJ%tygZWg0eJ%3%^LT2m(~Pa-=@Mna#*lEm{jj?!s+PON3(x?0|e0A(CR<*X$$}W N002ovPDHLkV1hKG!$kl9 diff --git a/Resources/Textures/Structures/Wallmounts/signs.rsi/drama1.png b/Resources/Textures/Structures/Wallmounts/signs.rsi/drama1.png new file mode 100644 index 0000000000000000000000000000000000000000..af0d276d5c0d73da964edf56eb88e80b2428eedd GIT binary patch literal 627 zcmV-(0*w8MP)Px%ElET{R9J=WS3OSaKoI^wP*4PfkbnaqfoP$kvAj~Q-~+rW2cW>6yHId|R2;xp zh_sO#s?Z{kH~=6;(R(RUyaI}3*0bYrY?B}g_?l$LyYqeXvtt?f=~&Z@M;CbiD#GVG zpR*v~=mPJX`@q(2Zo5C7{hmE6M?M_`|KEHOo&X|0JZU+b-J1Xa%&6to^uG+WN1g?M zm&b`GVqG5Qk#jP;Hz_#Qh&AEd&iw;Q2DXoZodf?67Xbjc90CA({RFAa5Saj-c9J`~ zIadXmQ44=xC;0c2XP{I7&j2SjahONh9pujAu&|Gxryv>$;8ANejZEM&klL*D4DSIc zpwI(a+MLtNAYy_xg$JbVqW{ZVJNE{aS_yr9IH=C%N-D^qQ;=Qk!{%+#g42 z24;l%At&r=@kHdrWdT&)f=)YeDeUzVuQXJ5X(Q5Eqb3Xe*XjXEWok2Y+C?H-^L=!V zM9__qPzTZd?XW;jps}ktBT+KlJeadT=glUe22Dg6xrCgAwFZ#{H7Jj)4!MR;WndXJ zdKXZK(~Otv$OMJw{8v8LQ2jEBL+>i_HT401&dZ`bZ!ADUyM9uz+`kBo1!x(m+P{h)`!WeQ2AlPMXa8F2Kj0Bix0MGb%MV|dtLwl N002ovPDHLkV1m5b9z_5E literal 0 HcmV?d00001 diff --git a/Resources/Textures/Structures/Wallmounts/signs.rsi/drama2.png b/Resources/Textures/Structures/Wallmounts/signs.rsi/drama2.png new file mode 100644 index 0000000000000000000000000000000000000000..538374ce404d406c0a81951dc09b15d291f6daeb GIT binary patch literal 588 zcmV-S0<-;zP)Px%21!IgR9J=WS3OU|Fc5tp7&?@y3*`qO!46ZGs*$>N?p!hTCp4R-4&f(w;s<2x z*hr4DFqO_Au~q_>3OaOP2t#nNFV1I+K!Ufl=dzwYUNt&upO6S69&2~GYy618Te zg2aC2>=MZV0O1_M@r#B8U{IhE!Z|Fv3)o!%fN=cCE`Y)cP-*$B4?gR|8rQ)+hJn>7 z!MFke08ypmI{2)Q$#4Nz1ONb61egpLl}MB$@CjE0ST3j9*m60I36()^515)tI6kk9thAWk1OO(w~OR9*~P=Woi|!2;xNCV+o(SPA!5W z@faPQ0e3g^c#O(AusRs^m{D$7J(XKcesOh)w}-FC$Vi~k%6?ExB+`;oygsir0+rqZ z*`V~8R=J2ODXd_x^_!4;3@y8>9VOM4eW3c)Z87;v6QEGf zIZY@D()n2^O~9l`-u$fy(294BA3p_&dtkEy8m;`js{+gJVzbi6e%FVIN@DlvBhXK? ae|!LaZ!HcAeT=sN0000Px${7FPXR9J=WS3OI^P!zpN9UQc{Sf_$e(6Muu(m;2o{)OfTxD=Oc`3vb^$S7`s z7qU1x)J?&ugIJeRD|E1+L%h%XzLJ+TqM&EV`#$HL`|gDR{B>;U23s9?|1QFZYmrkC z(CWbZ&LP0=LG|RTIl$YqC_)f`24{AsL2cH%_rk@x;$e$3~bQIEGx<9LQnjFkWi=Eqi~xQ-I)$TJ1d4W<(IDt+i5}PhybO7P@JsyrA`f7(Pfme44LF5VKXg{{)Fjxzqo6$<$ zEkc$k8iFRHA)+2Xvl>MK@nqfDHMi=hb~v`jr-- zb0ly5MgnxXT_t`z3zRyrngi4u`LQblXVin$TpasdKPFT}_4Fy^U$cLF0B@x-sd=Ud Qi~s-t07*qoM6N<$f{wWXvH$=8 literal 0 HcmV?d00001 diff --git a/Resources/Textures/Structures/Wallmounts/signs.rsi/drones.png b/Resources/Textures/Structures/Wallmounts/signs.rsi/drones.png deleted file mode 100644 index 3d7e65f7a57fd46dadbdee861e15d71d43057f7f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 405 zcmV;G0c!q&<>lg6GEvYYyw+YQ5Rty*)vyHYho#1l#Dv z3UNIYM5-2X-UIH_Z72{|R5!->syh4$J7ru$`yNv7K{fSx@$Kv`7al%OmslT51C{1>$SYpoan zJ^;k`=-eM)eKZKbDLL7CUEbXe_?-P%K5Nz|xTu5#!@|^000000NkvXXu0mjfUV61R diff --git a/Resources/Textures/Structures/Wallmounts/signs.rsi/eng.png b/Resources/Textures/Structures/Wallmounts/signs.rsi/eng.png index 2d12b080fc7cb40ed8ad81b42f7159274b9008c8..5a70940bd90814ff369ed54aecc486c030d27145 100644 GIT binary patch delta 393 zcmV;40e1ed1EK?vBYyw^b5ch_0Itp)=>Px$TuDShR9J=WmoZMmFcgM=5GSAmk{RFt zc&P%MB~uQOwIgc|ktt^ZqAunDFkmS|xk4GLSGlfVJ3eIx0FjkY>30A1a|;m_9WL&+;S@CkR9@ZA+(drdzh?sgi2B6- z=z&C9-BYy#RNklZvcK%X?($;UsXaqLlT4gKp zvSx3>wKW0jTYpf@BLq>T-WesR@O3U#Td}@oO4?Whj1m>RxjvgO006W30*n$uZA$(0jfu7$rD%?78`G`5kwB0(uCjDG;W_MXmq<002ovPDHLkV1m+) Bz`Xzf diff --git a/Resources/Textures/Structures/Wallmounts/signs.rsi/engine.png b/Resources/Textures/Structures/Wallmounts/signs.rsi/engine.png index 2c4f14d70771827b0096a605673649f6b68153e1..629680bfea85b70e0e38e41d12c97aa1df7c3312 100644 GIT binary patch delta 421 zcmV;W0b2go1HJ>0BYyw^b5ch_0Itp)=>Px$cu7P-R9J=WmpyKSKoEtWqnscVkw}po zAlo4Fa}_EMLF+PY4nf5Ma*8C#MeqUa!blYM2_iWKnrIC>3$u$YOUY|2GYjvVVOR#> zuWM!t&J*mXGI}Y@UM#>o!T$CJxDNfzn;KYe%n(KZGJm@FH-9I+FU=5_+zCUOhblu5 zC2YLPh+iS42|E&!K3nb+0p@c_8&UCf;T zOxe4d10GGNn-ds46%rUH05Yxe_@Ejm>47Sbja`1S9sv4%;L`)%Pl1oQ6F?9p_a(}qO96xWaI z>%{;-n>B5*)C1fgLUFxPw)LX`r0@6cFfw%hs0!E`u4~xs6YmP>+AfM-M!F%zB_kO- z6+b=zcUKZTyH-2k<5MsdH+2gj$%a#v$7pJE>^whAbRGzQ`&Qhi*}r}O$ZykGbfFR7 P00000NkvXXu0mjfXso;= delta 446 zcmV;v0YU!01J?tPBYy#&Nkl&^D` z8wVe6uY*1YC)b

FM|mscI|dN#J7deGWoAjv0}vMwC`o0Dn@1n0do%9;_^1kf#Oa zyJz-)RselRo)*Zn!m3m(08a}5ZCPkM-#sJG3IMPw6$>EG3KM;!OB_T9pxtZ)Ltr-n zh|&sD)kp#tjvpflTu4=$vE#=k8&?N7h|omm_%Rw?!trA)R|~Ty&k96o#md5DfFy8{ zX9bq4g^9A!Wq;=hboazn0i>$2TrJS(vJ*9Bg66q>V=_RLR-MSG_5gllgrm_;*oTlJ z1XR&+d=AAuiY$PG2+eLMQ3)t|DMA(m3jk=NqzoAK-x*?;;M$r5KppQEngn1Q`4n*W z9w4LCkoqn7rl$bF#h!l-a%9?L-v^|sjY9zDNYZz%*f$xV6n_DTUVtNjC{5XpCj%sb o+jc(-C4r0m$eKUDmfv;PH&+e1E0c-@S^xk507*qoM6N<$g7$&LfdBvi diff --git a/Resources/Textures/Structures/Wallmounts/signs.rsi/eva.png b/Resources/Textures/Structures/Wallmounts/signs.rsi/eva.png index 2db7d42645646bfbda6aa0634d6129076b12aa60..3e5d2db3c327eb11dd23129738481b66359c3f89 100644 GIT binary patch delta 492 zcmVTBYyw^b5ch_0Itp)=>Px$zez+vR9J=WS21eCFcf_)T?>Wcc67FY zM`Hq6O17N9U9;x~Ie~BBy=#4fZl+5i1dWDl@tB%Gp$Bl6epj|6>nk>NXdi?a$<}-N z`g+m_{yHxDI_Jw(Jr>d1%afMts*l{C&TxA_8BBgU9sr=$iGR=vAo9s{Hkcd$u5a$> zQ4wK`K;O*6z(c(7mG&$zA&Sa4Ub){Y?M4A6BzwdAq+g@yP~KNFZ@QVX-S*}P*{_7)R3EUfcokEQ3U7&5#dlc<$#Pa z$k_tq#1ci-OMgxwryLkXfGDa~=9|`4Zr`Lk>-w_=06#O5Bhmfo-m`&~gvmN;ML=gp z)J9uR6qWMbSpvF)(BNU*Yg>8)Yr$v%qFBE_Z>m1lWwlFj zfGk#aLXO+@L3>x9FIRQ=@F?GA2jlbO9pd#_sSk`vcsd?h0$kS?XfMZiZJ@wd8I4_- il>4o=I{Nj}>>poLtOnrvSizD2000015QSetiWIqlRVf5g?85300;^FML`qeu zjn83JyK-rQIyWwI2n(dzm2(GoPPNO%KPzS?IED49LA%WR7|mz|47zpQ^<9|Fmj{W# z^y59~5j>pDmxr&%Z!~SkGB;Ww-H(D04}D3Rw!`P!gauI46@Su~QSi<^E3;=%)RiO! zAE2l!lv$24%S8|@0N-%4+nzk5sJ90$85^yzSg%~%w4FPr^b85WngKu(#qOCOQzwQD zU=5Ne78$buY-x+S!e+O1rnV}aaV1y4mo=71^c`s0j$L{&z@;X<8i1YuPx$q)9|UR9J=Wm$7ZbFc3w5f=pn`g@F`q zk}C{k0jvy`5{VQEWe)5Pwbpc0Q+v-p*MY_2z`Q z^-UP!%R|=l0$fUWr%YOi7yz)6>xL~)2~tH~dvAb+h#{!hx8jBqc3zHY+HIXB1vOx| zj*0+(y&YmRC1syKMJEH8p?9S~Pys;%0FbI~OBJ<(1gAhyfh1E^JIPc9vXW~gnL4nW z^V)RO9^g>h?|*&NnSwm!uto>@=l49V$GRd=j&Jq{1JsKu2qGirwBK~iIV-uY_QQ`H zL!hn)T{;^;$PoluZo|j<6Q+~#U_jf?FT8GE!f(S%>G}Z{B1WE4bsX&{+qo`qKg(_( z4Zs!9b;eD*S@CShUI6w&Nv4pebO2;KDhm_^9mOC3+e#Tjxa>fA1iLOFR%azN%dIaB zF8!K1;EjOR8q>)*Xd`tg$rQBKPTO_%_>Ng;t8GCZCpiF^XKcBI#zVjfYM}N2Sx;7yb>!}B zwJlhzv0hDpyIu-G;5+7ioaAO5C;3q#st^RegD^_XI*ignoWm$B$oalwQ0D;8>{GJ* z7%D^XFzEsKc7H3+@;J$j8~`2{>x2FD{MiKfp@HudVs0lLAzN*mFGF%UZ!&fm_?j%& zgi2KfWJy(-NwP*8k*3Da=>xy-Wpr@@^O4$7MdPR^0(L0>FCEtvwwU6Dge~+dLP$R00000 LNkvXXu0mjfuWjKb diff --git a/Resources/Textures/Structures/Wallmounts/signs.rsi/gravi.png b/Resources/Textures/Structures/Wallmounts/signs.rsi/gravi.png index 21eb2e861365f25fd830d1a6ed79432e56bb494f..811d40aa898442b5812200188dfc94181c9d14d3 100644 GIT binary patch delta 398 zcmV;90dfAy1E&L!BYyw^b5ch_0Itp)=>Px$VM# zc&P$COQs$oYe!ZNktt^ZsxIjPU}&TaBql#coO&traF5&$YJo@rC%gZ%)HHB!%n z{P?)5#lG19xa^EW>%a?u=69a)6rAs(^q^%>V!Z delta 433 zcmV;i0Z#s>1Ih!CBYy#rNklj)B4c9T&*{km(vFr@0^@xafp5NrG=8G{vLlb0ih=42sTz8+v zp<)MQiJB%>5XL!>R!1=2q2BJsoeLNM&ZTM$5VaI(b^NtE8Nwwetg0Ytsq);n2gRvN z&oIt`(Gi)(M1R;tF1R!-;|MU`Dc@NRy=>dcI08R+Cx_mr9~c8fEk)lR#wf_q5Vl;Z zCsN%P;6y5b0O_lK-g&r8Wdz`R;CKVL9>*r&R;?JgmK@`qau3K7^>#Oo*+5%0qN2>f zc&FR}D9(#AAN#`H0fZxQ7RXg0bZbl}>ppPCR0+3ic`EEK09hP@IaWayhuF`|`SZW! b4?Xk^O1HJogTRu!00000NkvXXu0mjfxwOf~ diff --git a/Resources/Textures/Structures/Wallmounts/signs.rsi/hydro.png b/Resources/Textures/Structures/Wallmounts/signs.rsi/hydro.png new file mode 100644 index 0000000000000000000000000000000000000000..f23fa7960de10d47971976cec74d3a8d0b36374b GIT binary patch literal 479 zcmV<50U-W~P)Px$nMp)JR9J=WS36F`FccgR6cn(cVL8A`aE5K7SjrW0245kayIdh>$Q2?vO2ZjI z;s8Js!4@efmSW}Lc>T|=K!Rx!|MKQNd&Uaz*KuMST&=M^RG{YveJmq^)f(IL8{p!4 ze(<3OKHu~tv;;)(+xtuB$8(aP=ACoi%i~5%;?%UjC-a;npcz9>66ajg_lyL5Kr=RZ z#vq!2nzc_AbT|uLz{?f@K#CLq1I-w!hN0%2GUkV%3h=T;)v)os=G|WKs$t{%!3i7# z!30Fff$!~*vkyIxK?KC!$|MBj;2~$gXhc_cz+$O4A~|CLSMc}O4L+U%jK~JL5pU2NQ6?ma$L8eq04c9~gRIu?*L>4x~si^!l;i`C}rJm>+%z)34b-z5xFW V+gU*~Gv5FJ002ovPDHLkV1l>A(Sra0 literal 0 HcmV?d00001 diff --git a/Resources/Textures/Structures/Wallmounts/signs.rsi/hydro1.png b/Resources/Textures/Structures/Wallmounts/signs.rsi/hydro1.png deleted file mode 100644 index b20654fcd64d131182ac3e9f7bc4a124e5e44d85..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 428 zcmV;d0aN~oP)15QSetT7x0TDdomASiE;_+#2ZGOF+0iaSr z+yIdIe6h4P2Y|_RMyFDUd)Y%KU+#Mj;xK^kIj#5V-X{exG2gCTL`jP6+BJgc6@bir z7>1=t@7#9@FeFA;|U_J@KEApHy4l;tG=)aDcq1`vnA4GdSTA&8O`QIgg$B2ZVc zGSGyv5i0|Is&fXK=@w&7Hacg3OlTg6F-M~h!RP?2zkpUkF&-2k%S-D8h&1{TC;=$N zx}#VRG-K0x!72mItyql3dVvkloM>%ZFK27k0*H$XO*-A=;}j=WL!kR&lZ*k9zF@W4 zRsQpfSj}4N=lcuU$D6c2kgfyQ%NdjD%xa$}MM+A%fmG6Fq3_0|_&h1QqtRQlfBgal Wgr_VU2}0li0000*4}gCFZQ z(nest^bjQ}q9pwW0U)hK;5ZE20qhQi_Q3ic0XqZ8@=`ibG#VwT15QSetT7x0TDecanQV4^akj^JaTKBqvPM{m8PaB=Uok$Z1LZu;{RXWBH$N`jU zV6&Rt9a(D!w96nUyj8h#N#npfZQOdH$0&yv_5fNs>c zoHd|A6lEiZ$dVXE**O2#>nZ3H2~&D>i6fvx_)>2G0HV;I6~Jc{PVR(7*|0r;*3J%4 zZx3D~aZ(C=>h}Urer=!XL8V_uVPHMToB$H(C!TsuXN9Y2Spn24r>eJAxU~I>0n~O% z6>qD2={tZJz$KfPx$b4f%&R9J=Wmpx9zFc5{G5eJ~4N=>zO zE|7D$jUwkZ+a*FN*XP&^xTd1rR1~?v(BQ>uJc;cXgal98!to^Uo6-1Zfxj-XHrWAG z%IKN#VgWjUDgX}!%ohMN0}%wU=1&F8tzH?3JMM+p%q1B}GJl(K-1k_3RAWg7jZ(?q z$pTo*IJP2IY!4g&JSLiJQ3vC+sPP8i1qnUCY3?V?{j_Qx8gt6-0S?5E*#fywF?E~l zJdS9TVj(1%s48Stz?z@OG3WI>05|*4a&w=>W}gJ$%T{5pq5xuz8l{r5j|SKSwHtsl z@*A)kT2w;|;D2*BjDajt0c-558rn^WM9+-0RjeLd;?`D$pPMg1k7>yb@>9Qnt!B(r*G6$c0%%h?sM*~H#( z=6?GA8&R&fWyszKmJfiGY&dCAV`1ig=N}UnqJTfZm>K^I0Nw$)rqN&S8O%Wd0000< KMNUMnLSTY$BEIGT delta 369 zcmV-%0gnE;1B(NYBYy!>NklNL^(hY5DJAXfQ-*o58Tcq%dQ@%B1s zV{mYHIG%pKzrf5Q<3xnT^UEN_)7U1=jH+%#0L~gLM&^tHw13)fH#a>&M0o$)WTFWG zm>EO_rBwGXgwR3lw`Yi4m}G#eZs4rB@RAp=7hg2UIy4*ndYg5WKV?Zof-`||t) z{B<0Sb*|Rfg(7;mHFH@7tk&3_UI4Sjbn>cDv68YtzWhJpuH+yX_Pg}g+ zGg4qemPn^rs-nh5xkZDW0-E;_IOe>pXYX1D7w{c8xB!+5fbJhCD`_3j_M_Tdz>Yv! zNo2{V&1jh=a(`5u32Xt>-+E1;Ys1k0!3BiI?-Wp0vR{yB$<06D;R0U-b3tgZ1n6+5 zB7!Pvq$29u=^ml$F8hX81oUD?}s{ zhSn2N+W_-rm|TlIM%$SCe&)r5ikME{!FDzK$2$zQs}Zi$#nrt40000U$B!32COGiWi{{a60|De66lK=n!32;bRa{vGf6951U69E94oEQKA z00(qQO+^Ri3I-Ae0uQ)%Qvd(}9cffpbVF}#ZDnqB0000007G(RVRU6=Aa`kWXdp*P zO;BVmWd{HN0gOpRK~z}7V_+ERfDxC3rF;B;YFTo8=R%zJuz%pPTwdLbL0DXYV$0vY ze89lK!0;cJBUo@*uApv472op;h{2dx9l?Z6lZb>8RpS|-c~~95%*sYp2jDZ0gh5#~u^?`>B=dQh`z5_xX-dd4xkkv*#Smcq717KJj6;<%>jRZ|H7(x^?`>Bp$_u!M21X< zI>NxofXU zDrl${0*nI@1<01RL4(^!OO&BK%LJb7kV{AOsG&*-Fn=>KVXYI8Q$M+70KqiypMima zjg^t%$4~rq0JG2UG|9}NoTb@@yj4Jhi<+L-fz5(&so7x?dhc{2*>>Ukw*K8C30M*H^rW{-2 Ry#N3J00>D%PDHLkV1hwp<^KQx diff --git a/Resources/Textures/Structures/Wallmounts/signs.rsi/kitchen.png b/Resources/Textures/Structures/Wallmounts/signs.rsi/kitchen.png new file mode 100644 index 0000000000000000000000000000000000000000..322d62d8d2e6d584d30d7ae572accb2eb7545983 GIT binary patch literal 486 zcmV@P)Px$ph-kQR9J=WS20e*Fcf_t7#KpuLODPsm^*fH)cekUU=@=|P3I!>`Vku4q&jOw@5_xDbBIQ7+h-mZ% zF#QRPF^`5#lgim1Y?_$a{it&9i)Yis^d~T`Egq>5SqJP{3I(3BT4#95YM1Or0Xi#5 z)>HQfjRKn9z!l%BfI8%bg3ijQT@h(5hyi&m*sg$1H-66t>^{qO>k*L?7E%Emy}z9*ib`3eaIW53t_sD={>dW<}M~m@L4AM~(m;MDjYP zBZGAUBE%h1pIVNP#sXwN=;H280Fjd)03eAY0APz~B!I|?6hQUN72s?_SKM7dqY$K7 zfh3L;4^STPE`NaHEPCMAZUJRLA~nr<6HsTD-VzbTzRo%?0`kM9+MOJ8F*9TA@Z*OeDr{R16009_DL_t(og=75x|3AY(0>)7X40;Fj&00Z`3yabs z7|C`(->en?cXK>txN!LjS(Y2<>M*$ekjCo>f)41uy^~>OXn!GD4hUb}&rquBPCW;- z-`LGyD5J!1{>eQ!jSW<4xYEu6!~mK(V8@rcL^;5NN0~Mb81N84cL2;HT;eo!fT4^M z!~E@=7#J8B7*>WBqR7$Q0mzoa0J0;7zXQ-6LH8&?b_4?h14e-~d0f zfOF7V*7`(VS!p>37obj++Eof}uqmRk*49om%dVYB$=3ja<$LqPtbo6+=DV9a2(^rk zikAwogU|v`70eglq(CGA#Qdd#x#(Sic+eKqh}`l%6~LLN&fFVjfU)Ul4_nn(%qQ;w zn7lVZROtcHYCQqLCyTua9CbuZ+qs07w1Zw63f zHe>Z?YAt12l>5K)$0UZR;17!VzW_b~E8>Vp*tMzJ P00000NkvXXu0mjf!-lYR delta 340 zcmV-a0jvIu1MdQmB!3BTNLh0L01m_e01m_fl`9S#0003YNklL5?9F@MB4z(`9J!xD5pa;ShD zckbG2>Nx;p8M2RwQBPF|&=QO~VAKIbIRKOcNXhG@Px$TuDShR9J=Wm$7cbFc5}+s?JnV6)_@Z zVCceV3c0LOhrT zxOj6)JR`tw>E-~Blupa_#@ZlDVm<&RkWLhE@)Go&1!{lt3>0}<2fa2MvQLqx2&0ud zfbFgXkp3`HK~!VeKa9HLk^#OU&;n^1_fanZ6Nrs53xI2C1;D8VYyg`YK-JAl@g1NO zpqYH~em)DZTz_vcp9S@EdFjSk1E|5&pkcH^mc(_rm5JInVMze;KOn1J6O1Dgz;;)n z$kSHgaq)SQld!Am>6S^&36qSw;$ZAy%m0hK zU&wIz@&&Ri*VQ#(cq15(*AXm)47q&y0)ubfPO==Zd6GMWq+L8-HB4lgOhqu@4j>o> z$YAp%ccRph5@jSg00uk*60wSJ-!PwKvq+8tU0nmL7H!`!pMODD*MRm8kWn_oa0JY9 z8D&F~9Y9tTz$}6}f?UhVb^y!~*;PT}Q@Nyq!Ik|u=2Y3b~ z!X1I^7;*|Jk~yOQmL7cbAVIC*$bdpq-2u9~24v>~U0nl)Hw4rSc(Z&Ii~<0xBw52O SxfuBX0000Px$K}keGR9J=Wmpg8QKoExiL_R@WM8bu0fNW!7`z%x(g4ShP4nf6P>>!%;0qnvn zQQ#}sg*6s2JNp0JKR9W-*F(H=4Ti|v#owf>LlGB7yUao-Kb-&qk)SSf);?WC&c3_>Y?+(D z1_1#0^4j2ZVh7=0X#^MnMu1-da9xIhjth}#!BH~x^5qTSlbws6e+)d9o4x~)K*R+C zk=*~&)3n?62d4^ITr|l=CQ=g{YL? l_M8`!CPe@6H*r_9QCGiqcA-lz9ku`f002ovPDHLkV1hR8tX%*A literal 0 HcmV?d00001 diff --git a/Resources/Textures/Structures/Wallmounts/signs.rsi/medbay.png b/Resources/Textures/Structures/Wallmounts/signs.rsi/medbay.png index c9c6e1362a7f973039ffd199b7a7c4827b7dc6ab..e57571f6821a78822ed0771ed2c4c228a22933ec 100644 GIT binary patch delta 508 zcmVPx$&q+i&v)+V8iT>0x4D!O+kefw7D5X^<`Z_KePG~w z$as#x_u#WFxNxiMjOW__ti`Jq;?hKIdUG-bpgjh@*XemifF^S;TmaA>n;?1tsOCP~ zB8^y8?u_S1BX)4VEkrATx_KB2aN#127yuxR7`Si|#-cOCRTuM&=g9c}cREiahAla^N#R(T_W}S=Rlv6Yy#Ul4ES9VDh7dRm zT|JOz0U!uqAHpBWz-(Fq=vM)&Wk^a22T5V~=A_mYsC9>ot^?mg8nJ`Hlt%2d)39!; z!q9Y7GeA@EaIs*`dDyoWF1znX)>a`!}BGZ1rxD2I~ y7!93X{UwF5fRs{u?{|Kfs1Uu~zhwF}``0H01pc!c)+ho10000!{?0v delta 287 zcmV+)0pR|X1i1o`BYyz^Nkl%l|Kt z-@$PH%0;p)H`LK*hHwnC0D7E`mIK4a0c6(&mn2+`aDlvKx5 zaRAJ)4CiQu8GDy980zT58!0e0x*Sc4;*&40FfcGMFqn($FfcGcLgxIHiwuT3`V2Gn zE@jAYj)wDz1td9Of?yGfL+lU7!+mV1qYoD+1&~}4!h_ZpNfH;E8V)ej(I-0>80zRV lFg(PsX26@}qZnWm004RpTw$E^!8-r|002ovPDHLkV1hb+c!mG~ diff --git a/Resources/Textures/Structures/Wallmounts/signs.rsi/meta.json b/Resources/Textures/Structures/Wallmounts/signs.rsi/meta.json index 97be2aaa0d0..a13df6f7d66 100644 --- a/Resources/Textures/Structures/Wallmounts/signs.rsi/meta.json +++ b/Resources/Textures/Structures/Wallmounts/signs.rsi/meta.json @@ -5,1490 +5,490 @@ "y": 32 }, "license": "CC-BY-SA-3.0", - "copyright": "Taken from https://github.com/discordia-space/CEV-Eris at commit 4e0bbe682d0a00192d24708fdb7031008aa03f18 and bee station at commit https://github.com/BeeStation/BeeStation-Hornet/commit/13dd5ac712385642574138f6d7b30eea7c2fab9c, except numerical signs which were created by discord: brainfood#7460, states: 'survival' and 'ntmining' from https://github.com/tgstation/tgstation/commit/f743754ec3ef446c8172388431effa73aeddb7ff#diff-b429dd7fccbca60d740d4887c1077a178abf1efffe57e7ae2a0b607c8a9e2202, 'janitor' edited by forgotmyotheraccount on github, 'arcade', 'barbershop', 'direction_exam', 'direction_icu', 'laundromat', 'news', 'reception', and 'salvage' made by rosieposieeee (github)", + "copyright": "Taken from https://github.com/discordia-space/CEV-Eris at commit 4e0bbe682d0a00192d24708fdb7031008aa03f18 and bee station at commit https://github.com/BeeStation/BeeStation-Hornet/commit/13dd5ac712385642574138f6d7b30eea7c2fab9c, Job signs by EmoGarbage404 (github) with inspiration from yogstation and tgstation, 'direction_exam' and 'direction_icu' made by rosieposieeee (github)", "states": [ { - "name": "ai", - "delays": [ - [ - 1 - ] - ] + "name": "ai" }, { - "name": "anomaly", - "delays": [ - [ - 1 - ] - ] + "name": "ai_upload" }, { - "name": "anomaly2" + "name": "vault" }, { - "name": "arcade", - "delays": [ - [ - 1 - ] - ] + "name": "xenoarch" }, { - "name": "armory", - "delays": [ - [ - 1 - ] - ] + "name": "anomaly" }, { - "name": "barbershop", - "delays": [ - [ - 1 - ] - ] + "name": "arcade" }, { - "name": "ass", - "delays": [ - [ - 1 - ] - ] + "name": "armory" }, { - "name": "atmos", - "delays": [ - [ - 1 - ] - ] + "name": "barbershop" }, { - "name": "atmos_air", - "delays": [ - [ - 1 - ] - ] + "name": "ass" }, { - "name": "atmos_co2", - "delays": [ - [ - 1 - ] - ] + "name": "atmos" }, { - "name": "atmos_n2", - "delays": [ - [ - 1 - ] - ] + "name": "atmos_air" }, { - "name": "atmos_n2o", - "delays": [ - [ - 1 - ] - ] + "name": "atmos_co2" }, { - "name": "atmos_o2", - "delays": [ - [ - 1 - ] - ] + "name": "atmos_n2" }, { - "name": "atmos_plasma", - "delays": [ - [ - 1 - ] - ] + "name": "atmos_n2o" }, { - "name": "atmos_tritium", - "delays": [ - [ - 1 - ] - ] + "name": "atmos_o2" }, { - "name": "atmos_waste", - "delays": [ - [ - 1 - ] - ] + "name": "atmos_plasma" }, { - "name": "atmosplaque", - "delays": [ - [ - 1 - ] - ] + "name": "atmos_tritium" }, { - "name": "zumosplaque", - "delays": [ - [ - 1 - ] - ] + "name": "atmos_waste" }, { - "name": "bar", - "delays": [ - [ - 1 - ] - ] + "name": "atmosplaque" }, { - "name": "biblio", - "delays": [ - [ - 1 - ] - ] + "name": "zumosplaque" }, { - "name": "bio", - "delays": [ - [ - 1 - ] - ] + "name": "bar" }, { - "name": "biohazard", - "delays": [ - [ - 1 - ] - ] + "name": "biblio" }, { - "name": "bridge", - "delays": [ - [ - 1 - ] - ] + "name": "bio" }, { - "name": "canisters", - "delays": [ - [ - 1 - ] - ] + "name": "biohazard" }, { - "name": "cargo", - "delays": [ - [ - 1 - ] - ] + "name": "bridge" }, { - "name": "cargo_dock", - "delays": [ - [ - 1 - ] - ] + "name": "canisters" }, { - "name": "chapel", - "delays": [ - [ - 1 - ] - ] + "name": "cargo" }, { - "name": "chem", - "delays": [ - [ - 1 - ] - ] + "name": "cargo_dock" }, { - "name": "chemistry1", - "delays": [ - [ - 1 - ] - ] + "name": "chapel" }, { - "name": "chemistry2", - "delays": [ - [ - 1 - ] - ] + "name": "chem" }, { - "name": "commander", - "delays": [ - [ - 1 - ] - ] + "name": "commander" }, { - "name": "conference_room", - "delays": [ - [ - 1 - ] - ] + "name": "conference_room" }, { - "name": "corrosives", - "delays": [ - [ - 1 - ] - ] + "name": "corrosives" }, { - "name": "court", - "delays": [ - [ - 1 - ] - ] + "name": "cryogenics" }, { - "name": "cryogenics", - "delays": [ - [ - 1 - ] - ] + "name": "danger" }, { - "name": "danger", - "delays": [ - [ - 1 - ] - ] - }, - { - "name": "deathsposal", - "delays": [ - [ - 1 - ] - ] + "name": "deathsposal" }, { "name": "direction_bar", - "directions": 4, - "delays": [ - [ - 1 - ], - [ - 1 - ], - [ - 1 - ], - [ - 1 - ] - ] + "directions": 4 }, { "name": "direction_exam", - "directions": 4, - "delays": [ - [ - 1 - ], - [ - 1 - ], - [ - 1 - ], - [ - 1 - ] - ] + "directions": 4 }, { "name": "direction_icu", - "directions": 4, - "delays": [ - [ - 1 - ], - [ - 1 - ], - [ - 1 - ], - [ - 1 - ] - ] + "directions": 4 }, { "name": "direction_janitor", - "directions": 4, - "delays": [ - [ - 1 - ], - [ - 1 - ], - [ - 1 - ], - [ - 1 - ] - ] + "directions": 4 }, { "name": "direction_food", - "directions": 4, - "delays": [ - [ - 1 - ], - [ - 1 - ], - [ - 1 - ], - [ - 1 - ] - ] + "directions": 4 }, { "name": "direction_hop", - "directions": 4, - "delays": [ - [ - 1 - ], - [ - 1 - ], - [ - 1 - ], - [ - 1 - ] - ] + "directions": 4 }, { "name": "direction_library", - "directions": 4, - "delays": [ - [ - 1 - ], - [ - 1 - ], - [ - 1 - ], - [ - 1 - ] - ] + "directions": 4 }, { "name": "direction_chemistry", - "directions": 4, - "delays": [ - [ - 1 - ], - [ - 1 - ], - [ - 1 - ], - [ - 1 - ] - ] + "directions": 4 }, { "name": "direction_eng", - "directions": 4, - "delays": [ - [ - 1 - ], - [ - 1 - ], - [ - 1 - ], - [ - 1 - ] - ] + "directions": 4 }, { "name": "direction_evac", - "directions": 4, - "delays": [ - [ - 1 - ], - [ - 1 - ], - [ - 1 - ], - [ - 1 - ] - ] + "directions": 4 }, { "name": "direction_supply", - "directions": 4, - "delays": [ - [ - 1 - ], - [ - 1 - ], - [ - 1 - ], - [ - 1 - ] - ] + "directions": 4 }, { "name": "direction_bridge", - "directions": 4, - "delays": [ - [ - 1 - ], - [ - 1 - ], - [ - 1 - ], - [ - 1 - ] - ] + "directions": 4 }, { "name": "direction_med", - "directions": 4, - "delays": [ - [ - 1 - ], - [ - 1 - ], - [ - 1 - ], - [ - 1 - ] - ] + "directions": 4 }, { "name": "direction_sci", - "directions": 4, - "delays": [ - [ - 1 - ], - [ - 1 - ], - [ - 1 - ], - [ - 1 - ] - ] + "directions": 4 }, { "name": "direction_sec", - "directions": 4, - "delays": [ - [ - 1 - ], - [ - 1 - ], - [ - 1 - ], - [ - 1 - ] - ] + "directions": 4 }, { "name": "direction_brig", - "directions": 4, - "delays": [ - [ - 1 - ], - [ - 1 - ], - [ - 1 - ], - [ - 1 - ] - ] + "directions": 4 }, { "name": "direction_chapel", - "directions": 4, - "delays": [ - [ - 1 - ], - [ - 1 - ], - [ - 1 - ], - [ - 1 - ] - ] + "directions": 4 }, { "name": "direction_hydro", - "directions": 4, - "delays": [ - [ - 1 - ], - [ - 1 - ], - [ - 1 - ], - [ - 1 - ] - ] + "directions": 4 }, { "name": "direction_dorms", - "directions": 4, - "delays": [ - [ - 1 - ], - [ - 1 - ], - [ - 1 - ], - [ - 1 - ] - ] + "directions": 4 }, { "name": "direction_cryo", - "directions": 4, - "delays": [ - [ - 1 - ], - [ - 1 - ], - [ - 1 - ], - [ - 1 - ] - ] + "directions": 4 }, { "name": "direction_gravity", - "directions": 4, - "delays": [ - [ - 1 - ], - [ - 1 - ], - [ - 1 - ], - [ - 1 - ] - ] + "directions": 4 }, { "name": "direction_salvage", - "directions": 4, - "delays": [ - [ - 1 - ], - [ - 1 - ], - [ - 1 - ], - [ - 1 - ] - ] + "directions": 4 }, { "name": "direction_solar", - "directions": 4, - "delays": [ - [ - 1 - ], - [ - 1 - ], - [ - 1 - ], - [ - 1 - ] - ] + "directions": 4 }, { "name": "direction_wash", - "directions": 4, - "delays": [ - [ - 1 - ], - [ - 1 - ], - [ - 1 - ], - [ - 1 - ] - ] - }, - { - "name": "dock", - "delays": [ - [ - 1 - ] - ] - }, - { - "name": "doors", - "delays": [ - [ - 1 - ] - ] - }, - { - "name": "drones", - "delays": [ - [ - 1 - ] - ] - }, - { - "name": "electrical", - "delays": [ - [ - 1 - ] - ] - }, - { - "name": "eng", - "delays": [ - [ - 1 - ] - ] - }, - { - "name": "engine", - "delays": [ - [ - 1 - ] - ] - }, - { - "name": "eva", - "delays": [ - [ - 1 - ] - ] - }, - { - "name": "examroom", - "delays": [ - [ - 1 - ] - ] - }, - { - "name": "explosives", - "delays": [ - [ - 1 - ] - ] - }, - { - "name": "fire", - "delays": [ - [ - 1 - ] - ] - }, - { - "name": "flammable", - "delays": [ - [ - 1 - ] - ] - }, - { - "name": "cloning", - "delays": [ - [ - 1 - ] - ] + "directions": 4 + }, + { + "name": "dock" + }, + { + "name": "doors" + }, + { + "name": "mats" + }, + { + "name": "electrical" + }, + { + "name": "eng" + }, + { + "name": "engine" + }, + { + "name": "eva" + }, + { + "name": "examroom" }, { - "name": "gravi", - "delays": [ - [ - 1 - ] - ] + "name": "explosives" }, { - "name": "hydro1", - "delays": [ - [ - 1 - ] - ] + "name": "fire" }, { - "name": "hydro2", - "delays": [ - [ - 1 - ] - ] + "name": "flammable" }, { - "name": "hydro3", - "delays": [ - [ - 1 - ] - ] + "name": "cloning" }, { - "name": "interrogation", - "delays": [ - [ - 1 - ] - ] + "name": "gravi" }, { - "name": "janitor", - "delays": [ - [ - 1 - ] - ] + "name": "hydro" }, { - "name": "laser", - "delays": [ - [ - 1 - ] - ] + "name": "interrogation" }, { - "name": "laundromat", - "delays": [ - [ - 1 - ] - ] + "name": "janitor" }, { - "name": "law", - "delays": [ - [ - 1 - ] - ] + "name": "laser" }, { - "name": "magnetics", - "delays": [ - [ - 1 - ] - ] + "name": "laundromat" }, { - "name": "mail", - "delays": [ - [ - 1 - ] - ] + "name": "law" }, { - "name": "medbay", - "delays": [ - [ - 1 - ] - ] + "name": "magnetics" }, { - "name": "memetic", - "delays": [ - [ - 1 - ] - ] + "name": "mail" }, { - "name": "miner_dock", - "delays": [ - [ - 1 - ] - ] + "name": "medbay" }, { - "name": "monkey_painting", - "delays": [ - [ - 1 - ] - ] + "name": "memetic" }, { - "name": "morgue", - "delays": [ - [ - 1 - ] - ] + "name": "monkey_painting" }, { - "name": "news", - "delays": [ - [ - 1 - ] - ] + "name": "morgue" }, { - "name": "nosmoking", - "delays": [ - [ - 1 - ] - ] + "name": "news" }, { - "name": "nosmoking2", - "delays": [ - [ - 1 - ] - ] + "name": "kitchen" }, { - "name": "surgery", - "delays": [ - [ - 1 - ] - ] + "name": "drama1" }, { - "name": "optical", - "delays": [ - [ - 1 - ] - ] + "name": "drama2" }, { - "name": "oxidants", - "delays": [ - [ - 1 - ] - ] + "name": "drama3" }, { - "name": "pods", - "delays": [ - [ - 1 - ] - ] + "name": "restroom" }, { - "name": "prison", - "delays": [ - [ - 1 - ] - ] + "name": "nosmoking" }, { - "name": "psychology", - "delays": [ - [ - 1 - ] - ] + "name": "nosmoking2" }, { - "name": "radiation", - "delays": [ - [ - 1 - ] - ] + "name": "surgery" }, { - "name": "reception", - "delays": [ - [ - 1 - ] - ] + "name": "optical" }, { - "name": "rnd", - "delays": [ - [ - 1 - ] - ] + "name": "oxidants" }, { - "name": "robo", - "delays": [ - [ - 1 - ] - ] + "name": "pods" }, { - "name": "salvage", - "delays": [ - [ - 1 - ] - ] + "name": "prison" }, { - "name": "sci", - "delays": [ - [ - 1 - ] - ] + "name": "psychology" }, { - "name": "science1", - "delays": [ - [ - 1 - ] - ] + "name": "radiation" }, { - "name": "science2", - "delays": [ - [ - 1 - ] - ] + "name": "reception" }, { - "name": "secure", - "delays": [ - [ - 1 - ] - ] + "name": "rnd" }, { - "name": "securearea", - "delays": [ - [ - 1 - ] - ] + "name": "robo" }, { - "name": "shield", - "delays": [ - [ - 1 - ] - ] + "name": "salvage" }, { - "name": "shock", - "delays": [ - [ - 1 - ] - ] + "name": "sci" }, { - "name": "something-old1", - "delays": [ - [ - 1 - ] - ] + "name": "secure" }, { - "name": "something-old2", - "delays": [ - [ - 1 - ] - ] + "name": "securearea" }, { - "name": "space", - "delays": [ - [ - 1 - ] - ] + "name": "cans" }, { - "name": "telecoms", - "delays": [ - [ - 1 - ] - ] + "name": "shock" }, { - "name": "toxins2", - "delays": [ - [ - 1 - ] - ] + "name": "something-old1" }, { - "name": "toxins", - "delays": [ - [ - 1 - ] - ] + "name": "something-old2" }, { - "name": "virology", - "delays": [ - [ - 1 - ] - ] + "name": "space" }, { - "name": "xenobio", - "delays": [ - [ - 1 - ] - ] + "name": "telecoms" }, { - "name": "xenobio2", - "delays": [ - [ - 1 - ] - ] + "name": "toxins" }, { - "name": "xenolab", - "delays": [ - [ - 1 - ] - ] + "name": "virology" }, { - "name": "zomlab", - "delays": [ - [ - 1 - ] - ] + "name": "xenobio" }, { - "name": "small_secure_red", - "delays": [ - [ - 1 - ] - ] + "name": "zomlab" }, { - "name": "small_secure", - "delays": [ - [ - 1 - ] - ] + "name": "small_secure_red" }, { - "name": "medium_secure_red", - "delays": [ - [ - 1 - ] - ] + "name": "small_secure" }, { - "name": "medium_blank", - "delays": [ - [ - 1 - ] - ] + "name": "medium_secure_red" }, { - "name": "medium_magnetics", - "delays": [ - [ - 1 - ] - ] + "name": "medium_blank" }, { - "name": "medium_danger", - "delays": [ - [ - 1 - ] - ] + "name": "medium_magnetics" }, { - "name": "medium_explosives", - "delays": [ - [ - 1 - ] - ] + "name": "medium_danger" }, { - "name": "medium_cryogenics", - "delays": [ - [ - 1 - ] - ] + "name": "medium_explosives" }, { - "name": "medium_electrical", - "delays": [ - [ - 1 - ] - ] + "name": "medium_cryogenics" }, { - "name": "medium_biohazard", - "delays": [ - [ - 1 - ] - ] + "name": "medium_electrical" }, { - "name": "medium_radiation", - "delays": [ - [ - 1 - ] - ] + "name": "medium_biohazard" }, { - "name": "medium_flammable", - "delays": [ - [ - 1 - ] - ] + "name": "medium_radiation" }, { - "name": "medium_laser", - "delays": [ - [ - 1 - ] - ] + "name": "medium_flammable" }, { - "name": "medium_secure", - "delays": [ - [ - 1 - ] - ] + "name": "medium_laser" }, { - "name": "goldenplaque", - "delays": [ - [ - 1 - ] - ] + "name": "medium_secure" }, { - "name": "kiddieplaque", - "delays": [ - [ - 1 - ] - ] + "name": "goldenplaque" }, { - "name": "security", - "delays": [ - [ - 1 - ] - ] + "name": "kiddieplaque" }, { - "name": "nanotrasen_sign1", - "delays": [ - [ - 1 - ] - ] + "name": "security" }, { - "name": "nanotrasen_sign2", - "delays": [ - [ - 1 - ] - ] + "name": "data" }, { - "name": "nanotrasen_sign3", - "delays": [ - [ - 1 - ] - ] + "name": "cryo" }, { - "name": "nanotrasen_sign4", - "delays": [ - [ - 1 - ] - ] + "name": "nanotrasen_sign1" }, { - "name": "nanotrasen_sign5", - "delays": [ - [ - 1 - ] - ] + "name": "nanotrasen_sign2" }, { - "name": "atmominsky", - "delays": [ - [ - 1 - ] - ] - }, + "name": "nanotrasen_sign3" + }, { - "name": "one", - "delays": [ - [ - 1 - ] - ] - }, + "name": "nanotrasen_sign4" + }, { - "name": "two", - "delays": [ - [ - 1 - ] - ] - }, + "name": "nanotrasen_sign5" + }, { - "name": "three", - "delays": [ - [ - 1 - ] - ] - }, + "name": "one" + }, { - "name": "four", - "delays": [ - [ - 1 - ] - ] - }, + "name": "two" + }, { - "name": "five", - "delays": [ - [ - 1 - ] - ] - }, + "name": "three" + }, { - "name": "six", - "delays": [ - [ - 1 - ] - ] - }, + "name": "four" + }, { - "name": "seven", - "delays": [ - [ - 1 - ] - ] - }, + "name": "five" + }, { - "name": "eight", - "delays": [ - [ - 1 - ] - ] - }, + "name": "six" + }, + { + "name": "seven" + }, + { + "name": "eight" + }, { - "name": "nine", - "delays": [ - [ - 1 - ] - ] - }, + "name": "nine" + }, { - "name": "zero", - "delays": [ - [ - 1 - ] - ] - }, + "name": "zero" + }, { - "name": "survival", - "delays": [ - [ - 1 - ] - ] - }, + "name": "survival" + }, { - "name": "ntmining", - "delays": [ - [ - 1 - ] - ] + "name": "ntmining" } ] } diff --git a/Resources/Textures/Structures/Wallmounts/signs.rsi/miner_dock.png b/Resources/Textures/Structures/Wallmounts/signs.rsi/miner_dock.png deleted file mode 100644 index a9444f1ed6c073171a40752b1ecb271846153888..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 462 zcmV;<0WtoGP)V}V><;;-Mn<@Gjzz3EmP=}j)4pzQy;;Gn++X2 z2Kor;B=vF)_T42RL-T{dJ`3rybkZ5P=)dc#%V0d6Zx0FZ^8C~qqxI!@I^W)XzeDRP zC^(VA=62Kyant2Q>k4VH4gy$ChPZziwc2z7n9f*4O76|<5GilqYiCP99BW<4Wdeni z$~glz1k21!NU6L4mXjgUV!aa-`2F$_80Qk0bq9bX%VjOeaO*M77 zlkTt2S8pHA0OsHUAnh2%A5w~tvF%j?JAgS8LeC6mfZpH@y}{r0(1Xegz@B`^loP-q z$MI1B*qPaiyeE<@M^l&3x{@^?XsX0T08=PbcFr9uTu^JAX33yK%}tgusQp0`9&A~08l@Px$(Md!>R9J=WSG#S)Fc5tSGJ!vZffQ~M z76!6_21vtF1E}x@YO;hjNTC5-Y6WKi11^{}DFV2N!WEptK7~AyG$qSGfaC!NKX<%) zyd%#P@YiwWnw-n!{!$L#t7pq+i@;ni_mkNzMx)W-&b8L4cYhxi35x(ZUx+)Wfm9}~ zxmC3e>T&s2y;&r#`C{MBQ<-2@ts8^X=cGuFbhw<`ZxI**0|^#SE>sMA3C3bp%HZkT=$t1DszEK zO#lE=)K(t=vVTH#Cy>hIXdr0}5u^}J-!x8oCJ7?wA`v8D8sjjH1In7`&O->E0W#t; zCPm%+&Ve@qKeZnK)UgeNcFyzPivV!QTUYqf<-0{*0*3{s|4d@gyAWOK?wfEPLJB># zsZ3DjqNxRCF03)h`8vMdl~Qj6Ol2u*WQ9VRqdAP`n0Mqpgyi097&1r%`SlDPTA!@< zizq8pry9_!6cZ{nL77uQY8&Em-xvTMpI)rBtyl5=;sLYiIEGg*>^{Hny4^Id;#LH- z)|gGly^7E&WQBs(+M4@aA0{S=!Mz{BKh6H}4Q`PM!~8Hs82|tP07*qoM6N<$f^cZ% Ay#N3J delta 315 zcmV-B0mS~71l0nNBYy!LNkl%l|Kt z-@$PH%0;p)H`LK*hX<4HKsGSLIhx_*%PR~F43M@0 zj1Oba*t?V@2a}u&V3wJS>!9!rb@Ul#>|M%WsH0Dkc_cdkW--h%nB_2WQk!oiMZrPa zg$xY87#JdL-82w_won>foLUYr)X^t97Z~d3GcY{FuV%oT<)dH}003M@Xv62T2p#|c N002ovPDHLkV1jAjf$IPO diff --git a/Resources/Textures/Structures/Wallmounts/signs.rsi/news.png b/Resources/Textures/Structures/Wallmounts/signs.rsi/news.png index 575d943c769404a914cfa4e57e3bfdf5668647fe..40b73c7c2d272b8ba2a332c70cc83a9a1ebd7ec6 100644 GIT binary patch delta 448 zcmV;x0YCni7?>E4Be63>3V#8dNklMv7FCj%16(h)|>~RknOV zx@PAO@&)+=_O9g%vY{@OD#VD?EsQCORH+|8hxVu;J~+Tqhx9EzbKv)UJ{uo!>9}fg zE>@eu6w%B6QOkAHL~hUKxV@VWCO;hy08r>eXax}YbT%JM4gjO^gn!I45!c*DCT1=f zk6i-7&i4kBZ-bciwF*!Na2*Q(kfeFVR^d8U=}*$Ubpq@X)WH#wPbW?SQ3PDa!g^@~ zK-m)1e%)tGK$7O#nM=?nN+bZ#uRryH?_>?5tRxMiOe9(?Kpjjsa2RDJG1*21sM$>- zRGY}V=0WEOaFL*`+J7}yI&DLByQwW_OVBF^)IJvxX(U<&gi&VXIPNWA$QdAkI0r6Q zz|Qw7Ip8{00Dy!50Qvv` z0D$NK0Cg|`0P0`>06Lfe02gqax=}m;000SaNLh0L01FZT01FZU(%pXi0000RbVXQn zQ*UN;cVTj607GSLb9r+hQ*?D?X>TA@Z*OeDr{R1600AROL_t(og=75x|3AY(0>)7X z40;Fjf6ZD!kqe8`A{fbbK;Ntt|95jdWw>zp3R#vL=;|=I{*cD&2!amizP*!SWoRK; z4hUb}&rquBJ`5cYzPcZ)qtL}^8UolX!{$(`J7C9`yKwgW?VA`9J^kP`0|Ntt2ahuC z91y;`A8rvo0CNOY9T2{{A1-d7tAp18l^U+Je|LbPj1oNPVLooZv76z-;l(pa1{> diff --git a/Resources/Textures/Structures/Wallmounts/signs.rsi/prison.png b/Resources/Textures/Structures/Wallmounts/signs.rsi/prison.png index a6fe5ca1f399fc26dd62ecf9ea2c53721ed143e2..cea5bba81a9159ce005092b40175b474d274dcc3 100644 GIT binary patch delta 347 zcmV-h0i^!G0`&rrBYyw^b5ch_0Itp)=>Px$FG)l}R9J=Wmp^WUFcijru5y43nV36e z<^r69HA3b#-4aEN;T*jHbEmBF)PWngL$T!id6r8|OWS-BvY(9oeSG%g0sMEU&|n2N z713Vc5(QLXGhms3ya$XR;-&yc{+xi^;V6h$NE6(X7h02TH-DpvP2KRi+p!!3T;gf; z%2T2O`vUghT_>$a_YcE*w+?l*1O7IAwI9NdZ^0x2O52^a-!1^4Re98Xe{%~U&i=^+ zv?|BcP1H6_=D@E>L$MgGffea$!8`EAbupU11F0}u2ciU&wxhHih1S8?<$j^{S$wwu z_{?qpF#55}cU0GA+YPPC)4m5v+hOWPjHNlr1cV&82csRh9P?XKH&G734AM~iD((jX tu~jXER^{}<*gStsd=UxwK_Gts-~$z+rB9h_#QOjM002ovPDHLkV1oKQq@(}< delta 294 zcmV+>0onfb0>A>0BYy!0Nkl1p=5FCd*Log4KAK(WBL%@w85Zqa$NvTqe zu{)zmrNJ-A19A_UmpGLV1tQ(;Sx$=FG`F0Nnb8b~1Z4bo%t8lt?dfuhz}xHdsK)5S zU3c#16o$VR-3=(xV4y>m zmP3FXz-ezlc*+4Z2T^z}A1xY9Yd zU%vsc*l&@-xND{JCy?Xp%m%Q*eI1H*r?pTi5K#dBWQ+ZlL$PMD-vYSR`(w|ROhZfp z_-U8I@cGjU=zp%>!T=phViaw`p;$YQZ9v=lP)g?xDkcljZ-JkBn`XocFm7*1VSvB3 zxXg&vJb<#+G!-bGH=6a>g5miNKxcEB(fOk+C~J)r#_a(=xWDQ8)<|I{YeKXI{zSIm z^eyOH6jP9rD`6kT2eRJB27fU?2&k!6sQ4-jB$nbBkbjibpB%tKr0C=TsTu`nDnU~T zuH_W~*Ye8s*>S&}8Xr=0A=;?v_d3;oNcb25uD08Z*z5jhy8rwvfU?$X)ExjDb?0`v zz4qJC^J7Y?1Ks1;@x(7VmIY76A1^Lh7H27ZquT9%^W*+|{HeHYTb9LH()li=vevY1 pJ2>`l{veq65VNB{DfDahsz1DeBc7o7_;~;T002ovPDHLkV1oT06Pf@3 delta 557 zcmV+|0@D4!1jYoAB!3BTNLh0L01m_e01m_fl`9S#0005_Nkl*gou>@NKReu4T8+?~4%Zf=5zTLW%()Z*r(Xv`Dyl$W=6m%Ap= zK2WZ?yWI1;_q|*$Yte$Wya1#ps9iBwndw=c9<{xjbC{i253;@mB z*{=?5Zte1~5yBXOo&5vnpjQ{iGj*5OPuBhzZ~XFTY%>C^u5UPvhxg-YU9a29ui0h- zv5jX1u$jZC)BMb?8hIJVaWoo@@@qn&pDP-30nl73nKYufC@DZO8om&v05ab&fFVoH zUbe}U_&_)TWPjLu-8ipHvTM#-!ay*WP(JcX0SuBN1v&~?2ZZ|X(+En17l1a!Od-UC zYlC%&0Q>sL2>^P%0GVTgVaBqK;pZZ)1Rx=(p-KhKO;MVA5&nFC%|K8RMy9}JuE#3{ zNYh{I4SH4tV(v{dca2y1JU}ymBx?dua^vfE?JdV>oIV=+Zif;oyfa2_)e--ry@09^y vjw8AEhbD=Hu$|>Y75r&dc2k{N_*VP}eB5SSzumj100000NkvXXu0mjfm~R7- diff --git a/Resources/Textures/Structures/Wallmounts/signs.rsi/reception.png b/Resources/Textures/Structures/Wallmounts/signs.rsi/reception.png index b16670d5b5f6bfffcc8dcbd3b1cb2798b2a7557e..3f3e6dfa490179644e10f24b4c621c1101ba025a 100644 GIT binary patch delta 421 zcmV;W0b2f_82uNJBe63>3V#8CNkl$r0^dM;*X9J>k`5^p;jMvg@tA}_p$Bj$1=*IRCrc%i_M0Tcd*7$`BlLj3jtkS_ zcsega5xqV?YPqgV)XCJ`Ej=efI=riD?pO>2P1EC0O)jka(`J9aoJ=P;^q{8 zjVYiYP2$sIcU#ZggB)jO=6>S#swG` zrRW3`Aj#7t*51A+44bBmukh_4?hOU*Z+656HE8i8iwj~Py zfY~H+7C-?x1wVzew|}8A0@Zhacz1J31>?fHSM68py}JO_QMNf?Hi=5f`CW7~Vgqzgcg5 zeeRLHJk{od#v(lKw&-+wt)Ad27#DIjsG)H(3O$(QA8*>}=o;*!*+0Gk5&ytAhM@W` P00000NkvXXu0mjfk4VUn delta 454 zcmV;%0XhEt7oQlABMtxrXF*Lt006O%3;baPu^~kYe*hq3NK#Dz0D2|>0Dy!50Qvv` z0D$NK0Cg|`0P0`>06Lfe02gqax=}m;000SaNLh0L01FZT01FZU(%pXi0000RbVXQn zQ*UN;cVTj607GSLb9r+hQ*?D?X>TA@Z*OeDr{R1600ApWL_t(oh3(d{YQj(y#_@l) z4t;|=odN$IFqzH^2_Nt8wA_Hnbe{MZp9Eo)tGQ|DSYKBM5k~>f zZ?C)zA94X~&*kanRvo~JeE`NCs~*6yC2gtEKch^*o5`g^SLy>EmzX>Y? z6iG8CAOplR?6%s>mJ3Gx!EPS}VYFAP1Tg9km@OB;&($OLfobUK7LkY(`vhUM*H}zM wEcpaZNhyF@k5Yli)%`bx&hjd92GkDt27!L5&;k3efdBvi07*qoM6N<$f{HA-`v3p{ diff --git a/Resources/Textures/Structures/Wallmounts/signs.rsi/restroom.png b/Resources/Textures/Structures/Wallmounts/signs.rsi/restroom.png new file mode 100644 index 0000000000000000000000000000000000000000..f5903a7d155910ffd43d1ce8f8fa252070a4990d GIT binary patch literal 515 zcmV+e0{s1nP)Px$y-7qtR9J=WSG`WdFcALu-6~ar6t+|>l`=+Er7kF2pCGK=`v!S}zCm_Y`UGqh z3lfSlMq+Em5>-NC13?(jA?Iu-P7?$OzQs;^x$nDkd}jlH9Xn-zjwjQ+Eu!1&OC{HS z8M!?e;pn8_n0&Kd0YI)2p%g&m{lTa)IRJFJJ(@})c6BcupPm^xcOA>fPUlZ6VDI2i zBAU;J5~1(eMt0m^r2q~h;)L7U)fVtoFcz>_riHPo9YMPdMa*Zz&$;i}@I4zr7!`=w%uagu3$S7u;78%ohEmg%P`axRJ@1YuP9Ef_5UkDx4~x+oPu(eo|kI#wYI zO;Gv`P)a!wrMrzxXfyEo@(e&<>F9SF#r0Rs$sdO{19|=i;A6exB!lZ%g^}QUwoxX? zA4ltzur7X2CDg&R;_09~rHm)j+&#Y#`*>qKJw715xspyswMsFSRk7>_VI)0^+m=^H z4kH1g<2cErvdf>zwu&66@eS~vAVx`5(e!k*l>pvY#OUHAGip347%zbcu@8uAzRiyK zxw~MqUZKPx$dPzh$^&Gl5<)DHNC>tvzy&9bqxc*mB=|SiN&oN8=d%O+ zb)EH1%GLHbhROc<&gf&DkgM&{yY#T|7Eb0>S)qI@jS!tbl7IQ_&6Sfm>Hgu#2yt$D z$u@E!1(H0p{x2hdt$DE9Ad3s@cbx%rbG28~0+2ZXmN@`iaLwE6Eu@$}1G<9U211Hy z04Vw_E)e-?1LDU4l02+UDdn8%X9JMA9yzxF0cH`J8qQ<@dh|eZJKBm>ghC2d#dnF7 z0g5)jY1Fp;z<(+OeFsh(Zgc>bb?(#PB~W_><@2|j6M&v}{nShH@MPTeoHGFMz4ekj zgz{D05ov6CZZrUjjtsK6XtZUn1{Y!Er**`@XSLJVr8Bbc17zM_YyG4gBIB)ieZ9tV zKI8H=^z!jMP1wLS_2 RHyr=~002ovPDHLkV1h%G%<=#L delta 364 zcmV-y0h9i~1BL^TBYy!+Nkl%m0h4 z|ITpv!X>gS*EP^%coWEp*AXm)47q&a5`*u?M6w*P*?&HRWS}`-HB4lgj0ODJ@RDJ( z|9q155exxh0L)^~L@$!{QXB%vzGev!r>_H$E!Q>BBg+i39e?nk{w#{+moHpG5u>>S z6dH{gbPe;PD)xY>U`hJ~;wAq9|~29V?Z@`X!ervb7Yu-Sh;JSvbardv@=ZskO_1IY0iRUJS{ zbxaippc@J+^<_L0y%?UHe*#Yjo{3&0mkVSiLRiteef~DMm}jCF3ZJG9@J#fAhXAr; z$Y~FdT@d*OpwbEqq!&U&IY8GykL+BaYoN#QhJcy@ZPx$n@L1LR9J=WSG`WdKnymBp{P>RE(jr& zy$=v&$==6k=5BeCZke0MV9yfe0kTsGAr{C<2)43dbh-NHF6n>--x9^XoIm?MTNi-8 zjtj||F4o6$1*%>j$XG0abg@20*AdL3+34V=Gthl>BngrL27kZ5yXo1BCIbL~ZMc1l-J#kh?Ku zN3o6~KoPQ^ntxqGFo7~}dr!@-A-E0eswTz7+0RY@;kKo3+qqDWpv+sc3pfqfD4I+? z614(YT9<^+Oz>IbeFR)3r1d`VCNNZF8bl2gP1YMO?y&LoOO;baXiqboinib+KWaeI zf=WPBvX9aw1XW;&e>4Fb*a>#V_B-X*z}||Nw@a8$CqW_nM7+I!!r}RFaw}%r&~ygo y)5+kwfQ@au2h$nS_d9<~Y!aiRe}nrq`^OjHz2*-*l-6Vb0000b>!47?Owx_2p%p&yW-qC?+c1A&{dqo+Ke z56BDhfJ_=Q7J-4}6+sO90~s=A@0bn+1KCk+Qa0M5zQvSCkSCI&3=H`17_}KJmaB7@ z0PnN6#u$yt#d3AN|M*0i7eT?5(Kt=-8cE!?IVtl3lXV(IAb(3N9;PpiHa8N7hxrbN z`7T)RLu&?HP$?eq9Hj3|fJ%`i_Npwtz1|79M6$#}84aLYpNI%#iLI>N+u`aYWJFB} z;Bsn`>uV|48K4uo>88EeS$^6ciLYi(B(Pqg#bBouNle8XpEo6*xF4+&m}E>j(q{k zyg-!3*xC&MAWCDlPtjWtr7_C9z;S=95CU)^L^2ob3{XlZuisyH(EKF#LclkAxll&q h)ME4JzvTl4d;wiAot?M?=JWsn002ovPDHLkV1n3Bv3LLg diff --git a/Resources/Textures/Structures/Wallmounts/signs.rsi/salvage.png b/Resources/Textures/Structures/Wallmounts/signs.rsi/salvage.png index 8c51238f897b6fad6fbeac1dd4f134034ccb4b0d..20b0eb577de574a673c40d2fcce02a7d6b63f42d 100644 GIT binary patch delta 413 zcmV;O0b>5881)yBBe63>3V#84Nkl5dr6opT#&aF^|GFD>9&?O7c07G^L z&%6bU@D|Jr>>bQAuypB=0jXmZA*+3XbZCwEGhAY%1hr>D=3<}EzW5LL>$({W?sqsX zW%Tko?4<addKq;w$}z*6rgF; z?XA>Y^RoaX1kY)k&3}~EF$-MBLXf2Ou*UY!=&y+|hki8vST;w;g&+7D0AeE&d{zG%0)}eH@P{ z-$n0KtQ>(#2y9GqkzB_^d(dO$crGU#YHU|M~{{5E7^wputLr00000NkvXX Hu0mjfi>ADk delta 460 zcmV;-0W<#f7o`}GBMtxrXF*Lt006O%3;baPu^~kYe*hq3NK#Dz0D2|>0Dy!50Qvv` z0D$NK0Cg|`0P0`>06Lfe02gqax=}m;000SaNLh0L01FZT01FZU(%pXi0000RbVXQn zQ*UN;cVTj607GSLb9r+hQ*?D?X>TA@Z*OeDr{R1600A*cL_t(og=75x|3AY(0>)7X z40;Fjf6ZD!kqe8`A{fbbK;Ntt|3%&}WVn3!0$G;p>KZV-5sb&{2!alHeyEVaH*Y6d z4%j@&ok7yBpSlisu)mx^!LbvodUQFeJK(|oa=0A2Be2QQ!~rtOh73>cp2z9{bUCUz z0NID=7U7bknFC+|mOFHH4KU<}rvs4V9hr|ye~#*jaPuU0xEy-ffK8674nVd5n?=~< zs2&1;9<5+tk&A%S$N-z%@G1w8EgG<*m{dSD2T%frM+hK0VDlt*2G4**h9`H=Gsq|# zGHl;4pMik^QW{>qd;vo(O%frj2=)v}WME)mV0d!(Jj3P77Z^MP5>c`z%|Za#$1ob^ zG8mdWfD}L#2MlPV6y^xBY=;7hn&tEWqYfBw2LJ#JV8_sFOmsW|0000Px$^hrcPR9J=Wm$6QRP!xuLjf2LdwTm$( zy7K^(#IW}&x@O=G6VeQzOKo z=?^xUd%lM>58?S@y04s2;d+{90b^oSMC6SMZ83shdLA9TxLm0V^)q;GO4o% zRHk%^xqf&Aglo7%xlHaYcJQE9nU2h+yhPK^>eZZXc)P3D~Qf1kVfoy zxiQsa<<`tyvQ5_efIQ}I=lLE~rnKR$x4`sfs;7nVgMR?zy4Jzii0pytqcXnVp_KyLi zdARZDWktC5^b;z6n(8&x>u?yWyl2*8D;1hK#Eevj-Gme z9suP49Dpe!BSewl6eyN`0R}Hf>|K!PfSejg6Fa8rP~Mb$JO4fZ|NVb}8~!`)+BQt4 zvx5u4$NO6&N8{pTIy*ehKOq?JL>`b3yU|0Vh+dl$!8qcac7GC3BpIGZFO7TdJ9*X! ziX?M!(Otl1yhfZ;#5r{m(V7AsMUo*P;YC`Mh`O~l7)PK;GQ>HBpGE+V5zyBFz)vIV zh!_jd9S0?5lE_9_C-#i)pMofS?3T#2m&xDFg=0WRbCDgtz8YTy9J#v@A!ukS&Y5`u9I z=n$)HX)M}UKtMtOs7PcftFEYbLS-|BaU&9pLoj|qs5$J4P?oZ?nZl|ODX6=y-}yS* qRRpLh*98Fyv1{4$=fCAQ-0%gzXUoBQj%_gj0000Zq}6n(9_R;pCdj%16(h)|?%Y&`*UcW#gqaD(ifbAoQ!DpiOPsaqH$lryADANl#Q zjR{B@+P@HE$M5;Q?{5tJ^|-Nhyu7|0rULo=c(>x**}%j30*}wL(ct^t761-55@!Sm zKASI`6UR}2EDf>VG^py)va~>#RMb}02Fy*mAuH4j*xuUN5E;pded|hb8-Suc0Oev z!PlF{3EoSfs@pRXBt{U~*5G}s2YM_Z2@OVTbRX^U1@|IA5)w=*uw0cVq=tqU0h!$d ztLnA`WI>WDO{RdY;>q{y(_7Jpgfj^_ne-btdMy=TP?;2AN9Z<><)PKk+X6~H=Hp`&0a;+KLV$&aNk>KKy?*+JcMfQ8^`5`v zB(xIP@3!)Ddhn_=q2IfKF^rdmsV^qY_m}l{boHy*fBXO-!#dn{TP!620000U`J9^uJqlANQZhZph?s)^BAaCH_*(d1cRw&{qbUVjG?isF2bL3(o z$uFrL+TWr<^!xe!OZ)+U-L7m8o}OP$u|(eAUadMeHt}@3!~NqXSp0a{1Hj1!F$0j| zo9!-G8~|?b9^|bN;@b2Q#q&H%AUHEVTl$_6fFfQNDVlclem59E74L^>T>vQ#fFurB zy1>QseCJuRegsr2ixhd5tOFpuZ`u)6-CaQZIDp{nEGk1zseUqm6jwc`79c<@LfeM3 z8i49OaM_N&Mk>NQOGp)OGExMjw(d^&80BqZoi6iB8 Qod5s;07*qoM6N<$f)X>lga7~l diff --git a/Resources/Textures/Structures/Wallmounts/signs.rsi/security.png b/Resources/Textures/Structures/Wallmounts/signs.rsi/security.png index 7e27efa2b3220c9bd937bff71fa8694b5ad11231..2de5d34a5ee47c2512be0faa7c0baf09f092c63c 100644 GIT binary patch delta 400 zcmV;B0dM}<1F8d%B!2;OQb$4nuFf3k0004GNklQt%s z0(%Zxgvf2SV-=;$o+B5aPL+DA6nlf&%4isknejk=q~tZ2;paWuV;kVFqguMyf!m7c zS>aLzbl_^>ZUgcQa8^V_1qk`W2IPVdMZ}Hvz>?>U8`<~$WPbzf`+l-5?^6ZDASCCf z7wVy%?8c4MLp#|bE(dA~9)bH{T?kXChn7>do2`8U?-){$i+X5RJ#P{qp-&0QiBge( zx8rd}Bw~C!yf1~-dm!fVx9tHTU$YNP5rA|h#Jqd4n5{gm~6H!8L7SOnH z>U6#cA(u|M)PIt*(1AOEdj;p*I6GQxIUc~p#(OdX(%&V#e*Xs+*K=C8xe7}0WwT%{ zipFvH4WOOp;MO7_EVa~m4$RXq{NPwya^`6mHldQ{N|8K6%pdZ@IGMZb%lBNXYbyWZuVA4#Fn1Se74dED|dDl3|2EeGS zS&-&{@#X^841Z_{sff87pa~*s?gEe*PeRa~nUau202t9a=VPhqemM))eIWq7tT<}+ zwe>f}iVFZEm5GIhI@wtLxv#T2!+ zkal;qhP p6A95&%X{VCnr*tNq_)00{soO!Dbl$zmudh2002ovPDHLkV1l4Z*4qF8 diff --git a/Resources/Textures/Structures/Wallmounts/signs.rsi/shield.png b/Resources/Textures/Structures/Wallmounts/signs.rsi/shield.png deleted file mode 100644 index bb88d2a770e7e6da59be40ee3d317eea2cd814d3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 402 zcmV;D0d4+?P)L*939?4&&cGh2Yn~udBHqB+yfKA|F)I_|3DTu@ zZB)VeLKRizU%+7b|L!=S0Y?3IP5LJ6_J`X&2Jf4%|*j zI$uCQnR@{4xX6ANpe~g$wxRSpU;V8j)cPq>PW0XYadPP_GEUE6e*!yVZuBewI}3HG zj5)VsdhY@Q(P}u{cFh8~$FQx3Z$nZBeEa+00Niv_z{xd`w+@`udWq99g9rmm=L>VM zcL)`l46s@+QJ2aXIEF>$fYqf!LtK|!gr{Q$Sybi-wxiWq0N_AUM9zRtX#*gB{l4mF w4S+aFoaci8*gqh?5@CRI&zy(Px$$w@>(R9J=WSG{V3P!v8bT?2t)I+`uu zC=$q0-0}o=%`SZbU!cB$d)K%Zx`i%mAB9|3Dsp$VhU=TYN0VG+` z*|YfqZ+jvxWs6MVxygFc6d-)h>HSw$jdBip?|Y8+S!o350{lfqi3Fx`U?fy4Kt@1; zBuEMXO#Vj;7y{pOAdLg9_(1}wrxZz6bYoHIGQXn)@OjJ+HAJB+^e#Wtkj4Szhq|+M z(Cz{NvDZ=PGJoQH&tW__tpg(gbTK5N-thu45~BIm0{Fd*_Fpv{H0T7Dby zHa<`7`-dlc0iw!AA!XHc}a$QX|G3H1#jKBQb1WXkYok(R!g#iDNLP* zx^ZO+XwFSQ-vLQhFt)4)gx~6$?XLB2@95X;XncKsK>4!ooe!iDIG>I%n=iCEG(nOT scsA%kdNP{&U{b%o2~S7Ael+{XH`1sDU^f#ERsaA107*qoM6N<$f-foOL;wH) delta 490 zcmV z(7b_rSKSNUq)VYl#y~eSS`i9;06U#X0rh zw>?i80zw#gwg0mG&`3tshk<9@3urvR50D=&N+mE&A}gUr0XhN>A|X-$mH4+7a1O%2 zLz+ZJ@n;F(mU1kX+wxjG^()`41jsn9HwEIUue5HxDUc=+)|;YS+n})u0JYWe)USvO z1FvGaOCA^n@PEUIh+8KGk|$L6I}4DtOypFKWGxp)!F@A%tnYkYlvAbVLU=L4k&j{6;Y{edxlHdrjTG#ec0R`v<(YjkkE&u=k07*qoM6N<$f;{@<;s5{u diff --git a/Resources/Textures/Structures/Wallmounts/signs.rsi/surgery.png b/Resources/Textures/Structures/Wallmounts/signs.rsi/surgery.png index 254ada76fd4d76c38965d88101b216d133fa576c..f24ba5c1b331d0d183373f349b8d7a87eb245fa7 100644 GIT binary patch delta 405 zcmV;G0c!rN1Fi#*BYyw^b5ch_0Itp)=>Px$Xh}ptR9J=W*D-E`Fcb#hzg12^$bi%# zOY0$0FTfQ%asYO?RAz^MxWf)Ol$(sAoN1i=Dq)FT_g0*rxR11ushbr7N#kjeD4)cQW#l`#b2 zeH`Dd?vX6!gnv2EvU}g-dHY0v9A7FVKqk}Hp1^gi3embG)IG$E0+6Eq_9yEmFEy$H z*eKffZAcxk51w=P{i+Z_%aH`I%dC0p?WS+s7t$rLGx?mMK6d2myqmu9W`2AbdOKi@ zL9&>Svgyc64P%UR?03GHG!g9T$M{~&{__Fi&cFzhmkx(J00000NkvXXu0mjfofEqF delta 403 zcmV;E0c`%R1FQp(BYy#NNkl8b{6#iO@TZc{^`v(Hz)G0U|l=}iHzYeXw9+)8m z9&xSSHzpud&~VmMgf5IqkUIsEGLxzI%Me%r!Rblcmr(|~5>(k{C*ap1qBcguS+DjU zaiuK%I{ZBXLVy2a6zJM?6`@@MkGSyb@J9xQwyDr=!jHQ*fR5W{C7@f^*$LQO$77h> z1404aQC!2~xjRmURuewn6DhgZ)iaVZlWR$t!6RPx$X-PyuR9J=WmoZMmFcgM=5GSAmQW)R> zc&SV|OQswmYe&`|!c)!yL|x1QU}&TaP~ z2G=DHxs0A0x0e@SUE*+e3)~dx=6wfz?%WVg05X4iNH-_FynnkPE`13(cFtMP3-DXI zicJtzJ2^)yIS+uSTGry+c~Jo7qM<5iC83pML$CmB^U%UH&V`r+C`9cvcU8eQ)=Huf zH9EaH9e|R3Af{Z#A#)bM6bLESI2s@XLUD{S>EuR4MpT7Z<75ESoYS0U0iYv@>3mrM zQq8jfr0To@3V%^URPE0tqqqnn*Hk=M$F60s}I)$!~g&Q07*qoM6N<$g7eq8 A%K!iX delta 441 zcmV;q0Y?6>1JVPKBYy#zNklZrE5S&C&UXaqYB^O9*`3;uL2S5}QRCz!O z7YKjAk@AL!l_(-nQ|1L}oFd*6U*VnE@df6*7derI`Q))x#6#C5%sJB7?|&u04Y!z2X00*zy>7lD zIy2D3>-#4*yZzaBfn#Gadm2uFkpET^H{1d+6QM1jN`5X2fny_$ePa>Y0-EH_EC{iP zSj_YqSGx&`EC4`Ol#1L9w?|?ijeTTAS&P+yb_S;7QEiP9RzjkLvGnL9=Bfgurm`+Q zLX>dLCz>%jFn{uaDB;>ObAFQUW=t21K11dl@JQ92$O3Z?_h{8=?5mhT1W1PyS(uJT z*zERdpA{wCaBFPa#!e_AWI!?JYTsvO7z^l2bddn5`4G?&aLG8nih$~6()rCslrz(Q z(Ds4Au>t%vUEtV?NJ!<3$Qs6q1w@vbgjrE4(rP9EXfk_&krk^6SG`>J%~cbf0*I{M jUx7|3{`|N6h8w;C$9BhYDO7v+00000NkvXXu0mjf@*2&$ diff --git a/Resources/Textures/Structures/Wallmounts/signs.rsi/toxins.png b/Resources/Textures/Structures/Wallmounts/signs.rsi/toxins.png index 6c28bfde0033b911a4a60d8c897cef911abd6c47..cf11ed6155f27279e02623f7c3f3879089a18a8e 100644 GIT binary patch delta 516 zcmV+f0{i`_1DynrBYyw^b5ch_0Itp)=>Px$*GWV{R9J=WS20V&Kp1_BL#5C*i-=H% z4nluG$dbK3pp#QGXS-k0Epsw;>JM;kD1`igK!*+%L|keDqFWvGi1!$#Ar(O6*H;&f z$qDxlPf`)5ssUvyw`>bu>=fF(*nwqR$}y_>lmg1gXY(;!(=W8UrjOZtTq>d!0Wxw? z#J36npj>6$)dRrUF#=}uF~ES)bf33vmqzW?*A~DBPqc#X^I}J7lL##f_|yk1!75xA zNa?u>*9cgWw}0taQYnB^AFu?j=_3jw0LWKJc zA4BD3l%*L4-A<$JCAg-KEX|~Szw^a}7txsg6RKCUf4l>P;QUXv+9CJ=0000wB+v&H(a6d^1v0Lw&*9gFk>c|_k|hwfd3bH0!*nG(ca>;OQ0~m7Cg)G9UW6YobmX8|s0TS=0(+1jEN&o-=00>D%PDHLkV1k_dv}6DP diff --git a/Resources/Textures/Structures/Wallmounts/signs.rsi/toxins2.png b/Resources/Textures/Structures/Wallmounts/signs.rsi/toxins2.png deleted file mode 100644 index c2c35212d0b5bce15bd13d83f7fac3f65358fb13..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 433 zcmV;i0Z#sjP)9C7{yTsj_60h4%-%7b zK4T(^|A5+|yah0p-w*rQAHbylt}9!I-TrVMV({|()a%jva<@O6Z{NQlxd<|k(*&pO zO)tdEHi+Z`>th}SP-G1E+sEEMR)DTS`{WDj4Dk8-0m%j8G(oh8006310ML3aGKM%! zFn@b+8u!{2fN~HmBB)wvb23)7(jY#WaR%s`TFFJHna?tKWng{GTNxlDY6}UhcL=)- zLU#$^u>?QKoDtg&84ZApDDm_hG7~`nmsuDh?+gIVmjlfiP-N`)W`IQILlnFOk_&wp z4XGDFOF$6%eiOb8odCuPTrj|pay$ya6)T;gokO_HSNck( zBvmU7V^+yg0ZcOhs94!*H_Nq;oR?s>xzlN%qxspOd$Y}FS6Bhev))&6n&4#V^XI?i blO}xwSDT$DhFH7M00000NkvXXu0mjfS!KEb diff --git a/Resources/Textures/Structures/Wallmounts/signs.rsi/vault.png b/Resources/Textures/Structures/Wallmounts/signs.rsi/vault.png new file mode 100644 index 0000000000000000000000000000000000000000..33572ca25b572fe3f99f904a89906766308ad606 GIT binary patch literal 458 zcmV;*0X6=KP)Px$gh@m}R9J=WmqAX0Koo|5jcE*xgmj}TU9j)~-S!6M2!vfZ14rl?%8v91cmuW` zzy%9k*$p8j65^(Adf9N@Yi+LHfSu@r?HI6#|NpG62Mrl zPsZXJmsggyc~#^nvx5{u3P9%O&23{W@Lgl% zh*xHZ#=P^+NCV9|^Vk4WnFB3LP#3Ma_*iA?W6lQP2Ic^YV%NY_8U#R@4#`*>AdMV^ ziG{#-5hj*4L~j791uD$GMW+ow8Hb7W?Z0Z?=m54CW3$S!-R+gVftG0!0D`DrW#-%6 zo)wGT2e^;4ZqBKX(HjvrbJFim^$o1?6`?Zv1HdEx%d50g5Cw)>}4pJxC10LxCfy$yt^^8f$<07*qoM6N<$f|7RA A(f|Me literal 0 HcmV?d00001 diff --git a/Resources/Textures/Structures/Wallmounts/signs.rsi/virology.png b/Resources/Textures/Structures/Wallmounts/signs.rsi/virology.png index b83297d037c3c92d58d919e5fd167280daea92c2..232d9a74b553fcb8edbb9d42a46a2940b721df4e 100644 GIT binary patch delta 494 zcmVPx$!AV3xR9J=WSG#S)Fc7^2nLw5c0V&)h zDhy-+t-w+PsPG1!LmQ;<04lkH7YN{jNs}Ugi#S}tDU>tG(@{FfDgq=A5cHwQ_wFkS z;IHGRZ*ZkH=eda9^)t&A6|hp9bDG^lk|bA?TWjHT{9r|}0)LQvoj+VnjyRY%R>W;= zg2eJt6|mdpP^x0^-Pn3j0TdjO%1^+$V66}C;)*ZXknxGfe`AAA&5iZlTh+f6;P_8;~5DCJy5FR5>q7ftsXOP zk^n!`Rqm|AihpQxBP3|O;N~?tzW!hc(B0akz465`0JM4H&+EgW2Qd3-Ru6?CHgB{5 z3R(q@Y(J?AMhkF#z&*p<2>Zay0x+v-_oIZqha}Y^?gLzV#hRzJ&$aCs#2(<c3@)c4_LB1WwJ6LA$|dYl(88R z{SFW#jFF1?g)R(HCZ;Hoe}IvRy$c=StSF5VpNZ6=yd}mt-MxFhJOe!N-|^HIu-NP_ z_Z0YeA2-%$e7V@{E}w5-$W7r@TnUNkanwlSr7cNr3Zy#mB7YEO5vH%B#+YZX%(vv# zb$QPfYywn72?+q0otH>;VxL^J9zhjUEH?#0+&V{Oi-%dnBI2w-S>D_fRskg>l#mFs z$V&xh0@Qh!MNmQ_HwEIs1i2{?^o8A{n9d0Rz^XU5Yb7Ms`>j=?9K%t8Jp+WGFA(&_ zuYH;iR}#(yNPqe^ta@`myJlq&upR08@0|vd`xST{0S#PrkJ~-qX+*2u97;%}Izg%v zTYPq2a?|k%ki4V-5dyB~&$VOkyMTyP&zoyRPBY+h$#hEKp6j?10+cKsOsxCS4A8o4 z&+GlRdm{pX!^zlnJec5cGPT7ya3)aKebo!Px$dr3q=R9J=Wm%mQKFc8K+5JOR=rd<$1DtjIv^5VUZk<8ipB-t{jkHMZL$^&$# z5<)CsO9-~IaFLbTjsFcG_!jGA$M?I-ot*%GT^Hvj`D$~F<*0pq(E2h0@YUv+Tqjs0 zi(uzcNQe)ih0p?!^ZUD-$;}yO=-O^_-Q&}X7UI(MfKB9#GvrkY#@Xar(|$$(8|77s zGHZ}msrMe<0OP1_vJe%3q6ZL^1upv^s-KfYY6Jwho$M!i{)qw8aS8erH)Q!Oa z08ZXNwOy#J0b<>L-T*G5Y}s^;@vC@!yT)=piw5=f{)xl$;pD5>*acEZEax+)-Z!bt r8b~3vb3gOPM1=_U{w>q5*}uL31);w6U&E9Z00000NkvXXu0mjf{$tIP literal 0 HcmV?d00001 diff --git a/Resources/Textures/Structures/Wallmounts/signs.rsi/xenobio.png b/Resources/Textures/Structures/Wallmounts/signs.rsi/xenobio.png index 0d9336c01a19f7967bb4e2b70feb77d2b778b4ee..4f99ab19c3da09dae0f756c6b902996445ea472b 100644 GIT binary patch delta 465 zcmV;?0WSXG1nL8jBYyw^b5ch_0Itp)=>Px$q)9|UR9J=Wmp@CxKp4g!#i3GYn?*#Z zLk6KAAOuP}_XA{dO6P3(B-uKrQzt)wb4#K00~9(qSP*fE7m&KuK`&gcm-1dNsGtvo zgnKXd{O)}(e-8NTIyn~ftl_>cqj`F-^eP4Ltl_?W-bSn4GJiJDSO&IZN(dzYH^08R zFgE9Ue0otroR!@m&ippM!NBWlo6hD7OruRc9^0{lKBWMn23{YNXsrzp#C=S$Iojux zGSF zC4%Uv5&$>XHGiuOKn5{^sayj2S}qAyr1yZR&-Z~&sxCjImC#BK_Je?5%H?cZ@fl?XV zD?ea=K+qT1{X!}mcB>Ry#o1;dHtH-$XO)Qv1QJMjx4PQ#Xht)N6Sl~n#*8$+=iJw5 zF7Vm0V|vl)4d}f{e*gSt56Bq0XeT~o6Y7K;>gEnvP2ko7)_RlBOghc7i$}gDUgjZ;>h3l zL|28K#o1cZD4^YH79wO(u7^#M=0#+xU`#<6cqI?3E~V@-r;PX7TC;RZ?eqrJK0U+U z{z2s*>q6l9=>f^FsdhflM&R*&jlKN??Uk%9Mw2Da23lx`h4&szvb$U3bo9?hv;X)5 XTzo~p=G`P)jOX>HZ z5DkELdeo4*AcI}xP!>ZQt`|3SpxiYA`z71mg5StQLlU! zIgoKL@CiJGH<-!%0L+OzUGNdkNJA9?iOP16QVO6ooxkY;G*HTO_jpqg53m zxTv&|zF6&qW#XW8!LVPC%us&v@j){tmr+~pLKz}^W_K|5jJtb&n$3;Rk9RDdAEoyL zsRj1iHLfbP%%>X}EXSq0ffUkHL(vzL&D*Q;cJ%94vwwU6G}j0Z3SOnJ00000NkvXX Hu0mjff|UYh diff --git a/Resources/Textures/Structures/Wallmounts/signs.rsi/xenolab.png b/Resources/Textures/Structures/Wallmounts/signs.rsi/xenolab.png deleted file mode 100644 index 21eb486835b9418e35103b15dcfbe06efc4a22b6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 408 zcmV;J0cZY+P)9C6vn?+S-N+rlpz-YQDx{EKtd#AM^8OK4}f}r93T^8#tI=Nr>KJP1v)Th@0bpe zE$0u$@5OD0@+~&c#@`S7*#;Q&-*wa1VX<88uQ7OidA5338yCyf{{H<7vTj)BK@?&) zzq3M&`Ua78gR~SZfGR8SFn_Z4=>@P2Zi)+e>%+V&_9Fl`BMt;>27HPHP-O*zC`1s2 zXKgA@odt3dPTr=6N)Ej}gDBK-nbEc^dkHkiNu4SZKw1iX<{zEyRaTI= zi$#J>vDP~w775yI3t2a3G1tS%ISEbk@#7c(w0SHN4WVMLat7EGYi-nSTL91?=B!ZV zyaXx_(%GS$V0!dy##HGAfOEx~@9ui~{P}PBph4gKfS9#W%prRK0000EX>4Tx04R~OkOy}Ge_^C9a{vGV^GQTO zR9J=Wm%nO*P!z_$mJTTa6PHp7>EMaN?85#^PeHtoFXDv&RmP4P zrm@9p2*(W5wla`L09IhYF+*tc2!IN09$~6au=X|p)D+4J3~7kly5?M4SIs;DK$}OI zY_tNvC)4H;wyt{00#2*Xw&hFG2!K|;_BL3ohM4LT0NK?Oe++Qk4;-p70BP$UYkb}V zNS_?aF~bx}CJWM=kf)x~d^A755foc{n~Tg`4X_;97aNdjOkjYTi2>*GO!bBU9D>Bn z`KA+Psp@rq=lk<<)bDD5<;c#Ym1<0@hEuH!K zziUyfHh|3K!uNbQW(eQ&Gx1h4z^`JWmF3N8TvY}NZ^eVh0s7sJ44;%fzrL}1-^t&K zlQ==Y+mXInm1#M$k;I9x?RS2daEQk4Cl!5~{p$x)6WuE0;-PVY00000NkvXXu0mjf D?Hmoa literal 6115 zcmeHKdpwi<`=3ZPDix(tW)jN zaR{BHM}9MEcX4A z#Nbp?v+SYW)<b4OFPZKlZrny5KNk?SXT0aGt3w8>(Nw>_ zXSVo2@Tn2m#_Pvq!UFi45XtZKD<#=sjS25IDK7ZX;@aaXvAyX$U)@D)@ksAO#+7~} z--LGEso~-1b6ZVD>rKxM9A91Aqjp2LYv}LnHiF1B=0SsC9N&{)v2!tU)2a@t-`Ue^ zt{n%ZQIH*ML&f80LL;q2_qfwlJ@?!Om{uddVz9$oEzm4R(^c-7V#H?dIQyEb}j z@$r*^%Q8tTS*rZ;ootIs9XCr)tHsvjn@jX%EwSj0JD4VCN43h{Z`2-`jb{`NG%z|t z&6maREbtB76@-A@GToUmO+&t0o$d@PX%arPP?;OO=ox0uEP)&$#o2hea0^vSLvh_M z%^aC|gDvnd+_HF;#CY=+i%mR|wRSitXRYyBKdf4KN!8fb&EVRKyi~hCsJT^ZTr?b0 z9o^THvYc}=@mg0-kRIhZCA24IDNOre4)0r^6qP zqE3l=Svuk`Q7^bL*V;~ve50kvnZ`MN5V*F>Jt#LOTR%kS1iFVvd!rLlx%+gA*mizV z*?z71BTKN?VX8F)34gDUL*SRQ?Elf&tr2u!RgRL16~;~R%;$L#g?rK;5JubaHRbL{@7R)yO# z9!?<<$z`vbV8K|c6IB=bFWTB_kJYrBu^9W(P4$X;t~wZ6)?Jr$U3)*CBP4WCn&k?R z!s~82;-q>e#L)UYfg|kB!`1ck_kg2Bmmw1*@KV`@r{0X$aTBy^{vGXP7$YxmuFW z>z7itJ)`*~9(Qo=%UG_rp8DwOnL~kTO@GDx^|*fBoj%6wiE7&8uFV#Gv_pR=*~G=f za9-3}7sJiz>r~EqR^)AVebCb@aQb+8JjAKUEtB@0UrR&(wdkfbLh`Z=o z-jLQhvW35Fb?or5l>1SyVZle2pQ`4Y&9}kHnch_@tR*YQzZuMnP?!kwdoBAs8#CU% zGO(ws>bC9<&1Kx?T#S{aO38>M&~LMm&S6ResWaJyw3%h|q3whAu6s@HqjJ`E2ixe_ zSEo;9-|I>q8k#kTzJe6NV!Yy0YtI9^Y(JU=h$uFCbwR!8?hw$5p^Xt0|}i8GX9o@r0e|Izab0#&)MuSo)bAYIZdglL5U0-Ri)(l@ zK^$!;!Ew2LaiwEz$e{-L@pCV0G7^qd61y|pGMAQEU$*$9phq-qQC-?>8RfSl(fdqi z3;BG9kNyhByyu?ThpW^>)nFqsYp{-y<@vDf59+|FRJ6!cvOk8tkILGPx)SD8+Ze%ZSG6u7U2=4cl!P9)CSjTWSAWH z4_$O8X>)_K<=L_v&Vuezlj;-Vxmxz|@GT`6?ZCrS&vJ7It3w~3Y;WL;vZhzT4~GMH zV-F9eZ5v&GF~rDV-Fesr`Gxz?Y6jFcg$KYM-978_Nt(GGiHeO+L!REhl4<2`R;E(G zX>XG0dUhcdemBohv|;e*yEO|{;@dtCbd!V{qet{(G=yK)Q6y7?| z7BbLuhP^pky;Wy%yZ`onSlTjEaZ=EqVcm-^&dL+TcWlh{(K#5|;@ApT2p=xmDBKEM zI46Vt*iUH6UA}2T-}Ei4^53L^*HL}e`rH2QZD`*Yb>v@)PS>Yat0gaYO|FF7k&bLX z{?ZEulaa8kt!a+d)?eSN(AzXGE|cPLk*2)O^=62z{(>l_h!)zP20K#8>s59J9Bp%Z(+F5{9jCDXs9=}g0D>E36C*Ur>WPM`4C;^LZg z7I)zKPwnVQIYvPJ`Nk~bK-QXV@AIN>6(}q==lex{NE37c2|S zoX11QhdT;G_Mw@6o+jJ~&(=S>>vgsQYfqw%)wqPtjW9qatg&e+q055aJ8qO`(vh|! z*oB`8hFteJY4^yhk{)kJfM0!`^y&QA-P~;{5ky^OS+alFBtv!X=&ZC{&Q|r_s3Eym z=CWSCtpTO7Mu&=fe0_)KKIxS=EZ>-0KWEb@OxCrQ>5x8rOiLNwG`T#^eZiB)*|lE% zHO3tgA7RX3PbXs2c@2zP@eAV&k*KQU<%9gkQ(IuJY5W}KiLx?i2c*h|b~@fvXEKA! zF$9=gI%pWp;Xykg7|hf>ng=jKK_P+;2C>5_$g#RcB!bPPAia#K7%I;i3}!os`JlVl z#e*RZWssOib2GSUG#LWmfI`n_9vJ2j#Sz=3n>LbYz}Y63L^U_O(C20ovfc?la9=!^J5^8`8V93 zw7=#)qYPUcgGr1zc_aP59 z2Xq$#Qa-T+JPC)z7!!ylL>v)E_^#v$@&!;YN>Q;GL!-~g(!!9TbRcR0X{SN}GZs)b zWNSVM2)TR@E;o#Vlm>;6TFx{$!t`@l9M}R#BSzZuU%K8MjQITYc@l)NXNC}nnZ_jp zjL%L4KorQFaRk|Y9%2Lo;XxoY!@soDS2_E?l#7W0j7i3LI*I{8b;jfAP{m0`SQOoa z#lnF`MgRcC`IBP-mn9Sde9$ro$`r~5YN45I5Np4Xsr$3OC>WG7g@NWb29LrRd*E=hvHHT7l*0ev=L;SGLk|%2 zZzsRR?{B(()AdUX{F3tT?)pvFFEQ{-%D=no|BWvA_u~#24()(M&|&6}zUlzzAS6$B zvbTYKl70)$9oq{@=J6bS1TdJw66qxa%gs}TgmZ+BRNFa^<>Y70Lfcs)vZ3=X-OgNx&2mdyZ+{qlxx}<} zWkOxU_Mxe>*~x;ZO8JitgcsV$odpsHrz)a4+NuOi*f>CaOj*RNlL>tLv2#^IT)n=9 z-vfOM(8?4)$xJWh&&o<^3B7mxd2*(#dFe?$U9MFwI$QtQ@qPPGMq1UuhsV~#hHd=( zy)`YCx1Xtpop3WSA1hYOQp~vRre?q7RQ&mzevy5_i@938?6_c|Px&uSrBfRA_e|m4479{YZmVNLLoR=pv+r6hE>ns0a#i(?wmliglr@ zmUeCaKpR06EQpH~TnGwoY!#tkLj;A0y98Hls3_gJaNP7hZ*FGhy)>m$um{4+eRtl> zn=^Orc{2kzMq#z0lv1j&T2Zr08;U?S`IS9SN_mlU7Uiq`Kp2SELxoi@Nk!W3cZtJejiJ|cK%L^Q`^D<{}kSbB`pz_?- z!8tKOAXTRs5>55_<(xxDjBey@5wRD{<%_*NOc;}?5(eq^M605Ea3Fi@` z`!dyahJ%m1i8R~uGN)V~T?YVMI6txbta2YQeD@6SCq)PT3`K)!D?&z;3C<%%2i=aH zUs;)>xJt=#+z$Y+Kc{xD|8(HLSEY9^7eRa5-H`!rnmLacQWZe28d7zD#vT7wmIs%v z&D7acmvds|xsMEedF~|T-3GplD3xnklD|9}LpTKV_4FVXjbi@sa})~;?uh{!Rl@cq z+svjFPq6%GB$JMNZLPLlL1%jm?QId9`W?bNfKP*qW@5HCE8d)I6?6F_oh=#t@*GJ{ z8xuLU4K3-T12umC{<&9(p8;Znz)&v$T*Zyfhk9am6QlxwnFm|u9tXtsW(C!6AGN2E z&FruNjjBSUugg1f`;yjW9M5)cqyN`g^q%O&=|6pV3ShnKu3nW02XREZ->Rfr5Zdrz zVFBTeFhb!FB3 Date: Wed, 17 Jul 2024 04:36:25 +0000 Subject: [PATCH 244/765] Automatic changelog update --- Resources/Changelog/Changelog.yml | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index e0f8aef124b..2d6851dcc1c 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,12 +1,4 @@ Entries: -- author: Ghagliiarghii - changes: - - message: Security can now find replacements for their trusty Combat Knife in the - SecVend, or craft them with the Sec Lathe. - type: Tweak - id: 6425 - time: '2024-04-23T11:24:58.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/27224 - author: Whisper changes: - message: Fire stack limit reduced from 20 to 10. Fire transfers will be less effective, @@ -3806,3 +3798,10 @@ id: 6924 time: '2024-07-16T23:26:02.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/27879 +- author: EmoGarbage404 + changes: + - message: Resprited wall signs. + type: Tweak + id: 6925 + time: '2024-07-17T04:35:19.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/29806 From 42344fa5367ef8976984c31cbbff8ee68a1e6afe Mon Sep 17 00:00:00 2001 From: Ed <96445749+TheShuEd@users.noreply.github.com> Date: Wed, 17 Jul 2024 08:47:50 +0300 Subject: [PATCH 245/765] Character menu issuer localization (#29840) * Update CharacterUIController.cs * TODO Burn this shit * huh? * huh! --------- Co-authored-by: lzk <124214523+lzk228@users.noreply.github.com> --- .../Systems/Character/CharacterUIController.cs | 16 ++++++++++++---- .../CharacterInfo/CharacterInfoSystem.cs | 2 +- Content.Server/Objectives/ObjectivesSystem.cs | 4 ++-- .../Objectives/Components/ObjectiveComponent.cs | 7 +++++-- Resources/Prototypes/Objectives/dragon.yml | 2 +- Resources/Prototypes/Objectives/ninja.yml | 2 +- Resources/Prototypes/Objectives/thief.yml | 2 +- Resources/Prototypes/Objectives/traitor.yml | 2 +- 8 files changed, 24 insertions(+), 13 deletions(-) diff --git a/Content.Client/UserInterface/Systems/Character/CharacterUIController.cs b/Content.Client/UserInterface/Systems/Character/CharacterUIController.cs index 88edb6a4f12..1e4d2f27657 100644 --- a/Content.Client/UserInterface/Systems/Character/CharacterUIController.cs +++ b/Content.Client/UserInterface/Systems/Character/CharacterUIController.cs @@ -1,11 +1,13 @@ using System.Linq; using Content.Client.CharacterInfo; using Content.Client.Gameplay; +using Content.Client.Stylesheets; using Content.Client.UserInterface.Controls; using Content.Client.UserInterface.Systems.Character.Controls; using Content.Client.UserInterface.Systems.Character.Windows; using Content.Client.UserInterface.Systems.Objectives.Controls; using Content.Shared.Input; +using Content.Shared.Objectives.Systems; using JetBrains.Annotations; using Robust.Client.GameObjects; using Robust.Client.Player; @@ -121,11 +123,17 @@ private void CharacterUpdated(CharacterData data) Modulate = Color.Gray }; - objectiveControl.AddChild(new Label + + var objectiveText = new FormattedMessage(); + objectiveText.TryAddMarkup(groupId, out _); + + var objectiveLabel = new RichTextLabel { - Text = groupId, - Modulate = Color.LightSkyBlue - }); + StyleClasses = {StyleNano.StyleClassTooltipActionTitle} + }; + objectiveLabel.SetMessage(objectiveText); + + objectiveControl.AddChild(objectiveLabel); foreach (var condition in conditions) { diff --git a/Content.Server/CharacterInfo/CharacterInfoSystem.cs b/Content.Server/CharacterInfo/CharacterInfoSystem.cs index cb2216b5e3b..3099b2f90fc 100644 --- a/Content.Server/CharacterInfo/CharacterInfoSystem.cs +++ b/Content.Server/CharacterInfo/CharacterInfoSystem.cs @@ -43,7 +43,7 @@ private void OnRequestCharacterInfoEvent(RequestCharacterInfoEvent msg, EntitySe continue; // group objectives by their issuer - var issuer = Comp(objective).Issuer; + var issuer = Comp(objective).LocIssuer; if (!objectives.ContainsKey(issuer)) objectives[issuer] = new List(); objectives[issuer].Add(info.Value); diff --git a/Content.Server/Objectives/ObjectivesSystem.cs b/Content.Server/Objectives/ObjectivesSystem.cs index 9144a6ae57a..8ef2c9f32ed 100644 --- a/Content.Server/Objectives/ObjectivesSystem.cs +++ b/Content.Server/Objectives/ObjectivesSystem.cs @@ -129,12 +129,12 @@ private void AddSummary(StringBuilder result, string agent, List<(EntityUid, str var agentSummary = new StringBuilder(); agentSummary.AppendLine(Loc.GetString("objectives-with-objectives", ("custody", custody), ("title", title), ("agent", agent))); - foreach (var objectiveGroup in objectives.GroupBy(o => Comp(o).Issuer)) + foreach (var objectiveGroup in objectives.GroupBy(o => Comp(o).LocIssuer)) { //TO DO: //check for the right group here. Getting the target issuer is easy: objectiveGroup.Key //It should be compared to the type of the group's issuer. - agentSummary.AppendLine(Loc.GetString($"objective-issuer-{objectiveGroup.Key}")); + agentSummary.AppendLine(objectiveGroup.Key); foreach (var objective in objectiveGroup) { diff --git a/Content.Shared/Objectives/Components/ObjectiveComponent.cs b/Content.Shared/Objectives/Components/ObjectiveComponent.cs index 36d3fa0bded..fb2e6ca0a68 100644 --- a/Content.Shared/Objectives/Components/ObjectiveComponent.cs +++ b/Content.Shared/Objectives/Components/ObjectiveComponent.cs @@ -22,8 +22,11 @@ public sealed partial class ObjectiveComponent : Component ///

/// Organisation that issued this objective, used for grouping and as a header above common objectives. /// - [DataField(required: true)] - public string Issuer = string.Empty; + [DataField("issuer", required: true)] + private LocId Issuer { get; set; } + + [ViewVariables(VVAccess.ReadOnly)] + public string LocIssuer => Loc.GetString(Issuer); /// /// Unique objectives can only have 1 per prototype id. diff --git a/Resources/Prototypes/Objectives/dragon.yml b/Resources/Prototypes/Objectives/dragon.yml index 10ca942cb39..bbdac8faa1a 100644 --- a/Resources/Prototypes/Objectives/dragon.yml +++ b/Resources/Prototypes/Objectives/dragon.yml @@ -6,7 +6,7 @@ - type: Objective # difficulty isn't used at all since objective are fixed difficulty: 1.5 - issuer: dragon + issuer: objective-issuer-dragon - type: RoleRequirement roles: components: diff --git a/Resources/Prototypes/Objectives/ninja.yml b/Resources/Prototypes/Objectives/ninja.yml index c1f745d0fe4..00bf9d705b8 100644 --- a/Resources/Prototypes/Objectives/ninja.yml +++ b/Resources/Prototypes/Objectives/ninja.yml @@ -6,7 +6,7 @@ - type: Objective # difficulty isn't used since all objectives are picked difficulty: 1.5 - issuer: spiderclan + issuer: objective-issuer-spiderclan - type: RoleRequirement roles: components: diff --git a/Resources/Prototypes/Objectives/thief.yml b/Resources/Prototypes/Objectives/thief.yml index 91e26b44bf6..a623686846a 100644 --- a/Resources/Prototypes/Objectives/thief.yml +++ b/Resources/Prototypes/Objectives/thief.yml @@ -4,7 +4,7 @@ id: BaseThiefObjective components: - type: Objective - issuer: thief + issuer: objective-issuer-thief - type: RoleRequirement roles: components: diff --git a/Resources/Prototypes/Objectives/traitor.yml b/Resources/Prototypes/Objectives/traitor.yml index 4aa611aeff2..788800b7085 100644 --- a/Resources/Prototypes/Objectives/traitor.yml +++ b/Resources/Prototypes/Objectives/traitor.yml @@ -4,7 +4,7 @@ id: BaseTraitorObjective components: - type: Objective - issuer: syndicate + issuer: objective-issuer-syndicate - type: RoleRequirement roles: components: From 2256a335facc9f06ac753349589f1026ca6ca36a Mon Sep 17 00:00:00 2001 From: lzk <124214523+lzk228@users.noreply.github.com> Date: Wed, 17 Jul 2024 08:19:13 +0200 Subject: [PATCH 246/765] Add examine for caustic and cold damage (#29989) * Examinable cold damage * lightblue * update grammar * caustic --- .../en-US/health-examinable/health-examinable-carbon.ftl | 8 ++++++++ Resources/Prototypes/Entities/Mobs/base.yml | 2 ++ 2 files changed, 10 insertions(+) diff --git a/Resources/Locale/en-US/health-examinable/health-examinable-carbon.ftl b/Resources/Locale/en-US/health-examinable/health-examinable-carbon.ftl index ddd6de23673..ac536a1e25a 100644 --- a/Resources/Locale/en-US/health-examinable/health-examinable-carbon.ftl +++ b/Resources/Locale/en-US/health-examinable/health-examinable-carbon.ftl @@ -16,3 +16,11 @@ health-examinable-carbon-Heat-50 = [color=orange]{ CAPITALIZE(SUBJECT($target)) health-examinable-carbon-Heat-75 = [color=orange]{ CAPITALIZE(SUBJECT($target)) } { CONJUGATE-HAVE($target) } severe third-degree burns across { POSS-ADJ($target) } body![/color] health-examinable-carbon-Shock-50 = [color=lightgoldenrodyellow]{ CAPITALIZE(SUBJECT($target)) } { CONJUGATE-HAVE($target) } electrical shock marks across { POSS-ADJ($target) } body![/color] + +health-examinable-carbon-Cold-25 = [color=lightblue]{ CAPITALIZE(SUBJECT($target)) } { CONJUGATE-HAVE($target) } minor frostbite across { POSS-ADJ($target) } body.[/color] +health-examinable-carbon-Cold-50 = [color=lightblue]{ CAPITALIZE(SUBJECT($target)) } { CONJUGATE-HAVE($target) } major frostbite across { POSS-ADJ($target) } body.[/color] +health-examinable-carbon-Cold-75 = [color=lightblue]{ CAPITALIZE(SUBJECT($target)) } { CONJUGATE-HAVE($target) } severe third-degree frostbite across { POSS-ADJ($target) } body![/color] + +health-examinable-carbon-Caustic-25 = [color=yellowgreen]{ CAPITALIZE(SUBJECT($target)) } { CONJUGATE-HAVE($target) } minor chemical burns.[/color] +health-examinable-carbon-Caustic-50 = [color=yellowgreen]{ CAPITALIZE(SUBJECT($target)) } { CONJUGATE-HAVE($target) } chemical burns across { POSS-ADJ($target) } body.[/color] +health-examinable-carbon-Caustic-75 = [color=yellowgreen]{ CAPITALIZE(SUBJECT($target)) } { CONJUGATE-HAVE($target) } severe chemical burns all over { POSS-ADJ($target) } body![/color] diff --git a/Resources/Prototypes/Entities/Mobs/base.yml b/Resources/Prototypes/Entities/Mobs/base.yml index f3c9daeee76..a715886252b 100644 --- a/Resources/Prototypes/Entities/Mobs/base.yml +++ b/Resources/Prototypes/Entities/Mobs/base.yml @@ -99,6 +99,8 @@ - Piercing - Heat - Shock + - Cold + - Caustic - type: DamageOnHighSpeedImpact damage: types: From 7c6fc02f52bd1f2404981e818a6f120f719d7440 Mon Sep 17 00:00:00 2001 From: PJBot Date: Wed, 17 Jul 2024 06:20:20 +0000 Subject: [PATCH 247/765] Automatic changelog update --- Resources/Changelog/Changelog.yml | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 2d6851dcc1c..db39ddaacdc 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,12 +1,4 @@ Entries: -- author: Whisper - changes: - - message: Fire stack limit reduced from 20 to 10. Fire transfers will be less effective, - and fires will not last as long. - type: Tweak - id: 6426 - time: '2024-04-23T11:30:01.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/27159 - author: brainfood1183 changes: - message: Directional Exit signs for maints! @@ -3805,3 +3797,10 @@ id: 6925 time: '2024-07-17T04:35:19.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/29806 +- author: lzk228 + changes: + - message: Added health examine for caustic and cold damage. + type: Add + id: 6926 + time: '2024-07-17T06:19:13.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/29989 From 2779422cbe515a183fa3807878e4934579da947d Mon Sep 17 00:00:00 2001 From: lzk <124214523+lzk228@users.noreply.github.com> Date: Wed, 17 Jul 2024 08:26:10 +0200 Subject: [PATCH 248/765] Little saw debuff (#29995) --- .../Objects/Specific/Medical/surgery.yml | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) diff --git a/Resources/Prototypes/Entities/Objects/Specific/Medical/surgery.yml b/Resources/Prototypes/Entities/Objects/Specific/Medical/surgery.yml index c4f7798154e..8b1606dc5d3 100644 --- a/Resources/Prototypes/Entities/Objects/Specific/Medical/surgery.yml +++ b/Resources/Prototypes/Entities/Objects/Specific/Medical/surgery.yml @@ -173,12 +173,12 @@ sprite: Objects/Specific/Medical/Surgery/saw.rsi state: saw - type: Item + size: Normal sprite: Objects/Specific/Medical/Surgery/saw.rsi storedRotation: 90 - type: Tool qualities: - Sawing - speedModifier: 1.0 # No melee for regular saw because have you ever seen someone use a band saw as a weapon? It's dumb. - type: entity @@ -190,6 +190,7 @@ - type: Sprite state: improv - type: Item + size: Small heldPrefix: improv - type: MeleeWeapon damage: @@ -198,8 +199,6 @@ soundHit: path: /Audio/Weapons/bladeslice.ogg - type: Tool - qualities: - - Sawing speedModifier: 0.5 - type: entity @@ -212,7 +211,6 @@ state: electric - type: Item heldPrefix: electric - storedRotation: 90 - type: MeleeWeapon damage: groups: @@ -220,29 +218,19 @@ soundHit: path: /Audio/Items/drill_hit.ogg - type: Tool - qualities: - - Sawing speedModifier: 1.5 - type: entity name: advanced circular saw id: SawAdvanced - parent: Saw + parent: SawElectric description: You think you can cut anything with it. components: - type: Sprite state: advanced - type: Item heldPrefix: advanced - storedRotation: 90 - type: MeleeWeapon attackRate: 1.5 - damage: - groups: - Brute: 15 - soundHit: - path: /Audio/Items/drill_hit.ogg - type: Tool - qualities: - - Sawing speedModifier: 2.0 From 527b97af03735003992996ff05e40411519213f4 Mon Sep 17 00:00:00 2001 From: PJBot Date: Wed, 17 Jul 2024 06:27:16 +0000 Subject: [PATCH 249/765] Automatic changelog update --- Resources/Changelog/Changelog.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index db39ddaacdc..ec85d771e3a 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,11 +1,4 @@ Entries: -- author: brainfood1183 - changes: - - message: Directional Exit signs for maints! - type: Add - id: 6427 - time: '2024-04-23T11:31:48.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/26831 - author: pigeonpeas changes: - message: Adds the ability to purchase emitters in cargo. @@ -3804,3 +3797,10 @@ id: 6926 time: '2024-07-17T06:19:13.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/29989 +- author: lzk228 + changes: + - message: Surgery saws now are normal-sized (no more pocket circular saw). + type: Tweak + id: 6927 + time: '2024-07-17T06:26:10.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/29995 From 983ca6dd928b623777a0db801d3013d5817e5ef1 Mon Sep 17 00:00:00 2001 From: Flareguy <78941145+Flareguy@users.noreply.github.com> Date: Wed, 17 Jul 2024 02:43:11 -0500 Subject: [PATCH 250/765] Vox displacement updates (#29824) * more vox displacement maps * A * remove vox insuls sprites * sci magboots * Update vox.yml * Update meta.json --------- Co-authored-by: Ed <96445749+TheShuEd@users.noreply.github.com> --- .../Prototypes/Entities/Mobs/Species/vox.yml | 48 ++++++++++++++++++ .../Color/yellow.rsi/equipped-HAND-vox.png | Bin 387 -> 0 bytes .../Hands/Gloves/Color/yellow.rsi/meta.json | 27 +++++++++- .../equipped-OUTERCLOTHING-vox.png | Bin 0 -> 605 bytes .../open-equipped-OUTERCLOTHING-vox.png | Bin 0 -> 607 bytes .../equipped-OUTERCLOTHING-vox.png | Bin 0 -> 631 bytes .../open-equipped-OUTERCLOTHING-vox.png | Bin 0 -> 636 bytes .../equipped-OUTERCLOTHING-vox.png | Bin 0 -> 594 bytes .../open-equipped-OUTERCLOTHING-vox.png | Bin 0 -> 591 bytes .../equipped-OUTERCLOTHING-vox.png | Bin 0 -> 631 bytes .../open-equipped-OUTERCLOTHING-vox.png | Bin 0 -> 636 bytes .../equipped-OUTERCLOTHING-vox.png | Bin 0 -> 631 bytes .../open-equipped-OUTERCLOTHING-vox.png | Bin 0 -> 636 bytes .../equipped-OUTERCLOTHING-vox.png | Bin 0 -> 631 bytes .../open-equipped-OUTERCLOTHING-vox.png | Bin 0 -> 636 bytes .../combatboots.rsi/equipped-FEET-vox.png | Bin 0 -> 459 bytes .../Shoes/Boots/combatboots.rsi/meta.json | 6 ++- .../equipped-FEET-vox.png | Bin 0 -> 1164 bytes .../Boots/magboots-science.rsi/meta.json | 10 +++- .../on-equipped-FEET-vox.png | Bin 0 -> 1201 bytes .../speedboots.rsi/equipped-FEET-vox.png | Bin 0 -> 1486 bytes .../Shoes/Boots/speedboots.rsi/meta.json | 10 +++- .../speedboots.rsi/on-equipped-FEET-vox.png | Bin 0 -> 1491 bytes .../vox_parts.rsi/tail_stenciled.png | Bin 615 -> 297 bytes .../Species/Vox/displacement.rsi/back.png | Bin 0 -> 451 bytes .../Species/Vox/displacement.rsi/eyes.png | Bin 0 -> 508 bytes .../Species/Vox/displacement.rsi/hand.png | Bin 0 -> 483 bytes .../Species/Vox/displacement.rsi/meta.json | 14 ++++- .../Mobs/Species/Vox/parts.rsi/torso.png | Bin 866 -> 955 bytes 29 files changed, 110 insertions(+), 5 deletions(-) delete mode 100644 Resources/Textures/Clothing/Hands/Gloves/Color/yellow.rsi/equipped-HAND-vox.png create mode 100644 Resources/Textures/Clothing/OuterClothing/Coats/labcoat.rsi/equipped-OUTERCLOTHING-vox.png create mode 100644 Resources/Textures/Clothing/OuterClothing/Coats/labcoat.rsi/open-equipped-OUTERCLOTHING-vox.png create mode 100644 Resources/Textures/Clothing/OuterClothing/Coats/labcoat_chem.rsi/equipped-OUTERCLOTHING-vox.png create mode 100644 Resources/Textures/Clothing/OuterClothing/Coats/labcoat_chem.rsi/open-equipped-OUTERCLOTHING-vox.png create mode 100644 Resources/Textures/Clothing/OuterClothing/Coats/labcoat_cmo.rsi/equipped-OUTERCLOTHING-vox.png create mode 100644 Resources/Textures/Clothing/OuterClothing/Coats/labcoat_cmo.rsi/open-equipped-OUTERCLOTHING-vox.png create mode 100644 Resources/Textures/Clothing/OuterClothing/Coats/labcoat_gene.rsi/equipped-OUTERCLOTHING-vox.png create mode 100644 Resources/Textures/Clothing/OuterClothing/Coats/labcoat_gene.rsi/open-equipped-OUTERCLOTHING-vox.png create mode 100644 Resources/Textures/Clothing/OuterClothing/Coats/labcoat_sci.rsi/equipped-OUTERCLOTHING-vox.png create mode 100644 Resources/Textures/Clothing/OuterClothing/Coats/labcoat_sci.rsi/open-equipped-OUTERCLOTHING-vox.png create mode 100644 Resources/Textures/Clothing/OuterClothing/Coats/labcoat_viro.rsi/equipped-OUTERCLOTHING-vox.png create mode 100644 Resources/Textures/Clothing/OuterClothing/Coats/labcoat_viro.rsi/open-equipped-OUTERCLOTHING-vox.png create mode 100644 Resources/Textures/Clothing/Shoes/Boots/combatboots.rsi/equipped-FEET-vox.png create mode 100644 Resources/Textures/Clothing/Shoes/Boots/magboots-science.rsi/equipped-FEET-vox.png create mode 100644 Resources/Textures/Clothing/Shoes/Boots/magboots-science.rsi/on-equipped-FEET-vox.png create mode 100644 Resources/Textures/Clothing/Shoes/Boots/speedboots.rsi/equipped-FEET-vox.png create mode 100644 Resources/Textures/Clothing/Shoes/Boots/speedboots.rsi/on-equipped-FEET-vox.png create mode 100644 Resources/Textures/Mobs/Species/Vox/displacement.rsi/back.png create mode 100644 Resources/Textures/Mobs/Species/Vox/displacement.rsi/eyes.png create mode 100644 Resources/Textures/Mobs/Species/Vox/displacement.rsi/hand.png diff --git a/Resources/Prototypes/Entities/Mobs/Species/vox.yml b/Resources/Prototypes/Entities/Mobs/Species/vox.yml index 4d5239e50c5..02e2791e354 100644 --- a/Resources/Prototypes/Entities/Mobs/Species/vox.yml +++ b/Resources/Prototypes/Entities/Mobs/Species/vox.yml @@ -26,6 +26,30 @@ layerKey: dummy parameterTexture: displacementMap parameterUV: displacementUV + eyes: + layer: + sprite: Mobs/Species/Vox/displacement.rsi + state: eyes + copyToShaderParameters: + layerKey: dummy + parameterTexture: displacementMap + parameterUV: displacementUV + gloves: + layer: + sprite: Mobs/Species/Vox/displacement.rsi + state: hand + copyToShaderParameters: + layerKey: dummy + parameterTexture: displacementMap + parameterUV: displacementUV + back: + layer: + sprite: Mobs/Species/Vox/displacement.rsi + state: back + copyToShaderParameters: + layerKey: dummy + parameterTexture: displacementMap + parameterUV: displacementUV - type: Speech speechVerb: Vox speechSounds: Vox @@ -124,4 +148,28 @@ layerKey: dummy parameterTexture: displacementMap parameterUV: displacementUV + eyes: + layer: + sprite: Mobs/Species/Vox/displacement.rsi + state: eyes + copyToShaderParameters: + layerKey: dummy + parameterTexture: displacementMap + parameterUV: displacementUV + gloves: + layer: + sprite: Mobs/Species/Vox/displacement.rsi + state: hand + copyToShaderParameters: + layerKey: dummy + parameterTexture: displacementMap + parameterUV: displacementUV + back: + layer: + sprite: Mobs/Species/Vox/displacement.rsi + state: back + copyToShaderParameters: + layerKey: dummy + parameterTexture: displacementMap + parameterUV: displacementUV diff --git a/Resources/Textures/Clothing/Hands/Gloves/Color/yellow.rsi/equipped-HAND-vox.png b/Resources/Textures/Clothing/Hands/Gloves/Color/yellow.rsi/equipped-HAND-vox.png deleted file mode 100644 index b7f2122c19f5bb439cf0bb625613b5526410247e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 387 zcmV-}0et?6P)NklmZ0Zoi)+R&{1ZRto1s9U+%*3oL z|6i3N?}NviG!qd30000006aTv`>M;hp8{W$Zmz?&uL57}>j%Clm5GW%Pb*mzdP-$t z-9#7ldrdFIi7TVQL#Mus1`ml7S1abP>Q@dR@I}oQ#q;UfIHxD&`?E!nM=SVE>VL1F z%{RdI7_3)A?e#B3p{LfXq1_SK>^$x1mrmE7Y<8YeZ0UYE%Ve56Cb5%g?%XeDtNH){ z000000001JJSZaZ0 h2E3{s006+h_XW$Kw~dZe6Egq+002ovPDHLkV1hjUu0sF- diff --git a/Resources/Textures/Clothing/Hands/Gloves/Color/yellow.rsi/meta.json b/Resources/Textures/Clothing/Hands/Gloves/Color/yellow.rsi/meta.json index ccb1c5dcaf3..88e3ebd509d 100644 --- a/Resources/Textures/Clothing/Hands/Gloves/Color/yellow.rsi/meta.json +++ b/Resources/Textures/Clothing/Hands/Gloves/Color/yellow.rsi/meta.json @@ -1 +1,26 @@ -{"version": 1, "license": "CC-BY-SA-3.0", "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e", "size": {"x": 32, "y": 32}, "states": [{"name": "icon"}, {"name": "equipped-HAND", "directions": 4}, {"name": "inhand-left", "directions": 4}, {"name": "inhand-right", "directions": 4}, {"name": "equipped-HAND-vox", "directions": 4}]} +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "icon" + }, + { + "name": "equipped-HAND", + "directions": 4 + }, + { + "name": "inhand-left", + "directions": 4 + }, + { + "name": "inhand-right", + "directions": 4 + } + ] +} diff --git a/Resources/Textures/Clothing/OuterClothing/Coats/labcoat.rsi/equipped-OUTERCLOTHING-vox.png b/Resources/Textures/Clothing/OuterClothing/Coats/labcoat.rsi/equipped-OUTERCLOTHING-vox.png new file mode 100644 index 0000000000000000000000000000000000000000..a6546c4655791eb62a6a1dc791e48b35ce2c0d69 GIT binary patch literal 605 zcmV-j0;2tiP)Px#Ay7kc0#L>~w|Ns9?OiYT3ib6s{Yinx&003qr5lR3601I?d zPE-H?|NsC0|NsC007_2*@&Et<(@8`@R9J=Wmf>=QAPj^zAzYF7f8cKPtSE$Qr_<^E zkQq;KlkXy7Oi+J0a070@`vLHR3Gs2(n-!qzT`@*bPiB_R`Z1@ReT7Vu;os+dv_YWN zjRf#FOHXM0Px=AKv|tRpI2!=6=+j+WeV;)LG)SPo!nzP#w=IZuh7OS6zQRbwryal_ zJ^?5F3&5>KO7f6I5nUoyUG@!V^ixLob|0dH9o%1|%fSV}@El@6a~hq*&A^IX3|id{Tn+)ru;5~F z()Te0cye*v283g@PlvWY7&qVs+PyJ8es%%#MsCzfj<`3f42$i0vBv!G>QO)IkaJK*$k1qM0>Dgk?!I30c(7T z0EMOhCBWN*FpZ?o0I+I&1&t%%8K6m=g=$(Qm-r->ELE)r0Pu)#3kzZZNDv;kaeuIN rQE*ZKaBb3LO?r!o&D(uc{{ip`AWe)kacVDD00000NkvXXu0mjfsYwhK literal 0 HcmV?d00001 diff --git a/Resources/Textures/Clothing/OuterClothing/Coats/labcoat.rsi/open-equipped-OUTERCLOTHING-vox.png b/Resources/Textures/Clothing/OuterClothing/Coats/labcoat.rsi/open-equipped-OUTERCLOTHING-vox.png new file mode 100644 index 0000000000000000000000000000000000000000..2ecf1e68e01feba062c1a6211aeffa70f38d4e08 GIT binary patch literal 607 zcmV-l0-*hgP)Px#Ay7kc0#L>~w|Ns9?OiV&TLW+utYinx&000#r5c&WB01I?d zPE-H?|NsC0|NsC007_2*@&Et<)k#D_R9J=WmeG>KAP7YPv8Mk22k*r+twylBv$L~( zh%;?e;N%)jfa)(BU4RSlc>sFDB(^r%yAhGJtB{X?J*jFM?XNz}*+!J%;@&>Fr>%T z2OP}>JU4ef1W)_X`dQca2kin}fD7<9fN${D5#%JbwZkddt7Ygdiry@B>nUUyaBew1 zP(dyAuM-QhW6~`GZ1`TEQ_~qBBwO$-F}aDQ@C5)#Dcc$&0HFjCjsenYgq4C;JV*#Y z-5@C;y?OB!(7s^8yCS0>`@tz+@3tx3=tBdqklE=JV_X zkhKDN3t+j&3huI0Kw1?`SSi2~;1upcRjHg;3NlyG8UP4KggKWQE2t&ov}&K<$0dlg tV;a7VwhwWUwU-cnZ0z%KAJu;Vd;vVhjos4wY9Igr002ovPDHLkV1i-b1KPx#Do{*RMUjz_^z`)Q<>kc0#L>~ws7wa`|NsAx8O&x5OiWCQii$!)LThVl0001S zowS$$000hjQchF<|NsC0|NsC0|NsC007byu$N&HV;Ymb6R9J=Wmf^CTAPj|*5F#!5 z{;%5;_qu`*x1CO>_lKELfs=d_#4(}mFO43+1NeRb`oJW1>-APinj)0z2HTC*A z&XUY$WJ&TQK8qd3js6DYrI><1xR+%lxPDlxzX4R>fE;jHDdQ%fA1O$yA0uM*91|g4 zvhtPSy7FrS+UjpWB9CQaV;>FxU;F}e`Wt{(ODXXWP7rB0h+Y2zbb5CpCj66SNdMf% z0caO{2V`I|K%Br50iZK7;ETtptAM~FI{%OW5SEH71b_h306+=4u6`TN;H9UXfRDM= zsdvz-7l&4N2bV)YQd;Ta(CLRw0e-l2J|=|I+SRG=AJ_wU01x2b0DgmaA3^p3F*sa` zy?TWX8D4smUP8JFo7@ogc)2Moxh!U=kijnv|1=a|v!%4f{{mQKO!D;g4ayP&h)c;R zUN;$-40YODHpXmg^bS^I9u}_)sPQ!dRFwXY0B;Y%V+8#UK)NZmAaMrhVc-&PGUSXveKp-%BqY~U=0l>AJChMlRxbgXRKh^&L_ywV(wnZXP R>ev7P002ovPDHLkV1mO^AZ`Ev literal 0 HcmV?d00001 diff --git a/Resources/Textures/Clothing/OuterClothing/Coats/labcoat_chem.rsi/open-equipped-OUTERCLOTHING-vox.png b/Resources/Textures/Clothing/OuterClothing/Coats/labcoat_chem.rsi/open-equipped-OUTERCLOTHING-vox.png new file mode 100644 index 0000000000000000000000000000000000000000..bcf14c7791d1cf37c5c8c33f52062cc0041f49ad GIT binary patch literal 636 zcmV-?0)zdDP)Px#Do{*RMUjz_^z`)Q<>kc0#L>~ws7wa`|NsAx8O&x5OiWBdLPCm)ife0Y00002 znYAbY000hjQchF<|NsC0|NsC0|NsC007byu$N&HV=1D|BR9J=WmSJ38t^s>KlL(96~I3#gvXkKwndkR$rfp)p864 z@iHmz38pJQ3eZ;H0D%axRzkGL1Hd+)fKJ~4_-H}6l^f#gY6md=3F!3hM5JaQ-bHu; z+Rfg~CDgl?d z)v0sHSm)lM)$OZb@h$*Dc)pJTs|^9$;T|u+rmxoS4t;-M7vKV1fWHBJgLfW5@eShO zuxs{e9eVMi7i-CK|(-#8^srF=YSE5z21lnFo;=;9}}|O z0x=)AFJPf8aJ-KI*v!H@oGlxxgQS}Q^M3aLkn;@WEr8|jXKPx#8&FJCMI>T+aJbV{tIIKjpg^I;e81KiL{uSKZ~y=R#{02s00009bW%=J|NsC0 z|NsC008>wR5&!@J&`Cr=R9J=Wmf>=QAPj^zAt3Mn#NFsw5eRLk)9L+?8BcJN?;>GL zP=7h_03N{m0q_MA;^VG2D?sZT-!s?84) z0V-N}g#Z#bEC3);x6OZs92|Pu2|Ubcb`lQ*E7lpbx*ND00+L}vXK>TcF$H*Xaor|_ zYqU?Nwm%pT-~l{AsTNW7}_77O&O9Ut^{a*sSJqXiC z`U(K6##hid0-gby#964ORdR_>V#!j~Y5)L_2)D2x27mPx#8&FJCMI>T+aJbV{tIIKjpg^I;e81KiL{t_#NdN!<_VsVC00009bW%=J|NsC0 z|NsC008>wR5&!@J%}GQ-R9J=Wmf?=vAPj`%tE%e#2-0o<+h2x2 zVoU$aCJ*2N{5*hs!xZ(l+NY5S#uXAHXfI|~R{K|<=ISGmTLAVF6W!(1Q0??r#*n;y0PEce3+FhM$B0&r!C}8nH zA^_TYqeliHfz1+t6vI#eyY0ctUIu}OxkM*%I5dvi>M+~=Rq*%}Ktp+7W5C%$z-M#s zhu~vB+dLck{y}>H58wg(8^CYy_7M^!wY|e7*_&tRl;K&U*d=5cXvKyw;;~OG%#OT8 z2B1K>rluy-J8UHuw2) dAJzW=_ysa@a!sBdwLky>002ovPDHLkV1nRp1-SqK literal 0 HcmV?d00001 diff --git a/Resources/Textures/Clothing/OuterClothing/Coats/labcoat_gene.rsi/equipped-OUTERCLOTHING-vox.png b/Resources/Textures/Clothing/OuterClothing/Coats/labcoat_gene.rsi/equipped-OUTERCLOTHING-vox.png new file mode 100644 index 0000000000000000000000000000000000000000..03a4e52f7b9fb145ea77ab8dd02ca45bdb65bf03 GIT binary patch literal 631 zcmV--0*L*IP)Px#Do{*RMUjz_^z`)Q<>kc0#L>~wCu@TL|NkSp?JbzROiWCQii$!)LThVl0000H zHD{{;000hjQchF<|NsC0|NsC0|NsC007byu$N&HV;Ymb6R9J=Wmf^CTAPj|*5F#!5 z{;%5;_qu`*x1CO>_lKELfs=d_#4(}mFO43+1NeRb`oJW1>-APinj)0z2HTC*A z&XUY$WJ&TQK8qd3js6DYrI><1xR+%lxPDlxzX4R>fE;jHDdQ%fA1O$yA0uM*91|g4 zvhtPSy7FrS+UjpWB9CQaV;>FxU;F}e`Wt{(ODXXWP7rB0h+Y2zbb5CpCj66SNdMf% z0caO{2V`I|K%Br50iZK7;ETtptAM~FI{%OW5SEH71b_h306+=4u6`TN;H9UXfRDM= zsdvz-7l&4N2bV)YQd;Ta(CLRw0e-l2J|=|I+SRG=AJ_wU01x2b0DgmaA3^p3F*sa` zy?TWX8D4smUP8JFo7@ogc)2Moxh!U=kijnv|1=a|v!%4f{{mQKO!D;g4ayP&h)c;R zUN;$-40YODHpXmg^bS^I9u}_)sPQ!dRFwXY0B;Y%V+8#UK)NZmAaMrhVc-&PGUSXveKp-%BqY~U=0l>AJChMlRxbgXRKh^&L_ywV(wnZXP R>ev7P002ovPDHLkV1l!}AL#%9 literal 0 HcmV?d00001 diff --git a/Resources/Textures/Clothing/OuterClothing/Coats/labcoat_gene.rsi/open-equipped-OUTERCLOTHING-vox.png b/Resources/Textures/Clothing/OuterClothing/Coats/labcoat_gene.rsi/open-equipped-OUTERCLOTHING-vox.png new file mode 100644 index 0000000000000000000000000000000000000000..1824ac30a7f61de5020079eb92140e45a50265e5 GIT binary patch literal 636 zcmV-?0)zdDP)Px#Do{*RMUjz_^z`)Q<>kc0#L>~wCu@TL|NkSp?JbzROiWBdLPCm)ife0Y0001D zF=iV8000hjQchF<|NsC0|NsC0|NsC007byu$N&HV=1D|BR9J=WmSJ38t^s>KlL(96~I3#gvXkKwndkR$rfp)p864 z@iHmz38pJQ3eZ;H0D%axRzkGL1Hd+)fKJ~4_-H}6l^f#gY6md=3F!3hM5JaQ-bHu; z+Rfg~CDgl?d z)v0sHSm)lM)$OZb@h$*Dc)pJTs|^9$;T|u+rmxoS4t;-M7vKV1fWHBJgLfW5@eShO zuxs{e9eVMi7i-CK|(-#8^srF=YSE5z21lnFo;=;9}}|O z0x=)AFJPf8aJ-KI*v!H@oGlxxgQS}Q^M3aLkn;@WEr8|jXKPx#Do{*RMUjz_^z`)Q<>kc0#L>~wSO94M|Nof)nQ;JwOiWCQii$!)LThVl0001v zsbEF`000hjQchF<|NsC0|NsC0|NsC007byu$N&HV;Ymb6R9J=Wmf^CTAPj|*5F#!5 z{;%5;_qu`*x1CO>_lKELfs=d_#4(}mFO43+1NeRb`oJW1>-APinj)0z2HTC*A z&XUY$WJ&TQK8qd3js6DYrI><1xR+%lxPDlxzX4R>fE;jHDdQ%fA1O$yA0uM*91|g4 zvhtPSy7FrS+UjpWB9CQaV;>FxU;F}e`Wt{(ODXXWP7rB0h+Y2zbb5CpCj66SNdMf% z0caO{2V`I|K%Br50iZK7;ETtptAM~FI{%OW5SEH71b_h306+=4u6`TN;H9UXfRDM= zsdvz-7l&4N2bV)YQd;Ta(CLRw0e-l2J|=|I+SRG=AJ_wU01x2b0DgmaA3^p3F*sa` zy?TWX8D4smUP8JFo7@ogc)2Moxh!U=kijnv|1=a|v!%4f{{mQKO!D;g4ayP&h)c;R zUN;$-40YODHpXmg^bS^I9u}_)sPQ!dRFwXY0B;Y%V+8#UK)NZmAaMrhVc-&PGUSXveKp-%BqY~U=0l>AJChMlRxbgXRKh^&L_ywV(wnZXP R>ev7P002ovPDHLkV1k@)9`*nL literal 0 HcmV?d00001 diff --git a/Resources/Textures/Clothing/OuterClothing/Coats/labcoat_sci.rsi/open-equipped-OUTERCLOTHING-vox.png b/Resources/Textures/Clothing/OuterClothing/Coats/labcoat_sci.rsi/open-equipped-OUTERCLOTHING-vox.png new file mode 100644 index 0000000000000000000000000000000000000000..d4813efe64e46dd392b9ec7b2968c53803304ff3 GIT binary patch literal 636 zcmV-?0)zdDP)Px#Do{*RMUjz_^z`)Q<>kc0#L>~wSO94M|Nof)nQ;JwOiWBdLPCm)ife0Y0002} ztzq^6000hjQchF<|NsC0|NsC0|NsC007byu$N&HV=1D|BR9J=WmSJ38t^s>KlL(96~I3#gvXkKwndkR$rfp)p864 z@iHmz38pJQ3eZ;H0D%axRzkGL1Hd+)fKJ~4_-H}6l^f#gY6md=3F!3hM5JaQ-bHu; z+Rfg~CDgl?d z)v0sHSm)lM)$OZb@h$*Dc)pJTs|^9$;T|u+rmxoS4t;-M7vKV1fWHBJgLfW5@eShO zuxs{e9eVMi7i-CK|(-#8^srF=YSE5z21lnFo;=;9}}|O z0x=)AFJPf8aJ-KI*v!H@oGlxxgQS}Q^M3aLkn;@WEr8|jXKPx#Do{*RMUjz_^z`)Q<>kc0#L>~w6k`Pc|NkMV8W)ESOiWCQii$!)LThVl0000l zKkvK%000hjQchF<|NsC0|NsC0|NsC007byu$N&HV;Ymb6R9J=Wmf^CTAPj|*5F#!5 z{;%5;_qu`*x1CO>_lKELfs=d_#4(}mFO43+1NeRb`oJW1>-APinj)0z2HTC*A z&XUY$WJ&TQK8qd3js6DYrI><1xR+%lxPDlxzX4R>fE;jHDdQ%fA1O$yA0uM*91|g4 zvhtPSy7FrS+UjpWB9CQaV;>FxU;F}e`Wt{(ODXXWP7rB0h+Y2zbb5CpCj66SNdMf% z0caO{2V`I|K%Br50iZK7;ETtptAM~FI{%OW5SEH71b_h306+=4u6`TN;H9UXfRDM= zsdvz-7l&4N2bV)YQd;Ta(CLRw0e-l2J|=|I+SRG=AJ_wU01x2b0DgmaA3^p3F*sa` zy?TWX8D4smUP8JFo7@ogc)2Moxh!U=kijnv|1=a|v!%4f{{mQKO!D;g4ayP&h)c;R zUN;$-40YODHpXmg^bS^I9u}_)sPQ!dRFwXY0B;Y%V+8#UK)NZmAaMrhVc-&PGUSXveKp-%BqY~U=0l>AJChMlRxbgXRKh^&L_ywV(wnZXP R>ev7P002ovPDHLkV1hUg9#sGU literal 0 HcmV?d00001 diff --git a/Resources/Textures/Clothing/OuterClothing/Coats/labcoat_viro.rsi/open-equipped-OUTERCLOTHING-vox.png b/Resources/Textures/Clothing/OuterClothing/Coats/labcoat_viro.rsi/open-equipped-OUTERCLOTHING-vox.png new file mode 100644 index 0000000000000000000000000000000000000000..ca6d049a1fdc15f1510c661ad2cab63128e38574 GIT binary patch literal 636 zcmV-?0)zdDP)Px#Do{*RMUjz_^z`)Q<>kc0#L>~w6k`Pc|NkMV8W)ESOiWBdLPCm)ife0Y00017 zJMIhs000hjQchF<|NsC0|NsC0|NsC007byu$N&HV=1D|BR9J=WmSJ38t^s>KlL(96~I3#gvXkKwndkR$rfp)p864 z@iHmz38pJQ3eZ;H0D%axRzkGL1Hd+)fKJ~4_-H}6l^f#gY6md=3F!3hM5JaQ-bHu; z+Rfg~CDgl?d z)v0sHSm)lM)$OZb@h$*Dc)pJTs|^9$;T|u+rmxoS4t;-M7vKV1fWHBJgLfW5@eShO zuxs{e9eVMi7i-CK|(-#8^srF=YSE5z21lnFo;=;9}}|O z0x=)AFJPf8aJ-KI*v!H@oGlxxgQS}Q^M3aLkn;@WEr8|jXKP?JF$l#Tb;P-727J`LJk80vK|G)TYev2dhp$L59JnH} zW;4(4MIC>y_cd$0L8Uh+?D;hS^*IUmEh z=f-}^h1YET8Y5Wv_@l()iyRCaZoh5XFP*hBW>^3B@|rk3hK9or1JZxUe=?GIP-=F# zY&Y*YekqHYK2h4$Hgff6xFw5M??0!Gf3vBTi$>gTe~DWM4fH95vr literal 0 HcmV?d00001 diff --git a/Resources/Textures/Clothing/Shoes/Boots/combatboots.rsi/meta.json b/Resources/Textures/Clothing/Shoes/Boots/combatboots.rsi/meta.json index 8eb6b8a626a..b0c4419ddae 100644 --- a/Resources/Textures/Clothing/Shoes/Boots/combatboots.rsi/meta.json +++ b/Resources/Textures/Clothing/Shoes/Boots/combatboots.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Made by @ninruB#7795, based off tgstation's jackboots at commit https://github.com/tgstation/tgstation/commit/7e4e9d432d88981fb9bb463970c5b98ce85c0abe", + "copyright": "Made by @ninruB#7795, based off tgstation's jackboots at commit https://github.com/tgstation/tgstation/commit/7e4e9d432d88981fb9bb463970c5b98ce85c0abe. Vox state modified from jackboots.rsi by Flareguy", "size": { "x": 32, "y": 32 @@ -14,6 +14,10 @@ "name": "equipped-FEET", "directions": 4 }, + { + "name": "equipped-FEET-vox", + "directions": 4 + }, { "name": "inhand-left", "directions": 4 diff --git a/Resources/Textures/Clothing/Shoes/Boots/magboots-science.rsi/equipped-FEET-vox.png b/Resources/Textures/Clothing/Shoes/Boots/magboots-science.rsi/equipped-FEET-vox.png new file mode 100644 index 0000000000000000000000000000000000000000..dc22be4ac27c8b1e5023a512df3b885eb36a0423 GIT binary patch literal 1164 zcmV;71atd|P)Px(MoC0LRCt{2+D}YeMI6BK@2rhRpz^0hTcHG4+NH+CrlApbNt8lGAYh^`jR#pw zj7>11scmAaJ$R@zrY()cKRtNhZH<2*jR}!O6kEL%OenUErmX2>*9Sx??b`*HU}9xF zEIg@c%wU#_&gZguGn4uK=J#gbWd<}&(=<)fG)>bqP17_@(=<)f{wIX$z$X782_S?d zJu?OS<_$gwyeFRXx5&(_EM}tfEJzmuNx(RvJg;*6=0j3S!5Y^s)@Gy;i$)1_zAc)X zUy_+w>xkNONa+ILjB#8!{u-s={)6)IonF$?(gBFaXZYmfvj9w8k5RF+>b5>14oIW( zRMLv@eDi);Q(xme|2!EXI69VyKNV%i_J?`Ex5eofNU8b~lnU_e&}U3f{XjSzrmd|V zfQ5xW5}op|aj(DDLP4P$(==74Rd!3>ohU34i3^wf?Y8~}?jatZUF-*`zOmH`@Mvj0 zF7Z20);)_gISs(Z4LOUy4>CJ5%k0c7FSZe*OfCM2Z z-dae19~5sb#3kpMi_HTt{GAEhr97`v0RqMe(OF|i|NXfjAr=`Y>-shVK;_gUG|Vq> zUtSJEfN@>W+~-f~H{gtMTo^S0*|b>n*qBAn)gl14T`l0L^@7a8JP-n7Ds4sal?FC8 zHcEiGc$}*0Mlv!|Ie%`DfYC0R{0C*lP9L$EIR-xeh}5(+0J^%ml2(M}@pnD(G?8(O z=*>7rXS?t>AC#HvQpw-6i7&tSbj9&qDucY`b)=?jBx>87e)kxcE?*&FvF*MXmk=xBR)13heAcFC@n+j$s%!VK znmeFB*v%`i9^=;;8#5dMpg-8{=sEW;lW=M!1&b z+ab%fjlDsU+s(zP?YIl_F^ePg2fOJq+_*i7Hh>`KmFHa1n|iC`eQAaxn4uBp9Dc&G zC@HJrm&qTUaTAusg`uIO?gDRVsm#sGbDlTkY+-nCfTgy%c-$$%{?-?iV=LVcSYn0~ z6_46BUSBo4_wHk}$II~G027www3U=qtz=pyC1q9Y-n$R4ubK(VVt8Px(Ye_^wRCt{2+Fxu_RUE+a@2!i5ZLmN5mu(pxNVetWiMw+db#x_dDlz&%H0_fTAdhq9}@@D2k#eilQirqA1G$geE(%J+NBzE3)TfmHIqF7ezNAH~Hb0HjjW9R2b*0I|sgtJgF>)Te13LhtU( zTM=Ff?i9@%o9*Wt6A}7`N3;23ah_TE1PlGk?S2g*WM6_*0VZA7xGV|?hlknb-3CA= zb1&N|{uuXZxC?KEhuE@FnXuCCibu1BMIdnC5O*Hx&+r(jRC1;tg#5paKLWBIA@#))E5N#-672c7{1s zOVBjXCpCg!2lDz4IHK><^yZLgpDB7`)TB4O41n73QeK#+QC3q0nuZ=L&MCjtz_zwF z0gz6mXl!buw6utUQ-g%`gIarFmsq{VPhvVv|2JPyR9p-|Pft(Yitu3mb?Y|~88?Yf zrO>+%YJuP`Q8u@T>dH#K`}V7x^GkgKzJ?Zx3KtW%EDnG49v3cNBBUSG07Ci!?c${i z9R6@Gam!*>VFmRK8~@=_|C-;wj;Lu8w=BlYpY6p1=-mgjgq3D&rax+$`2B11nqN^A zMNt$*Q4~c{6h%=KMNt&xKOv{%tCkHL#Ju?)`&pkk9eU7?jy^K;RAg zjQZBiVNUe*<@bI7fZOdB^X7YKX>GCFO3DlE3H2QRUI4UhUi+^s9-ympulDCWJ397= zhKAMlm=nF=b{k@3WJGEn(vx+&-J-6pg_z60Tj3!b9cKB|lK?oERx`V#oStzVZ-s}> z;QRkd5jwix6yfMFZIuCjowhK>A^=>Od)c1T!mCb(hE5<`0O=j@R?XYAdNaUNl+LOI z*Lp%{CIDz%n1SDtJaT4p?yJf{?a>v~vVzuUlRyEz!`WLQhl1H1kSOqi7kVda35>K$ z#gs0<=bR)_m`!914PcC%=h~=2(}tHw6jo!5MKHAUTr-RumnHAr(RWzpbn;VdCC;VQ z7@i0x`;O70J8`OZcjFI#9IegSKSykW2FB4bnaZ%Ic?9fnN zKLcM~ov5g)vY!_%S^o-v7i9eoJL<%EAoeM3 P00000NkvXXu0mjfZD>iO literal 0 HcmV?d00001 diff --git a/Resources/Textures/Clothing/Shoes/Boots/speedboots.rsi/equipped-FEET-vox.png b/Resources/Textures/Clothing/Shoes/Boots/speedboots.rsi/equipped-FEET-vox.png new file mode 100644 index 0000000000000000000000000000000000000000..ff5c3a05894c08d233f91a43833a7b7c4ca78afb GIT binary patch literal 1486 zcma)+X*ARe0LB0FFs30p)0r8|L~<-yvW$H<9Px%GWO<5b#t>3N)|q(`qLd~39wwBO zNS3VG#+D{a#4trnwkD0`;dvk5xA)=x?z#7z`}N+%I$};j;ZOhoPTJX8IUl>(zk+~| zSxpR`0{~DE(b5u2^z{V*rL?d#WBYEbM1pLfb(Ivqv=vgzKh)n`qQ{BNbS}s7wPz_h zxTBt->_kH)J(0Zp@83P|q?FV!tK}fca*Iprlc&W-8!S>7h~Sa#=#6M}Bu{B(kVM<2 zl7#)+{9N0B`kNeg&Uw);E8>|f9V3Ejq2t!ZUQ>nn$Nc!!?W4Bl8XZCuSo;-37?H{r zplg@A#9+26uhX3Rm*R!vS+#;nF;%3tuHTb6lH`lu9SOat@~D7a_(b58Qj_%pd10>1 zOP9Rt)s()6ue+6N(LW@55U>VS zFNdnEZ24rO|Og`6xWMn*d6g}V8f;f~_l7QZ^D8>HQT2cO58LD)j7E{TcVJV09 z&bP5F`aMI@pk7kllwTktj?U~@s3Eu6$V zil7AWoEDwX^VzfK_(gbxFD6dD1$Bfp0=7Ad@|9Jw{Gh}H(un@5kXzOnj~})%^MpnX zhjZD!$5eh~ag-fshp2PP1C>y|D8AibEpgo5AUPZkWFABDb5z&;WcMKiX-GRr3XjVK z4fIy__79h==uO>3!o|fEfE)T^m3Mi1vJ;Xhza%x~$r|m6o)g7^bcf%l2Y3PLO(S6g zG8dV6QM2#>pF-cexw7XB#wkDQ2=h9Z8Y@gS(Z3rs12pX#RpFAEo4cNBvv`#>NJ3&_ zG~S|x{G%65^NDI&(JfjQHH|scgW-t^VxV;Oh^p)oc5_5gA7fiZ0#iTLc%PUDrxNq> zf@Y561+Vto%aKjBGatczY#65gxMHxw2EV=pW6xzbM77BrP6oxUj4~JvVz`&x1VAg9NIN$zHh|66l<5!bH;UJG3@AA?c!hCl`MxkY1?hL1ri>u)vj zy3fT>$J4T#tDg!Z`B1#%`gcXFx;GjE9fPZI!&G`dthn7JC3Eau1%D^iwyv?cOO~d- zx%fVoSt8Kdg658gDQ4)W4ZnV&s#9roeA1K|#8AUgLymYG(k>wHFnOh&X@OffVwv3W@GEQ`~D7f^wX-{qr zlYdN=ZqR70cp!A0v%4AfSX&$qGMH8xj;FB{BDTIAriB^y88*lylFZ5qd3H+N%0qK_ zrkY*NARy$=Wmg%~rN^A*ij-UQ!$XsHlgO^K*|iD29$cs(+1Tboh{(|zj2uFMDd_*= zef40h&W{*u@?c~Cs*oAvFBTeLEUk|bPC-ylaLUHRkWO50!<6pxo4E z74bdYUj~nNg`d1JuEpk~oVp;xArP+SlIP^t^@vpWXJC=kZTMtZl}io42+&ziUG91j j9^TowreTDd89x&6eY%8&L5xO@e;Tl}cC@OsxN`d+GJ(20 literal 0 HcmV?d00001 diff --git a/Resources/Textures/Clothing/Shoes/Boots/speedboots.rsi/meta.json b/Resources/Textures/Clothing/Shoes/Boots/speedboots.rsi/meta.json index 3aa61e31c5a..7c3599192c9 100644 --- a/Resources/Textures/Clothing/Shoes/Boots/speedboots.rsi/meta.json +++ b/Resources/Textures/Clothing/Shoes/Boots/speedboots.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC0-1.0", - "copyright": "Created by EmoGarbage404", + "copyright": "Created by EmoGarbage404. Vox states made by Flareguy, modified from magboots.rsi", "size": { "x": 32, "y": 32 @@ -15,6 +15,14 @@ "name": "on-equipped-FEET", "directions": 4 }, + { + "name": "equipped-FEET-vox", + "directions": 4 + }, + { + "name": "on-equipped-FEET-vox", + "directions": 4 + }, { "name": "icon" }, diff --git a/Resources/Textures/Clothing/Shoes/Boots/speedboots.rsi/on-equipped-FEET-vox.png b/Resources/Textures/Clothing/Shoes/Boots/speedboots.rsi/on-equipped-FEET-vox.png new file mode 100644 index 0000000000000000000000000000000000000000..66ae1ee7e843910fe716687d850b1bc9a1914684 GIT binary patch literal 1491 zcma)+Z9EeQ0LHhrwxw&N72(Rub*)-UjFi;O$V)avWwn+{Ha3?_BV(H;u6BwXYUJ%~ z8Z`_lugkn;g_4*1DK@)HXR^>j6X!nOxBKus&+qsD@O*lH&kaAqk#z=U1^@tHotGy* zU?s8t3Ibp#?uyH=&QE!XPkmEWvM0XrsdfCsX=Swo*Eqgjd^6ZoTX(s zT?G~X#y~WFLLz*ca_)JCS6!YZ&DyVT!PB;7IUEc_-6u?IzdjMV_U9x`=$0Gn${fPt zAed^Hq4_P%S_P)~c>IxR(WMgq&i6@%NovV=$arydV+--->_+ynNkUk=RdHPSg4saC z5b}w;ime(cB0I9j{VA_6W?d8&GZj?_XtAUfz+wsWreYTQ8YSt09`v0w{NSz{=uRYmNA9Wvx8H88WS%7#GQ z9v^~@w&gSfJDD@4&JA?ap-~vZ)(WJM#B$CtfYR=C+2e1&Uepb zP@-4Yvy3wIANiw0MqzVrANbAz0AMRGylY@=?ni+ub@;eNJIBl%FMT0R-(l4&3avSe)(QQ{epOgsRfHs1~X5byDod1zvWH7VQ=eFr2D^0E#Z zbwu4gdOO2gxZ-`Iqqi6L3>wg7B<3n^ccH@Rmc0A4F`2m6-k#T|wQRO6*=Wuvo(P2B zSGyFwH0tCwb=9@@hSp954mtWRO*Rr(d$2dZ@PqRJ+Pfh9VZE_?>cDtyTGfoC+OKW( zP}x8laQJbdDrOi%J9gnqsY7>HeWC^$2SpgHj@gj_a!-9N>WnVGCAH56pAAEM%}pQ~ z`kwKCuaN7wLZOz6D^yB)2&;NUol7DY`ml(xyg4T<$BcIL{qx~Yi6N#J z>^85l%y{mZ9AfK`dv@~me)@2`^kIPxr0UN%BdoB3)94JvUq5h9qqk=&LYGNZIuHl4 z98vw*exBoDYV?>}u^y7N+mfCH3|R{^55W$tYWcr7XK;k;#^NnF$Gr3W%s33aWEXWk z#$jDh`d;5z;ZfPeux1uwfon1t`C=DUkbLY>B|{LqyShynnkU%gHh!2R%);VkW2WlJ zB&foNzZf-%>6z*Q>Cm5!v%fxFo{nAgbkr7V>h#1bz>x#?ova*1?$QS}HYWuDiDgvg zGgID9_4|h>fGiHb0=*f2Rg)hk)~%Z_8Jqq+Ra95?vSMW|9mLP`F{jQvObnK(k;4VZKC-jAe3`WOb?PRFa|1C2WfV z7+sGnt+Ud#$szNq8wI<+H3NClaq_Rar_WZ-8sOzlz)Nsvul)l>y3CmX literal 0 HcmV?d00001 diff --git a/Resources/Textures/Mobs/Customization/vox_parts.rsi/tail_stenciled.png b/Resources/Textures/Mobs/Customization/vox_parts.rsi/tail_stenciled.png index 50627ac5220bfbc37e5b6f6516b5acacd1d75165..9072c9f4fc3184e3fda883e612f655c2a80f2a9a 100644 GIT binary patch delta 270 zcmV+p0rCFl1gQd$B!2;OQb$4nuFf3k0002vNkl;{Sm|aNRg6DWLu6L2><{90B}Fue+RIanfdmdQo39YhnbnT z)_m)=ARo)j+}*vD;;l6=rL6liMR@#VkiV_gst|&5&XS}Uqkkl6nkGr|BhTRy1u!!o zhCz~)b6(%QnR(y$r|$kbAKu@HF}@`qV^j!1wbr#8_PR^~B)ugsN%K4_gmC!IOBLYN zw*AL({Oob~oC4ePt){@z{=Td(rPST#53sc)eZRy30000000000000000NC#vunKoz URl)?F00000Ne4wvM6N<$fv<0QU!csPxvAmcDTOUXf&~Kv6)Jc?DUN+YReSs@BPmc_}qI@fKd<)RoF8{ zW=%T1Dd*1&{&wdgDL3QxAGhCL`%$mVV)X0q^E#!Lq?q;L?2N|o{*50j%OBR&goe&M znv{6%`R3?2z3F-P-hZDl%kZ`$C&P&kWxGq06z4f@+!wcA{pp9~OE>E)j5f)39hcH# zntCv+!gNUrgTsvZm0Wc;a(stwOcZGdSQ7tl_uY5(_xUQt6|+HD#lgSovgIG|I_LQRbkvJ&7pl{hox0dq z=Bj)X2?$=X^fTK>HlE`)=Z$S%?J8UM`fuI)(zv(xrA@SsoHI#s(0SM(c7%`jf>Uh7 zcg2$E2lXXZrV9^tm`Y5TefC)7M!?)?pf0ILJEFWLAXABJxX%*&{C_8s+ z=Dr%?olHjhW=F1k_))ZThTQExo{tw?Vr6kSSjM4vW3T9DcaEOF&yUTp`grEogn5mQ z3@aumM5uma3Org}So&LDzl~$Q>jN$)78eI7N)r0PB+chhU)FT(3j+{%y85}Sb4q9e E04!bnCIA2c diff --git a/Resources/Textures/Mobs/Species/Vox/displacement.rsi/back.png b/Resources/Textures/Mobs/Species/Vox/displacement.rsi/back.png new file mode 100644 index 0000000000000000000000000000000000000000..c300bba8a5ba9240ca02cb3fa28f619b4ba32b21 GIT binary patch literal 451 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=jKx9jP7LeL$-D%zYdu{YLn`LH zofTblM1hB;J;d(_t8V;-a3y)q+@)oInN)8}tlpn$+>`34IB8~A-Whh?1~r}qtQT4s zw=m2yXb^J{X1l)r*<29M!r;7W}Y{naeg}Ugvu9*ch z7}rkTap;MvW~}RrdO=g{mL)QvxM+de51;CuB}+}i=Q3{Ay*ux-KkuzS=}oHMoLQZJ z58l`(b>VQ~s$l1-jQW4~o#V-P>28*KAbA1Hvi)Cd%TDq8>aLealKf(l5dNM$N4IqH z$}fAkJTB!_em#C?*KPwBwu%DDgwK literal 0 HcmV?d00001 diff --git a/Resources/Textures/Mobs/Species/Vox/displacement.rsi/eyes.png b/Resources/Textures/Mobs/Species/Vox/displacement.rsi/eyes.png new file mode 100644 index 0000000000000000000000000000000000000000..f705c337de1c2fa90af22b5c1eb2f18d90396897 GIT binary patch literal 508 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=jKx9jP7LeL$-D%zw|TlahE&XX zJ1aWxkb!{f`zduB=IKmODXEY1XXU!wujJ7reZ2omQfl83{|R$mKi=5LbE!1o%?$oB z2D9DbA5QWKIBluidF`9uv+KXMRo*yqqSPj=g&ux2! z<5hJgZe{)QZ`R~3BCR_V*RA=ytzpU3yVetR9Ntf!eoA%CJ*LgIwllYM2w&Z?cf06D z?Wi}w4o7U`q6MuUB=I{a#2)zLmcQ|rrpL2yKK5l<)z*1IJi4 zFmEtqe8Z6A!(h!IjZdgEtFP?t7UdEy6D2){zL~v~7MtzR*;D_iq$gSKYknA`>ip^Y zrt;@G?=Cob!*Cm0ZrJvHq6b7%wH|bRbz(grPzopr00vCgx&QzG literal 0 HcmV?d00001 diff --git a/Resources/Textures/Mobs/Species/Vox/displacement.rsi/hand.png b/Resources/Textures/Mobs/Species/Vox/displacement.rsi/hand.png new file mode 100644 index 0000000000000000000000000000000000000000..4a0266dfd3733b7288b6690a682aa7dd518bed73 GIT binary patch literal 483 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=jKx9jP7LeL$-D%z=X$z0hE&XX zJKHetumO*&{mXeC!F*3vF2A5@_0(Zz$>K?}O^epWDlTjKA#NalL37&AUjo(*Q$5xe z%#ldt-f)s3htW*3LHB?f^9I%%DGb{fX7d~nOPI`fgDJ;|A-chrt)imgUV_) z{KG-+=jtU6ylL{3W=XxyDa$(l)`GH|r8d?7Ug|e)zsD_Xm%!$*-dVj&S7zsIb^e7)z-;Wa;({}(wy(4h(FzTsglkiE0EQqkyz2)_dBqlOdz zJ0Ao+;7d55DRw|Jpq6{Pwi9{li zNF)-8N9guc+%906+)<0C&ACOOz6i(si9Voleg9vMgN`G);r9>w>pIPy|fVgu~&0X_`PO zU5)$Sdt+t$TYtgVCxjpe_zL*OQc73hxHr=@xd^cGpGMbp=6pUIt+o4{&u0@8ezEe6 zF;1@4C02e=4gfy9z1{1}vOMiBR8_T#02}^QRYk2A>;M2@j5&iTrC^Lj36J4;Jc3f{ z5~1CC$Kx?-y&wm0&JAM><2bGo-#Ct7j71kCAzUsO0Dri73fS>bf+N6s+$O$lM&6rc zS#Y^rT#6}H!)6#iU8o_4iG{hrF6~G)9Dn| zqJ9+H9=F|TDWyA~5KFKF+P2Mn4%~E zJl6@<_@XGFl=^huBetv@&~=@8eSLM;_T&cuvw!`gJsn~r!JE4~lu``Cu+m}c2)kVX zU>JtgxNplZ{|8DbUS3`@;Ll@@5OVj<3L(%mjf(`O6sBpq8!g|(ziS&`A3_L(5H~v7 zZL&SQ#W^>=6P&V~bF890A-`f@V8rt1kaYoc|5{ zNr+9;Aj`5{BfuDAgb=Xj6|MYxx_wfeu58>s25*#a+cuL@LMe4uP@dKE8w-@d)^S-aHPrl027OO!tpcR&y>wyiKUhYU*?W>at-p^_xJIVMMpxXPU2Bv zKIvdI0YQ~Y+<05Iz5k2d>h+hGyQlArsq3i!ANhClzWehuZ+vg~Qnh#0-MsL-dEf7S ztFXCu?s;*kh0Lm#C9hsxZtmBM`2BaE$?NaGpL)*xe{I>WzyH>)?uc7`RqK_7_HxDM zPhYF{?*IPf<<;1=VOJ9jH2AtXel4(5+HcdVH{H9i#6o6TnnnMLGrz-6C2ibsHf{6n z&l47C%!|V;(zdm{Yll^eAy;7rYJ~yV55G_=cze8v0mbN z;~ZhLQj=wuGYwP&bH1bjUrFRt1=0u1D8&mZrgS7 z^9pgV2@8aaiafjnRSbk&4%XQ5*GJ8_{J8%8Y}MI~2d2GXXi;KtkNhCu%9P^LTk&j1 zEk9dC*^`Z`R;E|i|dR1_DPG>fh0%xYGi zrAH$FxM<{Ma24>b3w*x+(i0`+2c|I+2~BH{Zdkdxa{bgTe~DWM4fCLDpr From 5d5465b36fcce5abcb6d2b195ee8eaedc247af1b Mon Sep 17 00:00:00 2001 From: Winkarst <74284083+Winkarst-cpu@users.noreply.github.com> Date: Wed, 17 Jul 2024 16:50:24 +0300 Subject: [PATCH 251/765] Make the super door remote to be able to control Syndicate doors (#30033) * Make the super door remote to be able to control Syndicate doors * Fix --- Resources/Prototypes/Entities/Objects/Devices/door_remote.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Resources/Prototypes/Entities/Objects/Devices/door_remote.yml b/Resources/Prototypes/Entities/Objects/Devices/door_remote.yml index 76904ea2685..1e075a66996 100644 --- a/Resources/Prototypes/Entities/Objects/Devices/door_remote.yml +++ b/Resources/Prototypes/Entities/Objects/Devices/door_remote.yml @@ -160,3 +160,5 @@ - AllAccess tags: - CentralCommand + - NuclearOperative + - SyndicateAgent From cafbec1cbd85bd83fda90b9e881ce3ddf4dded84 Mon Sep 17 00:00:00 2001 From: PJBot Date: Wed, 17 Jul 2024 13:51:32 +0000 Subject: [PATCH 252/765] Automatic changelog update --- Resources/Changelog/Changelog.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index ec85d771e3a..fd909d6b12f 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,11 +1,4 @@ Entries: -- author: pigeonpeas - changes: - - message: Adds the ability to purchase emitters in cargo. - type: Add - id: 6428 - time: '2024-04-23T11:34:09.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/27229 - author: EmoGarbage404 changes: - message: Fixed cargo telepads not teleporting in orders from linked consoles. @@ -3804,3 +3797,10 @@ id: 6927 time: '2024-07-17T06:26:10.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/29995 +- author: Winkarst-cpu + changes: + - message: The super door remote is now able to control Syndicate doors. + type: Fix + id: 6928 + time: '2024-07-17T13:50:25.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/30033 From adbc072a5cd9a2d3746408c78c9dc35e58e6c2bf Mon Sep 17 00:00:00 2001 From: slarticodefast <161409025+slarticodefast@users.noreply.github.com> Date: Wed, 17 Jul 2024 20:25:19 +0200 Subject: [PATCH 253/765] Fix formatting warnings (#30122) --- Content.Server/Botany/Components/SeedComponent.cs | 2 +- Content.Server/Botany/Systems/MutationSystem.cs | 8 ++++---- Content.Server/Botany/Systems/SeedExtractorSystem.cs | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Content.Server/Botany/Components/SeedComponent.cs b/Content.Server/Botany/Components/SeedComponent.cs index f475ec3cfc4..ffa1b7ef4e9 100644 --- a/Content.Server/Botany/Components/SeedComponent.cs +++ b/Content.Server/Botany/Components/SeedComponent.cs @@ -24,7 +24,7 @@ public sealed partial class SeedComponent : SharedSeedComponent /// /// Name of a base seed prototype that is used if is null. /// - [DataField("seedId", customTypeSerializer:typeof(PrototypeIdSerializer))] + [DataField("seedId", customTypeSerializer: typeof(PrototypeIdSerializer))] public string? SeedId; } } diff --git a/Content.Server/Botany/Systems/MutationSystem.cs b/Content.Server/Botany/Systems/MutationSystem.cs index c7ce5d47efa..474859823a3 100644 --- a/Content.Server/Botany/Systems/MutationSystem.cs +++ b/Content.Server/Botany/Systems/MutationSystem.cs @@ -2,10 +2,8 @@ using Robust.Shared.Random; using Content.Shared.Random; using Content.Shared.Random.Helpers; -using Content.Shared.Chemistry.Reagent; using System.Linq; using Content.Shared.Atmos; -using FastAccessors; namespace Content.Server.Botany; @@ -42,6 +40,7 @@ public void MutateSeed(ref SeedData seed, float severity) // Add up everything in the bits column and put the number here. const int totalbits = 275; + #pragma warning disable IDE0055 // disable formatting warnings because this looks more readable // Tolerances (55) MutateFloat(ref seed.NutrientConsumption , 0.05f, 1.2f, 5, totalbits, severity); MutateFloat(ref seed.WaterConsumption , 3f , 9f , 5, totalbits, severity); @@ -75,6 +74,7 @@ public void MutateSeed(ref SeedData seed, float severity) MutateBool(ref seed.TurnIntoKudzu , true , 10, totalbits, severity); MutateBool(ref seed.CanScream , true , 10, totalbits, severity); seed.BioluminescentColor = RandomColor(seed.BioluminescentColor, 10, totalbits, severity); + #pragma warning restore IDE0055 // ConstantUpgade (10) MutateHarvestType(ref seed.HarvestRepeat, 10, totalbits, severity); @@ -261,7 +261,7 @@ private void MutateChemicals(ref Dictionary chemicals, { var pick = _randomChems.Pick(_robustRandom); string chemicalId = pick.reagent; - int amount = _robustRandom.Next(1, ((int)pick.quantity)); + int amount = _robustRandom.Next(1, (int)pick.quantity); SeedChemQuantity seedChemQuantity = new SeedChemQuantity(); if (chemicals.ContainsKey(chemicalId)) { @@ -274,7 +274,7 @@ private void MutateChemicals(ref Dictionary chemicals, seedChemQuantity.Max = 1 + amount; seedChemQuantity.Inherent = false; } - int potencyDivisor = (int) Math.Ceiling(100.0f / seedChemQuantity.Max); + int potencyDivisor = (int)Math.Ceiling(100.0f / seedChemQuantity.Max); seedChemQuantity.PotencyDivisor = potencyDivisor; chemicals[chemicalId] = seedChemQuantity; } diff --git a/Content.Server/Botany/Systems/SeedExtractorSystem.cs b/Content.Server/Botany/Systems/SeedExtractorSystem.cs index f1ae6c9f11a..9a5e70762e7 100644 --- a/Content.Server/Botany/Systems/SeedExtractorSystem.cs +++ b/Content.Server/Botany/Systems/SeedExtractorSystem.cs @@ -29,12 +29,12 @@ private void OnInteractUsing(EntityUid uid, SeedExtractorComponent seedExtractor return; if (!_botanySystem.TryGetSeed(produce, out var seed) || seed.Seedless) { - _popupSystem.PopupCursor(Loc.GetString("seed-extractor-component-no-seeds",("name", args.Used)), + _popupSystem.PopupCursor(Loc.GetString("seed-extractor-component-no-seeds", ("name", args.Used)), args.User, PopupType.MediumCaution); return; } - _popupSystem.PopupCursor(Loc.GetString("seed-extractor-component-interact-message",("name", args.Used)), + _popupSystem.PopupCursor(Loc.GetString("seed-extractor-component-interact-message", ("name", args.Used)), args.User, PopupType.Medium); QueueDel(args.Used); From cc5f401c67e4c1cb259f5198c49ff6702aab2356 Mon Sep 17 00:00:00 2001 From: Errant <35878406+Errant-4@users.noreply.github.com> Date: Thu, 18 Jul 2024 00:04:51 +0200 Subject: [PATCH 254/765] Temporarily remove Vox from space ninja and Unknown Shuttle ghostroles (#30099) * no vox ninjas * blacklist vox from UnknownShuttleEvent --- Resources/Prototypes/Entities/Mobs/Player/humanoid.yml | 10 ++++++++++ Resources/Prototypes/GameRules/events.yml | 4 ++++ 2 files changed, 14 insertions(+) diff --git a/Resources/Prototypes/Entities/Mobs/Player/humanoid.yml b/Resources/Prototypes/Entities/Mobs/Player/humanoid.yml index bd43d5d1879..f38092990bd 100644 --- a/Resources/Prototypes/Entities/Mobs/Player/humanoid.yml +++ b/Resources/Prototypes/Entities/Mobs/Player/humanoid.yml @@ -592,6 +592,8 @@ - type: randomHumanoidSettings id: LostCargoTechnician parent: EventHumanoid + speciesBlacklist: + - Vox components: - type: GhostRole name: ghost-role-information-lost-cargo-technical-name @@ -643,6 +645,8 @@ id: ClownTroupe parent: EventHumanoid randomizeName: false + speciesBlacklist: + - Vox components: - type: GhostRole name: ghost-role-information-clown-troupe-name @@ -693,6 +697,8 @@ - type: randomHumanoidSettings id: TravelingChef parent: EventHumanoid + speciesBlacklist: + - Vox components: - type: GhostRole name: ghost-role-information-traveling-chef-name @@ -753,6 +759,8 @@ - type: randomHumanoidSettings id: DisasterVictimHead parent: EventHumanoidMindShielded + speciesBlacklist: + - Vox components: - type: GhostRole name: ghost-role-information-disaster-victim-name @@ -811,6 +819,8 @@ - type: randomHumanoidSettings id: SyndieDisasterVictim parent: EventHumanoid + speciesBlacklist: + - Vox components: - type: NpcFactionMember factions: diff --git a/Resources/Prototypes/GameRules/events.yml b/Resources/Prototypes/GameRules/events.yml index 35ef33b24a2..d2c73b1ddfd 100644 --- a/Resources/Prototypes/GameRules/events.yml +++ b/Resources/Prototypes/GameRules/events.yml @@ -122,6 +122,10 @@ minimumPlayers: 40 # DeltaV - was 30 - type: SpaceSpawnRule - type: AntagLoadProfileRule + # Vox disabled until loadouts work on AntagSelection-based spawns + speciesOverride: Human + speciesOverrideBlacklist: + - Vox - type: AntagObjectives objectives: - StealResearchObjective From c620edfa0e1a031ab38f7a8e974a436c1665eb79 Mon Sep 17 00:00:00 2001 From: PJBot Date: Wed, 17 Jul 2024 22:05:58 +0000 Subject: [PATCH 255/765] Automatic changelog update --- Resources/Changelog/Changelog.yml | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index fd909d6b12f..99fa3976e32 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,11 +1,4 @@ Entries: -- author: EmoGarbage404 - changes: - - message: Fixed cargo telepads not teleporting in orders from linked consoles. - type: Fix - id: 6429 - time: '2024-04-23T12:07:12.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/27255 - author: Plykiya changes: - message: Do-after bars of other players are now shaded and harder to see in the @@ -3804,3 +3797,11 @@ id: 6928 time: '2024-07-17T13:50:25.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/30033 +- author: Errant + changes: + - message: Vox are temporarily removed from Space Ninjas and all Unknown Shuttle + ghostroles, until code supports giving them species-specific gear. + type: Tweak + id: 6929 + time: '2024-07-17T22:04:51.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/30099 From f040b209bcff317246fe292f4bb916f82bf5d56b Mon Sep 17 00:00:00 2001 From: Ed <96445749+TheShuEd@users.noreply.github.com> Date: Thu, 18 Jul 2024 01:37:03 +0300 Subject: [PATCH 256/765] DungeonSystem.Rooms bugfix (#30125) Update DungeonSystem.Rooms.cs --- Content.Server/Procedural/DungeonSystem.Rooms.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Content.Server/Procedural/DungeonSystem.Rooms.cs b/Content.Server/Procedural/DungeonSystem.Rooms.cs index 8a1606c4889..20d64acff15 100644 --- a/Content.Server/Procedural/DungeonSystem.Rooms.cs +++ b/Content.Server/Procedural/DungeonSystem.Rooms.cs @@ -118,7 +118,7 @@ public void SpawnRoom( // go BRRNNTTT on existing stuff if (clearExisting) { - var gridBounds = new Box2(Vector2.Transform(Vector2.Zero, roomTransform), Vector2.Transform(room.Size, roomTransform)); + var gridBounds = new Box2(Vector2.Transform(-room.Size/2, roomTransform), Vector2.Transform(room.Size/2, roomTransform)); _entitySet.Clear(); // Polygon skin moment gridBounds = gridBounds.Enlarged(-0.05f); From 7b51d1ab1be68f3f31aba6cec331c7220ac661ce Mon Sep 17 00:00:00 2001 From: kbailey-git <84491830+kbailey-git@users.noreply.github.com> Date: Wed, 17 Jul 2024 15:54:08 -0700 Subject: [PATCH 257/765] Updated slime storage capacity text in guidebook (#30121) --- Resources/ServerInfo/Guidebook/Mobs/SlimePerson.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Resources/ServerInfo/Guidebook/Mobs/SlimePerson.xml b/Resources/ServerInfo/Guidebook/Mobs/SlimePerson.xml index 0374d4cb958..2c11508749e 100644 --- a/Resources/ServerInfo/Guidebook/Mobs/SlimePerson.xml +++ b/Resources/ServerInfo/Guidebook/Mobs/SlimePerson.xml @@ -18,7 +18,7 @@ - Slimepeople have an [bold]internal 2x2 storage inventory[/bold] inside of their slime membrane. Anyone can see what's inside and take it out of you without asking, + Slimepeople have an [bold]internal 2x3 storage inventory[/bold] inside of their slime membrane. Anyone can see what's inside and take it out of you without asking, so be careful. They [bold]don't drop their internal storage when they morph into a geras, however![/bold] Slimepeople have slight accelerated regeneration compared to other humanoids. They're also capable of hardening their fists, and as such have stronger punches, From 967217d67abe0df8906e2ab43c99538ed51b6971 Mon Sep 17 00:00:00 2001 From: Cojoke <83733158+Cojoke-dot@users.noreply.github.com> Date: Wed, 17 Jul 2024 19:40:54 -0500 Subject: [PATCH 258/765] Prevent Quantum Spin Inverter from Teleporting Things into Microwaves (#29200) * Prevent Quantum Spin Inverter from Teleporting Things into Microwaves * Simplifies code, GetTeleportingEntity instead of TryGet, adds failed teleport message * remove using Linguini.Syntax.Ast; * capital... * re-add CanInsert and Fixes microwave issue * beb * beeb --- .../Kitchen/EntitySystems/MicrowaveSystem.cs | 27 +++++++++++++++++++ .../Systems/SwapTeleporterSystem.cs | 23 +++++++++++----- .../Locale/en-US/portal/swap-teleporter.ftl | 1 + 3 files changed, 45 insertions(+), 6 deletions(-) diff --git a/Content.Server/Kitchen/EntitySystems/MicrowaveSystem.cs b/Content.Server/Kitchen/EntitySystems/MicrowaveSystem.cs index eefa539149b..71986ae859e 100644 --- a/Content.Server/Kitchen/EntitySystems/MicrowaveSystem.cs +++ b/Content.Server/Kitchen/EntitySystems/MicrowaveSystem.cs @@ -79,6 +79,7 @@ public override void Initialize() SubscribeLocalEvent(OnContentUpdate); SubscribeLocalEvent(OnContentUpdate); SubscribeLocalEvent(OnInteractUsing, after: new[] { typeof(AnchorableSystem) }); + SubscribeLocalEvent(OnInsertAttempt); SubscribeLocalEvent(OnBreak); SubscribeLocalEvent(OnPowerChanged); SubscribeLocalEvent(OnAnchorChanged); @@ -309,6 +310,32 @@ private void OnContentUpdate(EntityUid uid, MicrowaveComponent component, Contai UpdateUserInterfaceState(uid, component); } + private void OnInsertAttempt(Entity ent, ref ContainerIsInsertingAttemptEvent args) + { + if (ent.Comp.Broken) + { + args.Cancel(); + return; + } + + if (TryComp(args.EntityUid, out var item)) + { + if (_item.GetSizePrototype(item.Size) > _item.GetSizePrototype(ent.Comp.MaxItemSize)) + { + args.Cancel(); + return; + } + } + else + { + args.Cancel(); + return; + } + + if (ent.Comp.Storage.Count >= ent.Comp.Capacity) + args.Cancel(); + } + private void OnInteractUsing(Entity ent, ref InteractUsingEvent args) { if (args.Handled) diff --git a/Content.Shared/Teleportation/Systems/SwapTeleporterSystem.cs b/Content.Shared/Teleportation/Systems/SwapTeleporterSystem.cs index 58c249fec54..a5ad77d43bf 100644 --- a/Content.Shared/Teleportation/Systems/SwapTeleporterSystem.cs +++ b/Content.Shared/Teleportation/Systems/SwapTeleporterSystem.cs @@ -150,8 +150,19 @@ public void DoTeleport(Entity ent) return; } - var teleEnt = GetTeleportingEntity((uid, xform)); - var otherTeleEnt = GetTeleportingEntity((linkedEnt, Transform(linkedEnt))); + var (teleEnt, cont) = GetTeleportingEntity((uid, xform)); + var (otherTeleEnt, otherCont) = GetTeleportingEntity((linkedEnt, Transform(linkedEnt))); + + if (otherCont != null && !_container.CanInsert(teleEnt, otherCont) || + cont != null && !_container.CanInsert(otherTeleEnt, cont)) + { + _popup.PopupEntity(Loc.GetString("swap-teleporter-popup-teleport-fail", + ("entity", Identity.Entity(linkedEnt, EntityManager))), + teleEnt, + teleEnt, + PopupType.MediumCaution); + return; + } _popup.PopupEntity(Loc.GetString("swap-teleporter-popup-teleport-other", ("entity", Identity.Entity(linkedEnt, EntityManager))), @@ -184,20 +195,20 @@ public void DestroyLink(Entity ent, EntityUid? user) DestroyLink(linked, user); // the linked one is shown globally } - private EntityUid GetTeleportingEntity(Entity ent) + private (EntityUid, BaseContainer?) GetTeleportingEntity(Entity ent) { var parent = ent.Comp.ParentUid; if (_container.TryGetOuterContainer(ent, ent, out var container)) parent = container.Owner; if (HasComp(parent) || HasComp(parent)) - return ent; + return (ent, container); if (!_xformQuery.TryGetComponent(parent, out var parentXform) || parentXform.Anchored) - return ent; + return (ent, container); if (!TryComp(parent, out var body) || body.BodyType == BodyType.Static) - return ent; + return (ent, container); return GetTeleportingEntity((parent, parentXform)); } diff --git a/Resources/Locale/en-US/portal/swap-teleporter.ftl b/Resources/Locale/en-US/portal/swap-teleporter.ftl index f13fa9be423..0040ad0a88b 100644 --- a/Resources/Locale/en-US/portal/swap-teleporter.ftl +++ b/Resources/Locale/en-US/portal/swap-teleporter.ftl @@ -5,6 +5,7 @@ swap-teleporter-popup-link-destroyed = Quantum link destroyed! swap-teleporter-popup-teleport-cancel-time = It's still recharging! swap-teleporter-popup-teleport-cancel-link = It's not linked with another device! swap-teleporter-popup-teleport-other = {CAPITALIZE(THE($entity))} activates, and you find yourself somewhere else. +swap-teleporter-popup-teleport-fail = {CAPITALIZE(THE($entity))} activates and fails to transport you anywhere. swap-teleporter-verb-destroy-link = Destroy Quantum Link From 47d13ccf860172044a757ef8e203081421afd577 Mon Sep 17 00:00:00 2001 From: slarticodefast <161409025+slarticodefast@users.noreply.github.com> Date: Thu, 18 Jul 2024 02:41:15 +0200 Subject: [PATCH 259/765] minor SharedInteractionSystem cleanup (#30139) cleanup SharedInteractionSystem --- Content.Shared/Interaction/SharedInteractionSystem.cs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/Content.Shared/Interaction/SharedInteractionSystem.cs b/Content.Shared/Interaction/SharedInteractionSystem.cs index 48076ca360f..c32b4bcf780 100644 --- a/Content.Shared/Interaction/SharedInteractionSystem.cs +++ b/Content.Shared/Interaction/SharedInteractionSystem.cs @@ -38,8 +38,6 @@ using Robust.Shared.Timing; using Robust.Shared.Utility; -#pragma warning disable 618 - namespace Content.Shared.Interaction { /// @@ -522,11 +520,11 @@ public void InteractUsingRanged(EntityUid user, EntityUid used, EntityUid? targe protected bool ValidateInteractAndFace(EntityUid user, EntityCoordinates coordinates) { // Verify user is on the same map as the entity they clicked on - if (coordinates.GetMapId(EntityManager) != Transform(user).MapID) + if (_transform.GetMapId(coordinates) != Transform(user).MapID) return false; if (!HasComp(user)) - _rotateToFaceSystem.TryFaceCoordinates(user, coordinates.ToMapPos(EntityManager, _transform)); + _rotateToFaceSystem.TryFaceCoordinates(user, _transform.ToMapCoordinates(coordinates).Position); return true; } @@ -859,7 +857,7 @@ public bool InRangeUnobstructed( Ignored? predicate = null, bool popup = false) { - return InRangeUnobstructed(origin, other.ToMap(EntityManager, _transform), range, collisionMask, predicate, popup); + return InRangeUnobstructed(origin, _transform.ToMapCoordinates(other), range, collisionMask, predicate, popup); } /// @@ -966,7 +964,7 @@ public void InteractUsing( /// public void InteractDoAfter(EntityUid user, EntityUid used, EntityUid? target, EntityCoordinates clickLocation, bool canReach) { - if (target is {Valid: false}) + if (target is { Valid: false }) target = null; var afterInteractEvent = new AfterInteractEvent(user, used, target, clickLocation, canReach); From ac6eda6fa2adb3500eb84c599b1fab6b4f3f25a3 Mon Sep 17 00:00:00 2001 From: PJBot Date: Thu, 18 Jul 2024 00:42:02 +0000 Subject: [PATCH 260/765] Automatic changelog update --- Resources/Changelog/Changelog.yml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 99fa3976e32..c768ac40e77 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,12 +1,4 @@ Entries: -- author: Plykiya - changes: - - message: Do-after bars of other players are now shaded and harder to see in the - dark. - type: Tweak - id: 6430 - time: '2024-04-24T02:42:34.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/27273 - author: Blackern5000 changes: - message: The cargo telepad is now tier 2 technology rather than tier 3. @@ -3805,3 +3797,11 @@ id: 6929 time: '2024-07-17T22:04:51.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/30099 +- author: Cojoke-dot + changes: + - message: You can no longer teleport objects that should not be in other objects + into other objects with the Quantum Spin Inverter + type: Fix + id: 6930 + time: '2024-07-18T00:40:54.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/29200 From f4c633e00d74ec8698c33461d077fae2cf5696a9 Mon Sep 17 00:00:00 2001 From: Plykiya <58439124+Plykiya@users.noreply.github.com> Date: Wed, 17 Jul 2024 17:48:08 -0700 Subject: [PATCH 261/765] Fix stun batons using excess charges when thrown (#30136) Fix stun batons Co-authored-by: plykiya --- Content.Shared/Damage/Systems/StaminaSystem.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Content.Shared/Damage/Systems/StaminaSystem.cs b/Content.Shared/Damage/Systems/StaminaSystem.cs index 1f9a7f1dd84..a5c8a4b38de 100644 --- a/Content.Shared/Damage/Systems/StaminaSystem.cs +++ b/Content.Shared/Damage/Systems/StaminaSystem.cs @@ -192,6 +192,11 @@ private void OnThrowHit(EntityUid uid, StaminaDamageOnCollideComponent component private void OnCollide(EntityUid uid, StaminaDamageOnCollideComponent component, EntityUid target) { + // you can't inflict stamina damage on things with no stamina component + // this prevents stun batons from using up charges when throwing it at lockers or lights + if (!HasComp(target)) + return; + var ev = new StaminaDamageOnHitAttemptEvent(); RaiseLocalEvent(uid, ref ev); if (ev.Cancelled) From 1c3257a76daf7f6353cd213acebf0ec89d2eb9fe Mon Sep 17 00:00:00 2001 From: PJBot Date: Thu, 18 Jul 2024 00:49:15 +0000 Subject: [PATCH 262/765] Automatic changelog update --- Resources/Changelog/Changelog.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index c768ac40e77..2ba6a098e0e 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,11 +1,4 @@ Entries: -- author: Blackern5000 - changes: - - message: The cargo telepad is now tier 2 technology rather than tier 3. - type: Tweak - id: 6431 - time: '2024-04-24T13:21:29.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/26270 - author: FungiFellow changes: - message: Truncheon now fits in SecBelt @@ -3805,3 +3798,10 @@ id: 6930 time: '2024-07-18T00:40:54.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/29200 +- author: Plykiya + changes: + - message: Stun batons no longer use up charges when hitting objects without stamina. + type: Fix + id: 6931 + time: '2024-07-18T00:48:09.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/30136 From 9f0d62620c9d1a37aa95c5362cd6170247b44be2 Mon Sep 17 00:00:00 2001 From: Brandon Hu <103440971+Brandon-Huu@users.noreply.github.com> Date: Thu, 18 Jul 2024 07:17:57 +0000 Subject: [PATCH 263/765] fix(dev_map): resave dev map (#30098) fix(dev_map): Resave devmap Co-authored-by: 4llv07e --- Resources/Maps/Test/dev_map.yml | 121 +++----------------------------- 1 file changed, 10 insertions(+), 111 deletions(-) diff --git a/Resources/Maps/Test/dev_map.yml b/Resources/Maps/Test/dev_map.yml index 0cbc93142fc..4cd09dfe80f 100644 --- a/Resources/Maps/Test/dev_map.yml +++ b/Resources/Maps/Test/dev_map.yml @@ -385,11 +385,11 @@ entities: - type: Transform - type: Map - type: PhysicsMap + - type: GridTree + - type: MovedGrids - type: Broadphase - type: OccluderTree - type: LoadedMap - - type: GridTree - - type: MovedGrids - proto: AirAlarm entities: - uid: 800 @@ -401,8 +401,6 @@ entities: - type: DeviceList devices: - 801 - - type: AtmosDevice - joinedGrid: 179 - proto: AirCanister entities: - uid: 458 @@ -410,8 +408,6 @@ entities: - type: Transform pos: 7.5,-0.5 parent: 179 - - type: AtmosDevice - joinedGrid: 179 - proto: Airlock entities: - uid: 48 @@ -901,33 +897,21 @@ entities: - type: Transform pos: -2.5,-14.5 parent: 179 - - type: DeviceLinkSink - links: - - 1013 - uid: 697 components: - type: Transform pos: 1.5,-14.5 parent: 179 - - type: DeviceLinkSink - links: - - 1014 - uid: 698 components: - type: Transform pos: 1.5,-16.5 parent: 179 - - type: DeviceLinkSink - links: - - 1014 - uid: 984 components: - type: Transform pos: -2.5,-16.5 parent: 179 - - type: DeviceLinkSink - links: - - 1013 - proto: BoozeDispenser entities: - uid: 752 @@ -2660,13 +2644,6 @@ entities: - type: Transform pos: 24.5,5.5 parent: 179 -- proto: chem_master - entities: - - uid: 311 - components: - - type: Transform - pos: 8.5,11.5 - parent: 179 - proto: ChemDispenser entities: - uid: 583 @@ -2704,6 +2681,13 @@ entities: - type: Transform pos: 6.4651074,9.828774 parent: 179 +- proto: ChemMaster + entities: + - uid: 311 + components: + - type: Transform + pos: 8.5,11.5 + parent: 179 - proto: ChemMasterMachineCircuitboard entities: - uid: 718 @@ -3031,27 +3015,18 @@ entities: - type: Transform pos: -2.5,-15.5 parent: 179 - - type: DeviceLinkSink - links: - - 699 - uid: 259 components: - type: Transform rot: 3.141592653589793 rad pos: 1.5,-14.5 parent: 179 - - type: DeviceLinkSink - links: - - 983 - uid: 463 components: - type: Transform rot: 3.141592653589793 rad pos: 1.5,-16.5 parent: 179 - - type: DeviceLinkSink - links: - - 983 - uid: 677 components: - type: Transform @@ -3063,61 +3038,40 @@ entities: rot: -1.5707963267948966 rad pos: -1.5,11.5 parent: 179 - - type: DeviceLinkSink - links: - - 722 - uid: 720 components: - type: Transform rot: -1.5707963267948966 rad pos: -0.5,11.5 parent: 179 - - type: DeviceLinkSink - links: - - 722 - uid: 721 components: - type: Transform rot: -1.5707963267948966 rad pos: 0.5,11.5 parent: 179 - - type: DeviceLinkSink - links: - - 722 - uid: 985 components: - type: Transform rot: 3.141592653589793 rad pos: 1.5,-13.5 parent: 179 - - type: DeviceLinkSink - links: - - 983 - uid: 989 components: - type: Transform rot: 3.141592653589793 rad pos: 1.5,-15.5 parent: 179 - - type: DeviceLinkSink - links: - - 983 - uid: 990 components: - type: Transform pos: -2.5,-13.5 parent: 179 - - type: DeviceLinkSink - links: - - 699 - uid: 991 components: - type: Transform pos: -2.5,-16.5 parent: 179 - - type: DeviceLinkSink - links: - - 699 - proto: CrateEngineeringToolbox entities: - uid: 692 @@ -3575,8 +3529,6 @@ entities: rot: -1.5707963267948966 rad pos: 3.5,-3.5 parent: 179 - - type: AtmosDevice - joinedGrid: 179 - proto: GasMixer entities: - uid: 747 @@ -3585,8 +3537,6 @@ entities: rot: -1.5707963267948966 rad pos: 3.5,-2.5 parent: 179 - - type: AtmosDevice - joinedGrid: 179 - proto: GasOutletInjector entities: - uid: 429 @@ -3595,8 +3545,6 @@ entities: rot: -1.5707963267948966 rad pos: 6.5,-1.5 parent: 179 - - type: AtmosDevice - joinedGrid: 179 - proto: GasPipeBend entities: - uid: 727 @@ -3635,8 +3583,6 @@ entities: rot: -1.5707963267948966 rad pos: 6.5,-0.5 parent: 179 - - type: AtmosDevice - joinedGrid: 179 - proto: GasPressurePump entities: - uid: 171 @@ -3645,8 +3591,6 @@ entities: rot: -1.5707963267948966 rad pos: 4.5,-3.5 parent: 179 - - type: AtmosDevice - joinedGrid: 179 - proto: GasValve entities: - uid: 168 @@ -3655,8 +3599,6 @@ entities: rot: -1.5707963267948966 rad pos: 4.5,-2.5 parent: 179 - - type: AtmosDevice - joinedGrid: 179 - proto: GasVentPump entities: - uid: 729 @@ -3665,8 +3607,6 @@ entities: rot: -1.5707963267948966 rad pos: 6.5,-3.5 parent: 179 - - type: AtmosDevice - joinedGrid: 179 - proto: GasVentScrubber entities: - uid: 452 @@ -3675,8 +3615,6 @@ entities: rot: -1.5707963267948966 rad pos: 6.5,-2.5 parent: 179 - - type: AtmosDevice - joinedGrid: 179 - proto: GasVolumePump entities: - uid: 160 @@ -3685,8 +3623,6 @@ entities: rot: -1.5707963267948966 rad pos: 4.5,-1.5 parent: 179 - - type: AtmosDevice - joinedGrid: 179 - proto: GeigerCounter entities: - uid: 759 @@ -4230,9 +4166,6 @@ entities: - type: Transform pos: 12.5,24.5 parent: 179 - - type: DeviceLinkSink - links: - - 1083 - proto: MachineFrame entities: - uid: 533 @@ -4386,8 +4319,6 @@ entities: - type: Transform pos: 7.5,-1.5 parent: 179 - - type: AtmosDevice - joinedGrid: 179 - proto: Ointment entities: - uid: 148 @@ -4407,8 +4338,6 @@ entities: - type: Transform pos: 7.5,-3.5 parent: 179 - - type: AtmosDevice - joinedGrid: 179 - proto: PaperBin10 entities: - uid: 977 @@ -4442,8 +4371,6 @@ entities: - type: Transform pos: 7.5,-2.5 parent: 179 - - type: AtmosDevice - joinedGrid: 179 - proto: PlasticFlapsAirtightClear entities: - uid: 997 @@ -5119,7 +5046,7 @@ entities: - type: Transform pos: -6.5,-12.5 parent: 179 -- proto: soda_dispenser +- proto: SodaDispenser entities: - uid: 751 components: @@ -5171,20 +5098,6 @@ entities: - type: Transform pos: -3.5,4.5 parent: 179 -- proto: SpawnVehicleATV - entities: - - uid: 1176 - components: - - type: Transform - pos: -7.5,1.5 - parent: 179 -- proto: SpawnVehicleJanicart - entities: - - uid: 904 - components: - - type: Transform - pos: 5.5,16.5 - parent: 179 - proto: Spear entities: - uid: 185 @@ -5816,20 +5729,6 @@ entities: - type: Transform pos: -7.5,4.5 parent: 179 -- proto: VehicleKeyATV - entities: - - uid: 1187 - components: - - type: Transform - pos: -6.8905525,1.5128828 - parent: 179 -- proto: VehicleKeyJanicart - entities: - - uid: 14 - components: - - type: Transform - pos: 6.5,16.5 - parent: 179 - proto: VendingMachineCigs entities: - uid: 870 From c265ea930b820884313a5cc974012819cd092207 Mon Sep 17 00:00:00 2001 From: slarticodefast <161409025+slarticodefast@users.noreply.github.com> Date: Thu, 18 Jul 2024 20:43:20 +0200 Subject: [PATCH 264/765] Correct .editorconfig to use no space after casting (#30132) --- .editorconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.editorconfig b/.editorconfig index a5dfab07a50..1583c600aa5 100644 --- a/.editorconfig +++ b/.editorconfig @@ -129,7 +129,7 @@ csharp_indent_braces = false csharp_indent_switch_labels = true # Space preferences -csharp_space_after_cast = true +csharp_space_after_cast = false csharp_space_after_colon_in_inheritance_clause = true csharp_space_after_comma = true csharp_space_after_dot = false From c5653546c6486bcd9f378eeaf44f30133aae56c2 Mon Sep 17 00:00:00 2001 From: Ed <96445749+TheShuEd@users.noreply.github.com> Date: Thu, 18 Jul 2024 22:29:20 +0300 Subject: [PATCH 265/765] LatheSystem independently of energy (#30148) * Update LatheSystem.cs * Emo --- Content.Server/Power/EntitySystems/StaticPowerSystem.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Content.Server/Power/EntitySystems/StaticPowerSystem.cs b/Content.Server/Power/EntitySystems/StaticPowerSystem.cs index 9e11d9311af..61a23e501df 100644 --- a/Content.Server/Power/EntitySystems/StaticPowerSystem.cs +++ b/Content.Server/Power/EntitySystems/StaticPowerSystem.cs @@ -9,7 +9,7 @@ public static class StaticPowerSystem public static bool IsPowered(this EntitySystem system, EntityUid uid, IEntityManager entManager, ApcPowerReceiverComponent? receiver = null) { if (receiver == null && !entManager.TryGetComponent(uid, out receiver)) - return false; + return true; return receiver.Powered; } From 4a6d94e75dde8a5ee5a6d38956f976ee922d047e Mon Sep 17 00:00:00 2001 From: Smirnov Peter <131467813+Sh18RW@users.noreply.github.com> Date: Fri, 19 Jul 2024 01:34:18 +0300 Subject: [PATCH 266/765] Add item checking for moth food (#30019) * Add ContainerContainer component checking for moth food * Use ItemSlotsComponent checking on food item --- Content.Server/Nutrition/EntitySystems/FoodSystem.cs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/Content.Server/Nutrition/EntitySystems/FoodSystem.cs b/Content.Server/Nutrition/EntitySystems/FoodSystem.cs index fc9d228b056..d609f737e72 100644 --- a/Content.Server/Nutrition/EntitySystems/FoodSystem.cs +++ b/Content.Server/Nutrition/EntitySystems/FoodSystem.cs @@ -10,7 +10,6 @@ using Content.Shared.Body.Components; using Content.Shared.Body.Organ; using Content.Shared.Chemistry; -using Content.Shared.Chemistry.Reagent; using Content.Shared.Database; using Content.Shared.DoAfter; using Content.Shared.FixedPoint; @@ -31,6 +30,7 @@ using Robust.Shared.Audio.Systems; using Robust.Shared.Utility; using System.Linq; +using Content.Shared.Containers.ItemSlots; using Robust.Server.GameObjects; using Content.Shared.Whitelist; @@ -138,6 +138,16 @@ private void OnFeedFood(Entity entity, ref AfterInteractEvent arg return (false, true); } + // Checks for used item slots + if (TryComp(food, out var itemSlots)) + { + if (itemSlots.Slots.Any(slot => slot.Value.HasItem)) + { + _popup.PopupEntity(Loc.GetString("food-has-used-storage", ("food", food)), user, user); + return (false, true); + } + } + var flavors = _flavorProfile.GetLocalizedFlavorsMessage(food, user, foodSolution); if (GetUsesRemaining(food, foodComp) <= 0) From a6e61f9f94d33d7577170ed5246c9f57ff448f3e Mon Sep 17 00:00:00 2001 From: PJBot Date: Thu, 18 Jul 2024 22:35:26 +0000 Subject: [PATCH 267/765] Automatic changelog update --- Resources/Changelog/Changelog.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 2ba6a098e0e..e2ceb5193a9 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,11 +1,4 @@ Entries: -- author: FungiFellow - changes: - - message: Truncheon now fits in SecBelt - type: Tweak - id: 6432 - time: '2024-04-24T13:43:56.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/27281 - author: pigeonpeas changes: - message: Adds a trash bag to the advanced cleaning module. @@ -3805,3 +3798,10 @@ id: 6931 time: '2024-07-18T00:48:09.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/30136 +- author: Sh18RW + changes: + - message: Moth can't eat boots with an item more + type: Fix + id: 6932 + time: '2024-07-18T22:34:18.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/30019 From f35215634379615d33282e492204c28ad26aae90 Mon Sep 17 00:00:00 2001 From: portfiend <109661617+portfiend@users.noreply.github.com> Date: Thu, 18 Jul 2024 18:36:53 -0400 Subject: [PATCH 268/765] fix: give reptilians species mask sprites in lobby (#30095) --- Resources/Prototypes/Entities/Mobs/Species/reptilian.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Resources/Prototypes/Entities/Mobs/Species/reptilian.yml b/Resources/Prototypes/Entities/Mobs/Species/reptilian.yml index c9d3ed34804..f855047f7a3 100644 --- a/Resources/Prototypes/Entities/Mobs/Species/reptilian.yml +++ b/Resources/Prototypes/Entities/Mobs/Species/reptilian.yml @@ -72,5 +72,11 @@ components: - type: HumanoidAppearance species: Reptilian + hideLayersOnEquip: + - Snout + - HeadTop + - HeadSide + - type: Inventory + speciesId: reptilian #Weh From abb6f9c2e0e4d7063c0ba471c4a4dc2ec972e080 Mon Sep 17 00:00:00 2001 From: PJBot Date: Thu, 18 Jul 2024 22:37:59 +0000 Subject: [PATCH 269/765] Automatic changelog update --- Resources/Changelog/Changelog.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index e2ceb5193a9..6f0ba27d307 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,11 +1,4 @@ Entries: -- author: pigeonpeas - changes: - - message: Adds a trash bag to the advanced cleaning module. - type: Add - id: 6433 - time: '2024-04-24T21:27:34.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/27226 - author: Beck Thompson changes: - message: Radio jammer now has 3 selectable power operating levels and a battery @@ -3805,3 +3798,10 @@ id: 6932 time: '2024-07-18T22:34:18.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/30019 +- author: portfiend + changes: + - message: Reptilians display correct mask sprites in character customization screen. + type: Fix + id: 6933 + time: '2024-07-18T22:36:53.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/30095 From 224f1de03eadc2f16dce97f781b7d59161d80571 Mon Sep 17 00:00:00 2001 From: Plykiya <58439124+Plykiya@users.noreply.github.com> Date: Thu, 18 Jul 2024 17:21:01 -0700 Subject: [PATCH 270/765] Fix arrow pointing animation (#30134) Fixa the arrows Co-authored-by: plykiya --- Content.Server/Pointing/EntitySystems/PointingSystem.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Content.Server/Pointing/EntitySystems/PointingSystem.cs b/Content.Server/Pointing/EntitySystems/PointingSystem.cs index 4b7f50fb86c..f2f60f3063e 100644 --- a/Content.Server/Pointing/EntitySystems/PointingSystem.cs +++ b/Content.Server/Pointing/EntitySystems/PointingSystem.cs @@ -152,9 +152,7 @@ public bool TryPoint(ICommonSession? session, EntityCoordinates coordsPointed, E if (TryComp(arrow, out var pointing)) { - if (TryComp(player, out TransformComponent? xformPlayer)) - pointing.StartPosition = _transform.ToCoordinates((player, xformPlayer), _transform.ToMapCoordinates(xformPlayer.Coordinates)).Position; - + pointing.StartPosition = _transform.ToCoordinates((arrow, Transform(arrow)), _transform.ToMapCoordinates(Transform(player).Coordinates)).Position; pointing.EndTime = _gameTiming.CurTime + PointDuration; Dirty(arrow, pointing); From 4b43756e66205f7185207daa3e0a0dffb017adab Mon Sep 17 00:00:00 2001 From: Cojoke <83733158+Cojoke-dot@users.noreply.github.com> Date: Thu, 18 Jul 2024 19:22:23 -0500 Subject: [PATCH 271/765] Remove all Assigned Values that are Never Used (#30110) Remove all Assigned Values that are never used --- .../Administration/UI/Tabs/ObjectsTab/ObjectsTab.xaml.cs | 1 - Content.Client/Construction/ConstructionSystem.cs | 1 - Content.Client/Lathe/UI/LatheMenu.xaml.cs | 1 + Content.Client/VendingMachines/UI/VendingMachineMenu.xaml.cs | 1 - Content.Server/Ame/EntitySystems/AmeControllerSystem.cs | 2 -- Content.Server/Chat/Systems/ChatSystem.cs | 1 - Content.Server/Cluwne/CluwneSystem.cs | 1 - Content.Server/Doors/Systems/FirelockSystem.cs | 1 - Content.Server/Dragon/DragonSystem.cs | 1 - Content.Server/GameTicking/Rules/LoadMapRuleSystem.cs | 1 - Content.Server/GameTicking/Rules/SecretRuleSystem.cs | 1 - Content.Server/GameTicking/Rules/ThiefRuleSystem.cs | 2 -- Content.Server/GameTicking/Rules/TraitorRuleSystem.cs | 1 - Content.Server/Instruments/InstrumentSystem.cs | 1 - Content.Server/Medical/DefibrillatorSystem.cs | 1 - Content.Server/Ninja/Systems/SpaceNinjaSystem.cs | 3 --- Content.Server/Nutrition/EntitySystems/SliceableFoodSystem.cs | 1 - .../Players/PlayTimeTracking/PlayTimeTrackingSystem.cs | 1 - Content.Server/Power/EntitySystems/PowerNetSystem.cs | 1 - Content.Server/Power/EntitySystems/PowerReceiverSystem.cs | 1 - Content.Server/Procedural/DungeonSystem.cs | 1 - Content.Server/Silicons/Borgs/BorgSystem.cs | 1 - Content.Server/Station/Systems/StationJobsSystem.Roundstart.cs | 1 - Content.Server/Station/Systems/StationSystem.cs | 2 -- Content.Server/Traits/TraitSystem.cs | 1 - Content.Shared/Actions/SharedActionsSystem.cs | 1 - Content.Shared/Beeper/Systems/ProximityBeeperSystem.cs | 2 -- Content.Shared/Clothing/ClothingSpeedModifierSystem.cs | 3 --- Content.Shared/Movement/Pulling/Systems/PullingSystem.cs | 1 - Content.Shared/Ninja/Systems/DashAbilitySystem.cs | 1 - 30 files changed, 1 insertion(+), 37 deletions(-) diff --git a/Content.Client/Administration/UI/Tabs/ObjectsTab/ObjectsTab.xaml.cs b/Content.Client/Administration/UI/Tabs/ObjectsTab/ObjectsTab.xaml.cs index 78eefa34628..7082617c944 100644 --- a/Content.Client/Administration/UI/Tabs/ObjectsTab/ObjectsTab.xaml.cs +++ b/Content.Client/Administration/UI/Tabs/ObjectsTab/ObjectsTab.xaml.cs @@ -14,7 +14,6 @@ namespace Content.Client.Administration.UI.Tabs.ObjectsTab; public sealed partial class ObjectsTab : Control { [Dependency] private readonly IEntityManager _entityManager = default!; - [Dependency] private readonly IGameTiming _timing = default!; private readonly Color _altColor = Color.FromHex("#292B38"); private readonly Color _defaultColor = Color.FromHex("#2F2F3B"); diff --git a/Content.Client/Construction/ConstructionSystem.cs b/Content.Client/Construction/ConstructionSystem.cs index 889c992f7f6..f909b23423d 100644 --- a/Content.Client/Construction/ConstructionSystem.cs +++ b/Content.Client/Construction/ConstructionSystem.cs @@ -26,7 +26,6 @@ public sealed class ConstructionSystem : SharedConstructionSystem { [Dependency] private readonly IPlayerManager _playerManager = default!; [Dependency] private readonly IPrototypeManager _prototypeManager = default!; - [Dependency] private readonly SharedInteractionSystem _interactionSystem = default!; [Dependency] private readonly ExamineSystemShared _examineSystem = default!; [Dependency] private readonly SharedTransformSystem _transformSystem = default!; [Dependency] private readonly PopupSystem _popupSystem = default!; diff --git a/Content.Client/Lathe/UI/LatheMenu.xaml.cs b/Content.Client/Lathe/UI/LatheMenu.xaml.cs index 7cedf604781..b7ec8791f5b 100644 --- a/Content.Client/Lathe/UI/LatheMenu.xaml.cs +++ b/Content.Client/Lathe/UI/LatheMenu.xaml.cs @@ -19,6 +19,7 @@ public sealed partial class LatheMenu : DefaultWindow { [Dependency] private readonly IEntityManager _entityManager = default!; [Dependency] private readonly IPrototypeManager _prototypeManager = default!; + private EntityUid _owner; private readonly SpriteSystem _spriteSystem; private readonly LatheSystem _lathe; diff --git a/Content.Client/VendingMachines/UI/VendingMachineMenu.xaml.cs b/Content.Client/VendingMachines/UI/VendingMachineMenu.xaml.cs index 2c71fa8c40e..ac51cdbac5e 100644 --- a/Content.Client/VendingMachines/UI/VendingMachineMenu.xaml.cs +++ b/Content.Client/VendingMachines/UI/VendingMachineMenu.xaml.cs @@ -17,7 +17,6 @@ public sealed partial class VendingMachineMenu : FancyWindow { [Dependency] private readonly IPrototypeManager _prototypeManager = default!; [Dependency] private readonly IEntityManager _entityManager = default!; - [Dependency] private readonly IGameTiming _timing = default!; private readonly Dictionary _dummies = []; diff --git a/Content.Server/Ame/EntitySystems/AmeControllerSystem.cs b/Content.Server/Ame/EntitySystems/AmeControllerSystem.cs index eda91582739..bac2648307c 100644 --- a/Content.Server/Ame/EntitySystems/AmeControllerSystem.cs +++ b/Content.Server/Ame/EntitySystems/AmeControllerSystem.cs @@ -22,8 +22,6 @@ namespace Content.Server.Ame.EntitySystems; public sealed class AmeControllerSystem : EntitySystem { [Dependency] private readonly IAdminLogManager _adminLogger = default!; - [Dependency] private readonly IAdminManager _adminManager = default!; - [Dependency] private readonly IChatManager _chatManager = default!; [Dependency] private readonly IGameTiming _gameTiming = default!; [Dependency] private readonly AppearanceSystem _appearanceSystem = default!; [Dependency] private readonly SharedAudioSystem _audioSystem = default!; diff --git a/Content.Server/Chat/Systems/ChatSystem.cs b/Content.Server/Chat/Systems/ChatSystem.cs index c4f793c7b77..f7d2386714c 100644 --- a/Content.Server/Chat/Systems/ChatSystem.cs +++ b/Content.Server/Chat/Systems/ChatSystem.cs @@ -63,7 +63,6 @@ public sealed partial class ChatSystem : SharedChatSystem [Dependency] private readonly StationSystem _stationSystem = default!; [Dependency] private readonly MobStateSystem _mobStateSystem = default!; [Dependency] private readonly SharedAudioSystem _audio = default!; - [Dependency] private readonly SharedInteractionSystem _interactionSystem = default!; [Dependency] private readonly ReplacementAccentSystem _wordreplacement = default!; [Dependency] private readonly EntityWhitelistSystem _whitelistSystem = default!; [Dependency] private readonly ExamineSystemShared _examineSystem = default!; diff --git a/Content.Server/Cluwne/CluwneSystem.cs b/Content.Server/Cluwne/CluwneSystem.cs index 18d82659deb..f24f0143f31 100644 --- a/Content.Server/Cluwne/CluwneSystem.cs +++ b/Content.Server/Cluwne/CluwneSystem.cs @@ -29,7 +29,6 @@ public sealed class CluwneSystem : EntitySystem [Dependency] private readonly IPrototypeManager _prototypeManager = default!; [Dependency] private readonly ChatSystem _chat = default!; [Dependency] private readonly AutoEmoteSystem _autoEmote = default!; - [Dependency] private readonly MetaDataSystem _metaData = default!; [Dependency] private readonly NameModifierSystem _nameMod = default!; public override void Initialize() diff --git a/Content.Server/Doors/Systems/FirelockSystem.cs b/Content.Server/Doors/Systems/FirelockSystem.cs index 93ee18f6831..87e5887c422 100644 --- a/Content.Server/Doors/Systems/FirelockSystem.cs +++ b/Content.Server/Doors/Systems/FirelockSystem.cs @@ -16,7 +16,6 @@ namespace Content.Server.Doors.Systems public sealed class FirelockSystem : SharedFirelockSystem { [Dependency] private readonly SharedDoorSystem _doorSystem = default!; - [Dependency] private readonly AtmosAlarmableSystem _atmosAlarmable = default!; [Dependency] private readonly AtmosphereSystem _atmosSystem = default!; [Dependency] private readonly SharedAppearanceSystem _appearance = default!; [Dependency] private readonly SharedMapSystem _mapping = default!; diff --git a/Content.Server/Dragon/DragonSystem.cs b/Content.Server/Dragon/DragonSystem.cs index e626edeb269..1f15def5ce5 100644 --- a/Content.Server/Dragon/DragonSystem.cs +++ b/Content.Server/Dragon/DragonSystem.cs @@ -24,7 +24,6 @@ public sealed partial class DragonSystem : EntitySystem [Dependency] private readonly MovementSpeedModifierSystem _movement = default!; [Dependency] private readonly NpcFactionSystem _faction = default!; [Dependency] private readonly PopupSystem _popup = default!; - [Dependency] private readonly RoleSystem _role = default!; [Dependency] private readonly SharedActionsSystem _actions = default!; [Dependency] private readonly SharedAudioSystem _audio = default!; [Dependency] private readonly SharedTransformSystem _transform = default!; diff --git a/Content.Server/GameTicking/Rules/LoadMapRuleSystem.cs b/Content.Server/GameTicking/Rules/LoadMapRuleSystem.cs index 1c09d6e86e1..14293edb330 100644 --- a/Content.Server/GameTicking/Rules/LoadMapRuleSystem.cs +++ b/Content.Server/GameTicking/Rules/LoadMapRuleSystem.cs @@ -13,7 +13,6 @@ public sealed class LoadMapRuleSystem : GameRuleSystem [Dependency] private readonly IPrototypeManager _prototypeManager = default!; [Dependency] private readonly MapSystem _map = default!; [Dependency] private readonly MapLoaderSystem _mapLoader = default!; - [Dependency] private readonly MetaDataSystem _metaData = default!; [Dependency] private readonly TransformSystem _transform = default!; [Dependency] private readonly GridPreloaderSystem _gridPreloader = default!; diff --git a/Content.Server/GameTicking/Rules/SecretRuleSystem.cs b/Content.Server/GameTicking/Rules/SecretRuleSystem.cs index d25262b797a..9b4914fd91c 100644 --- a/Content.Server/GameTicking/Rules/SecretRuleSystem.cs +++ b/Content.Server/GameTicking/Rules/SecretRuleSystem.cs @@ -21,7 +21,6 @@ public sealed class SecretRuleSystem : GameRuleSystem [Dependency] private readonly IRobustRandom _random = default!; [Dependency] private readonly IConfigurationManager _configurationManager = default!; [Dependency] private readonly IAdminLogManager _adminLogger = default!; - [Dependency] private readonly IChatManager _chatManager = default!; [Dependency] private readonly IComponentFactory _compFact = default!; private string _ruleCompName = default!; diff --git a/Content.Server/GameTicking/Rules/ThiefRuleSystem.cs b/Content.Server/GameTicking/Rules/ThiefRuleSystem.cs index faec4a9e9ca..074b4c0df7a 100644 --- a/Content.Server/GameTicking/Rules/ThiefRuleSystem.cs +++ b/Content.Server/GameTicking/Rules/ThiefRuleSystem.cs @@ -12,10 +12,8 @@ namespace Content.Server.GameTicking.Rules; public sealed class ThiefRuleSystem : GameRuleSystem { - [Dependency] private readonly IRobustRandom _random = default!; [Dependency] private readonly MindSystem _mindSystem = default!; [Dependency] private readonly AntagSelectionSystem _antag = default!; - [Dependency] private readonly ObjectivesSystem _objectives = default!; public override void Initialize() { diff --git a/Content.Server/GameTicking/Rules/TraitorRuleSystem.cs b/Content.Server/GameTicking/Rules/TraitorRuleSystem.cs index 29de85a42e5..08200f4fabf 100644 --- a/Content.Server/GameTicking/Rules/TraitorRuleSystem.cs +++ b/Content.Server/GameTicking/Rules/TraitorRuleSystem.cs @@ -29,7 +29,6 @@ public sealed class TraitorRuleSystem : GameRuleSystem [Dependency] private readonly MindSystem _mindSystem = default!; [Dependency] private readonly SharedRoleSystem _roleSystem = default!; [Dependency] private readonly SharedJobSystem _jobs = default!; - [Dependency] private readonly ObjectivesSystem _objectives = default!; public override void Initialize() { diff --git a/Content.Server/Instruments/InstrumentSystem.cs b/Content.Server/Instruments/InstrumentSystem.cs index 6814b596dc5..f74dd7fb131 100644 --- a/Content.Server/Instruments/InstrumentSystem.cs +++ b/Content.Server/Instruments/InstrumentSystem.cs @@ -30,7 +30,6 @@ public sealed partial class InstrumentSystem : SharedInstrumentSystem [Dependency] private readonly UserInterfaceSystem _bui = default!; [Dependency] private readonly PopupSystem _popup = default!; [Dependency] private readonly TransformSystem _transform = default!; - [Dependency] private readonly InteractionSystem _interactions = default!; [Dependency] private readonly ExamineSystemShared _examineSystem = default!; private const float MaxInstrumentBandRange = 10f; diff --git a/Content.Server/Medical/DefibrillatorSystem.cs b/Content.Server/Medical/DefibrillatorSystem.cs index 1896f51eddc..b6b50d4215f 100644 --- a/Content.Server/Medical/DefibrillatorSystem.cs +++ b/Content.Server/Medical/DefibrillatorSystem.cs @@ -46,7 +46,6 @@ public sealed class DefibrillatorSystem : EntitySystem [Dependency] private readonly PowerCellSystem _powerCell = default!; [Dependency] private readonly SharedAppearanceSystem _appearance = default!; [Dependency] private readonly SharedAudioSystem _audio = default!; - [Dependency] private readonly UseDelaySystem _useDelay = default!; [Dependency] private readonly SharedMindSystem _mind = default!; /// diff --git a/Content.Server/Ninja/Systems/SpaceNinjaSystem.cs b/Content.Server/Ninja/Systems/SpaceNinjaSystem.cs index 28ab6332276..1ece045774c 100644 --- a/Content.Server/Ninja/Systems/SpaceNinjaSystem.cs +++ b/Content.Server/Ninja/Systems/SpaceNinjaSystem.cs @@ -32,10 +32,7 @@ public sealed class SpaceNinjaSystem : SharedSpaceNinjaSystem [Dependency] private readonly AlertsSystem _alerts = default!; [Dependency] private readonly BatterySystem _battery = default!; [Dependency] private readonly CodeConditionSystem _codeCondition = default!; - [Dependency] private readonly IChatManager _chatMan = default!; [Dependency] private readonly PowerCellSystem _powerCell = default!; - [Dependency] private readonly RoleSystem _role = default!; - [Dependency] private readonly SharedAudioSystem _audio = default!; [Dependency] private readonly SharedMindSystem _mind = default!; public override void Initialize() diff --git a/Content.Server/Nutrition/EntitySystems/SliceableFoodSystem.cs b/Content.Server/Nutrition/EntitySystems/SliceableFoodSystem.cs index e872a491e3d..eb78238a7c2 100644 --- a/Content.Server/Nutrition/EntitySystems/SliceableFoodSystem.cs +++ b/Content.Server/Nutrition/EntitySystems/SliceableFoodSystem.cs @@ -18,7 +18,6 @@ public sealed class SliceableFoodSystem : EntitySystem { [Dependency] private readonly SolutionContainerSystem _solutionContainerSystem = default!; [Dependency] private readonly SharedAudioSystem _audio = default!; - [Dependency] private readonly SharedContainerSystem _containerSystem = default!; [Dependency] private readonly TransformSystem _xformSystem = default!; public override void Initialize() diff --git a/Content.Server/Players/PlayTimeTracking/PlayTimeTrackingSystem.cs b/Content.Server/Players/PlayTimeTracking/PlayTimeTrackingSystem.cs index 88b46cd922f..defb2f4894a 100644 --- a/Content.Server/Players/PlayTimeTracking/PlayTimeTrackingSystem.cs +++ b/Content.Server/Players/PlayTimeTracking/PlayTimeTrackingSystem.cs @@ -35,7 +35,6 @@ public sealed class PlayTimeTrackingSystem : EntitySystem [Dependency] private readonly MindSystem _minds = default!; [Dependency] private readonly PlayTimeTrackingManager _tracking = default!; [Dependency] private readonly IAdminManager _adminManager = default!; - [Dependency] private readonly SharedRoleSystem _role = default!; public override void Initialize() { diff --git a/Content.Server/Power/EntitySystems/PowerNetSystem.cs b/Content.Server/Power/EntitySystems/PowerNetSystem.cs index 6c35ba20083..a7098649cef 100644 --- a/Content.Server/Power/EntitySystems/PowerNetSystem.cs +++ b/Content.Server/Power/EntitySystems/PowerNetSystem.cs @@ -22,7 +22,6 @@ public sealed class PowerNetSystem : EntitySystem [Dependency] private readonly PowerNetConnectorSystem _powerNetConnector = default!; [Dependency] private readonly IConfigurationManager _cfg = default!; [Dependency] private readonly IParallelManager _parMan = default!; - [Dependency] private readonly PowerReceiverSystem _powerReceiver = default!; private readonly PowerState _powerState = new(); private readonly HashSet _powerNetReconnectQueue = new(); diff --git a/Content.Server/Power/EntitySystems/PowerReceiverSystem.cs b/Content.Server/Power/EntitySystems/PowerReceiverSystem.cs index 51520f04644..191d3fc4bdb 100644 --- a/Content.Server/Power/EntitySystems/PowerReceiverSystem.cs +++ b/Content.Server/Power/EntitySystems/PowerReceiverSystem.cs @@ -21,7 +21,6 @@ public sealed class PowerReceiverSystem : SharedPowerReceiverSystem { [Dependency] private readonly IAdminLogManager _adminLogger = default!; [Dependency] private readonly IAdminManager _adminManager = default!; - [Dependency] private readonly AppearanceSystem _appearance = default!; [Dependency] private readonly AudioSystem _audio = default!; private EntityQuery _recQuery; private EntityQuery _provQuery; diff --git a/Content.Server/Procedural/DungeonSystem.cs b/Content.Server/Procedural/DungeonSystem.cs index b73e843fffd..9a7abb7e334 100644 --- a/Content.Server/Procedural/DungeonSystem.cs +++ b/Content.Server/Procedural/DungeonSystem.cs @@ -33,7 +33,6 @@ public sealed partial class DungeonSystem : SharedDungeonSystem [Dependency] private readonly AnchorableSystem _anchorable = default!; [Dependency] private readonly DecalSystem _decals = default!; [Dependency] private readonly EntityLookupSystem _lookup = default!; - [Dependency] private readonly TagSystem _tag = default!; [Dependency] private readonly TileSystem _tile = default!; [Dependency] private readonly MapLoaderSystem _loader = default!; [Dependency] private readonly SharedMapSystem _maps = default!; diff --git a/Content.Server/Silicons/Borgs/BorgSystem.cs b/Content.Server/Silicons/Borgs/BorgSystem.cs index 1c40e9489eb..3f32afbffbd 100644 --- a/Content.Server/Silicons/Borgs/BorgSystem.cs +++ b/Content.Server/Silicons/Borgs/BorgSystem.cs @@ -40,7 +40,6 @@ public sealed partial class BorgSystem : SharedBorgSystem [Dependency] private readonly IBanManager _banManager = default!; [Dependency] private readonly IGameTiming _timing = default!; [Dependency] private readonly IRobustRandom _random = default!; - [Dependency] private readonly SharedAccessSystem _access = default!; [Dependency] private readonly ActionsSystem _actions = default!; [Dependency] private readonly AlertsSystem _alerts = default!; [Dependency] private readonly DeviceNetworkSystem _deviceNetwork = default!; diff --git a/Content.Server/Station/Systems/StationJobsSystem.Roundstart.cs b/Content.Server/Station/Systems/StationJobsSystem.Roundstart.cs index e145e233e9e..8a918bd2fd0 100644 --- a/Content.Server/Station/Systems/StationJobsSystem.Roundstart.cs +++ b/Content.Server/Station/Systems/StationJobsSystem.Roundstart.cs @@ -17,7 +17,6 @@ public sealed partial class StationJobsSystem { [Dependency] private readonly IPrototypeManager _prototypeManager = default!; [Dependency] private readonly IBanManager _banManager = default!; - [Dependency] private readonly PlayTimeTrackingSystem _playTime = default!; private Dictionary> _jobsByWeight = default!; private List _orderedWeights = default!; diff --git a/Content.Server/Station/Systems/StationSystem.cs b/Content.Server/Station/Systems/StationSystem.cs index 84e44b6469c..5930eef39bd 100644 --- a/Content.Server/Station/Systems/StationSystem.cs +++ b/Content.Server/Station/Systems/StationSystem.cs @@ -27,10 +27,8 @@ namespace Content.Server.Station.Systems; [PublicAPI] public sealed class StationSystem : EntitySystem { - [Dependency] private readonly IConfigurationManager _cfgManager = default!; [Dependency] private readonly ILogManager _logManager = default!; [Dependency] private readonly IPlayerManager _player = default!; - [Dependency] private readonly IRobustRandom _random = default!; [Dependency] private readonly ChatSystem _chatSystem = default!; [Dependency] private readonly GameTicker _ticker = default!; [Dependency] private readonly SharedTransformSystem _transform = default!; diff --git a/Content.Server/Traits/TraitSystem.cs b/Content.Server/Traits/TraitSystem.cs index f41512b6ac2..3bd540a3049 100644 --- a/Content.Server/Traits/TraitSystem.cs +++ b/Content.Server/Traits/TraitSystem.cs @@ -11,7 +11,6 @@ namespace Content.Server.Traits; public sealed class TraitSystem : EntitySystem { [Dependency] private readonly IPrototypeManager _prototypeManager = default!; - [Dependency] private readonly ISerializationManager _serializationManager = default!; [Dependency] private readonly SharedHandsSystem _sharedHandsSystem = default!; [Dependency] private readonly EntityWhitelistSystem _whitelistSystem = default!; diff --git a/Content.Shared/Actions/SharedActionsSystem.cs b/Content.Shared/Actions/SharedActionsSystem.cs index 013348eb4f7..ca6bd1dcc2a 100644 --- a/Content.Shared/Actions/SharedActionsSystem.cs +++ b/Content.Shared/Actions/SharedActionsSystem.cs @@ -25,7 +25,6 @@ public abstract class SharedActionsSystem : EntitySystem [Dependency] private readonly ISharedAdminLogManager _adminLogger = default!; [Dependency] private readonly SharedInteractionSystem _interactionSystem = default!; [Dependency] private readonly ActionBlockerSystem _actionBlockerSystem = default!; - [Dependency] private readonly SharedContainerSystem _containerSystem = default!; [Dependency] private readonly RotateToFaceSystem _rotateToFaceSystem = default!; [Dependency] private readonly SharedAudioSystem _audio = default!; [Dependency] private readonly SharedTransformSystem _transformSystem = default!; diff --git a/Content.Shared/Beeper/Systems/ProximityBeeperSystem.cs b/Content.Shared/Beeper/Systems/ProximityBeeperSystem.cs index ed3c6366c13..9830e165e56 100644 --- a/Content.Shared/Beeper/Systems/ProximityBeeperSystem.cs +++ b/Content.Shared/Beeper/Systems/ProximityBeeperSystem.cs @@ -12,8 +12,6 @@ namespace Content.Shared.Beeper.Systems; /// public sealed class ProximityBeeperSystem : EntitySystem { - [Dependency] private readonly SharedAppearanceSystem _appearance = default!; - [Dependency] private readonly ProximityDetectionSystem _proximity = default!; [Dependency] private readonly BeeperSystem _beeper = default!; /// diff --git a/Content.Shared/Clothing/ClothingSpeedModifierSystem.cs b/Content.Shared/Clothing/ClothingSpeedModifierSystem.cs index c1efe0b3ddd..897f3791561 100644 --- a/Content.Shared/Clothing/ClothingSpeedModifierSystem.cs +++ b/Content.Shared/Clothing/ClothingSpeedModifierSystem.cs @@ -14,13 +14,10 @@ namespace Content.Shared.Clothing; public sealed class ClothingSpeedModifierSystem : EntitySystem { - [Dependency] private readonly SharedAppearanceSystem _appearance = default!; - [Dependency] private readonly ClothingSpeedModifierSystem _clothingSpeedModifier = default!; [Dependency] private readonly SharedContainerSystem _container = default!; [Dependency] private readonly ExamineSystemShared _examine = default!; [Dependency] private readonly MovementSpeedModifierSystem _movementSpeed = default!; [Dependency] private readonly ItemToggleSystem _toggle = default!; - [Dependency] private readonly SharedPowerCellSystem _powerCell = default!; public override void Initialize() { diff --git a/Content.Shared/Movement/Pulling/Systems/PullingSystem.cs b/Content.Shared/Movement/Pulling/Systems/PullingSystem.cs index f563440af04..557c316e26d 100644 --- a/Content.Shared/Movement/Pulling/Systems/PullingSystem.cs +++ b/Content.Shared/Movement/Pulling/Systems/PullingSystem.cs @@ -43,7 +43,6 @@ public sealed class PullingSystem : EntitySystem [Dependency] private readonly SharedHandsSystem _handsSystem = default!; [Dependency] private readonly SharedInteractionSystem _interaction = default!; [Dependency] private readonly SharedPhysicsSystem _physics = default!; - [Dependency] private readonly SharedPopupSystem _popup = default!; [Dependency] private readonly HeldSpeedModifierSystem _clothingMoveSpeed = default!; public override void Initialize() diff --git a/Content.Shared/Ninja/Systems/DashAbilitySystem.cs b/Content.Shared/Ninja/Systems/DashAbilitySystem.cs index 1385219e473..09be1085058 100644 --- a/Content.Shared/Ninja/Systems/DashAbilitySystem.cs +++ b/Content.Shared/Ninja/Systems/DashAbilitySystem.cs @@ -18,7 +18,6 @@ public sealed class DashAbilitySystem : EntitySystem { [Dependency] private readonly ActionContainerSystem _actionContainer = default!; [Dependency] private readonly IGameTiming _timing = default!; - [Dependency] private readonly SharedAudioSystem _audio = default!; [Dependency] private readonly SharedChargesSystem _charges = default!; [Dependency] private readonly SharedHandsSystem _hands = default!; [Dependency] private readonly ExamineSystemShared _examine = default!; From a7e6e3a1aaf3a206b09db2f6d7a712b8b6bd7922 Mon Sep 17 00:00:00 2001 From: Plykiya <58439124+Plykiya@users.noreply.github.com> Date: Thu, 18 Jul 2024 18:08:52 -0700 Subject: [PATCH 272/765] Fix for thrown items dealing damage twice to first target (#30115) * FUCK YOU * fine --------- Co-authored-by: plykiya --- .../Damage/Systems/DamageOtherOnHitSystem.cs | 32 ++++++++----------- 1 file changed, 13 insertions(+), 19 deletions(-) diff --git a/Content.Server/Damage/Systems/DamageOtherOnHitSystem.cs b/Content.Server/Damage/Systems/DamageOtherOnHitSystem.cs index ff4d1cabe98..8a7b3df0b24 100644 --- a/Content.Server/Damage/Systems/DamageOtherOnHitSystem.cs +++ b/Content.Server/Damage/Systems/DamageOtherOnHitSystem.cs @@ -32,31 +32,25 @@ public override void Initialize() private void OnDoHit(EntityUid uid, DamageOtherOnHitComponent component, ThrowDoHitEvent args) { - if (!TerminatingOrDeleted(args.Target)) - { - var dmg = _damageable.TryChangeDamage(args.Target, component.Damage, component.IgnoreResistances, origin: args.Component.Thrower); + if (TerminatingOrDeleted(args.Target)) + return; - // Log damage only for mobs. Useful for when people throw spears at each other, but also avoids log-spam when explosions send glass shards flying. - if (dmg != null && HasComp(args.Target)) - _adminLogger.Add(LogType.ThrowHit, $"{ToPrettyString(args.Target):target} received {dmg.GetTotal():damage} damage from collision"); + var dmg = _damageable.TryChangeDamage(args.Target, component.Damage, component.IgnoreResistances, origin: args.Component.Thrower); - if (dmg is { Empty: false }) - { - _color.RaiseEffect(Color.Red, new List() { args.Target }, Filter.Pvs(args.Target, entityManager: EntityManager)); - } + // Log damage only for mobs. Useful for when people throw spears at each other, but also avoids log-spam when explosions send glass shards flying. + if (dmg != null && HasComp(args.Target)) + _adminLogger.Add(LogType.ThrowHit, $"{ToPrettyString(args.Target):target} received {dmg.GetTotal():damage} damage from collision"); - _guns.PlayImpactSound(args.Target, dmg, null, false); - if (TryComp(uid, out var body) && body.LinearVelocity.LengthSquared() > 0f) - { - var direction = body.LinearVelocity.Normalized(); - _sharedCameraRecoil.KickCamera(args.Target, direction); - } + if (dmg is { Empty: false }) + { + _color.RaiseEffect(Color.Red, new List() { args.Target }, Filter.Pvs(args.Target, entityManager: EntityManager)); } - // TODO: If more stuff touches this then handle it after. - if (TryComp(uid, out var physics)) + _guns.PlayImpactSound(args.Target, dmg, null, false); + if (TryComp(uid, out var body) && body.LinearVelocity.LengthSquared() > 0f) { - _thrownItem.LandComponent(args.Thrown, args.Component, physics, false); + var direction = body.LinearVelocity.Normalized(); + _sharedCameraRecoil.KickCamera(args.Target, direction); } } From 4743ba099ada5e09fc4da82788b27836de5e10b9 Mon Sep 17 00:00:00 2001 From: PJBot Date: Fri, 19 Jul 2024 01:10:01 +0000 Subject: [PATCH 273/765] Automatic changelog update --- Resources/Changelog/Changelog.yml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 6f0ba27d307..74a116880f6 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,12 +1,4 @@ Entries: -- author: Beck Thompson - changes: - - message: Radio jammer now has 3 selectable power operating levels and a battery - level led indicator! - type: Tweak - id: 6434 - time: '2024-04-25T02:19:17.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/25912 - author: cooldolphin changes: - message: Three variants of glasses are now available in the loadout menu. @@ -3805,3 +3797,11 @@ id: 6933 time: '2024-07-18T22:36:53.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/30095 +- author: Plykiya + changes: + - message: You no longer deal double damage to your first target when throwing an + item. + type: Fix + id: 6934 + time: '2024-07-19T01:08:52.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/30115 From e401ccff85b71dd6d5c31cf2b1fc0f0f1c9fd814 Mon Sep 17 00:00:00 2001 From: Ed <96445749+TheShuEd@users.noreply.github.com> Date: Fri, 19 Jul 2024 11:13:35 +0300 Subject: [PATCH 274/765] randomize iconSmoothing (#28158) * randomize iconSmoothing * Revert "randomize iconSmoothing" This reverts commit 094356f975737c0af24ce39d849aec7852b9af6e. * try 2 * trying work with client-server communication * still dont work * Tayrtahn good suggestion * remove outdated code * Fix! * move data to Appearance * Update RandomIconSmoothComponent.cs --- .../ClientRandomIconSmoothSystem.cs | 29 ++++++++ .../IconSmoothing/IconSmoothComponent.cs | 2 +- .../IconSmoothing/IconSmoothSystem.cs | 35 +++++++--- .../IconSmoothing/RandomIconSmoothSystem.cs | 26 +++++++ .../RandomIconSmoothComponent.cs | 16 +++++ .../SharedRandomIconSmoothSystem.cs | 12 ++++ .../Entities/Structures/Walls/walls.yml | 5 ++ .../Structures/Walls/mining.rsi/meta.json | 66 +++++++++++++----- .../Structures/Walls/mining.rsi/miningB0.png | Bin 0 -> 1192 bytes .../Structures/Walls/mining.rsi/miningB1.png | Bin 0 -> 1470 bytes .../Structures/Walls/mining.rsi/miningB2.png | Bin 0 -> 1192 bytes .../Structures/Walls/mining.rsi/miningB3.png | Bin 0 -> 1470 bytes .../Structures/Walls/mining.rsi/miningB4.png | Bin 0 -> 1446 bytes .../Structures/Walls/mining.rsi/miningB5.png | Bin 0 -> 1451 bytes .../Structures/Walls/mining.rsi/miningB6.png | Bin 0 -> 1446 bytes .../Structures/Walls/mining.rsi/miningB7.png | Bin 0 -> 962 bytes 16 files changed, 165 insertions(+), 26 deletions(-) create mode 100644 Content.Client/IconSmoothing/ClientRandomIconSmoothSystem.cs create mode 100644 Content.Server/IconSmoothing/RandomIconSmoothSystem.cs create mode 100644 Content.Shared/IconSmoothing/RandomIconSmoothComponent.cs create mode 100644 Content.Shared/IconSmoothing/SharedRandomIconSmoothSystem.cs create mode 100644 Resources/Textures/Structures/Walls/mining.rsi/miningB0.png create mode 100644 Resources/Textures/Structures/Walls/mining.rsi/miningB1.png create mode 100644 Resources/Textures/Structures/Walls/mining.rsi/miningB2.png create mode 100644 Resources/Textures/Structures/Walls/mining.rsi/miningB3.png create mode 100644 Resources/Textures/Structures/Walls/mining.rsi/miningB4.png create mode 100644 Resources/Textures/Structures/Walls/mining.rsi/miningB5.png create mode 100644 Resources/Textures/Structures/Walls/mining.rsi/miningB6.png create mode 100644 Resources/Textures/Structures/Walls/mining.rsi/miningB7.png diff --git a/Content.Client/IconSmoothing/ClientRandomIconSmoothSystem.cs b/Content.Client/IconSmoothing/ClientRandomIconSmoothSystem.cs new file mode 100644 index 00000000000..73db9e1ab95 --- /dev/null +++ b/Content.Client/IconSmoothing/ClientRandomIconSmoothSystem.cs @@ -0,0 +1,29 @@ +using Content.Shared.IconSmoothing; +using Robust.Client.GameObjects; + +namespace Content.Client.IconSmoothing; + +public sealed class ClientRandomIconSmoothSystem : SharedRandomIconSmoothSystem +{ + [Dependency] private readonly IconSmoothSystem _iconSmooth = default!; + [Dependency] private readonly AppearanceSystem _appearance = default!; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnAppearanceChange); + } + + private void OnAppearanceChange(Entity ent, ref AppearanceChangeEvent args) + { + if (!TryComp(ent, out var smooth)) + return; + + if (!_appearance.TryGetData(ent, RandomIconSmoothState.State, out var state, args.Component)) + return; + + smooth.StateBase = state; + _iconSmooth.SetStateBase(ent, smooth, state); + } +} diff --git a/Content.Client/IconSmoothing/IconSmoothComponent.cs b/Content.Client/IconSmoothing/IconSmoothComponent.cs index 88b1f613cb7..040198529c7 100644 --- a/Content.Client/IconSmoothing/IconSmoothComponent.cs +++ b/Content.Client/IconSmoothing/IconSmoothComponent.cs @@ -30,7 +30,7 @@ public sealed partial class IconSmoothComponent : Component /// Prepended to the RSI state. /// [ViewVariables(VVAccess.ReadWrite), DataField("base")] - public string StateBase { get; private set; } = string.Empty; + public string StateBase { get; set; } = string.Empty; [DataField("shader", customTypeSerializer:typeof(PrototypeIdSerializer))] public string? Shader; diff --git a/Content.Client/IconSmoothing/IconSmoothSystem.cs b/Content.Client/IconSmoothing/IconSmoothSystem.cs index 4b025608465..11ca75bc824 100644 --- a/Content.Client/IconSmoothing/IconSmoothSystem.cs +++ b/Content.Client/IconSmoothing/IconSmoothSystem.cs @@ -55,6 +55,33 @@ private void OnStartup(EntityUid uid, IconSmoothComponent component, ComponentSt if (component.Mode != IconSmoothingMode.Corners || !TryComp(uid, out SpriteComponent? sprite)) return; + SetCornerLayers(sprite, component); + + if (component.Shader != null) + { + sprite.LayerSetShader(CornerLayers.SE, component.Shader); + sprite.LayerSetShader(CornerLayers.NE, component.Shader); + sprite.LayerSetShader(CornerLayers.NW, component.Shader); + sprite.LayerSetShader(CornerLayers.SW, component.Shader); + } + } + + public void SetStateBase(EntityUid uid, IconSmoothComponent component, string newState) + { + if (!TryComp(uid, out var sprite)) + return; + + component.StateBase = newState; + SetCornerLayers(sprite, component); + } + + private void SetCornerLayers(SpriteComponent sprite, IconSmoothComponent component) + { + sprite.LayerMapRemove(CornerLayers.SE); + sprite.LayerMapRemove(CornerLayers.NE); + sprite.LayerMapRemove(CornerLayers.NW); + sprite.LayerMapRemove(CornerLayers.SW); + var state0 = $"{component.StateBase}0"; sprite.LayerMapSet(CornerLayers.SE, sprite.AddLayerState(state0)); sprite.LayerSetDirOffset(CornerLayers.SE, DirectionOffset.None); @@ -64,14 +91,6 @@ private void OnStartup(EntityUid uid, IconSmoothComponent component, ComponentSt sprite.LayerSetDirOffset(CornerLayers.NW, DirectionOffset.Flip); sprite.LayerMapSet(CornerLayers.SW, sprite.AddLayerState(state0)); sprite.LayerSetDirOffset(CornerLayers.SW, DirectionOffset.Clockwise); - - if (component.Shader != null) - { - sprite.LayerSetShader(CornerLayers.SE, component.Shader); - sprite.LayerSetShader(CornerLayers.NE, component.Shader); - sprite.LayerSetShader(CornerLayers.NW, component.Shader); - sprite.LayerSetShader(CornerLayers.SW, component.Shader); - } } private void OnShutdown(EntityUid uid, IconSmoothComponent component, ComponentShutdown args) diff --git a/Content.Server/IconSmoothing/RandomIconSmoothSystem.cs b/Content.Server/IconSmoothing/RandomIconSmoothSystem.cs new file mode 100644 index 00000000000..4ddfb17ac84 --- /dev/null +++ b/Content.Server/IconSmoothing/RandomIconSmoothSystem.cs @@ -0,0 +1,26 @@ +using Content.Shared.IconSmoothing; +using Robust.Shared.Random; + +namespace Content.Server.IconSmoothing; + +public sealed partial class RandomIconSmoothSystem : SharedRandomIconSmoothSystem +{ + [Dependency] private readonly IRobustRandom _random = default!; + [Dependency] private readonly SharedAppearanceSystem _appearance = default!; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnMapInit); + } + + private void OnMapInit(Entity ent, ref MapInitEvent args) + { + if (ent.Comp.RandomStates.Count == 0) + return; + + var state = _random.Pick(ent.Comp.RandomStates); + _appearance.SetData(ent, RandomIconSmoothState.State, state); + } +} diff --git a/Content.Shared/IconSmoothing/RandomIconSmoothComponent.cs b/Content.Shared/IconSmoothing/RandomIconSmoothComponent.cs new file mode 100644 index 00000000000..6cdf167b295 --- /dev/null +++ b/Content.Shared/IconSmoothing/RandomIconSmoothComponent.cs @@ -0,0 +1,16 @@ +using Robust.Shared.GameStates; + +namespace Content.Shared.IconSmoothing; + +/// +/// Allow randomize StateBase of IconSmoothComponent for random visual variation +/// +[RegisterComponent, NetworkedComponent] +public sealed partial class RandomIconSmoothComponent : Component +{ + /// + /// StateBase will be randomly selected from this list. Allows to randomize the visual. + /// + [DataField(required: true)] + public List RandomStates = new(); +} diff --git a/Content.Shared/IconSmoothing/SharedRandomIconSmoothSystem.cs b/Content.Shared/IconSmoothing/SharedRandomIconSmoothSystem.cs new file mode 100644 index 00000000000..5cb5299858c --- /dev/null +++ b/Content.Shared/IconSmoothing/SharedRandomIconSmoothSystem.cs @@ -0,0 +1,12 @@ +using Robust.Shared.Serialization; + +namespace Content.Shared.IconSmoothing; + +public abstract class SharedRandomIconSmoothSystem : EntitySystem +{ +} +[Serializable, NetSerializable] +public enum RandomIconSmoothState : byte +{ + State +} diff --git a/Resources/Prototypes/Entities/Structures/Walls/walls.yml b/Resources/Prototypes/Entities/Structures/Walls/walls.yml index c1c525b7d38..272f9c0e569 100644 --- a/Resources/Prototypes/Entities/Structures/Walls/walls.yml +++ b/Resources/Prototypes/Entities/Structures/Walls/walls.yml @@ -1113,6 +1113,11 @@ - type: IconSmooth key: walls base: mining + - type: RandomIconSmooth + randomStates: + - mining + - miningB + - type: Appearance - type: entity parent: WallShuttleDiagonal diff --git a/Resources/Textures/Structures/Walls/mining.rsi/meta.json b/Resources/Textures/Structures/Walls/mining.rsi/meta.json index 4ce4691c516..77f43229984 100644 --- a/Resources/Textures/Structures/Walls/mining.rsi/meta.json +++ b/Resources/Textures/Structures/Walls/mining.rsi/meta.json @@ -7,40 +7,72 @@ "y": 32 }, "states": [ - { + { "name": "full" }, - { + { "name": "mining0", - "directions": 4 + "directions": 4 }, - { + { "name": "mining1", - "directions": 4 + "directions": 4 }, - { + { "name": "mining2", - "directions": 4 + "directions": 4 }, - { + { "name": "mining3", - "directions": 4 + "directions": 4 }, - { + { "name": "mining4", - "directions": 4 + "directions": 4 }, - { + { "name": "mining5", - "directions": 4 + "directions": 4 }, - { + { "name": "mining6", - "directions": 4 + "directions": 4 }, - { + { "name": "mining7", - "directions": 4 + "directions": 4 + }, + { + "name": "miningB0", + "directions": 4 + }, + { + "name": "miningB1", + "directions": 4 + }, + { + "name": "miningB2", + "directions": 4 + }, + { + "name": "miningB3", + "directions": 4 + }, + { + "name": "miningB4", + "directions": 4 + }, + { + "name": "miningB5", + "directions": 4 + }, + { + "name": "miningB6", + "directions": 4 + }, + { + "name": "miningB7", + "directions": 4 } ] } diff --git a/Resources/Textures/Structures/Walls/mining.rsi/miningB0.png b/Resources/Textures/Structures/Walls/mining.rsi/miningB0.png new file mode 100644 index 0000000000000000000000000000000000000000..f65f066b65aa26487dec4d03b79e560239294cff GIT binary patch literal 1192 zcmV;Z1XufsP)Px(Vo5|nRCt`-TTN=*Fckh$x|&^(jAj$M8cd<|08@jHP>L^CdWRfB;P?Qg5X7uX zH+C(P-E5}|^=V{{JxMFI7XBbiMwa8~`RTpy{pbb@W3$!d*BC z!dKcZV$TFG|f7^z#N*UnHe{#&seq& zFW`ba0)6KBTa;yquIua^Aq1q9Q0g)GdC3UCRc|tM08o}C?(gqMTcYnflw}F6^*S_Q ziue$^u0@{jFbq#tC^Wtr9^m?ar4A^H0!kf5a~QiFu|+esLLOi+9UizEa5}Aw3DOqG z^BwB?!R~n>wv+R>+iesLNWuoVZ#K)sNd2Xhzr8?f$As8IO1T~;2$=mm4E-N}h7zG* z0T7k_n|~e%kLN=XWeaf5QB~Efn&$ZqN&!Vtpzn#$>}HwX|3t6=7|T$WCBA+8IvVf$ zpD4?6#Mb)0yKrSoBiIWJLyxv?C$Eu47~lQ@N*yi|9ZMrv0E}h0adz?i8#a^X7~fKe zq5&?Z7@P6!^@z`>q6twnz$Ysd)BEET(_iEM{~N(Za2R@rteivEckkXqO8I+^(Fm9D zq=G13K&i*8u{q`QT%@uEqG-T=zXt$IVW+}ZADr_jR5ldBEbQ*?jSbzVl9uOdCei68 zKVwkYP(-1^A3uIV-*+Po05H-5r4ARx4W%9z7eEvnKn#x-=2m(LsaSm<(RsjgNKFt? zcz_SLyhXqJRzDS&7{vyJ+`qI9NG2t=6r$t2>|B>5)pDOJrSYQ5G^SR5EZ_esqL?n3g6wmInf(`jtWzdL|6qC z9){l5>k0mMiWXg@Vhf_!0M7Yr^~TK;xLqEpgu_uZpsK2iw0K=VpsFe;^_X-t>@Llz+-1}CEc0000Px)cu7P-RCt`-ThD9bMil#?ycD7+LJ$O?lx_wOm`o<{{dS2AmHRA&XKV)F zZzD;P&Eo-lwpaa@En#DLKqf43QNZQC<+hEn0MGNJXR~7FW%K9oJWq=S)b0ccaq-#q z89v;%@%&ka(+dlLjiZx!Ve*GJZNOGBF8XJ(ITmns`RGPK6xYLjyYK-=Cv%)$SU1Ya zaX{u;EI^qEwOYH`k6(O@>+6330H+rgj!x!F{T8#B|#T#Z9 zzn?$L@cQKz4)<*w?k}G6Sp;$=?QOr)GJ~p6_5p;r`1@%S-~Kkav#)3woz4p|_KWK4 zm7&D~l4Lc7T}5t^Br(DQlocQgu}WaM&9W>lUR)JgEMRdzTOunWn_Fgj8)5;T=OK>A zD@jYae;&+iHk(FRfbte(+ji#rA7L;UlzaiDQ@HL903b~l_W;mr=Eqq|sq%SV6#4=D;aXTj<~)mv{(SYuL@dwAs9>H`)$N=z73}7^k!rm zqtQt9^~z9IK`Ar^Py;WeJF(E?|+o;Hj=S9;4sy z6+FNsXi>oFg(d9m%SU1nJjZVew1vg_F}I2Z`hFY3VN^&%l#bN=o(EfW!UzRapjya|l3QQ6`t* z0eV;g>&7VlCulL5J3=NGRbR^vn+$>dGNQ-aCZ4f`Q65RH%N#J#?l90RqG4> Y0~R0y=v@s6*Z=?k07*qoM6N<$f>*Mv2><{9 literal 0 HcmV?d00001 diff --git a/Resources/Textures/Structures/Walls/mining.rsi/miningB2.png b/Resources/Textures/Structures/Walls/mining.rsi/miningB2.png new file mode 100644 index 0000000000000000000000000000000000000000..f65f066b65aa26487dec4d03b79e560239294cff GIT binary patch literal 1192 zcmV;Z1XufsP)Px(Vo5|nRCt`-TTN=*Fckh$x|&^(jAj$M8cd<|08@jHP>L^CdWRfB;P?Qg5X7uX zH+C(P-E5}|^=V{{JxMFI7XBbiMwa8~`RTpy{pbb@W3$!d*BC z!dKcZV$TFG|f7^z#N*UnHe{#&seq& zFW`ba0)6KBTa;yquIua^Aq1q9Q0g)GdC3UCRc|tM08o}C?(gqMTcYnflw}F6^*S_Q ziue$^u0@{jFbq#tC^Wtr9^m?ar4A^H0!kf5a~QiFu|+esLLOi+9UizEa5}Aw3DOqG z^BwB?!R~n>wv+R>+iesLNWuoVZ#K)sNd2Xhzr8?f$As8IO1T~;2$=mm4E-N}h7zG* z0T7k_n|~e%kLN=XWeaf5QB~Efn&$ZqN&!Vtpzn#$>}HwX|3t6=7|T$WCBA+8IvVf$ zpD4?6#Mb)0yKrSoBiIWJLyxv?C$Eu47~lQ@N*yi|9ZMrv0E}h0adz?i8#a^X7~fKe zq5&?Z7@P6!^@z`>q6twnz$Ysd)BEET(_iEM{~N(Za2R@rteivEckkXqO8I+^(Fm9D zq=G13K&i*8u{q`QT%@uEqG-T=zXt$IVW+}ZADr_jR5ldBEbQ*?jSbzVl9uOdCei68 zKVwkYP(-1^A3uIV-*+Po05H-5r4ARx4W%9z7eEvnKn#x-=2m(LsaSm<(RsjgNKFt? zcz_SLyhXqJRzDS&7{vyJ+`qI9NG2t=6r$t2>|B>5)pDOJrSYQ5G^SR5EZ_esqL?n3g6wmInf(`jtWzdL|6qC z9){l5>k0mMiWXg@Vhf_!0M7Yr^~TK;xLqEpgu_uZpsK2iw0K=VpsFe;^_X-t>@Llz+-1}CEc0000Px)cu7P-RCt`-ThD9bMil#?ycD7+LJ$O?lx_wOm`o<{{dS2AmHRA&XKV)F zZzD;P&Eo-lwpaa@En#DLKqf43QNZQC<+hEn0MGNJXR~7FW%K9oJWq=S)b0ccaq-#q z89v;%@%&ka(+dlLjiZx!Ve*GJZNOGBF8XJ(ITmns`RGPK6xYLjyYK-=Cv%)$SU1Ya zaX{u;EI^qEwOYH`k6(O@>+6330H+rgj!x!F{T8#B|#T#Z9 zzn?$L@cQKz4)<*w?k}G6Sp;$=?QOr)GJ~p6_5p;r`1@%S-~Kkav#)3woz4p|_KWK4 zm7&D~l4Lc7T}5t^Br(DQlocQgu}WaM&9W>lUR)JgEMRdzTOunWn_Fgj8)5;T=OK>A zD@jYae;&+iHk(FRfbte(+ji#rA7L;UlzaiDQ@HL903b~l_W;mr=Eqq|sq%SV6#4=D;aXTj<~)mv{(SYuL@dwAs9>H`)$N=z73}7^k!rm zqtQt9^~z9IK`Ar^Py;WeJF(E?|+o;Hj=S9;4sy z6+FNsXi>oFg(d9m%SU1nJjZVew1vg_F}I2Z`hFY3VN^&%l#bN=o(EfW!UzRapjya|l3QQ6`t* z0eV;g>&7VlCulL5J3=NGRbR^vn+$>dGNQ-aCZ4f`Q65RH%N#J#?l90RqG4> Y0~R0y=v@s6*Z=?k07*qoM6N<$f>*Mv2><{9 literal 0 HcmV?d00001 diff --git a/Resources/Textures/Structures/Walls/mining.rsi/miningB4.png b/Resources/Textures/Structures/Walls/mining.rsi/miningB4.png new file mode 100644 index 0000000000000000000000000000000000000000..1412f0026964552f50657b6c65ef5cb0c17fe7dc GIT binary patch literal 1446 zcmV;X1zGxuP)Px)U`a$lRCt`-ThD9bMilXKlGX`pgVHjzm3-Up z$bW?zknv$SLBHQe7)}5HQ4|%77jbglkZxBS2iye4nn;p){(N%Yz<0m=DgC`#IDm7W zUtPC@APAOup$IVo4v!Z~+SbAWrfF`>0gYvpi@i_J_+4&0qnoL=0MZd;8T zC14mv3IL2*NRrtbUl)solnv4jFbpHT>pu@b+5lNd4}ot#{}_8aukqu>9-=5hW651@ z+lKG^NRrud`T_=ne$MQG4#wlLZ1d8Pc0l{#CBk_FzaRfrct0AA;CUXx@Q?i6Y&Kn^ zx^+XzEKr`3Xugi)OvMSq2?m4y8k5rjN*r)<-pG6Qrd1l}{8r5GZ9&;INUOD~b-XyY zlcRKTf|3Xzae}z|ZN~X^tnY0?+5u%oMoU)F3A!ad5lX4BxMXFlSr9X*oUk=R;P7}+ zP-(<*Zdt8DU2?=G`Kt~{JD@7-({oy}U?bzVCIWz>I8im;MXjHDerqD&i;vzb5TSAc z)E&|esA7S{2^_}(fHkdOm+%J^5TOST?&D=*pxf;riXxb1miW5er|^BhP?yS7E4#Hq zW^0?YfI6W>50Lr%|6UIOfL^b+MsmtozWk2z#9|@0zb^~vB*>VR-&1nC$#?>(LUlp` z5n35>TY^J%MCa87B@tj*t>wuLGOU^Z0jmWPX#uX=foZn1hyZ1xD3ED>04jHN0HEK` z%7b84es=b%)+8w1c)Puu62YOBAU&7Y3FY$fcwGA|Q0p|vm{ofONKb=|Sujl#!{IO& zL8~CH3?0XT@B0PCxGqRLAW3HMJTE`WRxF$6iz9I;1VI4L^T0XZ4jvH4aX|=Kud_0q zB=abWw3r2y@__PExJnx=p8VJn9+0L*Jz#U)V%gS20ImC1@8$)aP<&5t97l@?P%;aA zvU7^}_YFLGoGxW@BNt2QI9n#1Jjy>8{2gyk1e{*n%atLzzSuYN9B_ENz{z=|u!nHK z7Ft9=?FS^K_2Bjh6CJ*i{r|IJ- z+8t0f;<`Nrv8>T(D49iScYtWbrfoKnQxuuzmPCN#tRIHFZe0!6ccX*XsdTm(0p2m#f%U z&>{lpzDhI|Q5IdbI4Ua(!!Xk4&p!p{(>IC$%W7dX3Z!#D?L&Yu3!G;sNH_g(icl`! zIvyZG++o_Z+q5-2po~qMtL6Kx;Q=zAmra8I0^6hPx)Wl2OqRCt`-Tfb`~M-={)tcuf}3b89|a5%zYMh#cEcwv#TG`Oft)U&3b3Y z8s6JC?|t*$Tfi_1g~H_F!%rvcURBq(bO@n}dc6+cznR`uL1`DYS`D2}2d?`W8jS`# z&kN@hLh$YVYXHDkKmDn+ws8g6b{W2Z1I7l^`%>h2qtU?0$q8Jy8jkt?4IXb7uvJtx z0DPqU3yNT@zwo)|d2roos34B5;sjU2obvj{6=2)t>9rJl`_Xx&L?x)g_!eNS4@#qB z^?Ducb~`p#RM6EhmkkBjb~&=Y0ifM(!*#3Zbb{@{*dS&dI)n#Opa91Dp`aqfF>d~g zw#d3Lt^nIE!*Lum8V&S%vrspgzFO6;n}V7 z`o|vUA$mc>>1Xs4lMzWeeaY zFB6$Xo*V#rJuej&pw$V=e4YO-UpbZ~L;eqFj{+i*kxy|l)60wn@CdL9IFYGTNGdEq z3lZ8XP7=@SJ3CKsad8gE*+4EA9dET-u8y2waXi8}}G0~YRAHb313tYDvCOSn>3gZ@_90laJzbK0XM31{^ zumCMgFi8oNc0mZ4^Iv?Pc^;s=1uV;gTM9y(Sit0=P6po|ja2(c1WO524(K~Hr< z0m@r|u|90Oyw)`hP~HN6{O~mZ;J3dXMG7003PG#Y0%Lu+ZWWYb8U=z#;5b28G#v$$ z74YH17+1p_E-ud_<8R-#(QGzB>HEld^vG=93bY)C`d?Pjrgyb`T`CpZtXHKc(DXvqigVx=e`KljUNauJ!Z0GVF_F4_`= zkW^TJvJ=ebEdY0T_55kL6+}gR|K%s)T(QLM-oM5#DX;)#1-yPY3=5>d%m)O5$D18Q z>YN51V6-+51PPU2zxy2H@i?*ll~L)oPJ3-b=77Wu~KF*th}$3+P71!~|+CmvoBM z_xX%*1teL3{L$2G?jUyJR7EPH0I(jJXPoD_~htq*958NFd+=M|+#f z>l@z!!B=A&bD#4NDHmQJKe*PizVYKQ?-5wH#ID+I{}1==6A-gv-!lLJ002ovPDHLk FV1kdcq8Px)U`a$lRCt`-ThD9bMilXKlGX`pgVHjzm3-Up z$bW?zknv$SLBHQe7)}5HQ4|%77jbglkZxBS2iye4nn;p){(N%Yz<0m=DgC`#IDm7W zUtPC@APAOup$IVo4v!Z~+SbAWrfF`>0gYvpi@i_J_+4&0qnoL=0MZd;8T zC14mv3IL2*NRrtbUl)solnv4jFbpHT>pu@b+5lNd4}ot#{}_8aukqu>9-=5hW651@ z+lKG^NRrud`T_=ne$MQG4#wlLZ1d8Pc0l{#CBk_FzaRfrct0AA;CUXx@Q?i6Y&Kn^ zx^+XzEKr`3Xugi)OvMSq2?m4y8k5rjN*r)<-pG6Qrd1l}{8r5GZ9&;INUOD~b-XyY zlcRKTf|3Xzae}z|ZN~X^tnY0?+5u%oMoU)F3A!ad5lX4BxMXFlSr9X*oUk=R;P7}+ zP-(<*Zdt8DU2?=G`Kt~{JD@7-({oy}U?bzVCIWz>I8im;MXjHDerqD&i;vzb5TSAc z)E&|esA7S{2^_}(fHkdOm+%J^5TOST?&D=*pxf;riXxb1miW5er|^BhP?yS7E4#Hq zW^0?YfI6W>50Lr%|6UIOfL^b+MsmtozWk2z#9|@0zb^~vB*>VR-&1nC$#?>(LUlp` z5n35>TY^J%MCa87B@tj*t>wuLGOU^Z0jmWPX#uX=foZn1hyZ1xD3ED>04jHN0HEK` z%7b84es=b%)+8w1c)Puu62YOBAU&7Y3FY$fcwGA|Q0p|vm{ofONKb=|Sujl#!{IO& zL8~CH3?0XT@B0PCxGqRLAW3HMJTE`WRxF$6iz9I;1VI4L^T0XZ4jvH4aX|=Kud_0q zB=abWw3r2y@__PExJnx=p8VJn9+0L*Jz#U)V%gS20ImC1@8$)aP<&5t97l@?P%;aA zvU7^}_YFLGoGxW@BNt2QI9n#1Jjy>8{2gyk1e{*n%atLzzSuYN9B_ENz{z=|u!nHK z7Ft9=?FS^K_2Bjh6CJ*i{r|IJ- z+8t0f;<`Nrv8>T(D49iScYtWbrfoKnQxuuzmPCN#tRIHFZe0!6ccX*XsdTm(0p2m#f%U z&>{lpzDhI|Q5IdbI4Ua(!!Xk4&p!p{(>IC$%W7dX3Z!#D?L&Yu3!G;sNH_g(icl`! zIvyZG++o_Z+q5-2po~qMtL6Kx;Q=zAmra8I0^6hPx&d`Uz>RCt{2TQO_fKotJmT0@m&a4sTRLJ7f^2a`bi144&VD1;W|xj&*yhOX(5 zrE|&HIfj-%A#~CZ$kM%vF{Yc0qh?U64t7xobB?SK$GUgn#M$2>$&!7(Pv70W_wGGF zF-+4;HZ~q7qDN}`Wf`5IVr^{=uInNQf|;JTZ5ywax&VM@?|+ioR!#t87It@c(Q38e zIMtcHb9Q!y`rZz%Ut1M)8r5r%yPK>)|8A`Gu)c>W5GQ^nRwf=*N-x38Q4#;nwN zWhx0_cm>8P<7*iTP(B30us?B~?qC+_d!49+6#B2v{gU zPyw=_oB+lwlmu6^X3ZqGubhCa0`6J{)6l{YO3wk=b^hkF*LK4G(??R;S580}_OZTh z!}r@$JI}#b1-{>wVg&*PFoYPh@OrsBw(SqU|DCwsteL2#`1KFR7cm^CI{u6b zji~S z0GWXF+s*6Gt2Tpyd$0p$_2);|8Yn;%NusF&@<0m(P>d066d+2177C!aq}nJTO+p@j zUJC`J-O@b%{OEZN6u@_A^7`|(Z5KiTWM80MF2kuH*XCxUu?^4j3ZVcpC|ld6Y0`sw zM39F-81})KC3GwT$V1@k+ZOs=3lWXij>Z5y8F;qvklaZKCar-DqtU@$}{ zDxr0fZ-3u)T^t>Kq&826G&>+~JRk@(i3b4b5Z59eFn{p?$_9lt3J~3^*Fpi5Lm?P7z~DZet1IaLt!#R(#qhSO&eMKoZqXj zUgsuIpqv24EPVO1IdeRL=OVmY)C(-?1s3%Jb6qc>O}e~lb67b6s?A~L1c)j?MwTd0 z00Kl6AY%mp3P6Bpy+9`_=}|BtS}&lL0&H8XUO)>&h%pPE=iQlKkgh9gG`3M+?n-H2 kxjW2r1Vp#ksp Date: Fri, 19 Jul 2024 05:04:43 -0400 Subject: [PATCH 275/765] Remove geras description in Slime Person guidebook page (#30140) remove entry --- Resources/ServerInfo/Guidebook/Mobs/SlimePerson.xml | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/Resources/ServerInfo/Guidebook/Mobs/SlimePerson.xml b/Resources/ServerInfo/Guidebook/Mobs/SlimePerson.xml index 2c11508749e..976ab472a9c 100644 --- a/Resources/ServerInfo/Guidebook/Mobs/SlimePerson.xml +++ b/Resources/ServerInfo/Guidebook/Mobs/SlimePerson.xml @@ -10,16 +10,8 @@ They exhale nitrous oxide and are unaffected by it. Their body can process 6 reagents at the same time instead of just 2. - Slimepeople can morph into a [bold]"geras"[/bold] (an archaic slimefolk term), which is a smaller slime form that can [bold]pass through grilles[/bold], - but forces them to drop their inventory and held items. It's handy for a quick getaway. A geras is small enough to pick up (with two hands) - and fits in a duffelbag. - - - - - Slimepeople have an [bold]internal 2x3 storage inventory[/bold] inside of their slime membrane. Anyone can see what's inside and take it out of you without asking, - so be careful. They [bold]don't drop their internal storage when they morph into a geras, however![/bold] + so be careful. Slimepeople have slight accelerated regeneration compared to other humanoids. They're also capable of hardening their fists, and as such have stronger punches, although they punch a little slower. From 92053e4212208c47f84df8976b81450d93df2156 Mon Sep 17 00:00:00 2001 From: PJBot Date: Fri, 19 Jul 2024 09:05:50 +0000 Subject: [PATCH 276/765] Automatic changelog update --- Resources/Changelog/Changelog.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 74a116880f6..88915109f55 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,11 +1,4 @@ Entries: -- author: cooldolphin - changes: - - message: Three variants of glasses are now available in the loadout menu. - type: Add - id: 6435 - time: '2024-04-25T23:18:39.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/27286 - author: EmoGarbage404 changes: - message: Traitors now have the correct number of objectives. @@ -3805,3 +3798,10 @@ id: 6934 time: '2024-07-19T01:08:52.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/30115 +- author: deepdarkdepths + changes: + - message: Removed the description about geras in the Slime guidebook section. + type: Remove + id: 6935 + time: '2024-07-19T09:04:43.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/30140 From 402962d097d5155dd63d76c425961bfb3412457f Mon Sep 17 00:00:00 2001 From: Alzore <140123969+Blackern5000@users.noreply.github.com> Date: Fri, 19 Jul 2024 04:38:26 -0500 Subject: [PATCH 277/765] Add the Syndicate Raid Suit (#29845) * Syndicate Raid Suit * Raid suit speed and whitelist * Fix copyright for the syndicate raid helmet --- .../Locale/en-US/store/uplink-catalog.ftl | 3 + .../Catalog/Fills/Backpacks/duffelbag.yml | 13 ++++ .../Prototypes/Catalog/uplink_catalog.yml | 16 ++++ .../Entities/Clothing/Head/helmets.yml | 18 +++++ .../Entities/Clothing/OuterClothing/armor.yml | 72 ++++++++++++++++++ .../syndie-raid.rsi/equipped-HELMET-vox.png | Bin 0 -> 464 bytes .../syndie-raid.rsi/equipped-HELMET.png | Bin 0 -> 439 bytes .../Head/Helmets/syndie-raid.rsi/icon.png | Bin 0 -> 289 bytes .../Helmets/syndie-raid.rsi/inhand-left.png | Bin 0 -> 388 bytes .../Helmets/syndie-raid.rsi/inhand-right.png | Bin 0 -> 376 bytes .../Head/Helmets/syndie-raid.rsi/meta.json | 30 ++++++++ .../equipped-OUTERCLOTHING-light-vox.png | Bin 0 -> 264 bytes .../equipped-OUTERCLOTHING-light.png | Bin 0 -> 268 bytes .../equipped-OUTERCLOTHING-vox.png | Bin 0 -> 743 bytes .../equipped-OUTERCLOTHING.png | Bin 0 -> 740 bytes .../Armor/syndie-raid.rsi/icon.png | Bin 0 -> 349 bytes .../Armor/syndie-raid.rsi/inhand-left.png | Bin 0 -> 422 bytes .../Armor/syndie-raid.rsi/inhand-right.png | Bin 0 -> 412 bytes .../Armor/syndie-raid.rsi/light-overlay.png | Bin 0 -> 199 bytes .../Armor/syndie-raid.rsi/meta.json | 41 ++++++++++ 20 files changed, 193 insertions(+) create mode 100644 Resources/Textures/Clothing/Head/Helmets/syndie-raid.rsi/equipped-HELMET-vox.png create mode 100644 Resources/Textures/Clothing/Head/Helmets/syndie-raid.rsi/equipped-HELMET.png create mode 100644 Resources/Textures/Clothing/Head/Helmets/syndie-raid.rsi/icon.png create mode 100644 Resources/Textures/Clothing/Head/Helmets/syndie-raid.rsi/inhand-left.png create mode 100644 Resources/Textures/Clothing/Head/Helmets/syndie-raid.rsi/inhand-right.png create mode 100644 Resources/Textures/Clothing/Head/Helmets/syndie-raid.rsi/meta.json create mode 100644 Resources/Textures/Clothing/OuterClothing/Armor/syndie-raid.rsi/equipped-OUTERCLOTHING-light-vox.png create mode 100644 Resources/Textures/Clothing/OuterClothing/Armor/syndie-raid.rsi/equipped-OUTERCLOTHING-light.png create mode 100644 Resources/Textures/Clothing/OuterClothing/Armor/syndie-raid.rsi/equipped-OUTERCLOTHING-vox.png create mode 100644 Resources/Textures/Clothing/OuterClothing/Armor/syndie-raid.rsi/equipped-OUTERCLOTHING.png create mode 100644 Resources/Textures/Clothing/OuterClothing/Armor/syndie-raid.rsi/icon.png create mode 100644 Resources/Textures/Clothing/OuterClothing/Armor/syndie-raid.rsi/inhand-left.png create mode 100644 Resources/Textures/Clothing/OuterClothing/Armor/syndie-raid.rsi/inhand-right.png create mode 100644 Resources/Textures/Clothing/OuterClothing/Armor/syndie-raid.rsi/light-overlay.png create mode 100644 Resources/Textures/Clothing/OuterClothing/Armor/syndie-raid.rsi/meta.json diff --git a/Resources/Locale/en-US/store/uplink-catalog.ftl b/Resources/Locale/en-US/store/uplink-catalog.ftl index 3a3e6e54e6c..4b91bcda982 100644 --- a/Resources/Locale/en-US/store/uplink-catalog.ftl +++ b/Resources/Locale/en-US/store/uplink-catalog.ftl @@ -319,6 +319,9 @@ uplink-hardsuit-carp-desc = Looks like an ordinary carp suit, except fully space uplink-hardsuit-syndie-name = Syndicate Hardsuit uplink-hardsuit-syndie-desc = The Syndicate's well known armored blood red hardsuit, capable of space walks and bullet resistant. +uplink-syndie-raid-name = Syndicate Raid Suit +uplink-syndie-raid-desc = A very durable and reasonably flexible suit of blood-red armor, reinforced against all common forms of damage but not capable of space walks. Comes with a sick helmet. + uplink-hardsuit-syndieelite-name = Syndicate Elite Hardsuit uplink-hardsuit-syndieelite-desc = An elite version of the blood-red hardsuit, with improved mobility and fireproofing. Property of Gorlex Marauders. diff --git a/Resources/Prototypes/Catalog/Fills/Backpacks/duffelbag.yml b/Resources/Prototypes/Catalog/Fills/Backpacks/duffelbag.yml index c07b0eccf19..75c23a0e61b 100644 --- a/Resources/Prototypes/Catalog/Fills/Backpacks/duffelbag.yml +++ b/Resources/Prototypes/Catalog/Fills/Backpacks/duffelbag.yml @@ -264,6 +264,19 @@ - id: DoubleEmergencyOxygenTankFilled - id: DoubleEmergencyNitrogenTankFilled +- type: entity + parent: ClothingBackpackDuffelSyndicateBundle + id: ClothingBackpackDuffelSyndicateRaidBundle + name: syndicate raid suit bundle + description: "Contains the Syndicate's durable raid armor suit." + components: + - type: StorageFill + contents: + - id: ClothingOuterArmorRaid + - id: ClothingHeadHelmetRaid + - id: ClothingMaskGasSyndicate + - id: ClothingHandsGlovesCombat + - type: entity parent: ClothingBackpackDuffelSyndicateBundle id: ClothingBackpackDuffelSyndicateHardsuitBundle diff --git a/Resources/Prototypes/Catalog/uplink_catalog.yml b/Resources/Prototypes/Catalog/uplink_catalog.yml index 8f6f0f2ce31..af4b9a9ce00 100644 --- a/Resources/Prototypes/Catalog/uplink_catalog.yml +++ b/Resources/Prototypes/Catalog/uplink_catalog.yml @@ -1308,6 +1308,22 @@ categories: - UplinkWearables +- type: listing + id: UplinkClothingOuterArmorRaid + name: uplink-syndie-raid-name + description: uplink-syndie-raid-desc + icon: { sprite: /Textures/Clothing/OuterClothing/Armor/syndie-raid.rsi, state: icon } + productEntity: ClothingBackpackDuffelSyndicateRaidBundle + cost: + Telecrystal: 8 + categories: + - UplinkWearables + conditions: + - !type:StoreWhitelistCondition + whitelist: + tags: + - NukeOpsUplink + - type: listing id: UplinkHardsuitSyndieElite name: uplink-hardsuit-syndieelite-name diff --git a/Resources/Prototypes/Entities/Clothing/Head/helmets.yml b/Resources/Prototypes/Entities/Clothing/Head/helmets.yml index 54e69ff708f..1593aecc01f 100644 --- a/Resources/Prototypes/Entities/Clothing/Head/helmets.yml +++ b/Resources/Prototypes/Entities/Clothing/Head/helmets.yml @@ -357,6 +357,24 @@ - type: Clothing sprite: Clothing/Head/Helmets/ert_janitor.rsi +- type: entity + parent: ClothingHeadHelmetBasic + id: ClothingHeadHelmetRaid + name: syndicate raid helmet + description: An armored helmet for use with the syndicate raid suit. Very stylish. + components: + - type: Sprite + sprite: Clothing/Head/Helmets/syndie-raid.rsi + - type: Clothing + sprite: Clothing/Head/Helmets/syndie-raid.rsi + - type: Armor + modifiers: #There's gotta be SOME reason to use this over other helmets. + coefficients: + Blunt: 0.85 + Slash: 0.85 + Piercing: 0.85 + Heat: 0.85 + #Bone Helmet - type: entity parent: ClothingHeadHelmetBasic diff --git a/Resources/Prototypes/Entities/Clothing/OuterClothing/armor.yml b/Resources/Prototypes/Entities/Clothing/OuterClothing/armor.yml index 606af0b127a..6de0c78220f 100644 --- a/Resources/Prototypes/Entities/Clothing/OuterClothing/armor.yml +++ b/Resources/Prototypes/Entities/Clothing/OuterClothing/armor.yml @@ -99,6 +99,78 @@ reflects: - Energy +- type: entity + parent: [ClothingOuterBaseLarge, AllowSuitStorageClothing] + id: ClothingOuterArmorRaid + name: syndicate raid suit + description: A somewhat flexible and well-armored suit with a powerful shoulder mounted flashlight manufactured in the Gorlex Marauder's iconic blood-red color scheme, it does not protect it's wearer from space. + components: + - type: Sprite + sprite: Clothing/OuterClothing/Armor/syndie-raid.rsi + layers: + - state: icon + - state: light-overlay + visible: false + shader: unshaded + - type: Clothing + sprite: Clothing/OuterClothing/Armor/syndie-raid.rsi + - type: Armor + modifiers: + coefficients: + Blunt: 0.35 + Slash: 0.35 + Piercing: 0.35 + Heat: 0.35 + Caustic: 0.5 + - type: ExplosionResistance + damageCoefficient: 0.35 + - type: ClothingSpeedModifier + walkModifier: 0.9 + sprintModifier: 0.9 + #Shoulder mounted flashlight + - type: ToggleableLightVisuals + spriteLayer: light + clothingVisuals: + outerClothing: + - state: equipped-OUTERCLOTHING-light + shader: unshaded + - type: Appearance + - type: HandheldLight + addPrefix: false + blinkingBehaviourId: blinking + radiatingBehaviourId: radiating + - type: PointLight + enabled: false + color: "#80ff80" + radius: 5 + energy: 2 + mask: /Textures/Effects/LightMasks/cone.png + autoRot: true + netsync: false + - type: LightBehaviour + behaviours: + - !type:FadeBehaviour + id: radiating + interpolate: Linear + maxDuration: 2.0 + startValue: 3.0 + endValue: 2.0 + isLooped: true + reverseWhenFinished: true + - !type:PulseBehaviour + id: blinking + interpolate: Nearest + maxDuration: 1.0 + minValue: 0.1 + maxValue: 2.0 + isLooped: true + - type: Battery + maxCharge: 600 + startingCharge: 600 + - type: BatterySelfRecharger + autoRecharge: true + autoRechargeRate: 2 + - type: entity parent: ClothingOuterBaseLarge id: ClothingOuterArmorCult diff --git a/Resources/Textures/Clothing/Head/Helmets/syndie-raid.rsi/equipped-HELMET-vox.png b/Resources/Textures/Clothing/Head/Helmets/syndie-raid.rsi/equipped-HELMET-vox.png new file mode 100644 index 0000000000000000000000000000000000000000..c7ab17e261db024cc28cc4bd39ccd9b5c96b9e2c GIT binary patch literal 464 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!7>k44ofy`glX(f`u%tWsIx;Y9 z?C1WI$O_~u2Ka=ydOBK|D5)edGlyE*WV*T^^$qqgFsxVCZusA@-rNePDzB9}XD2{24z1g*gj6B8wRq_>O=u<5X=vX`rQwo-U3d5$KYp zo1ahp)c&2EIj1>9HZ?vtR&m=uQ~n`y)x$JBlT(?8f81hY)r)t=;*IBdW1O3>m)3D1K|TW(6Tw5}F070Fl7`&Bbh>b$(8 z!l7TUpR=4Ut$MT~Do_0lqmk44ofy`glX(f`u%tWsIx;Y9 z?C1WI$O_~u2Ka=ydOBK|D5)edGlyE*WV*T^^$qqgFsxVCZusA@-rNePDzB9}XD2{24z1g*gj6B8wRq_zr?F*gaY|`gSWBu+v0fK#xHIwTw0HJA9&^9ExzxN|qQxZc_WQbyUk7uTqjob2MX5H| TzhwLcw4K4z)z4*}Q$iB}x@KnK literal 0 HcmV?d00001 diff --git a/Resources/Textures/Clothing/Head/Helmets/syndie-raid.rsi/inhand-left.png b/Resources/Textures/Clothing/Head/Helmets/syndie-raid.rsi/inhand-left.png new file mode 100644 index 0000000000000000000000000000000000000000..e8db961b7709cc1d13fba055e3128a3caa51f270 GIT binary patch literal 388 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!7>k44ofy`glX(f`u%tWsIx;Y9 z?C1WI$O`032l#}zdOBK|D5)edGlyE*9Q6(MFfgoF*KYXV0F;*(J!=G{I7@>3g8xGS zL$H5^5J<4VBeIx*f$snaGiF`ulFziEw{A?KIzE1s;~l)=&TAW6Um`I_5oP zMUekIXO3+%UFMi=kuPlIZs3k#Sks`XZ+Do*@Z5F%=TlbB6L9p3ICs3gAy)1^ci03k zt6xD&6sP`kxa!1W`Yr$HDweJP|G%|gp}&D6V3stm;1cEMH9fOu^xV3Wu_j?!Npp{H z1pC&l`%Evmacn!2m5{x!8)!q!1EvQ}`?*hi32r>e$IohJUC=mZ!k0Gk44ofy`glX(f`u%tWsIx;Y9 z?C1WI$O`032l#}zdOBK|D5)edGlyE*9Q6(MFfgoF*KYXV0F;*(J!=G{I7@>3g8xGS zL$H5^5J<4VBeIx*f$snaGiF`uVFq{;NbRCFAJD{u<7Ts+qlFrREavMK94z3&HQ23@(aD*ce`Jke-+62SM_CGP3a1t zfg%kI9ZVnO4@iB!`!-)FG+x3?U*4l4*S99W|N`g~UXwE0V; zL~L4A#JFaiIk0I`^NUSSHu*6yxF3?5S9x>mwPL%XH2+muJq1VgW)$BG$(`~^`xkHO1>s-RwWNGrB=3e_GPZzmMvTy?$^1B+LS|ih_pf4;%)4?`V&Qj9jjvm;SU%sg@>jsA zeu?uE-c^FnKAhYeHM=n2c^-4upN%5k@7e#)oVHP_b3V{s5K#Yfc-Naxt2eHf4lp~m z*#F?luN7;p3QjrSmArB3PQxM}2cB{^w`X-=wbPA!^A&?kn+1*Z7JvjiUHx3vIVCg! E0L}ztoB#j- literal 0 HcmV?d00001 diff --git a/Resources/Textures/Clothing/OuterClothing/Armor/syndie-raid.rsi/equipped-OUTERCLOTHING-vox.png b/Resources/Textures/Clothing/OuterClothing/Armor/syndie-raid.rsi/equipped-OUTERCLOTHING-vox.png new file mode 100644 index 0000000000000000000000000000000000000000..1ab6e6cfefe51dee46c988f49638bdb6991abdd1 GIT binary patch literal 743 zcmV?P)Px#1ZP1_K>z@;j|==^1poj5Ay7MMqCTIaN74 zNH8$~006-buL}SG01I?dPE-H?|NsC0|NsC007_2*@&Et;32;bRa{vGi!2kdb!2!6D zYwZ940ys%TK~z{r?N-~8>>volRiozrKX@A?33%Dm);SORFrCV%w01xph0cG(N8lsC z_@4r=T0u+K^QqGpMXAKt%Mq77Qe1vEP)yvSl=Dg<=A77vkTTuA7y-&DQeZ$Rn@=c& zKR_Rze*_}N7X}opkBS|C*9uWMj-%iWL`AI+m@gH4g@WN9DM(j+$~?aFMIOgLA;5wA zp+yK3TCJs(TASss8l`kQP(zaSun@krR`5Fh7Qhre0&b-RM3FtH@`m`hpcP_EX!>Z| zgTQwW!V~x{An4lw8$sJ6mb}#}*o1gcs>K6#rnBd*K!yUQr!4j%W6e8(gxx}AwUHTX z-qd+<2-AlJQ;P=(<#z%+{iYm&>2qa=6{wXNEoNX9h3~}$D}YZ2{apdd7|PpeBft{Z z&k{YhAwnnchSdjtC9uLr;3L5Ja{}{W{02XO;@6wPm_4}u5qH*$z?41M{x~&Ll#^c# z1B8lcd#G{>aOD7MaS(!&19$J)x*Xb^Bpho2W`cB53&RTVH;#iZ*JTWW?_G#{|C|8C zabj|UpausaY8~d;g@Y>tXEwW_76&0(+g~hbME2lE0eIkZ2iw5CPwc|xV&EGC4j=+c zJ2i$Zw$=wMsYw7KZf#_S002ovPDHLkV1h+HHWUB= literal 0 HcmV?d00001 diff --git a/Resources/Textures/Clothing/OuterClothing/Armor/syndie-raid.rsi/equipped-OUTERCLOTHING.png b/Resources/Textures/Clothing/OuterClothing/Armor/syndie-raid.rsi/equipped-OUTERCLOTHING.png new file mode 100644 index 0000000000000000000000000000000000000000..e6a0733e3e7a11c8d9eb3f1203348634d169174b GIT binary patch literal 740 zcmVPx#1ZP1_K>z@;j|==^1poj5Ay7vPg zlxW}gf=8;>dZP2S)QLZ8g@|i~L#<3yto4NO=v|=U_*1GBu2#ymKX_)yOJN@Pw?HYG z_oL*CgzyakHiXzl{w+W`9RXBMmswQ4wN~&r{t!r*f}^;VRuDD`BB=UcD_jLo;bx_q z69{~dfRA3l=t$Tmf@|lFB|jR4@`kcl!;V5iZ=QD%KmnVqgb}QGC$M3+P}xF(74HSG zI(Us(V8M?D%SVDJ!*fB`W?CR8APZ=}OR(~ub^`d0`p+8J2jJyrfD@3x@q_}a0sIT0 zZ`d8M0nF;~0#8^B@H>G8J^~*B!G8BzMr{AQFH)Nq$fx0p;K`@}q!A;K0KDZ{`Ff2sqHD zH}nx?s+u2I!vv)&`Q*X94yLE+^==IllxmpjXbv_eT8j_yT+hQ~EHu z-(?2^O(7g6^X6_==mqZJ1?2L761csc*t~X0000B9}XD2{24z1g*gj6B8wRq_zr_Go-U3d7XEK11o9nL;BlVI%Jldj z`@GA`RM%YnW}C^kBEeR{^qBbH##qjVBS{xoJ~UVW-hB4pr}agAMMoY}hL&`rDUtLY2t7Di867xAXpqHaJ8kuCuk- zE79KnL5!itljSH!%T^|y)e(ZnQa-zj9e8YFcUbV4^?@xmdfTLab36R3{K;Y=#C=_M e!wdEX!#IO?%1Re@d_4_xIfJLGpUXO@geCxweu13; literal 0 HcmV?d00001 diff --git a/Resources/Textures/Clothing/OuterClothing/Armor/syndie-raid.rsi/inhand-left.png b/Resources/Textures/Clothing/OuterClothing/Armor/syndie-raid.rsi/inhand-left.png new file mode 100644 index 0000000000000000000000000000000000000000..64d25308ab68dab7296df91bbd2c646a2ef7698b GIT binary patch literal 422 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!7>k44ofy`glX(f`u%tWsIx;Y9 z?C1WI$O`032l#}zCNVQN{BNjN*EUg7*(%59?`WCn>K8JN?v*SZ zX&$$@MDMfTFJ5eH{Gh02z?jG+ETB`7l6k0vTmQ}qH3~CuF-aCJgyYjbohQ0ZG{kWivL!KKf_g!Ntwcwsq92n5LU%8{3=eky@ z1?P*kul_eWiR!Vg*>k9g$NolHKc|nwi~}r3;yFdGuBct7?d+6UF2Xqf_tFPbx$=tl zKNUIC&XTv>;qX`CM?2-27b`X%Z?X_CiFsL**4Ne&=*{t}c)#k_&%F*@mza52zxRJ| zb?iA&yg&JZ2ve@df-*hUt8A$rJ97QY*L=u!T6l{an^LB{Ts5 D1;C-U literal 0 HcmV?d00001 diff --git a/Resources/Textures/Clothing/OuterClothing/Armor/syndie-raid.rsi/inhand-right.png b/Resources/Textures/Clothing/OuterClothing/Armor/syndie-raid.rsi/inhand-right.png new file mode 100644 index 0000000000000000000000000000000000000000..fd3c44d4ad09e49a525fcb1f0e7f0ddd22400859 GIT binary patch literal 412 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!7>k44ofy`glX(f`u%tWsIx;Y9 z?C1WI$O`032l#}zCNVQN{BNjN*EUg7*(%59?`WCn>KB*Ojew1a#t3Op{mLmU79Pl|SMv67hF zd-L$ON`YlhDnA?u_$4I1!=bQ|TSS}T)b8~&Bx@@!nj1gg%dlv2pu=mg+uNodHF;&g z^h}^ca0Y*4ua%FJNV1QnTb8oG+#4C4UsqN$y6`GQIMr1(_DXpK>?;$TvEpNsLtpwU zJ?2Hs3K#y{{woj&P4N0w-?+k{bN*u{aSgqK#!ux;1ybAz!V?ZJ&`4m+VOpvo(>;eH zf?+m;9+!tgE!lvI6;>1s;*b3=DjSK$uZf!>a)(7~|>U7!u+B_EI8Og91<6!<#4fM7~bDcP7o} zgL}(F!K=Ry{5WDi+nMo$)GX6qg)2^eHjHKd@%piBG{?N%v)WYCS0B}y%FVm$X=poh qNGWqzX2|2qcE33p85sWgrLaa6iMXCUbW#Fn4}+(xpUXO@geCyZ)kISO literal 0 HcmV?d00001 diff --git a/Resources/Textures/Clothing/OuterClothing/Armor/syndie-raid.rsi/meta.json b/Resources/Textures/Clothing/OuterClothing/Armor/syndie-raid.rsi/meta.json new file mode 100644 index 00000000000..ff590848daa --- /dev/null +++ b/Resources/Textures/Clothing/OuterClothing/Armor/syndie-raid.rsi/meta.json @@ -0,0 +1,41 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Made by alzore_(Discord) for SS14 using the colors of the blood-red hardsuit", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "icon" + }, + { + "name": "light-overlay" + }, + { + "name": "equipped-OUTERCLOTHING", + "directions": 4 + }, + { + "name": "equipped-OUTERCLOTHING-light", + "directions": 4 + }, + { + "name": "equipped-OUTERCLOTHING-vox", + "directions": 4 + }, + { + "name": "equipped-OUTERCLOTHING-light-vox", + "directions": 4 + }, + { + "name": "inhand-left", + "directions": 4 + }, + { + "name": "inhand-right", + "directions": 4 + } + ] +} From 97b634bdfaa69804a28695773b188c06f21aab93 Mon Sep 17 00:00:00 2001 From: PJBot Date: Fri, 19 Jul 2024 09:39:32 +0000 Subject: [PATCH 278/765] Automatic changelog update --- Resources/Changelog/Changelog.yml | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 88915109f55..762d5d942d9 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,16 +1,4 @@ Entries: -- author: EmoGarbage404 - changes: - - message: Traitors now have the correct number of objectives. - type: Fix - - message: Declaring war now gives TC again. - type: Fix - - message: Latejoining antagonists will now properly exclude command and security - staff. - type: Fix - id: 6436 - time: '2024-04-26T00:25:57.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/27319 - author: Tayrtahn changes: - message: Fixed Bibles not healing. @@ -3805,3 +3793,11 @@ id: 6935 time: '2024-07-19T09:04:43.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/30140 +- author: Blackern5000 + changes: + - message: Nuclear operatives are now able to purchase durable armor which is NOT + space-proof. + type: Add + id: 6936 + time: '2024-07-19T09:38:26.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/29845 From a453d90df560ecc09f41bd5f117f026140f161e9 Mon Sep 17 00:00:00 2001 From: slarticodefast <161409025+slarticodefast@users.noreply.github.com> Date: Fri, 19 Jul 2024 11:42:58 +0200 Subject: [PATCH 279/765] Fix EmbeddableProjectileComponent and ThrowingAngleComponent interaction (#30112) * fix embeddable offset with throwing angle * number --- Content.Shared/Projectiles/SharedProjectileSystem.cs | 5 ++++- .../Prototypes/Entities/Objects/Weapons/Melee/spear.yml | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/Content.Shared/Projectiles/SharedProjectileSystem.cs b/Content.Shared/Projectiles/SharedProjectileSystem.cs index b718c3a6900..1f6f2b6918f 100644 --- a/Content.Shared/Projectiles/SharedProjectileSystem.cs +++ b/Content.Shared/Projectiles/SharedProjectileSystem.cs @@ -120,7 +120,10 @@ private void Embed(EntityUid uid, EntityUid target, EntityUid? user, EmbeddableP if (component.Offset != Vector2.Zero) { - _transform.SetLocalPosition(uid, xform.LocalPosition + xform.LocalRotation.RotateVec(component.Offset), + var rotation = xform.LocalRotation; + if (TryComp(uid, out var throwingAngleComp)) + rotation += throwingAngleComp.Angle; + _transform.SetLocalPosition(uid, xform.LocalPosition + rotation.RotateVec(component.Offset), xform); } diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Melee/spear.yml b/Resources/Prototypes/Entities/Objects/Weapons/Melee/spear.yml index ea2e73ac151..608fb2544ae 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Melee/spear.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Melee/spear.yml @@ -5,7 +5,7 @@ description: Definition of a Classic. Keeping murder affordable since 200,000 BCE. components: - type: EmbeddableProjectile - offset: 0.15,0.15 + offset: -0.15,0.0 - type: ThrowingAngle angle: 225 - type: LandAtCursor From b4d359cf6c65393f475bdd2251587b092f82ae79 Mon Sep 17 00:00:00 2001 From: PJBot Date: Fri, 19 Jul 2024 09:44:04 +0000 Subject: [PATCH 280/765] Automatic changelog update --- Resources/Changelog/Changelog.yml | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 762d5d942d9..bf3d66cacee 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,13 +1,4 @@ Entries: -- author: Tayrtahn - changes: - - message: Fixed Bibles not healing. - type: Fix - - message: Fixed quick insert and area insert not working on ore/plant/trash bags. - type: Fix - id: 6437 - time: '2024-04-26T02:25:52.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/27234 - author: SkaldetSkaeg changes: - message: The handheld radio no longer plays a message spoken into it. @@ -3801,3 +3792,10 @@ id: 6936 time: '2024-07-19T09:38:26.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/29845 +- author: Plykiya, slarticodefast + changes: + - message: Explosive pens now correctly embed into their target. + type: Fix + id: 6937 + time: '2024-07-19T09:42:58.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/30112 From d32ccbf26de864c69a900cbf9c08d7314ae5f264 Mon Sep 17 00:00:00 2001 From: DakotaGay Date: Fri, 19 Jul 2024 16:18:39 +0200 Subject: [PATCH 281/765] Fix Markup Tags in Station News (#30169) * Fix (hopefully) * Fixed Spelling Mistake and minor Code Cleanup * Revert "Fixed Spelling Mistake and minor Code Cleanup" due to Pull Request Guidelines This reverts commit cee3e0226b349187bd8fd8b639e161fb877e8bdb. --- .../CartridgeLoader/Cartridges/NewsReaderUiFragment.xaml.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Content.Client/CartridgeLoader/Cartridges/NewsReaderUiFragment.xaml.cs b/Content.Client/CartridgeLoader/Cartridges/NewsReaderUiFragment.xaml.cs index f3b2d373d74..2d4d192ea8a 100644 --- a/Content.Client/CartridgeLoader/Cartridges/NewsReaderUiFragment.xaml.cs +++ b/Content.Client/CartridgeLoader/Cartridges/NewsReaderUiFragment.xaml.cs @@ -31,7 +31,7 @@ public void UpdateState(NewsArticle article, int targetNum, int totalNum, bool n Author.Visible = true; PageName.Text = article.Title; - PageText.SetMarkup(article.Content); + PageText.SetMarkupPermissive(article.Content); PageNum.Text = $"{targetNum}/{totalNum}"; From 1790b76fd91a498b6b560fb88d157841a0f4d101 Mon Sep 17 00:00:00 2001 From: PJBot Date: Fri, 19 Jul 2024 14:19:45 +0000 Subject: [PATCH 282/765] Automatic changelog update --- Resources/Changelog/Changelog.yml | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index bf3d66cacee..dc929e08dc6 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,11 +1,4 @@ Entries: -- author: SkaldetSkaeg - changes: - - message: The handheld radio no longer plays a message spoken into it. - type: Tweak - id: 6438 - time: '2024-04-26T07:34:20.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/27046 - author: FungiFellow changes: - message: Added SecBelt whitelist to Sec webbing @@ -3799,3 +3792,11 @@ id: 6937 time: '2024-07-19T09:42:58.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/30112 +- author: ThatOneEnby1337 + changes: + - message: News Reporters are now able to use markup tags in their reports without + bricking the PDAs of readers + type: Fix + id: 6938 + time: '2024-07-19T14:18:39.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/30169 From 3706f265a8d525387b275ad76ca5254a6cba8d0a Mon Sep 17 00:00:00 2001 From: themias <89101928+themias@users.noreply.github.com> Date: Fri, 19 Jul 2024 22:31:26 -0400 Subject: [PATCH 283/765] Fix mailing unit UI (#30174) --- Content.Client/Disposal/UI/MailingUnitWindow.xaml.cs | 9 +++++++-- Content.Server/Disposal/Mailing/MailingUnitSystem.cs | 5 +++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/Content.Client/Disposal/UI/MailingUnitWindow.xaml.cs b/Content.Client/Disposal/UI/MailingUnitWindow.xaml.cs index 797e20ae7d2..489d749a0cf 100644 --- a/Content.Client/Disposal/UI/MailingUnitWindow.xaml.cs +++ b/Content.Client/Disposal/UI/MailingUnitWindow.xaml.cs @@ -2,6 +2,7 @@ using Robust.Client.AutoGenerated; using Robust.Client.UserInterface.CustomControls; using Robust.Client.UserInterface.XAML; +using Robust.Shared.Timing; namespace Content.Client.Disposal.UI { @@ -11,6 +12,8 @@ namespace Content.Client.Disposal.UI [GenerateTypedNameReferences] public sealed partial class MailingUnitWindow : DefaultWindow { + public TimeSpan FullPressure; + public MailingUnitWindow() { RobustXamlLoader.Load(this); @@ -26,6 +29,7 @@ public bool UpdateState(MailingUnitBoundUserInterfaceState state) Title = Loc.GetString("ui-mailing-unit-window-title", ("tag", state.Tag ?? " ")); UnitState.Text = disposalState.UnitState; + FullPressure = disposalState.FullPressureTime; var pressureReached = PressureBar.UpdatePressure(disposalState.FullPressureTime); Power.Pressed = disposalState.Powered; Engage.Pressed = disposalState.Engaged; @@ -42,9 +46,10 @@ public bool UpdateState(MailingUnitBoundUserInterfaceState state) return !disposalState.Powered || pressureReached; } - public bool UpdatePressure(TimeSpan stateFullPressureTime) + protected override void FrameUpdate(FrameEventArgs args) { - return PressureBar.UpdatePressure(stateFullPressureTime); + base.FrameUpdate(args); + PressureBar.UpdatePressure(FullPressure); } } } diff --git a/Content.Server/Disposal/Mailing/MailingUnitSystem.cs b/Content.Server/Disposal/Mailing/MailingUnitSystem.cs index e1fbdbf0894..6249b9497d8 100644 --- a/Content.Server/Disposal/Mailing/MailingUnitSystem.cs +++ b/Content.Server/Disposal/Mailing/MailingUnitSystem.cs @@ -9,6 +9,7 @@ using Content.Shared.Interaction; using Robust.Server.GameObjects; using Robust.Shared.Player; +using Robust.Shared.Utility; namespace Content.Server.Disposal.Mailing; @@ -35,7 +36,7 @@ public override void Initialize() SubscribeLocalEvent(OnPacketReceived); SubscribeLocalEvent(OnBeforeFlush); SubscribeLocalEvent(OnConfigurationUpdated); - SubscribeLocalEvent(HandleActivate); + SubscribeLocalEvent(HandleActivate, before: new[] { typeof(DisposalUnitSystem) }); SubscribeLocalEvent(OnDisposalUnitUIStateChange); SubscribeLocalEvent(OnTargetSelected); } @@ -179,7 +180,7 @@ private void UpdateUserInterface(EntityUid uid, MailingUnitComponent component) if (component.DisposalUnitInterfaceState == null) return; - var state = new MailingUnitBoundUserInterfaceState(component.DisposalUnitInterfaceState, component.Target, component.TargetList, component.Tag); + var state = new MailingUnitBoundUserInterfaceState(component.DisposalUnitInterfaceState, component.Target, component.TargetList.ShallowClone(), component.Tag); _userInterfaceSystem.SetUiState(uid, MailingUnitUiKey.Key, state); } From 659a43973c43049f5af95d7ca58a793853e85636 Mon Sep 17 00:00:00 2001 From: PJBot Date: Sat, 20 Jul 2024 02:32:34 +0000 Subject: [PATCH 284/765] Automatic changelog update --- Resources/Changelog/Changelog.yml | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index dc929e08dc6..fcbbd0bc204 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,13 +1,4 @@ Entries: -- author: FungiFellow - changes: - - message: Added SecBelt whitelist to Sec webbing - type: Tweak - - message: Added more Ammo holders to SecBelt whitelist - type: Tweak - id: 6439 - time: '2024-04-26T07:44:41.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/27303 - author: IlyaElDunaev changes: - message: Ammonia heal blood loss in the Rat King @@ -3800,3 +3791,10 @@ id: 6938 time: '2024-07-19T14:18:39.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/30169 +- author: themias + changes: + - message: Mailing units are functional again + type: Fix + id: 6939 + time: '2024-07-20T02:31:26.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/30174 From 94fc83508b7fd21cf18218b84c220bb31ba68251 Mon Sep 17 00:00:00 2001 From: Ghagliiarghii <68826635+Ghagliiarghii@users.noreply.github.com> Date: Fri, 19 Jul 2024 22:59:31 -0400 Subject: [PATCH 285/765] Give NukeOps Reinforcements an ID Card (in a PDA) (#28088) * Give NukeOps Reinforcements an ID Card (in a PDA) * add warning comment * create syndicateoperativegeatreinforcementnukeops in traitor.yml * revert fun/misc_startinggear.yml --- .../Prototypes/Entities/Mobs/Player/human.yml | 2 + Resources/Prototypes/Roles/Antags/traitor.yml | 40 +++++++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/Resources/Prototypes/Entities/Mobs/Player/human.yml b/Resources/Prototypes/Entities/Mobs/Player/human.yml index 1bfd016cd50..229709fa546 100644 --- a/Resources/Prototypes/Entities/Mobs/Player/human.yml +++ b/Resources/Prototypes/Entities/Mobs/Player/human.yml @@ -38,6 +38,8 @@ id: MobHumanSyndicateAgentNukeops # Reinforcement exclusive to nukeops uplink suffix: Human, NukeOps components: + - type: Loadout + prototypes: [SyndicateOperativeGearReinforcementNukeOps] - type: NukeOperative # Nuclear Operative diff --git a/Resources/Prototypes/Roles/Antags/traitor.yml b/Resources/Prototypes/Roles/Antags/traitor.yml index 3e0c5a2cae8..5d541b2d0c0 100644 --- a/Resources/Prototypes/Roles/Antags/traitor.yml +++ b/Resources/Prototypes/Roles/Antags/traitor.yml @@ -15,3 +15,43 @@ antagonist: true setPreference: true objective: roles-antag-syndicate-agent-sleeper-objective + +# Syndicate Operative Outfit - Monkey +- type: startingGear + id: SyndicateOperativeGearMonkey + equipment: + head: ClothingHeadHatOutlawHat + jumpsuit: ClothingUniformJumpsuitOperative + mask: CigaretteSyndicate + +# Syndicate Operative Outfit - Barratry +- type: startingGear + id: SyndicateOperativeGearExtremelyBasic + equipment: + jumpsuit: ClothingUniformJumpsuitOperative + back: ClothingBackpackSyndicate + shoes: ClothingShoesBootsCombatFilled + gloves: ClothingHandsGlovesColorBlack + storage: + back: + - BoxSurvivalSyndicate + - WeaponPistolViper + - PinpointerSyndicateNuclear + - DeathAcidifierImplanter + +# Syndicate Reinforcement NukeOps +- type: startingGear + id: SyndicateOperativeGearReinforcementNukeOps + parent: SyndicateOperativeGearExtremelyBasic + equipment: + id: SyndiPDA #Do not give a PDA to the normal Reinforcement - it will spawn with a 20TC uplink + +#Syndicate Operative Outfit - Basic +- type: startingGear + id: SyndicateOperativeGearBasic + parent: SyndicateOperativeGearExtremelyBasic + equipment: + ears: ClothingHeadsetAltSyndicate + gloves: ClothingHandsGlovesCombat + pocket1: BaseUplinkRadio40TC + id: SyndiPDA From 4167e6eda55cdc48a0118dde8d46515d069956a3 Mon Sep 17 00:00:00 2001 From: JIPDawg <51352440+JIPDawg@users.noreply.github.com> Date: Fri, 19 Jul 2024 22:00:00 -0500 Subject: [PATCH 286/765] Removed references to pipestacking and changed example setup in Guidebook (#30181) Removed references to pipestacking and changed example setup Co-authored-by: JIP --- Resources/ServerInfo/Guidebook/Engineering/TEG.xml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Resources/ServerInfo/Guidebook/Engineering/TEG.xml b/Resources/ServerInfo/Guidebook/Engineering/TEG.xml index 63a62fecf80..786990c92f8 100644 --- a/Resources/ServerInfo/Guidebook/Engineering/TEG.xml +++ b/Resources/ServerInfo/Guidebook/Engineering/TEG.xml @@ -70,7 +70,7 @@ - The Space Vent - The Scrubber Array - Here is one layer of an example setup: (pipes can and do need to be layered under the scrubbers below to connect them!) + Here is one layer of an example setup: @@ -81,15 +81,15 @@ - - + + - - + + From 15be0c5d1b47cb284ec2885c9f54c320a6dd0467 Mon Sep 17 00:00:00 2001 From: Plykiya <58439124+Plykiya@users.noreply.github.com> Date: Fri, 19 Jul 2024 20:00:28 -0700 Subject: [PATCH 287/765] Fix Chameleon Scarf menu being blank (#30156) fixa the scarfa Co-authored-by: plykiya --- .../Prototypes/Entities/Clothing/Neck/base_clothingneck.yml | 1 + Resources/Prototypes/Entities/Clothing/Neck/specific.yml | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Resources/Prototypes/Entities/Clothing/Neck/base_clothingneck.yml b/Resources/Prototypes/Entities/Clothing/Neck/base_clothingneck.yml index d7f04f49bc3..608f061dd89 100644 --- a/Resources/Prototypes/Entities/Clothing/Neck/base_clothingneck.yml +++ b/Resources/Prototypes/Entities/Clothing/Neck/base_clothingneck.yml @@ -39,3 +39,4 @@ tags: - Scarf - ClothMade + - WhitelistChameleon diff --git a/Resources/Prototypes/Entities/Clothing/Neck/specific.yml b/Resources/Prototypes/Entities/Clothing/Neck/specific.yml index 56fddceaad6..b98cdd02e0c 100644 --- a/Resources/Prototypes/Entities/Clothing/Neck/specific.yml +++ b/Resources/Prototypes/Entities/Clothing/Neck/specific.yml @@ -1,4 +1,4 @@ -- type: entity +- type: entity parent: ClothingNeckBase id: ClothingNeckChameleon name: striped red scarf @@ -12,7 +12,7 @@ - type: Clothing sprite: Clothing/Neck/Scarfs/red.rsi - type: ChameleonClothing - slot: [neck] + slot: [NECK] default: ClothingNeckScarfStripedRed - type: UserInterface interfaces: From 2426193e6b8839e9b3a8ad34971ecb5bb45cd87c Mon Sep 17 00:00:00 2001 From: PJBot Date: Sat, 20 Jul 2024 03:01:35 +0000 Subject: [PATCH 288/765] Automatic changelog update --- Resources/Changelog/Changelog.yml | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index fcbbd0bc204..09ab407edd9 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,18 +1,4 @@ Entries: -- author: IlyaElDunaev - changes: - - message: Ammonia heal blood loss in the Rat King - type: Add - id: 6440 - time: '2024-04-26T07:47:02.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/26887 -- author: FungiFellow - changes: - - message: Added Quiver Recipe, go wild Robin Hood. - type: Add - id: 6441 - time: '2024-04-26T07:48:15.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/27198 - author: Boaz1111 changes: - message: Refactored Cluster's medbay, including cryo in the bottom left room @@ -3798,3 +3784,17 @@ id: 6939 time: '2024-07-20T02:31:26.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/30174 +- author: Ghagliiarghii + changes: + - message: Nuclear Operatives' Reinforcements now have a PDA! + type: Tweak + id: 6940 + time: '2024-07-20T02:59:31.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/28088 +- author: Plykiya + changes: + - message: Chameleon scarves now work again. + type: Fix + id: 6941 + time: '2024-07-20T03:00:28.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/30156 From 6521c91ae9ce656eac5645100b6489b5be730a97 Mon Sep 17 00:00:00 2001 From: DrSmugleaf <10968691+DrSmugleaf@users.noreply.github.com> Date: Fri, 19 Jul 2024 20:03:43 -0700 Subject: [PATCH 289/765] Make ActionsSystem.UpdateAction public (#30056) --- Content.Client/Actions/ActionsSystem.cs | 2 +- Content.Shared/Actions/SharedActionsSystem.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Content.Client/Actions/ActionsSystem.cs b/Content.Client/Actions/ActionsSystem.cs index b9d554607cf..553a9cd5d56 100644 --- a/Content.Client/Actions/ActionsSystem.cs +++ b/Content.Client/Actions/ActionsSystem.cs @@ -108,7 +108,7 @@ private void BaseHandleState(EntityUid uid, BaseActionComponent component, Ba UpdateAction(uid, component); } - protected override void UpdateAction(EntityUid? actionId, BaseActionComponent? action = null) + public override void UpdateAction(EntityUid? actionId, BaseActionComponent? action = null) { if (!ResolveActionData(actionId, ref action)) return; diff --git a/Content.Shared/Actions/SharedActionsSystem.cs b/Content.Shared/Actions/SharedActionsSystem.cs index ca6bd1dcc2a..0033078b1b7 100644 --- a/Content.Shared/Actions/SharedActionsSystem.cs +++ b/Content.Shared/Actions/SharedActionsSystem.cs @@ -237,7 +237,7 @@ private void OnRejuventate(EntityUid uid, ActionsComponent component, Rejuvenate } #region ComponentStateManagement - protected virtual void UpdateAction(EntityUid? actionId, BaseActionComponent? action = null) + public virtual void UpdateAction(EntityUid? actionId, BaseActionComponent? action = null) { // See client-side code. } From 860fa180c7603d7f08d21c9448fa75a5abb45cc2 Mon Sep 17 00:00:00 2001 From: SlamBamActionman <83650252+SlamBamActionman@users.noreply.github.com> Date: Sat, 20 Jul 2024 05:18:34 +0200 Subject: [PATCH 290/765] Directional Fans (#27772) * Initial commit * Description update * Updated texture --- .../Piping/Atmospherics/special.yml | 29 ++++++++++++++++++ .../Atmospherics/directionalfan.rsi/icon.png | Bin 0 -> 16522 bytes .../Atmospherics/directionalfan.rsi/meta.json | 29 ++++++++++++++++++ 3 files changed, 58 insertions(+) create mode 100644 Resources/Textures/Structures/Piping/Atmospherics/directionalfan.rsi/icon.png create mode 100644 Resources/Textures/Structures/Piping/Atmospherics/directionalfan.rsi/meta.json diff --git a/Resources/Prototypes/Entities/Structures/Piping/Atmospherics/special.yml b/Resources/Prototypes/Entities/Structures/Piping/Atmospherics/special.yml index 4eec014f11b..eff831fa9ea 100644 --- a/Resources/Prototypes/Entities/Structures/Piping/Atmospherics/special.yml +++ b/Resources/Prototypes/Entities/Structures/Piping/Atmospherics/special.yml @@ -25,3 +25,32 @@ - type: Tag tags: - SpreaderIgnore + +- type: entity + id: AtmosDeviceFanDirectional + name: directional fan + description: A thin fan, stopping the movement of gases across it. + placement: + mode: SnapgridCenter + components: + - type: Transform + anchored: true + - type: Physics + bodyType: Static + - type: Sprite + sprite: Structures/Piping/Atmospherics/directionalfan.rsi + state: icon + - type: Fixtures + fixtures: + fix1: + shape: + !type:PhysShapeAabb + bounds: "-0.48,-0.48,0.48,-0.40" + - type: Airtight + noAirWhenFullyAirBlocked: false + airBlockedDirection: + - South + - type: Clickable + - type: Tag + tags: + - SpreaderIgnore diff --git a/Resources/Textures/Structures/Piping/Atmospherics/directionalfan.rsi/icon.png b/Resources/Textures/Structures/Piping/Atmospherics/directionalfan.rsi/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..577175edcd281daf52757d9005f3b4be3bc4794c GIT binary patch literal 16522 zcmeI4e{j>*9l#Y}nVSJ)Sv%-p;5sl^!ItFT7Pdng2a+qM88IbrkVKK?L=ao9C1WQW zNk&I0U4b5D3#F_b9lNF+bjOVXWn`h0(k*mZDWM%SgpH1L%lJ`XSs*3Jo@^&}UYvL7 z+PmF)vd)&i@B6;r?|Yx`(^t|T^2Yo{3&y2=I}O9Iae29p#b946eHE$T_f0!}3heIj z=Pna4Z2Sr7oAT4y<0oU7mEl~4Vxe;(#qeGY?dD5aP1x%Py@4(>?5CO4tf(wy%Q&A+ zb^W)EDkbN(sg@d?gwvnRmUFpP0k)uOk&CHX%~;&3OnaI&OaTX8R-~0-Z-q~w!ZuaJ zF9nXJW?ZF=bP-qER9R9$WuY@)nau}Sr9op>HeimQM3VblYusLhMR5FsyUgSLSFlQdDY$Wn-A z$O`64Wd~SV>{-kDXr;59|=8SAK?6P(;_`0 zFNu8<{J0s)!w0;yXy?3i8H@XUWmY`in9y@zRZ-b|1s?#zV(mIBo~${km4j!3(z4F- zF{}WRAtWRTq$+aaK17!dZtYi8aCVRsjhk~*jMhMyXb+<{)1*%AaqCI7nIz3>nkm&< zbe2*E99VJbbOlE7kw~5*t%GAEP5?DRDe+DxmFE*g8cZP15g88$#-nFJKqG5W8wfX{ z_GtBHwb@LwU{&aeQjd`_(PnpKH4HY7k1Xc8KYGmd$fp_|S%Ucx*N+4^P_pTYgg&2* zW;8?+H$y_@a#C(9A@EW*3fRX6x5jfDDXxAxAh1&Du&MfM$3Qg(T?anaNC~27Mk>p8 zMmn=u0C-Sqd|0p|iu4-ZiNJfr5FKE%%D_1@lA;y$ zI@k<$pZvT4j3Q@W1@}1;A<%0+UmEn5QkpdDb!s=Q*Q*&F_$hUhMzzUgwivWV3(1hi z{xtu$X)q9!&e&gE|95GSfJdV<<+QJib=&d&ne{jPUuAAY6)-yC&ziZUm&GqZ=Avif z;F{Qfl^9w>tlPZL5ngjG#^MSN(#p6XAZSs>h2{fkWn2&tv?$|3 z^MSN7E(i!(lyRZ?Kw23W1OzS0xX^qct&9r-f)-_5Xg-iu#svXEi!v@WA4n_Xf`Fh! zB(Ajho5QRRye=F9?*-q=^KJs~6f2qB#ZC;XngQNTejLN@^nv|9Ff2%5SVswlQQI+W zBEPlxt@#)>dRLw!%N0I<<>&i-yNP>qF6N#oymr@CuzT0`)ST1R?W^uRoqzbbb=P-g zYtDH#DNb*_e2$s_rp4Jh9X~m<^^N_1tempoM;`^+)0NoBx1)Qp_s_3*K6O#k^}daPv*q;_Z7o+P9IrpDU=&#$-Pxc~^^$Kg1sQ4Y3K7)`soAN ziap(rVLCgW5<-nRUe+5w4}#ed;hiCJ>54x zEx3-Y?#cZ18Pph^-RSkM7Eo0&#Zp1@YbY% zb&;F9GfVb4t9H!N-gjl~TwjCY#{K5E7w$Y*-TX?4x3AdqU|}{m8fSTVoq@RT9T!pX z#=@^;-f?}BQFiLUv==tJUVLueJZz-f7;Mn?`%`!8pS7)No!ZcQxBkV;o39HSoByaUVF*5Z~FQvZ(rU` zWUeZ!T>gjGTd>_z>$Xx@pRl4Sr;&a*>X5Eb%$1JjXMh%&5IrXW%Ji_iWo&Q#8K!hj?EAuiV%?trD-fQggSfa%1?P*?1D>VvO8@bquK*7$JWM@7BqosAb#4vz08#-78EH}4PE rckfNJn-#U-p9N|$|H9s}*t_3+K)CStye-nd1?1%{a=iLb$-4gl(nVV- literal 0 HcmV?d00001 diff --git a/Resources/Textures/Structures/Piping/Atmospherics/directionalfan.rsi/meta.json b/Resources/Textures/Structures/Piping/Atmospherics/directionalfan.rsi/meta.json new file mode 100644 index 00000000000..217a9f3d782 --- /dev/null +++ b/Resources/Textures/Structures/Piping/Atmospherics/directionalfan.rsi/meta.json @@ -0,0 +1,29 @@ +{ + "version": 1, + "license": "CC-BY-NC-SA-3.0", + "copyright": "Made by SlamBamActionman", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "icon", + "directions": 4, + "delays":[ + [ + 0.01,0.01,0.01,0.01 + ], + [ + 0.01,0.01,0.01,0.01 + ], + [ + 0.01,0.01,0.01,0.01 + ], + [ + 0.01,0.01,0.01,0.01 + ] + ] + } + ] +} From 5467cdfc92b30568591125cbfecbf581bae729de Mon Sep 17 00:00:00 2001 From: deltanedas <39013340+deltanedas@users.noreply.github.com> Date: Sat, 20 Jul 2024 03:23:46 +0000 Subject: [PATCH 291/765] fix fish petting misprediction (#30175) * make fish petting ignore use delay * m * troll --------- Co-authored-by: deltanedas <@deltanedas:kde.org> --- .../Friends/Systems/PettableFriendSystem.cs | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/Content.Shared/Friends/Systems/PettableFriendSystem.cs b/Content.Shared/Friends/Systems/PettableFriendSystem.cs index 00a4ddd155c..6e41f4bdea9 100644 --- a/Content.Shared/Friends/Systems/PettableFriendSystem.cs +++ b/Content.Shared/Friends/Systems/PettableFriendSystem.cs @@ -32,23 +32,23 @@ private void OnUseInHand(Entity ent, ref UseInHandEvent { var (uid, comp) = ent; var user = args.User; - if (args.Handled || !_exceptionQuery.TryGetComponent(uid, out var exceptionComp)) - return; - - if (_useDelayQuery.TryGetComponent(uid, out var useDelay) && !_useDelay.TryResetDelay((uid, useDelay), true)) + if (args.Handled || !_exceptionQuery.TryComp(uid, out var exceptionComp)) return; var exception = (uid, exceptionComp); - if (_factionException.IsIgnored(exception, user)) + if (!_factionException.IsIgnored(exception, user)) { - _popup.PopupClient(Loc.GetString(comp.FailureString, ("target", uid)), user, user); + // you have made a new friend :) + _popup.PopupClient(Loc.GetString(comp.SuccessString, ("target", uid)), user, user); + _factionException.IgnoreEntity(exception, user); + args.Handled = true; return; } - // you have made a new friend :) - _popup.PopupClient(Loc.GetString(comp.SuccessString, ("target", uid)), user, user); - _factionException.IgnoreEntity(exception, user); - args.Handled = true; + if (_useDelayQuery.TryComp(uid, out var useDelay) && !_useDelay.TryResetDelay((uid, useDelay), true)) + return; + + _popup.PopupClient(Loc.GetString(comp.FailureString, ("target", uid)), user, user); } private void OnRehydrated(Entity ent, ref GotRehydratedEvent args) From ad3dec7a3df7457ee02c4506ba7832c0fe7476b9 Mon Sep 17 00:00:00 2001 From: CaasGit <87243814+CaasGit@users.noreply.github.com> Date: Fri, 19 Jul 2024 20:36:22 -0700 Subject: [PATCH 292/765] fix(FaxVisualsSystem): Fax can Play() when a anim key has been added. (#30013) Adds a check to see if a faxecute animation is being played before playing another animation. The old code can thrown an exception which I've seen on live while ghosting. --- Content.Client/Fax/System/FaxVisualsSystem.cs | 34 +++++++++++-------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/Content.Client/Fax/System/FaxVisualsSystem.cs b/Content.Client/Fax/System/FaxVisualsSystem.cs index 892aec1d954..e752fbf48e6 100644 --- a/Content.Client/Fax/System/FaxVisualsSystem.cs +++ b/Content.Client/Fax/System/FaxVisualsSystem.cs @@ -25,24 +25,30 @@ private void OnAppearanceChanged(EntityUid uid, FaxMachineComponent component, r if (args.Sprite == null) return; - if (_appearance.TryGetData(uid, FaxMachineVisuals.VisualState, out FaxMachineVisualState visuals) && visuals == FaxMachineVisualState.Inserting) + if (_player.HasRunningAnimation(uid, "faxecute")) + return; + + if (_appearance.TryGetData(uid, FaxMachineVisuals.VisualState, out FaxMachineVisualState visuals) && + visuals == FaxMachineVisualState.Inserting) { - _player.Play(uid, new Animation() - { - Length = TimeSpan.FromSeconds(2.4), - AnimationTracks = + _player.Play(uid, + new Animation() { - new AnimationTrackSpriteFlick() + Length = TimeSpan.FromSeconds(2.4), + AnimationTracks = { - LayerKey = FaxMachineVisuals.VisualState, - KeyFrames = + new AnimationTrackSpriteFlick() { - new AnimationTrackSpriteFlick.KeyFrame(component.InsertingState, 0f), - new AnimationTrackSpriteFlick.KeyFrame("icon", 2.4f), - } - } - } - }, "faxecute"); + LayerKey = FaxMachineVisuals.VisualState, + KeyFrames = + { + new AnimationTrackSpriteFlick.KeyFrame(component.InsertingState, 0f), + new AnimationTrackSpriteFlick.KeyFrame("icon", 2.4f), + }, + }, + }, + }, + "faxecute"); } } } From f1d1416a13714ec78de06ac1b98e357e791d93c6 Mon Sep 17 00:00:00 2001 From: eoineoineoin Date: Sat, 20 Jul 2024 04:54:36 +0100 Subject: [PATCH 293/765] Add a background for OptionsButton popup (#29792) Add a reasonable background for OptionsButton popup Co-authored-by: Eoin Mcloughlin Co-authored-by: ShadowCommander <10494922+ShadowCommander@users.noreply.github.com> --- Content.Client/Stylesheets/StyleNano.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Content.Client/Stylesheets/StyleNano.cs b/Content.Client/Stylesheets/StyleNano.cs index 4df332ec32d..cbce193ea1a 100644 --- a/Content.Client/Stylesheets/StyleNano.cs +++ b/Content.Client/Stylesheets/StyleNano.cs @@ -1343,6 +1343,9 @@ public StyleNano(IResourceCache resCache) : base(resCache) new StyleProperty(Label.StylePropertyAlignMode, Label.AlignMode.Center), }), + Element().Class(OptionButton.StyleClassOptionsBackground) + .Prop(PanelContainer.StylePropertyPanel, new StyleBoxFlat(Color.FromHex("#25252A"))), + new StyleRule(new SelectorElement(typeof(PanelContainer), new []{ ClassHighDivider}, null, null), new [] { new StyleProperty(PanelContainer.StylePropertyPanel, new StyleBoxFlat { BackgroundColor = NanoGold, ContentMarginBottomOverride = 2, ContentMarginLeftOverride = 2}), From 6e985608365fa62ae014cd4c5e4c7e2d734da304 Mon Sep 17 00:00:00 2001 From: DrSmugleaf <10968691+DrSmugleaf@users.noreply.github.com> Date: Fri, 19 Jul 2024 20:58:33 -0700 Subject: [PATCH 294/765] Fix NPC line of sight not working if trying to ranged target a blocking entity (#30055) --- Content.Server/NPC/Systems/NPCCombatSystem.Ranged.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Content.Server/NPC/Systems/NPCCombatSystem.Ranged.cs b/Content.Server/NPC/Systems/NPCCombatSystem.Ranged.cs index 10ec54c8954..d7196ea73c7 100644 --- a/Content.Server/NPC/Systems/NPCCombatSystem.Ranged.cs +++ b/Content.Server/NPC/Systems/NPCCombatSystem.Ranged.cs @@ -1,7 +1,6 @@ using Content.Server.NPC.Components; using Content.Shared.CombatMode; using Content.Shared.Interaction; -using Content.Shared.Physics; using Content.Shared.Weapons.Ranged.Components; using Content.Shared.Weapons.Ranged.Events; using Robust.Shared.Map; @@ -134,7 +133,7 @@ private void UpdateRanged(float frameTime) { comp.LOSAccumulator += UnoccludedCooldown; // For consistency with NPC steering. - comp.TargetInLOS = _interaction.InRangeUnobstructed(uid, Transform(comp.Target).Coordinates, distance + 0.1f); + comp.TargetInLOS = _interaction.InRangeUnobstructed(uid, comp.Target, distance + 0.1f); } if (!comp.TargetInLOS) From 7af5d3dbaf2dd8702686e9afec63191bf841b7de Mon Sep 17 00:00:00 2001 From: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com> Date: Sat, 20 Jul 2024 15:40:16 +1000 Subject: [PATCH 295/765] Remove some BUI boilerplate (#28399) * Remove some BUI boilerplate - The disposals overrides got removed due to the helper method handling it. - Replace window creation with CreateWindow helper. - Fixed some stinky code which would cause exceptions. * More * moar * weh * done * More BUIs * More updates * weh * moar * look who it is * weh * merge * weh * fixes --- .../UI/AccessOverriderBoundUserInterface.cs | 45 +++-- .../Access/UI/AccessOverriderWindow.xaml.cs | 41 ++--- .../UI/AgentIDCardBoundUserInterface.cs | 19 +- .../Access/UI/AgentIDCardWindow.xaml.cs | 10 +- .../Ame/UI/AmeControllerBoundUserInterface.cs | 16 +- Content.Client/Ame/UI/AmeWindow.xaml.cs | 19 +- .../Ui/AnomalyGeneratorBoundUserInterface.cs | 20 +- .../Anomaly/Ui/AnomalyGeneratorWindow.xaml.cs | 8 +- Content.Client/Arcade/BlockGameMenu.cs | 45 +++-- .../Arcade/SpaceVillainArcadeMenu.cs | 45 ++--- .../Arcade/UI/BlockGameBoundUserInterface.cs | 5 +- .../SpaceVillainArcadeBoundUserInterface.cs | 16 +- .../Monitor/UI/AirAlarmBoundUserInterface.cs | 12 +- .../Atmos/Monitor/UI/AirAlarmWindow.xaml.cs | 7 +- .../Atmos/UI/GasCanisterBoundUserInterface.cs | 9 +- .../Atmos/UI/GasFilterBoundUserInterface.cs | 11 +- .../Atmos/UI/GasFilterWindow.xaml.cs | 7 +- .../Atmos/UI/GasMixerBoundUserInteface.cs | 18 +- .../UI/GasPressurePumpBoundUserInterface.cs | 17 +- .../UI/GasThermomachineBoundUserInterface.cs | 17 +- .../UI/GasVolumePumpBoundUserInterface.cs | 19 +- .../Atmos/UI/SpaceHeaterBoundUserInterface.cs | 10 +- .../Jukebox/JukeboxBoundUserInterface.cs | 21 +-- .../CryostorageBoundUserInterface.cs | 15 +- .../CargoBountyConsoleBoundUserInterface.cs | 17 +- .../CargoPalletConsoleBoundUserInterface.cs | 15 +- .../CargoShuttleConsoleBoundUserInterface.cs | 24 +-- .../Cargo/UI/CargoShuttleMenu.xaml.cs | 13 +- .../UI/ChemMasterBoundUserInterface.cs | 20 +- .../UI/ReagentDispenserBoundUserInterface.cs | 27 +-- .../UI/TransferAmountBoundUserInterface.cs | 12 +- .../UI/CloningConsoleBoundUserInterface.cs | 25 +-- .../UI/ChameleonBoundUserInterface.cs | 16 +- ...CommunicationsConsoleBoundUserInterface.cs | 72 +++----- .../UI/CommunicationsConsoleMenu.xaml.cs | 81 +++++---- .../Computer/ComputerBoundUserInterface.cs | 15 +- .../UI/ConfigurationBoundUserInterface.cs | 28 +-- .../Configurable/UI/ConfigurationMenu.cs | 18 +- .../UI/FlatpackCreatorBoundUserInterface.cs | 14 +- .../UI/FlatpackCreatorMenu.xaml.cs | 13 +- .../Crayon/UI/CrayonBoundUserInterface.cs | 40 ++-- Content.Client/Crayon/UI/CrayonWindow.xaml.cs | 18 +- .../UI/DisposalRouterBoundUserInterface.cs | 22 +-- .../UI/DisposalTaggerBoundUserInterface.cs | 23 +-- .../DoorElectronicsBoundUserInterface.cs | 31 ++-- .../DoorElectronicsConfigurationMenu.xaml.cs | 21 ++- Content.Client/Fax/UI/FaxBoundUi.cs | 12 +- .../ForensicScannerBoundUserInterface.cs | 15 +- .../Gateway/UI/GatewayBoundUserInterface.cs | 16 +- .../Gateway/UI/GatewayWindow.xaml.cs | 10 +- .../UI/GravityGeneratorBoundUserInterface.cs | 23 +-- .../Gravity/UI/GravityGeneratorWindow.xaml.cs | 15 +- .../UI/HealthAnalyzerBoundUserInterface.cs | 23 +-- ...manoidMarkingModifierBoundUserInterface.cs | 4 +- .../Instruments/UI/BandMenu.xaml.cs | 6 +- .../Instruments/UI/ChannelsMenu.xaml.cs | 5 +- .../UI/InstrumentBoundUserInterface.cs | 36 +++- .../Instruments/UI/InstrumentMenu.xaml.cs | 171 ++++++++++-------- .../Inventory/StrippableBoundUserInterface.cs | 25 ++- Content.Client/Kitchen/UI/GrinderMenu.xaml.cs | 42 ++--- .../Kitchen/UI/MicrowaveBoundUserInterface.cs | 43 +---- .../Kitchen/UI/MicrowaveMenu.xaml.cs | 24 ++- .../UI/ReagentGrinderBoundUserInterface.cs | 34 ++-- .../UI/HandLabelerBoundUserInterface.cs | 16 +- .../Lathe/UI/LatheBoundUserInterface.cs | 17 +- Content.Client/Lathe/UI/LatheMenu.xaml.cs | 34 ++-- .../UI/SignalTimerBoundUserInterface.cs | 24 +-- .../UI/SignalTimerWindow.xaml.cs | 24 +-- .../MagicMirrorBoundUserInterface.cs | 15 +- .../Ui/NewsWriterBoundUserInterface.cs | 18 +- .../MassMedia/Ui/NewsWriterMenu.xaml.cs | 6 +- .../Mech/Ui/MechBoundUserInterface.cs | 16 +- Content.Client/Mech/Ui/MechMenu.xaml.cs | 9 +- .../CrewMonitoringBoundUserInterface.cs | 18 +- .../CrewMonitoringWindow.xaml.cs | 17 +- .../NetworkConfiguratorBoundUserInterface.cs | 39 ++-- ...tworkConfiguratorConfigurationMenu.xaml.cs | 8 +- .../NetworkConfiguratorDeviceList.xaml.cs | 12 +- .../NetworkConfiguratorLinkMenu.xaml.cs | 16 +- .../NetworkConfiguratorListMenu.xaml.cs | 13 +- Content.Client/Nuke/NukeBoundUserInterface.cs | 17 +- .../WarDeclaratorBoundUserInterface.cs | 18 +- .../NukeOps/WarDeclaratorWindow.xaml.cs | 9 +- Content.Client/PDA/PdaBoundUserInterface.cs | 17 +- .../PDA/Ringer/RingerBoundUserInterface.cs | 4 +- .../Paper/UI/PaperBoundUserInterface.cs | 17 +- Content.Client/Paper/UI/PaperWindow.xaml.cs | 6 +- .../ParticleAcceleratorBoundUserInterface.cs | 16 +- .../UI/ParticleAcceleratorControlMenu.cs | 30 +-- .../UI/NavMapBeaconBoundUserInterface.cs | 16 +- .../Pinpointer/UI/NavMapBeaconWindow.xaml.cs | 25 ++- .../UI/StationMapBoundUserInterface.cs | 15 +- .../Pinpointer/UI/StationMapWindow.xaml.cs | 11 +- .../UI/UntrackedMapBoundUserInterface.cs | 15 +- .../Power/APC/ApcBoundUserInterface.cs | 16 +- Content.Client/Power/APC/UI/ApcMenu.xaml.cs | 12 +- .../Power/Generator/GeneratorWindow.xaml.cs | 52 +++--- .../PortableGeneratorBoundUserInterface.cs | 25 ++- ...owerMonitoringConsoleBoundUserInterface.cs | 19 +- .../PowerMonitoringWindow.xaml.Widgets.cs | 6 +- .../Power/PowerMonitoringWindow.xaml.cs | 84 +++++---- Content.Client/RCD/RCDMenu.xaml.cs | 35 ++-- .../RCD/RCDMenuBoundUserInterface.cs | 16 +- .../Radio/Ui/IntercomBoundUserInterface.cs | 20 +- Content.Client/Radio/Ui/IntercomMenu.xaml.cs | 4 +- .../UI/DiskConsoleBoundUserInterface.cs | 15 +- .../UI/ResearchClientBoundUserInterface.cs | 16 +- .../ResearchClientServerSelectionMenu.xaml.cs | 11 +- .../UI/ResearchConsoleBoundUserInterface.cs | 28 +-- .../Research/UI/ResearchConsoleMenu.xaml.cs | 29 +-- .../UI/RoboticsConsoleBoundUserInterface.cs | 18 +- .../Robotics/UI/RoboticsConsoleWindow.xaml.cs | 25 ++- ...vageExpeditionConsoleBoundUserInterface.cs | 12 +- .../UI/SalvageMagnetBoundUserInterface.cs | 21 +-- .../BUI/IFFConsoleBoundUserInterface.cs | 4 +- .../BUI/RadarConsoleBoundUserInterface.cs | 14 +- .../BUI/ShuttleConsoleBoundUserInterface.cs | 5 +- .../Silicons/Borgs/BorgBoundUserInterface.cs | 18 +- Content.Client/Silicons/Borgs/BorgMenu.xaml | 2 +- .../Silicons/Borgs/BorgMenu.xaml.cs | 49 +++-- .../Laws/Ui/SiliconLawBoundUserInterface.cs | 14 +- .../UI/SprayPainterBoundUserInterface.cs | 27 +-- ...lStationRecordConsoleBoundUserInterface.cs | 13 +- .../Store/Ui/StoreBoundUserInterface.cs | 15 +- Content.Client/Strip/StrippingMenu.cs | 11 +- .../UI/SurveillanceCameraMonitorBoundUi.cs | 11 +- .../Thief/ThiefBackpackBoundUserInterface.cs | 19 +- .../Thief/ThiefBackpackMenu.xaml.cs | 28 ++- .../GasTank/GasTankBoundUserInterface.cs | 11 +- .../Systems/Atmos/GasTank/GasTankWindow.cs | 43 +++-- .../VendingMachineBoundUserInterface.cs | 8 +- .../VoiceMask/VoiceMaskBoundUserInterface.cs | 8 +- .../VoiceMaskNameChangeWindow.xaml.cs | 6 +- .../Melee/UI/MeleeSpeechBoundUserInterface.cs | 10 +- .../Wires/UI/WiresBoundUserInterface.cs | 7 +- Content.Client/Wires/UI/WiresMenu.cs | 16 +- .../Ui/AnalysisConsoleBoundUserInterface.cs | 6 +- 137 files changed, 1095 insertions(+), 1753 deletions(-) diff --git a/Content.Client/Access/UI/AccessOverriderBoundUserInterface.cs b/Content.Client/Access/UI/AccessOverriderBoundUserInterface.cs index c1b63dc4d05..d80c600c03e 100644 --- a/Content.Client/Access/UI/AccessOverriderBoundUserInterface.cs +++ b/Content.Client/Access/UI/AccessOverriderBoundUserInterface.cs @@ -2,6 +2,7 @@ using Content.Shared.Access.Components; using Content.Shared.Access.Systems; using Content.Shared.Containers.ItemSlots; +using Robust.Client.UserInterface; using Robust.Shared.Prototypes; using static Content.Shared.Access.Components.AccessOverriderComponent; @@ -23,6 +24,28 @@ protected override void Open() { base.Open(); + _window = this.CreateWindow(); + RefreshAccess(); + _window.Title = EntMan.GetComponent(Owner).EntityName; + _window.OnSubmit += SubmitData; + + _window.PrivilegedIdButton.OnPressed += _ => SendMessage(new ItemSlotButtonPressedEvent(PrivilegedIdCardSlotId)); + } + + public override void OnProtoReload(PrototypesReloadedEventArgs args) + { + base.OnProtoReload(args); + if (!args.WasModified()) + return; + + RefreshAccess(); + + if (State != null) + _window?.UpdateState(_prototypeManager, (AccessOverriderBoundUserInterfaceState) State); + } + + private void RefreshAccess() + { List> accessLevels; if (EntMan.TryGetComponent(Owner, out var accessOverrider)) @@ -30,38 +53,20 @@ protected override void Open() accessLevels = accessOverrider.AccessLevels; accessLevels.Sort(); } - else { accessLevels = new List>(); _accessOverriderSystem.Log.Error($"No AccessOverrider component found for {EntMan.ToPrettyString(Owner)}!"); } - _window = new AccessOverriderWindow(this, _prototypeManager, accessLevels) - { - Title = EntMan.GetComponent(Owner).EntityName - }; - - _window.PrivilegedIdButton.OnPressed += _ => SendMessage(new ItemSlotButtonPressedEvent(PrivilegedIdCardSlotId)); - - _window.OnClose += Close; - _window.OpenCentered(); - } - - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - if (!disposing) - return; - - _window?.Dispose(); + _window?.SetAccessLevels(_prototypeManager, accessLevels); } protected override void UpdateState(BoundUserInterfaceState state) { base.UpdateState(state); var castState = (AccessOverriderBoundUserInterfaceState) state; - _window?.UpdateState(castState); + _window?.UpdateState(_prototypeManager, castState); } public void SubmitData(List> newAccessList) diff --git a/Content.Client/Access/UI/AccessOverriderWindow.xaml.cs b/Content.Client/Access/UI/AccessOverriderWindow.xaml.cs index 6025c3b551f..ba087718583 100644 --- a/Content.Client/Access/UI/AccessOverriderWindow.xaml.cs +++ b/Content.Client/Access/UI/AccessOverriderWindow.xaml.cs @@ -13,26 +13,24 @@ namespace Content.Client.Access.UI [GenerateTypedNameReferences] public sealed partial class AccessOverriderWindow : DefaultWindow { - [Dependency] private readonly ILogManager _logManager = default!; - [Dependency] private readonly IPrototypeManager _prototypeManager = default!; - - private readonly AccessOverriderBoundUserInterface _owner; private readonly Dictionary _accessButtons = new(); - public AccessOverriderWindow(AccessOverriderBoundUserInterface owner, IPrototypeManager prototypeManager, - List> accessLevels) + public event Action>>? OnSubmit; + + public AccessOverriderWindow() { RobustXamlLoader.Load(this); - IoCManager.InjectDependencies(this); - var logMill = _logManager.GetSawmill(SharedAccessOverriderSystem.Sawmill); + } - _owner = owner; + public void SetAccessLevels(IPrototypeManager protoManager, List> accessLevels) + { + _accessButtons.Clear(); + AccessLevelGrid.DisposeAllChildren(); foreach (var access in accessLevels) { - if (!prototypeManager.TryIndex(access, out var accessLevel)) + if (!protoManager.TryIndex(access, out var accessLevel)) { - logMill.Error($"Unable to find accesslevel for {access}"); continue; } @@ -44,11 +42,16 @@ public AccessOverriderWindow(AccessOverriderBoundUserInterface owner, IPrototype AccessLevelGrid.AddChild(newButton); _accessButtons.Add(accessLevel.ID, newButton); - newButton.OnPressed += _ => SubmitData(); + newButton.OnPressed += _ => + { + OnSubmit?.Invoke( + // Iterate over the buttons dictionary, filter by `Pressed`, only get key from the key/value pair + _accessButtons.Where(x => x.Value.Pressed).Select(x => new ProtoId(x.Key)).ToList()); + }; } } - public void UpdateState(AccessOverriderBoundUserInterfaceState state) + public void UpdateState(IPrototypeManager protoManager, AccessOverriderBoundUserInterfaceState state) { PrivilegedIdLabel.Text = state.PrivilegedIdName; PrivilegedIdButton.Text = state.IsPrivilegedIdPresent @@ -66,11 +69,11 @@ public void UpdateState(AccessOverriderBoundUserInterfaceState state) if (state.MissingPrivilegesList != null && state.MissingPrivilegesList.Any()) { - List missingPrivileges = new List(); + var missingPrivileges = new List(); foreach (string tag in state.MissingPrivilegesList) { - string privilege = Loc.GetString(_prototypeManager.Index(tag)?.Name ?? "generic-unknown"); + var privilege = Loc.GetString(protoManager.Index(tag)?.Name ?? "generic-unknown"); missingPrivileges.Add(privilege); } @@ -90,13 +93,5 @@ public void UpdateState(AccessOverriderBoundUserInterfaceState state) } } } - - private void SubmitData() - { - _owner.SubmitData( - - // Iterate over the buttons dictionary, filter by `Pressed`, only get key from the key/value pair - _accessButtons.Where(x => x.Value.Pressed).Select(x => new ProtoId(x.Key)).ToList()); - } } } diff --git a/Content.Client/Access/UI/AgentIDCardBoundUserInterface.cs b/Content.Client/Access/UI/AgentIDCardBoundUserInterface.cs index 761f52988a9..50add43dc91 100644 --- a/Content.Client/Access/UI/AgentIDCardBoundUserInterface.cs +++ b/Content.Client/Access/UI/AgentIDCardBoundUserInterface.cs @@ -1,6 +1,7 @@ using Content.Shared.Access.Systems; using Content.Shared.StatusIcon; using Robust.Client.GameObjects; +using Robust.Client.UserInterface; using Robust.Shared.Prototypes; namespace Content.Client.Access.UI @@ -20,16 +21,11 @@ protected override void Open() { base.Open(); - _window?.Dispose(); - _window = new AgentIDCardWindow(this); - if (State != null) - UpdateState(State); + _window = this.CreateWindow(); - _window.OpenCentered(); - - _window.OnClose += Close; _window.OnNameChanged += OnNameChanged; _window.OnJobChanged += OnJobChanged; + _window.OnJobIconChanged += OnJobIconChanged; } private void OnNameChanged(string newName) @@ -61,14 +57,5 @@ protected override void UpdateState(BoundUserInterfaceState state) _window.SetCurrentJob(cast.CurrentJob); _window.SetAllowedIcons(cast.Icons, cast.CurrentJobIconId); } - - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - if (!disposing) - return; - - _window?.Dispose(); - } } } diff --git a/Content.Client/Access/UI/AgentIDCardWindow.xaml.cs b/Content.Client/Access/UI/AgentIDCardWindow.xaml.cs index 6d0b2a184f4..071ce41a069 100644 --- a/Content.Client/Access/UI/AgentIDCardWindow.xaml.cs +++ b/Content.Client/Access/UI/AgentIDCardWindow.xaml.cs @@ -17,19 +17,19 @@ public sealed partial class AgentIDCardWindow : DefaultWindow [Dependency] private readonly IPrototypeManager _prototypeManager = default!; [Dependency] private readonly IEntitySystemManager _entitySystem = default!; private readonly SpriteSystem _spriteSystem; - private readonly AgentIDCardBoundUserInterface _bui; private const int JobIconColumnCount = 10; public event Action? OnNameChanged; public event Action? OnJobChanged; - public AgentIDCardWindow(AgentIDCardBoundUserInterface bui) + public event Action>? OnJobIconChanged; + + public AgentIDCardWindow() { RobustXamlLoader.Load(this); IoCManager.InjectDependencies(this); _spriteSystem = _entitySystem.GetEntitySystem(); - _bui = bui; NameLineEdit.OnTextEntered += e => OnNameChanged?.Invoke(e.Text); NameLineEdit.OnFocusExit += e => OnNameChanged?.Invoke(e.Text); @@ -67,7 +67,7 @@ public void SetAllowedIcons(HashSet> icons, string }; // Generate buttons textures - TextureRect jobIconTexture = new TextureRect + var jobIconTexture = new TextureRect { Texture = _spriteSystem.Frame0(jobIcon.Icon), TextureScale = new Vector2(2.5f, 2.5f), @@ -75,7 +75,7 @@ public void SetAllowedIcons(HashSet> icons, string }; jobIconButton.AddChild(jobIconTexture); - jobIconButton.OnPressed += _ => _bui.OnJobIconChanged(jobIconId); + jobIconButton.OnPressed += _ => OnJobIconChanged?.Invoke(jobIcon.ID); IconGrid.AddChild(jobIconButton); if (jobIconId.Equals(currentJobIconId)) diff --git a/Content.Client/Ame/UI/AmeControllerBoundUserInterface.cs b/Content.Client/Ame/UI/AmeControllerBoundUserInterface.cs index e84cf5d34de..3d65f751899 100644 --- a/Content.Client/Ame/UI/AmeControllerBoundUserInterface.cs +++ b/Content.Client/Ame/UI/AmeControllerBoundUserInterface.cs @@ -1,5 +1,6 @@ using Content.Shared.Ame.Components; using JetBrains.Annotations; +using Robust.Client.UserInterface; namespace Content.Client.Ame.UI { @@ -16,9 +17,8 @@ protected override void Open() { base.Open(); - _window = new AmeWindow(this); - _window.OnClose += Close; - _window.OpenCentered(); + _window = this.CreateWindow(); + _window.OnAmeButton += ButtonPressed; } /// @@ -40,15 +40,5 @@ public void ButtonPressed(UiButton button) { SendMessage(new UiButtonPressedMessage(button)); } - - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - - if (disposing) - { - _window?.Dispose(); - } - } } } diff --git a/Content.Client/Ame/UI/AmeWindow.xaml.cs b/Content.Client/Ame/UI/AmeWindow.xaml.cs index 8b91ec59660..d6d580bcdaf 100644 --- a/Content.Client/Ame/UI/AmeWindow.xaml.cs +++ b/Content.Client/Ame/UI/AmeWindow.xaml.cs @@ -1,3 +1,4 @@ +using System.Linq; using Content.Client.UserInterface; using Content.Shared.Ame.Components; using Robust.Client.AutoGenerated; @@ -9,15 +10,17 @@ namespace Content.Client.Ame.UI [GenerateTypedNameReferences] public sealed partial class AmeWindow : DefaultWindow { - public AmeWindow(AmeControllerBoundUserInterface ui) + public event Action? OnAmeButton; + + public AmeWindow() { RobustXamlLoader.Load(this); IoCManager.InjectDependencies(this); - EjectButton.OnPressed += _ => ui.ButtonPressed(UiButton.Eject); - ToggleInjection.OnPressed += _ => ui.ButtonPressed(UiButton.ToggleInjection); - IncreaseFuelButton.OnPressed += _ => ui.ButtonPressed(UiButton.IncreaseFuel); - DecreaseFuelButton.OnPressed += _ => ui.ButtonPressed(UiButton.DecreaseFuel); + EjectButton.OnPressed += _ => OnAmeButton?.Invoke(UiButton.Eject); + ToggleInjection.OnPressed += _ => OnAmeButton?.Invoke(UiButton.ToggleInjection); + IncreaseFuelButton.OnPressed += _ => OnAmeButton?.Invoke(UiButton.IncreaseFuel); + DecreaseFuelButton.OnPressed += _ => OnAmeButton?.Invoke(UiButton.DecreaseFuel); } /// @@ -29,7 +32,7 @@ public void UpdateState(BoundUserInterfaceState state) var castState = (AmeControllerBoundUserInterfaceState) state; // Disable all buttons if not powered - if (Contents.Children != null) + if (Contents.Children.Any()) { ButtonHelpers.SetButtonDisabledRecursive(Contents, !castState.HasPower); EjectButton.Disabled = false; @@ -65,8 +68,8 @@ public void UpdateState(BoundUserInterfaceState state) CoreCount.Text = $"{castState.CoreCount}"; InjectionAmount.Text = $"{castState.InjectionAmount}"; // format power statistics to pretty numbers - CurrentPowerSupply.Text = $"{castState.CurrentPowerSupply.ToString("N1")}"; - TargetedPowerSupply.Text = $"{castState.TargetedPowerSupply.ToString("N1")}"; + CurrentPowerSupply.Text = $"{castState.CurrentPowerSupply:N1}"; + TargetedPowerSupply.Text = $"{castState.TargetedPowerSupply:N1}"; } } } diff --git a/Content.Client/Anomaly/Ui/AnomalyGeneratorBoundUserInterface.cs b/Content.Client/Anomaly/Ui/AnomalyGeneratorBoundUserInterface.cs index 5764d0a097d..5d1985485c4 100644 --- a/Content.Client/Anomaly/Ui/AnomalyGeneratorBoundUserInterface.cs +++ b/Content.Client/Anomaly/Ui/AnomalyGeneratorBoundUserInterface.cs @@ -2,6 +2,7 @@ using Content.Shared.Gravity; using JetBrains.Annotations; using Robust.Client.GameObjects; +using Robust.Client.UserInterface; namespace Content.Client.Anomaly.Ui; @@ -18,10 +19,8 @@ protected override void Open() { base.Open(); - _window = new(Owner); - - _window.OpenCentered(); - _window.OnClose += Close; + _window = this.CreateWindow(); + _window.SetEntity(Owner); _window.OnGenerateButtonPressed += () => { @@ -37,18 +36,5 @@ protected override void UpdateState(BoundUserInterfaceState state) return; _window?.UpdateState(msg); } - - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - if (!disposing) return; - - _window?.Dispose(); - } - - public void SetPowerSwitch(bool on) - { - SendMessage(new SharedGravityGeneratorComponent.SwitchGeneratorMessage(on)); - } } diff --git a/Content.Client/Anomaly/Ui/AnomalyGeneratorWindow.xaml.cs b/Content.Client/Anomaly/Ui/AnomalyGeneratorWindow.xaml.cs index 08438e2a1b2..82d41192dd0 100644 --- a/Content.Client/Anomaly/Ui/AnomalyGeneratorWindow.xaml.cs +++ b/Content.Client/Anomaly/Ui/AnomalyGeneratorWindow.xaml.cs @@ -18,17 +18,21 @@ public sealed partial class AnomalyGeneratorWindow : FancyWindow public Action? OnGenerateButtonPressed; - public AnomalyGeneratorWindow(EntityUid gen) + public AnomalyGeneratorWindow() { RobustXamlLoader.Load(this); IoCManager.InjectDependencies(this); - EntityView.SetEntity(gen); EntityView.SpriteOffset = false; GenerateButton.OnPressed += _ => OnGenerateButtonPressed?.Invoke(); } + public void SetEntity(EntityUid uid) + { + EntityView.SetEntity(uid); + } + public void UpdateState(AnomalyGeneratorUserInterfaceState state) { _cooldownEnd = state.CooldownEndTime; diff --git a/Content.Client/Arcade/BlockGameMenu.cs b/Content.Client/Arcade/BlockGameMenu.cs index eeda2a31020..4a579fc4bf4 100644 --- a/Content.Client/Arcade/BlockGameMenu.cs +++ b/Content.Client/Arcade/BlockGameMenu.cs @@ -28,8 +28,6 @@ public sealed class BlockGameMenu : DefaultWindow private static readonly Vector2 BlockSize = new(15, 15); - private readonly BlockGameBoundUserInterface _owner; - private readonly PanelContainer _mainPanel; private readonly BoxContainer _gameRootContainer; @@ -58,10 +56,11 @@ public sealed class BlockGameMenu : DefaultWindow private bool _isPlayer = false; private bool _gameOver = false; - public BlockGameMenu(BlockGameBoundUserInterface owner) + public event Action? OnAction; + + public BlockGameMenu() { Title = Loc.GetString("blockgame-menu-title"); - _owner = owner; MinSize = SetSize = new Vector2(410, 490); @@ -176,7 +175,7 @@ public BlockGameMenu(BlockGameBoundUserInterface owner) }; _newGameButton.OnPressed += (e) => { - _owner.SendAction(BlockGamePlayerAction.NewGame); + OnAction?.Invoke(BlockGamePlayerAction.NewGame); }; pauseMenuContainer.AddChild(_newGameButton); pauseMenuContainer.AddChild(new Control { MinSize = new Vector2(1, 10) }); @@ -186,7 +185,10 @@ public BlockGameMenu(BlockGameBoundUserInterface owner) Text = Loc.GetString("blockgame-menu-button-scoreboard"), TextAlign = Label.AlignMode.Center }; - _scoreBoardButton.OnPressed += (e) => _owner.SendAction(BlockGamePlayerAction.ShowHighscores); + _scoreBoardButton.OnPressed += (e) => + { + OnAction?.Invoke(BlockGamePlayerAction.ShowHighscores); + }; pauseMenuContainer.AddChild(_scoreBoardButton); _unpauseButtonMargin = new Control { MinSize = new Vector2(1, 10), Visible = false }; pauseMenuContainer.AddChild(_unpauseButtonMargin); @@ -199,7 +201,7 @@ public BlockGameMenu(BlockGameBoundUserInterface owner) }; _unpauseButton.OnPressed += (e) => { - _owner.SendAction(BlockGamePlayerAction.Unpause); + OnAction?.Invoke(BlockGamePlayerAction.Unpause); }; pauseMenuContainer.AddChild(_unpauseButton); @@ -257,7 +259,7 @@ public BlockGameMenu(BlockGameBoundUserInterface owner) }; _finalNewGameButton.OnPressed += (e) => { - _owner.SendAction(BlockGamePlayerAction.NewGame); + OnAction?.Invoke(BlockGamePlayerAction.NewGame); }; gameOverMenuContainer.AddChild(_finalNewGameButton); @@ -327,7 +329,10 @@ public BlockGameMenu(BlockGameBoundUserInterface owner) Text = Loc.GetString("blockgame-menu-button-back"), TextAlign = Label.AlignMode.Center }; - _highscoreBackButton.OnPressed += (e) => _owner.SendAction(BlockGamePlayerAction.Pause); + _highscoreBackButton.OnPressed += (e) => + { + OnAction?.Invoke(BlockGamePlayerAction.Pause); + }; menuContainer.AddChild(_highscoreBackButton); menuInnerPanel.AddChild(menuContainer); @@ -473,7 +478,7 @@ protected override void KeyboardFocusExited() private void TryPause() { - _owner.SendAction(BlockGamePlayerAction.Pause); + OnAction?.Invoke(BlockGamePlayerAction.Pause); } public void SetStarted() @@ -576,19 +581,19 @@ protected override void KeyBindDown(GUIBoundKeyEventArgs args) return; else if (args.Function == ContentKeyFunctions.ArcadeLeft) - _owner.SendAction(BlockGamePlayerAction.StartLeft); + OnAction?.Invoke(BlockGamePlayerAction.StartLeft); else if (args.Function == ContentKeyFunctions.ArcadeRight) - _owner.SendAction(BlockGamePlayerAction.StartRight); + OnAction?.Invoke(BlockGamePlayerAction.StartRight); else if (args.Function == ContentKeyFunctions.ArcadeUp) - _owner.SendAction(BlockGamePlayerAction.Rotate); + OnAction?.Invoke(BlockGamePlayerAction.Rotate); else if (args.Function == ContentKeyFunctions.Arcade3) - _owner.SendAction(BlockGamePlayerAction.CounterRotate); + OnAction?.Invoke(BlockGamePlayerAction.CounterRotate); else if (args.Function == ContentKeyFunctions.ArcadeDown) - _owner.SendAction(BlockGamePlayerAction.SoftdropStart); + OnAction?.Invoke(BlockGamePlayerAction.SoftdropStart); else if (args.Function == ContentKeyFunctions.Arcade2) - _owner.SendAction(BlockGamePlayerAction.Hold); + OnAction?.Invoke(BlockGamePlayerAction.Hold); else if (args.Function == ContentKeyFunctions.Arcade1) - _owner.SendAction(BlockGamePlayerAction.Harddrop); + OnAction?.Invoke(BlockGamePlayerAction.Harddrop); } protected override void KeyBindUp(GUIBoundKeyEventArgs args) @@ -599,11 +604,11 @@ protected override void KeyBindUp(GUIBoundKeyEventArgs args) return; else if (args.Function == ContentKeyFunctions.ArcadeLeft) - _owner.SendAction(BlockGamePlayerAction.EndLeft); + OnAction?.Invoke(BlockGamePlayerAction.EndLeft); else if (args.Function == ContentKeyFunctions.ArcadeRight) - _owner.SendAction(BlockGamePlayerAction.EndRight); + OnAction?.Invoke(BlockGamePlayerAction.EndRight); else if (args.Function == ContentKeyFunctions.ArcadeDown) - _owner.SendAction(BlockGamePlayerAction.SoftdropEnd); + OnAction?.Invoke(BlockGamePlayerAction.SoftdropEnd); } public void UpdateNextBlock(BlockGameBlock[] blocks) diff --git a/Content.Client/Arcade/SpaceVillainArcadeMenu.cs b/Content.Client/Arcade/SpaceVillainArcadeMenu.cs index e5542a5848e..1ee4c268184 100644 --- a/Content.Client/Arcade/SpaceVillainArcadeMenu.cs +++ b/Content.Client/Arcade/SpaceVillainArcadeMenu.cs @@ -8,8 +8,6 @@ namespace Content.Client.Arcade { public sealed class SpaceVillainArcadeMenu : DefaultWindow { - public SpaceVillainArcadeBoundUserInterface Owner { get; set; } - private readonly Label _enemyNameLabel; private readonly Label _playerInfoLabel; private readonly Label _enemyInfoLabel; @@ -17,11 +15,13 @@ public sealed class SpaceVillainArcadeMenu : DefaultWindow private readonly Label _enemyActionLabel; private readonly Button[] _gameButtons = new Button[3]; //used to disable/enable all game buttons - public SpaceVillainArcadeMenu(SpaceVillainArcadeBoundUserInterface owner) + + public event Action? OnPlayerAction; + + public SpaceVillainArcadeMenu() { MinSize = SetSize = new Vector2(300, 225); Title = Loc.GetString("spacevillain-menu-title"); - Owner = owner; var grid = new GridContainer { Columns = 1 }; @@ -47,32 +47,43 @@ public SpaceVillainArcadeMenu(SpaceVillainArcadeBoundUserInterface owner) grid.AddChild(_enemyActionLabel); var buttonGrid = new GridContainer { Columns = 3 }; - _gameButtons[0] = new ActionButton(Owner, SharedSpaceVillainArcadeComponent.PlayerAction.Attack) + _gameButtons[0] = new Button() { Text = Loc.GetString("spacevillain-menu-button-attack") }; + + _gameButtons[0].OnPressed += + _ => OnPlayerAction?.Invoke(SharedSpaceVillainArcadeComponent.PlayerAction.Attack); buttonGrid.AddChild(_gameButtons[0]); - _gameButtons[1] = new ActionButton(Owner, SharedSpaceVillainArcadeComponent.PlayerAction.Heal) + _gameButtons[1] = new Button() { Text = Loc.GetString("spacevillain-menu-button-heal") }; + + _gameButtons[1].OnPressed += + _ => OnPlayerAction?.Invoke(SharedSpaceVillainArcadeComponent.PlayerAction.Heal); buttonGrid.AddChild(_gameButtons[1]); - _gameButtons[2] = new ActionButton(Owner, SharedSpaceVillainArcadeComponent.PlayerAction.Recharge) + _gameButtons[2] = new Button() { Text = Loc.GetString("spacevillain-menu-button-recharge") }; + + _gameButtons[2].OnPressed += + _ => OnPlayerAction?.Invoke(SharedSpaceVillainArcadeComponent.PlayerAction.Recharge); buttonGrid.AddChild(_gameButtons[2]); centerContainer = new CenterContainer(); centerContainer.AddChild(buttonGrid); grid.AddChild(centerContainer); - var newGame = new ActionButton(Owner, SharedSpaceVillainArcadeComponent.PlayerAction.NewGame) + var newGame = new Button() { Text = Loc.GetString("spacevillain-menu-button-new-game") }; + + newGame.OnPressed += _ => OnPlayerAction?.Invoke(SharedSpaceVillainArcadeComponent.PlayerAction.NewGame); grid.AddChild(newGame); Contents.AddChild(grid); @@ -99,23 +110,5 @@ public void UpdateInfo(SharedSpaceVillainArcadeComponent.SpaceVillainArcadeDataU _playerActionLabel.Text = message.PlayerActionMessage; _enemyActionLabel.Text = message.EnemyActionMessage; } - - private sealed class ActionButton : Button - { - private readonly SpaceVillainArcadeBoundUserInterface _owner; - private readonly SharedSpaceVillainArcadeComponent.PlayerAction _playerAction; - - public ActionButton(SpaceVillainArcadeBoundUserInterface owner, SharedSpaceVillainArcadeComponent.PlayerAction playerAction) - { - _owner = owner; - _playerAction = playerAction; - OnPressed += Clicked; - } - - private void Clicked(ButtonEventArgs e) - { - _owner.SendAction(_playerAction); - } - } } } diff --git a/Content.Client/Arcade/UI/BlockGameBoundUserInterface.cs b/Content.Client/Arcade/UI/BlockGameBoundUserInterface.cs index 1a3422dec0f..8fa8035afd6 100644 --- a/Content.Client/Arcade/UI/BlockGameBoundUserInterface.cs +++ b/Content.Client/Arcade/UI/BlockGameBoundUserInterface.cs @@ -1,5 +1,6 @@ using Content.Shared.Arcade; using Robust.Client.GameObjects; +using Robust.Client.UserInterface; namespace Content.Client.Arcade.UI; @@ -15,9 +16,7 @@ protected override void Open() { base.Open(); - _menu = new BlockGameMenu(this); - _menu.OnClose += Close; - _menu.OpenCentered(); + _menu = this.CreateWindow(); } protected override void ReceiveMessage(BoundUserInterfaceMessage message) diff --git a/Content.Client/Arcade/UI/SpaceVillainArcadeBoundUserInterface.cs b/Content.Client/Arcade/UI/SpaceVillainArcadeBoundUserInterface.cs index 40bbe8b2d8c..c0704530de2 100644 --- a/Content.Client/Arcade/UI/SpaceVillainArcadeBoundUserInterface.cs +++ b/Content.Client/Arcade/UI/SpaceVillainArcadeBoundUserInterface.cs @@ -1,4 +1,5 @@ using Robust.Client.GameObjects; +using Robust.Client.UserInterface; using Robust.Shared.GameObjects; using Robust.Shared.ViewVariables; using static Content.Shared.Arcade.SharedSpaceVillainArcadeComponent; @@ -9,8 +10,6 @@ public sealed class SpaceVillainArcadeBoundUserInterface : BoundUserInterface { [ViewVariables] private SpaceVillainArcadeMenu? _menu; - //public SharedSpaceVillainArcadeComponent SpaceVillainArcade; - public SpaceVillainArcadeBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey) { SendAction(PlayerAction.RequestData); @@ -25,10 +24,7 @@ protected override void Open() { base.Open(); - _menu = new SpaceVillainArcadeMenu(this); - - _menu.OnClose += Close; - _menu.OpenCentered(); + _menu = this.CreateWindow(); } protected override void ReceiveMessage(BoundUserInterfaceMessage message) @@ -36,12 +32,4 @@ protected override void ReceiveMessage(BoundUserInterfaceMessage message) if (message is SpaceVillainArcadeDataUpdateMessage msg) _menu?.UpdateInfo(msg); } - - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - - if (disposing) - _menu?.Dispose(); - } } diff --git a/Content.Client/Atmos/Monitor/UI/AirAlarmBoundUserInterface.cs b/Content.Client/Atmos/Monitor/UI/AirAlarmBoundUserInterface.cs index 8f3b507c806..2ae15188355 100644 --- a/Content.Client/Atmos/Monitor/UI/AirAlarmBoundUserInterface.cs +++ b/Content.Client/Atmos/Monitor/UI/AirAlarmBoundUserInterface.cs @@ -2,6 +2,7 @@ using Content.Shared.Atmos.Monitor; using Content.Shared.Atmos.Monitor.Components; using Robust.Client.GameObjects; +using Robust.Client.UserInterface; using Robust.Shared.GameObjects; using Robust.Shared.IoC; using Robust.Shared.Log; @@ -20,16 +21,9 @@ protected override void Open() { base.Open(); - _window = new AirAlarmWindow(this); + _window = this.CreateWindow(); + _window.SetEntity(Owner); - if (State != null) - { - UpdateState(State); - } - - _window.OpenCentered(); - - _window.OnClose += Close; _window.AtmosDeviceDataChanged += OnDeviceDataChanged; _window.AtmosDeviceDataCopied += OnDeviceDataCopied; _window.AtmosAlarmThresholdChanged += OnThresholdChanged; diff --git a/Content.Client/Atmos/Monitor/UI/AirAlarmWindow.xaml.cs b/Content.Client/Atmos/Monitor/UI/AirAlarmWindow.xaml.cs index 43be67c9d6b..eeec11c7660 100644 --- a/Content.Client/Atmos/Monitor/UI/AirAlarmWindow.xaml.cs +++ b/Content.Client/Atmos/Monitor/UI/AirAlarmWindow.xaml.cs @@ -47,7 +47,7 @@ public sealed partial class AirAlarmWindow : FancyWindow private CheckBox _autoMode => AutoModeCheckBox; - public AirAlarmWindow(BoundUserInterface owner) + public AirAlarmWindow() { RobustXamlLoader.Load(this); @@ -95,8 +95,11 @@ public AirAlarmWindow(BoundUserInterface owner) _sensors.Clear(); ResyncAllRequested!.Invoke(); }; + } - EntityView.SetEntity(owner.Owner); + public void SetEntity(EntityUid uid) + { + EntityView.SetEntity(uid); } public void UpdateState(AirAlarmUIState state) diff --git a/Content.Client/Atmos/UI/GasCanisterBoundUserInterface.cs b/Content.Client/Atmos/UI/GasCanisterBoundUserInterface.cs index a5e316a8def..7bf9b396d5e 100644 --- a/Content.Client/Atmos/UI/GasCanisterBoundUserInterface.cs +++ b/Content.Client/Atmos/UI/GasCanisterBoundUserInterface.cs @@ -1,6 +1,7 @@ using Content.Shared.Atmos.Piping.Binary.Components; using JetBrains.Annotations; using Robust.Client.GameObjects; +using Robust.Client.UserInterface; namespace Content.Client.Atmos.UI { @@ -21,14 +22,8 @@ protected override void Open() { base.Open(); - _window = new GasCanisterWindow(); + _window = this.CreateWindow(); - if (State != null) - UpdateState(State); - - _window.OpenCentered(); - - _window.OnClose += Close; _window.ReleaseValveCloseButtonPressed += OnReleaseValveClosePressed; _window.ReleaseValveOpenButtonPressed += OnReleaseValveOpenPressed; _window.ReleasePressureSet += OnReleasePressureSet; diff --git a/Content.Client/Atmos/UI/GasFilterBoundUserInterface.cs b/Content.Client/Atmos/UI/GasFilterBoundUserInterface.cs index 1904e2b3402..2b8020924cf 100644 --- a/Content.Client/Atmos/UI/GasFilterBoundUserInterface.cs +++ b/Content.Client/Atmos/UI/GasFilterBoundUserInterface.cs @@ -3,6 +3,7 @@ using Content.Shared.Atmos.Piping.Trinary.Components; using Content.Shared.Localizations; using JetBrains.Annotations; +using Robust.Client.UserInterface; namespace Content.Client.Atmos.UI { @@ -28,14 +29,8 @@ protected override void Open() var atmosSystem = EntMan.System(); - _window = new GasFilterWindow(atmosSystem.Gases); - - if (State != null) - UpdateState(State); - - _window.OpenCentered(); - - _window.OnClose += Close; + _window = this.CreateWindow(); + _window.PopulateGasList(atmosSystem.Gases); _window.ToggleStatusButtonPressed += OnToggleStatusButtonPressed; _window.FilterTransferRateChanged += OnFilterTransferRatePressed; diff --git a/Content.Client/Atmos/UI/GasFilterWindow.xaml.cs b/Content.Client/Atmos/UI/GasFilterWindow.xaml.cs index 28766c688a0..62748b52592 100644 --- a/Content.Client/Atmos/UI/GasFilterWindow.xaml.cs +++ b/Content.Client/Atmos/UI/GasFilterWindow.xaml.cs @@ -26,10 +26,9 @@ public sealed partial class GasFilterWindow : DefaultWindow public event Action? FilterTransferRateChanged; public event Action? SelectGasPressed; - public GasFilterWindow(IEnumerable gases) + public GasFilterWindow() { RobustXamlLoader.Load(this); - PopulateGasList(gases); ToggleStatusButton.OnPressed += _ => SetFilterStatus(!FilterStatus); ToggleStatusButton.OnPressed += _ => ToggleStatusButtonPressed?.Invoke(); @@ -73,7 +72,7 @@ public void SetGasFiltered(string? id, string name) SelectGasButton.Disabled = true; } - private void PopulateGasList(IEnumerable gases) + public void PopulateGasList(IEnumerable gases) { GasList.Add(new ItemList.Item(GasList) { @@ -81,7 +80,7 @@ private void PopulateGasList(IEnumerable gases) Text = Loc.GetString("comp-gas-filter-ui-filter-gas-none") }); - foreach (GasPrototype gas in gases) + foreach (var gas in gases) { var gasName = Loc.GetString(gas.Name); GasList.Add(GetGasItem(gas.ID, gasName, GasList)); diff --git a/Content.Client/Atmos/UI/GasMixerBoundUserInteface.cs b/Content.Client/Atmos/UI/GasMixerBoundUserInteface.cs index 709c06517cb..392fbf1cd9a 100644 --- a/Content.Client/Atmos/UI/GasMixerBoundUserInteface.cs +++ b/Content.Client/Atmos/UI/GasMixerBoundUserInteface.cs @@ -2,7 +2,7 @@ using Content.Shared.Atmos.Piping.Trinary.Components; using Content.Shared.Localizations; using JetBrains.Annotations; -using Robust.Client.GameObjects; +using Robust.Client.UserInterface; namespace Content.Client.Atmos.UI { @@ -26,14 +26,7 @@ protected override void Open() { base.Open(); - _window = new GasMixerWindow(); - - if (State != null) - UpdateState(State); - - _window.OpenCentered(); - - _window.OnClose += Close; + _window = this.CreateWindow(); _window.ToggleStatusButtonPressed += OnToggleStatusButtonPressed; _window.MixerOutputPressureChanged += OnMixerOutputPressurePressed; @@ -83,12 +76,5 @@ protected override void UpdateState(BoundUserInterfaceState state) _window.SetOutputPressure(cast.OutputPressure); _window.SetNodePercentages(cast.NodeOne); } - - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - if (!disposing) return; - _window?.Dispose(); - } } } diff --git a/Content.Client/Atmos/UI/GasPressurePumpBoundUserInterface.cs b/Content.Client/Atmos/UI/GasPressurePumpBoundUserInterface.cs index 6eba2e0d215..220fdbe875c 100644 --- a/Content.Client/Atmos/UI/GasPressurePumpBoundUserInterface.cs +++ b/Content.Client/Atmos/UI/GasPressurePumpBoundUserInterface.cs @@ -3,6 +3,7 @@ using Content.Shared.Localizations; using JetBrains.Annotations; using Robust.Client.GameObjects; +using Robust.Client.UserInterface; namespace Content.Client.Atmos.UI { @@ -26,14 +27,7 @@ protected override void Open() { base.Open(); - _window = new GasPressurePumpWindow(); - - if (State != null) - UpdateState(State); - - _window.OpenCentered(); - - _window.OnClose += Close; + _window = this.CreateWindow(); _window.ToggleStatusButtonPressed += OnToggleStatusButtonPressed; _window.PumpOutputPressureChanged += OnPumpOutputPressurePressed; @@ -67,12 +61,5 @@ protected override void UpdateState(BoundUserInterfaceState state) _window.SetPumpStatus(cast.Enabled); _window.SetOutputPressure(cast.OutputPressure); } - - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - if (!disposing) return; - _window?.Dispose(); - } } } diff --git a/Content.Client/Atmos/UI/GasThermomachineBoundUserInterface.cs b/Content.Client/Atmos/UI/GasThermomachineBoundUserInterface.cs index 1664c8b9d75..d62be8f4bb4 100644 --- a/Content.Client/Atmos/UI/GasThermomachineBoundUserInterface.cs +++ b/Content.Client/Atmos/UI/GasThermomachineBoundUserInterface.cs @@ -2,6 +2,7 @@ using Content.Shared.Atmos.Piping.Unary.Components; using JetBrains.Annotations; using Robust.Client.GameObjects; +using Robust.Client.UserInterface; namespace Content.Client.Atmos.UI { @@ -31,14 +32,7 @@ protected override void Open() { base.Open(); - _window = new GasThermomachineWindow(); - - if (State != null) - UpdateState(State); - - _window.OpenCentered(); - - _window.OnClose += Close; + _window = this.CreateWindow(); _window.ToggleStatusButton.OnPressed += _ => OnToggleStatusButtonPressed(); _window.TemperatureSpinbox.OnValueChanged += _ => OnTemperatureChanged(_window.TemperatureSpinbox.Value); @@ -91,12 +85,5 @@ protected override void UpdateState(BoundUserInterfaceState state) true => Loc.GetString("comp-gas-thermomachine-ui-title-heater") }; } - - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - if (!disposing) return; - _window?.Dispose(); - } } } diff --git a/Content.Client/Atmos/UI/GasVolumePumpBoundUserInterface.cs b/Content.Client/Atmos/UI/GasVolumePumpBoundUserInterface.cs index 1b39306181a..642f34c2f92 100644 --- a/Content.Client/Atmos/UI/GasVolumePumpBoundUserInterface.cs +++ b/Content.Client/Atmos/UI/GasVolumePumpBoundUserInterface.cs @@ -3,6 +3,7 @@ using Content.Shared.Localizations; using JetBrains.Annotations; using Robust.Client.GameObjects; +using Robust.Client.UserInterface; namespace Content.Client.Atmos.UI { @@ -26,14 +27,7 @@ protected override void Open() { base.Open(); - _window = new GasVolumePumpWindow(); - - if (State != null) - UpdateState(State); - - _window.OpenCentered(); - - _window.OnClose += Close; + _window = this.CreateWindow(); _window.ToggleStatusButtonPressed += OnToggleStatusButtonPressed; _window.PumpTransferRateChanged += OnPumpTransferRatePressed; @@ -64,16 +58,9 @@ protected override void UpdateState(BoundUserInterfaceState state) if (_window == null || state is not GasVolumePumpBoundUserInterfaceState cast) return; - _window.Title = (cast.PumpLabel); + _window.Title = cast.PumpLabel; _window.SetPumpStatus(cast.Enabled); _window.SetTransferRate(cast.TransferRate); } - - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - if (!disposing) return; - _window?.Dispose(); - } } } diff --git a/Content.Client/Atmos/UI/SpaceHeaterBoundUserInterface.cs b/Content.Client/Atmos/UI/SpaceHeaterBoundUserInterface.cs index 4d8d1191e91..e70426575d4 100644 --- a/Content.Client/Atmos/UI/SpaceHeaterBoundUserInterface.cs +++ b/Content.Client/Atmos/UI/SpaceHeaterBoundUserInterface.cs @@ -1,5 +1,6 @@ using Content.Shared.Atmos.Piping.Portable.Components; using JetBrains.Annotations; +using Robust.Client.UserInterface; using Robust.Client.UserInterface.Controls; namespace Content.Client.Atmos.UI; @@ -21,14 +22,7 @@ protected override void Open() { base.Open(); - _window = new SpaceHeaterWindow(); - - if (State != null) - UpdateState(State); - - _window.OpenCentered(); - - _window.OnClose += Close; + _window = this.CreateWindow(); _window.ToggleStatusButton.OnPressed += _ => OnToggleStatusButtonPressed(); _window.IncreaseTempRange.OnPressed += _ => OnTemperatureRangeChanged(_window.TemperatureChangeDelta); diff --git a/Content.Client/Audio/Jukebox/JukeboxBoundUserInterface.cs b/Content.Client/Audio/Jukebox/JukeboxBoundUserInterface.cs index 60fe339069a..865dfc478d0 100644 --- a/Content.Client/Audio/Jukebox/JukeboxBoundUserInterface.cs +++ b/Content.Client/Audio/Jukebox/JukeboxBoundUserInterface.cs @@ -1,8 +1,7 @@ using Content.Shared.Audio.Jukebox; using Robust.Client.Audio; -using Robust.Client.Player; +using Robust.Client.UserInterface; using Robust.Shared.Audio.Components; -using Robust.Shared.Player; using Robust.Shared.Prototypes; namespace Content.Client.Audio.Jukebox; @@ -23,9 +22,7 @@ protected override void Open() { base.Open(); - _menu = new JukeboxMenu(); - _menu.OnClose += Close; - _menu.OpenCentered(); + _menu = this.CreateWindow(); _menu.OnPlayPressed += args => { @@ -100,19 +97,5 @@ public void SetTime(float time) SendMessage(new JukeboxSetTimeMessage(sentTime)); } - - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - if (!disposing) - return; - - if (_menu == null) - return; - - _menu.OnClose -= Close; - _menu.Dispose(); - _menu = null; - } } diff --git a/Content.Client/Bed/Cryostorage/CryostorageBoundUserInterface.cs b/Content.Client/Bed/Cryostorage/CryostorageBoundUserInterface.cs index ffab1625483..09f3cec8fbf 100644 --- a/Content.Client/Bed/Cryostorage/CryostorageBoundUserInterface.cs +++ b/Content.Client/Bed/Cryostorage/CryostorageBoundUserInterface.cs @@ -1,5 +1,6 @@ using Content.Shared.Bed.Cryostorage; using JetBrains.Annotations; +using Robust.Client.UserInterface; namespace Content.Client.Bed.Cryostorage; @@ -17,9 +18,7 @@ protected override void Open() { base.Open(); - _menu = new(); - - _menu.OnClose += Close; + _menu = this.CreateWindow(); _menu.SlotRemoveButtonPressed += (ent, slot) => { @@ -30,8 +29,6 @@ protected override void Open() { SendMessage(new CryostorageRemoveItemBuiMessage(ent, hand, CryostorageRemoveItemBuiMessage.RemovalType.Hand)); }; - - _menu.OpenCentered(); } protected override void UpdateState(BoundUserInterfaceState state) @@ -45,12 +42,4 @@ protected override void UpdateState(BoundUserInterfaceState state) break; } } - - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - if (!disposing) - return; - _menu?.Dispose(); - } } diff --git a/Content.Client/Cargo/BUI/CargoBountyConsoleBoundUserInterface.cs b/Content.Client/Cargo/BUI/CargoBountyConsoleBoundUserInterface.cs index d3365702bcf..44c40143d83 100644 --- a/Content.Client/Cargo/BUI/CargoBountyConsoleBoundUserInterface.cs +++ b/Content.Client/Cargo/BUI/CargoBountyConsoleBoundUserInterface.cs @@ -1,6 +1,7 @@ using Content.Client.Cargo.UI; using Content.Shared.Cargo.Components; using JetBrains.Annotations; +using Robust.Client.UserInterface; namespace Content.Client.Cargo.BUI; @@ -18,9 +19,7 @@ protected override void Open() { base.Open(); - _menu = new(); - - _menu.OnClose += Close; + _menu = this.CreateWindow(); _menu.OnLabelButtonPressed += id => { @@ -31,8 +30,6 @@ protected override void Open() { SendMessage(new BountySkipMessage(id)); }; - - _menu.OpenCentered(); } protected override void UpdateState(BoundUserInterfaceState message) @@ -44,14 +41,4 @@ protected override void UpdateState(BoundUserInterfaceState message) _menu?.UpdateEntries(state.Bounties, state.UntilNextSkip); } - - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - - if (!disposing) - return; - - _menu?.Dispose(); - } } diff --git a/Content.Client/Cargo/BUI/CargoPalletConsoleBoundUserInterface.cs b/Content.Client/Cargo/BUI/CargoPalletConsoleBoundUserInterface.cs index 20c23a48a0d..2461dafb5f3 100644 --- a/Content.Client/Cargo/BUI/CargoPalletConsoleBoundUserInterface.cs +++ b/Content.Client/Cargo/BUI/CargoPalletConsoleBoundUserInterface.cs @@ -2,6 +2,7 @@ using Content.Shared.Cargo.BUI; using Content.Shared.Cargo.Events; using Robust.Client.GameObjects; +using Robust.Client.UserInterface; namespace Content.Client.Cargo.BUI; @@ -18,21 +19,9 @@ protected override void Open() { base.Open(); - _menu = new CargoPalletMenu(); + _menu = this.CreateWindow(); _menu.AppraiseRequested += OnAppraisal; _menu.SellRequested += OnSell; - _menu.OnClose += Close; - - _menu.OpenCentered(); - } - - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - if (disposing) - { - _menu?.Dispose(); - } } private void OnAppraisal() diff --git a/Content.Client/Cargo/BUI/CargoShuttleConsoleBoundUserInterface.cs b/Content.Client/Cargo/BUI/CargoShuttleConsoleBoundUserInterface.cs index 422d03707a0..02b721b9020 100644 --- a/Content.Client/Cargo/BUI/CargoShuttleConsoleBoundUserInterface.cs +++ b/Content.Client/Cargo/BUI/CargoShuttleConsoleBoundUserInterface.cs @@ -2,6 +2,7 @@ using Content.Shared.Cargo.BUI; using JetBrains.Annotations; using Robust.Client.GameObjects; +using Robust.Client.UserInterface; using Robust.Shared.Prototypes; namespace Content.Client.Cargo.BUI; @@ -9,6 +10,8 @@ namespace Content.Client.Cargo.BUI; [UsedImplicitly] public sealed class CargoShuttleConsoleBoundUserInterface : BoundUserInterface { + [Dependency] private readonly IPrototypeManager _protoManager = default!; + [ViewVariables] private CargoShuttleMenu? _menu; @@ -19,24 +22,7 @@ public CargoShuttleConsoleBoundUserInterface(EntityUid owner, Enum uiKey) : base protected override void Open() { base.Open(); - var collection = IoCManager.Instance; - - if (collection == null) - return; - - _menu = new CargoShuttleMenu(collection.Resolve(), collection.Resolve().GetEntitySystem()); - _menu.OnClose += Close; - - _menu.OpenCentered(); - } - - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - if (disposing) - { - _menu?.Dispose(); - } + _menu = this.CreateWindow(); } protected override void UpdateState(BoundUserInterfaceState state) @@ -45,6 +31,6 @@ protected override void UpdateState(BoundUserInterfaceState state) if (state is not CargoShuttleConsoleBoundUserInterfaceState cargoState) return; _menu?.SetAccountName(cargoState.AccountName); _menu?.SetShuttleName(cargoState.ShuttleName); - _menu?.SetOrders(cargoState.Orders); + _menu?.SetOrders(EntMan.System(), _protoManager, cargoState.Orders); } } diff --git a/Content.Client/Cargo/UI/CargoShuttleMenu.xaml.cs b/Content.Client/Cargo/UI/CargoShuttleMenu.xaml.cs index c591f917da3..43b00089e16 100644 --- a/Content.Client/Cargo/UI/CargoShuttleMenu.xaml.cs +++ b/Content.Client/Cargo/UI/CargoShuttleMenu.xaml.cs @@ -12,14 +12,9 @@ namespace Content.Client.Cargo.UI [GenerateTypedNameReferences] public sealed partial class CargoShuttleMenu : FancyWindow { - private readonly IPrototypeManager _protoManager; - private readonly SpriteSystem _spriteSystem; - - public CargoShuttleMenu(IPrototypeManager protoManager, SpriteSystem spriteSystem) + public CargoShuttleMenu() { RobustXamlLoader.Load(this); - _protoManager = protoManager; - _spriteSystem = spriteSystem; Title = Loc.GetString("cargo-shuttle-console-menu-title"); } @@ -33,19 +28,19 @@ public void SetShuttleName(string name) ShuttleNameLabel.Text = name; } - public void SetOrders(List orders) + public void SetOrders(SpriteSystem sprites, IPrototypeManager protoManager, List orders) { Orders.DisposeAllChildren(); foreach (var order in orders) { - var product = _protoManager.Index(order.ProductId); + var product = protoManager.Index(order.ProductId); var productName = product.Name; var row = new CargoOrderRow { Order = order, - Icon = { Texture = _spriteSystem.Frame0(product) }, + Icon = { Texture = sprites.Frame0(product) }, ProductName = { Text = Loc.GetString( diff --git a/Content.Client/Chemistry/UI/ChemMasterBoundUserInterface.cs b/Content.Client/Chemistry/UI/ChemMasterBoundUserInterface.cs index 988fea7978b..3ef7f0ae73e 100644 --- a/Content.Client/Chemistry/UI/ChemMasterBoundUserInterface.cs +++ b/Content.Client/Chemistry/UI/ChemMasterBoundUserInterface.cs @@ -2,6 +2,7 @@ using Content.Shared.Containers.ItemSlots; using JetBrains.Annotations; using Robust.Client.GameObjects; +using Robust.Client.UserInterface; namespace Content.Client.Chemistry.UI { @@ -27,13 +28,8 @@ protected override void Open() base.Open(); // Setup window layout/elements - _window = new ChemMasterWindow - { - Title = EntMan.GetComponent(Owner).EntityName, - }; - - _window.OpenCentered(); - _window.OnClose += Close; + _window = this.CreateWindow(); + _window.Title = EntMan.GetComponent(Owner).EntityName; // Setup static button actions. _window.InputEjectButton.OnPressed += _ => SendMessage( @@ -75,15 +71,5 @@ protected override void UpdateState(BoundUserInterfaceState state) _window?.UpdateState(castState); // Update window state } - - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - - if (disposing) - { - _window?.Dispose(); - } - } } } diff --git a/Content.Client/Chemistry/UI/ReagentDispenserBoundUserInterface.cs b/Content.Client/Chemistry/UI/ReagentDispenserBoundUserInterface.cs index 99e5a3d3953..2ad1b718887 100644 --- a/Content.Client/Chemistry/UI/ReagentDispenserBoundUserInterface.cs +++ b/Content.Client/Chemistry/UI/ReagentDispenserBoundUserInterface.cs @@ -3,6 +3,7 @@ using Content.Shared.Containers.ItemSlots; using JetBrains.Annotations; using Robust.Client.GameObjects; +using Robust.Client.UserInterface; namespace Content.Client.Chemistry.UI { @@ -15,9 +16,6 @@ public sealed class ReagentDispenserBoundUserInterface : BoundUserInterface [ViewVariables] private ReagentDispenserWindow? _window; - [ViewVariables] - private ReagentDispenserBoundUserInterfaceState? _lastState; - public ReagentDispenserBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey) { } @@ -32,14 +30,9 @@ protected override void Open() base.Open(); // Setup window layout/elements - _window = new() - { - Title = EntMan.GetComponent(Owner).EntityName, - HelpGuidebookIds = EntMan.GetComponent(Owner).Guides - }; - - _window.OpenCentered(); - _window.OnClose += Close; + _window = this.CreateWindow(); + _window.Title = EntMan.GetComponent(Owner).EntityName; + _window.HelpGuidebookIds = EntMan.GetComponent(Owner).Guides; // Setup static button actions. _window.EjectButton.OnPressed += _ => SendMessage(new ItemSlotButtonPressedEvent(SharedReagentDispenser.OutputSlotName)); @@ -63,19 +56,7 @@ protected override void UpdateState(BoundUserInterfaceState state) base.UpdateState(state); var castState = (ReagentDispenserBoundUserInterfaceState) state; - _lastState = castState; - _window?.UpdateState(castState); //Update window state } - - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - - if (disposing) - { - _window?.Dispose(); - } - } } } diff --git a/Content.Client/Chemistry/UI/TransferAmountBoundUserInterface.cs b/Content.Client/Chemistry/UI/TransferAmountBoundUserInterface.cs index 35df131312d..f1cb27a62a4 100644 --- a/Content.Client/Chemistry/UI/TransferAmountBoundUserInterface.cs +++ b/Content.Client/Chemistry/UI/TransferAmountBoundUserInterface.cs @@ -2,6 +2,7 @@ using Content.Shared.FixedPoint; using JetBrains.Annotations; using Robust.Client.GameObjects; +using Robust.Client.UserInterface; namespace Content.Client.Chemistry.UI { @@ -18,7 +19,7 @@ public TransferAmountBoundUserInterface(EntityUid owner, Enum uiKey) : base(owne protected override void Open() { base.Open(); - _window = new TransferAmountWindow(); + _window = this.CreateWindow(); _window.ApplyButton.OnPressed += _ => { @@ -28,15 +29,6 @@ protected override void Open() _window.Close(); } }; - _window.OnClose += Close; - _window.OpenCentered(); - } - - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - if (!disposing) return; - _window?.Dispose(); } } } diff --git a/Content.Client/CloningConsole/UI/CloningConsoleBoundUserInterface.cs b/Content.Client/CloningConsole/UI/CloningConsoleBoundUserInterface.cs index 26f0994701e..62a02f37186 100644 --- a/Content.Client/CloningConsole/UI/CloningConsoleBoundUserInterface.cs +++ b/Content.Client/CloningConsole/UI/CloningConsoleBoundUserInterface.cs @@ -1,6 +1,7 @@ using JetBrains.Annotations; using Robust.Client.GameObjects; using Content.Shared.Cloning.CloningConsole; +using Robust.Client.UserInterface; namespace Content.Client.CloningConsole.UI { @@ -17,13 +18,11 @@ public CloningConsoleBoundUserInterface(EntityUid owner, Enum uiKey) : base(owne protected override void Open() { base.Open(); - _window = new CloningConsoleWindow - { - Title = Loc.GetString("cloning-console-window-title") - }; - _window.OnClose += Close; + + _window = this.CreateWindow(); + _window.Title = Loc.GetString("cloning-console-window-title"); + _window.CloneButton.OnPressed += _ => SendMessage(new UiButtonPressedMessage(UiButton.Clone)); - _window.OpenCentered(); } protected override void UpdateState(BoundUserInterfaceState state) @@ -32,19 +31,5 @@ protected override void UpdateState(BoundUserInterfaceState state) _window?.Populate((CloningConsoleBoundUserInterfaceState) state); } - - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - if (!disposing) - return; - - if (_window != null) - { - _window.OnClose -= Close; - _window.CloneButton.OnPressed -= _ => SendMessage(new UiButtonPressedMessage(UiButton.Clone)); - } - _window?.Dispose(); - } } } diff --git a/Content.Client/Clothing/UI/ChameleonBoundUserInterface.cs b/Content.Client/Clothing/UI/ChameleonBoundUserInterface.cs index 5b0d5fcf21f..83f6ba15662 100644 --- a/Content.Client/Clothing/UI/ChameleonBoundUserInterface.cs +++ b/Content.Client/Clothing/UI/ChameleonBoundUserInterface.cs @@ -2,6 +2,7 @@ using Content.Shared.Clothing.Components; using JetBrains.Annotations; using Robust.Client.GameObjects; +using Robust.Client.UserInterface; namespace Content.Client.Clothing.UI; @@ -22,10 +23,8 @@ protected override void Open() { base.Open(); - _menu = new ChameleonMenu(); - _menu.OnClose += Close; + _menu = this.CreateWindow(); _menu.OnIdSelected += OnIdSelected; - _menu.OpenCentered(); } protected override void UpdateState(BoundUserInterfaceState state) @@ -42,15 +41,4 @@ private void OnIdSelected(string selectedId) { SendMessage(new ChameleonPrototypeSelectedMessage(selectedId)); } - - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - - if (disposing) - { - _menu?.Close(); - _menu = null; - } - } } diff --git a/Content.Client/Communications/UI/CommunicationsConsoleBoundUserInterface.cs b/Content.Client/Communications/UI/CommunicationsConsoleBoundUserInterface.cs index 1c94d32bf8d..0310e91eeb0 100644 --- a/Content.Client/Communications/UI/CommunicationsConsoleBoundUserInterface.cs +++ b/Content.Client/Communications/UI/CommunicationsConsoleBoundUserInterface.cs @@ -1,6 +1,7 @@ using Content.Shared.CCVar; using Content.Shared.Chat; using Content.Shared.Communications; +using Robust.Client.UserInterface; using Robust.Shared.Configuration; using Robust.Shared.Timing; @@ -8,34 +9,11 @@ namespace Content.Client.Communications.UI { public sealed class CommunicationsConsoleBoundUserInterface : BoundUserInterface { - [Dependency] private readonly IGameTiming _gameTiming = default!; [Dependency] private readonly IConfigurationManager _cfg = default!; [ViewVariables] private CommunicationsConsoleMenu? _menu; - [ViewVariables] - public bool CanAnnounce { get; private set; } - [ViewVariables] - public bool CanBroadcast { get; private set; } - - [ViewVariables] - public bool CanCall { get; private set; } - - [ViewVariables] - public bool CountdownStarted { get; private set; } - - [ViewVariables] - public bool AlertLevelSelectable { get; private set; } - - [ViewVariables] - public string CurrentLevel { get; private set; } = default!; - - [ViewVariables] - private TimeSpan? _expectedCountdownTime; - - public int Countdown => _expectedCountdownTime == null ? 0 : Math.Max((int) _expectedCountdownTime.Value.Subtract(_gameTiming.CurTime).TotalSeconds, 0); - public CommunicationsConsoleBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey) { } @@ -44,23 +22,25 @@ protected override void Open() { base.Open(); - _menu = new CommunicationsConsoleMenu(this); - _menu.OnClose += Close; - _menu.OpenCentered(); + _menu = this.CreateWindow(); + _menu.OnAnnounce += AnnounceButtonPressed; + _menu.OnBroadcast += BroadcastButtonPressed; + _menu.OnAlertLevel += AlertLevelSelected; + _menu.OnEmergencyLevel += EmergencyShuttleButtonPressed; } public void AlertLevelSelected(string level) { - if (AlertLevelSelectable) + if (_menu!.AlertLevelSelectable) { - CurrentLevel = level; + _menu.CurrentLevel = level; SendMessage(new CommunicationsConsoleSelectAlertLevelMessage(level)); } } public void EmergencyShuttleButtonPressed() { - if (CountdownStarted) + if (_menu!.CountdownStarted) RecallShuttle(); else CallShuttle(); @@ -95,31 +75,23 @@ protected override void UpdateState(BoundUserInterfaceState state) if (state is not CommunicationsConsoleInterfaceState commsState) return; - CanAnnounce = commsState.CanAnnounce; - CanBroadcast = commsState.CanBroadcast; - CanCall = commsState.CanCall; - _expectedCountdownTime = commsState.ExpectedCountdownEnd; - CountdownStarted = commsState.CountdownStarted; - AlertLevelSelectable = commsState.AlertLevels != null && !float.IsNaN(commsState.CurrentAlertDelay) && commsState.CurrentAlertDelay <= 0; - CurrentLevel = commsState.CurrentAlert; - if (_menu != null) { + _menu.CanAnnounce = commsState.CanAnnounce; + _menu.CanBroadcast = commsState.CanBroadcast; + _menu.CanCall = commsState.CanCall; + _menu.CountdownStarted = commsState.CountdownStarted; + _menu.AlertLevelSelectable = commsState.AlertLevels != null && !float.IsNaN(commsState.CurrentAlertDelay) && commsState.CurrentAlertDelay <= 0; + _menu.CurrentLevel = commsState.CurrentAlert; + _menu.CountdownEnd = commsState.ExpectedCountdownEnd; + _menu.UpdateCountdown(); - _menu.UpdateAlertLevels(commsState.AlertLevels, CurrentLevel); - _menu.AlertLevelButton.Disabled = !AlertLevelSelectable; - _menu.EmergencyShuttleButton.Disabled = !CanCall; - _menu.AnnounceButton.Disabled = !CanAnnounce; - _menu.BroadcastButton.Disabled = !CanBroadcast; + _menu.UpdateAlertLevels(commsState.AlertLevels, _menu.CurrentLevel); + _menu.AlertLevelButton.Disabled = !_menu.AlertLevelSelectable; + _menu.EmergencyShuttleButton.Disabled = !_menu.CanCall; + _menu.AnnounceButton.Disabled = !_menu.CanAnnounce; + _menu.BroadcastButton.Disabled = !_menu.CanBroadcast; } } - - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - if (!disposing) return; - - _menu?.Dispose(); - } } } diff --git a/Content.Client/Communications/UI/CommunicationsConsoleMenu.xaml.cs b/Content.Client/Communications/UI/CommunicationsConsoleMenu.xaml.cs index bbca06f5194..cef68efd1f3 100644 --- a/Content.Client/Communications/UI/CommunicationsConsoleMenu.xaml.cs +++ b/Content.Client/Communications/UI/CommunicationsConsoleMenu.xaml.cs @@ -1,31 +1,40 @@ -using Content.Client.UserInterface.Controls; -using System.Threading; +using System.Globalization; +using Content.Client.UserInterface.Controls; using Content.Shared.CCVar; using Robust.Client.AutoGenerated; using Robust.Client.UserInterface.XAML; using Robust.Shared.Configuration; +using Robust.Shared.Timing; using Robust.Shared.Utility; -using Timer = Robust.Shared.Timing.Timer; namespace Content.Client.Communications.UI { [GenerateTypedNameReferences] public sealed partial class CommunicationsConsoleMenu : FancyWindow { - private CommunicationsConsoleBoundUserInterface Owner { get; set; } - private readonly CancellationTokenSource _timerCancelTokenSource = new(); - [Dependency] private readonly IConfigurationManager _cfg = default!; - - public CommunicationsConsoleMenu(CommunicationsConsoleBoundUserInterface owner) + [Dependency] private readonly IGameTiming _timing = default!; + [Dependency] private readonly ILocalizationManager _loc = default!; + + public bool CanAnnounce; + public bool CanBroadcast; + public bool CanCall; + public bool AlertLevelSelectable; + public bool CountdownStarted; + public string CurrentLevel = string.Empty; + public TimeSpan? CountdownEnd; + + public event Action? OnEmergencyLevel; + public event Action? OnAlertLevel; + public event Action? OnAnnounce; + public event Action? OnBroadcast; + + public CommunicationsConsoleMenu() { IoCManager.InjectDependencies(this); RobustXamlLoader.Load(this); - Owner = owner; - - var loc = IoCManager.Resolve(); - MessageInput.Placeholder = new Rope.Leaf(loc.GetString("comms-console-menu-announcement-placeholder")); + MessageInput.Placeholder = new Rope.Leaf(_loc.GetString("comms-console-menu-announcement-placeholder")); var maxAnnounceLength = _cfg.GetCVar(CCVars.ChatMaxAnnouncementLength); MessageInput.OnTextChanged += (args) => @@ -37,33 +46,38 @@ public CommunicationsConsoleMenu(CommunicationsConsoleBoundUserInterface owner) } else { - AnnounceButton.Disabled = !owner.CanAnnounce; + AnnounceButton.Disabled = !CanAnnounce; AnnounceButton.ToolTip = null; } }; - AnnounceButton.OnPressed += (_) => Owner.AnnounceButtonPressed(Rope.Collapse(MessageInput.TextRope)); - AnnounceButton.Disabled = !owner.CanAnnounce; + AnnounceButton.OnPressed += _ => OnAnnounce?.Invoke(Rope.Collapse(MessageInput.TextRope)); + AnnounceButton.Disabled = !CanAnnounce; - BroadcastButton.OnPressed += (_) => Owner.BroadcastButtonPressed(Rope.Collapse(MessageInput.TextRope)); - BroadcastButton.Disabled = !owner.CanBroadcast; + BroadcastButton.OnPressed += _ => OnBroadcast?.Invoke(Rope.Collapse(MessageInput.TextRope)); + BroadcastButton.Disabled = !CanBroadcast; AlertLevelButton.OnItemSelected += args => { var metadata = AlertLevelButton.GetItemMetadata(args.Id); if (metadata != null && metadata is string cast) { - Owner.AlertLevelSelected(cast); + OnAlertLevel?.Invoke(cast); } }; - AlertLevelButton.Disabled = !owner.AlertLevelSelectable; - EmergencyShuttleButton.OnPressed += (_) => Owner.EmergencyShuttleButtonPressed(); - EmergencyShuttleButton.Disabled = !owner.CanCall; + AlertLevelButton.Disabled = !AlertLevelSelectable; + + EmergencyShuttleButton.OnPressed += _ => OnEmergencyLevel?.Invoke(); + EmergencyShuttleButton.Disabled = !CanCall; + } + + protected override void FrameUpdate(FrameEventArgs args) + { + base.FrameUpdate(args); UpdateCountdown(); - Timer.SpawnRepeating(1000, UpdateCountdown, _timerCancelTokenSource.Token); } // The current alert could make levels unselectable, so we need to ensure that the UI reacts properly. @@ -105,32 +119,19 @@ public void UpdateAlertLevels(List? alerts, string currentAlert) public void UpdateCountdown() { - if (!Owner.CountdownStarted) + if (!CountdownStarted) { - CountdownLabel.SetMessage(""); + CountdownLabel.SetMessage(string.Empty); EmergencyShuttleButton.Text = Loc.GetString("comms-console-menu-call-shuttle"); return; } + var diff = (CountdownEnd - _timing.CurTime) ?? TimeSpan.Zero; + EmergencyShuttleButton.Text = Loc.GetString("comms-console-menu-recall-shuttle"); var infoText = Loc.GetString($"comms-console-menu-time-remaining", - ("time", Owner.Countdown.ToString())); + ("time", diff.TotalSeconds.ToString(CultureInfo.CurrentCulture))); CountdownLabel.SetMessage(infoText); } - - public override void Close() - { - base.Close(); - - _timerCancelTokenSource.Cancel(); - } - - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - - if (disposing) - _timerCancelTokenSource.Cancel(); - } } } diff --git a/Content.Client/Computer/ComputerBoundUserInterface.cs b/Content.Client/Computer/ComputerBoundUserInterface.cs index bdbfe03fa10..11c26b252e9 100644 --- a/Content.Client/Computer/ComputerBoundUserInterface.cs +++ b/Content.Client/Computer/ComputerBoundUserInterface.cs @@ -1,4 +1,5 @@ using Robust.Client.GameObjects; +using Robust.Client.UserInterface; using Robust.Client.UserInterface.CustomControls; namespace Content.Client.Computer @@ -19,10 +20,8 @@ protected override void Open() { base.Open(); - _window = (TWindow) _dynamicTypeFactory.CreateInstance(typeof(TWindow)); + _window = this.CreateWindow(); _window.SetupComputerWindow(this); - _window.OnClose += Close; - _window.OpenCentered(); } // Alas, this constructor has to be copied to the subclass. :( @@ -42,16 +41,6 @@ protected override void UpdateState(BoundUserInterfaceState state) _window.UpdateState((TState) state); } - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - - if (disposing) - { - _window?.Dispose(); - } - } - protected override void ReceiveMessage(BoundUserInterfaceMessage message) { _window?.ReceiveMessage(message); diff --git a/Content.Client/Configurable/UI/ConfigurationBoundUserInterface.cs b/Content.Client/Configurable/UI/ConfigurationBoundUserInterface.cs index 4fea44f2253..e4966f1ec43 100644 --- a/Content.Client/Configurable/UI/ConfigurationBoundUserInterface.cs +++ b/Content.Client/Configurable/UI/ConfigurationBoundUserInterface.cs @@ -1,5 +1,6 @@ using System.Text.RegularExpressions; using Robust.Client.GameObjects; +using Robust.Client.UserInterface; using static Content.Shared.Configurable.ConfigurationComponent; namespace Content.Client.Configurable.UI @@ -9,9 +10,6 @@ public sealed class ConfigurationBoundUserInterface : BoundUserInterface [ViewVariables] private ConfigurationMenu? _menu; - [ViewVariables] - public Regex? Validation { get; internal set; } - public ConfigurationBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey) { } @@ -19,10 +17,8 @@ public ConfigurationBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner protected override void Open() { base.Open(); - _menu = new ConfigurationMenu(this); - - _menu.OnClose += Close; - _menu.OpenCentered(); + _menu = this.CreateWindow(); + _menu.OnConfiguration += SendConfiguration; } protected override void UpdateState(BoundUserInterfaceState state) @@ -30,9 +26,7 @@ protected override void UpdateState(BoundUserInterfaceState state) base.UpdateState(state); if (state is not ConfigurationBoundUserInterfaceState configurationState) - { return; - } _menu?.Populate(configurationState); } @@ -41,9 +35,12 @@ protected override void ReceiveMessage(BoundUserInterfaceMessage message) { base.ReceiveMessage(message); + if (_menu == null) + return; + if (message is ValidationUpdateMessage msg) { - Validation = new Regex(msg.ValidationString, RegexOptions.Compiled); + _menu.Validation = new Regex(msg.ValidationString, RegexOptions.Compiled); } } @@ -51,16 +48,5 @@ public void SendConfiguration(Dictionary config) { SendMessage(new ConfigurationUpdatedMessage(config)); } - - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - - if (disposing && _menu != null) - { - _menu.OnClose -= Close; - _menu.Close(); - } - } } } diff --git a/Content.Client/Configurable/UI/ConfigurationMenu.cs b/Content.Client/Configurable/UI/ConfigurationMenu.cs index cc24af28692..29217eef7be 100644 --- a/Content.Client/Configurable/UI/ConfigurationMenu.cs +++ b/Content.Client/Configurable/UI/ConfigurationMenu.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using System.Numerics; +using System.Text.RegularExpressions; using Robust.Client.UserInterface; using Robust.Client.UserInterface.Controls; using Robust.Client.UserInterface.CustomControls; @@ -13,23 +14,25 @@ namespace Content.Client.Configurable.UI { public sealed class ConfigurationMenu : DefaultWindow { - public ConfigurationBoundUserInterface Owner { get; } - private readonly BoxContainer _column; private readonly BoxContainer _row; private readonly List<(string name, LineEdit input)> _inputs; - public ConfigurationMenu(ConfigurationBoundUserInterface owner) + [ViewVariables] + public Regex? Validation { get; internal set; } + + public event Action>? OnConfiguration; + + public ConfigurationMenu() { MinSize = SetSize = new Vector2(300, 250); - Owner = owner; _inputs = new List<(string name, LineEdit input)>(); Title = Loc.GetString("configuration-menu-device-title"); - BoxContainer baseContainer = new BoxContainer + var baseContainer = new BoxContainer { Orientation = LayoutOrientation.Vertical, VerticalExpand = true, @@ -116,14 +119,13 @@ public void Populate(ConfigurationBoundUserInterfaceState state) private void OnConfirm(ButtonEventArgs args) { var config = GenerateDictionary(_inputs, "Text"); - - Owner.SendConfiguration(config); + OnConfiguration?.Invoke(config); Close(); } private bool Validate(string value) { - return Owner.Validation == null || Owner.Validation.IsMatch(value); + return Validation?.IsMatch(value) != false; } private Dictionary GenerateDictionary(IEnumerable<(string name, LineEdit input)> inputs, string propertyName) diff --git a/Content.Client/Construction/UI/FlatpackCreatorBoundUserInterface.cs b/Content.Client/Construction/UI/FlatpackCreatorBoundUserInterface.cs index 86f1b8b83c7..887492955e9 100644 --- a/Content.Client/Construction/UI/FlatpackCreatorBoundUserInterface.cs +++ b/Content.Client/Construction/UI/FlatpackCreatorBoundUserInterface.cs @@ -1,5 +1,6 @@ using Content.Shared.Construction.Components; using JetBrains.Annotations; +using Robust.Client.UserInterface; namespace Content.Client.Construction.UI { @@ -17,8 +18,8 @@ protected override void Open() { base.Open(); - _menu = new FlatpackCreatorMenu(Owner); - _menu.OnClose += Close; + _menu = this.CreateWindow(); + _menu.SetEntity(Owner); _menu.PackButtonPressed += () => { @@ -27,14 +28,5 @@ protected override void Open() _menu.OpenCentered(); } - - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - if (!disposing) - return; - - _menu?.Dispose(); - } } } diff --git a/Content.Client/Construction/UI/FlatpackCreatorMenu.xaml.cs b/Content.Client/Construction/UI/FlatpackCreatorMenu.xaml.cs index 00261632378..2a386a03de6 100644 --- a/Content.Client/Construction/UI/FlatpackCreatorMenu.xaml.cs +++ b/Content.Client/Construction/UI/FlatpackCreatorMenu.xaml.cs @@ -25,7 +25,7 @@ public sealed partial class FlatpackCreatorMenu : FancyWindow private readonly MaterialStorageSystem _materialStorage; private readonly SpriteSystem _spriteSystem; - private readonly EntityUid _owner; + private EntityUid _owner; [ValidatePrototypeId] public const string NoBoardEffectId = "FlatpackerNoBoardEffect"; @@ -35,7 +35,7 @@ public sealed partial class FlatpackCreatorMenu : FancyWindow public event Action? PackButtonPressed; - public FlatpackCreatorMenu(EntityUid uid) + public FlatpackCreatorMenu() { RobustXamlLoader.Load(this); IoCManager.InjectDependencies(this); @@ -45,14 +45,17 @@ public FlatpackCreatorMenu(EntityUid uid) _materialStorage = _entityManager.System(); _spriteSystem = _entityManager.System(); - _owner = uid; - PackButton.OnPressed += _ => PackButtonPressed?.Invoke(); - MaterialStorageControl.SetOwner(uid); InsertLabel.SetMarkup(Loc.GetString("flatpacker-ui-insert-board")); } + public void SetEntity(EntityUid uid) + { + _owner = uid; + MaterialStorageControl.SetOwner(uid); + } + protected override void FrameUpdate(FrameEventArgs args) { base.FrameUpdate(args); diff --git a/Content.Client/Crayon/UI/CrayonBoundUserInterface.cs b/Content.Client/Crayon/UI/CrayonBoundUserInterface.cs index e2c4d51ecd1..e5be0b1811f 100644 --- a/Content.Client/Crayon/UI/CrayonBoundUserInterface.cs +++ b/Content.Client/Crayon/UI/CrayonBoundUserInterface.cs @@ -2,12 +2,15 @@ using Content.Shared.Crayon; using Content.Shared.Decals; using Robust.Client.GameObjects; +using Robust.Client.UserInterface; using Robust.Shared.Prototypes; namespace Content.Client.Crayon.UI { public sealed class CrayonBoundUserInterface : BoundUserInterface { + [Dependency] private readonly IPrototypeManager _protoManager = default!; + [ViewVariables] private CrayonWindow? _menu; @@ -18,15 +21,29 @@ public CrayonBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey protected override void Open() { base.Open(); - _menu = new CrayonWindow(this); - - _menu.OnClose += Close; - var prototypeManager = IoCManager.Resolve(); - var crayonDecals = prototypeManager.EnumeratePrototypes().Where(x => x.Tags.Contains("crayon")); - _menu.Populate(crayonDecals); + _menu = this.CreateWindow(); + _menu.OnColorSelected += SelectColor; + _menu.OnSelected += Select; + PopulateCrayons(); _menu.OpenCenteredLeft(); } + private void PopulateCrayons() + { + var crayonDecals = _protoManager.EnumeratePrototypes().Where(x => x.Tags.Contains("crayon")); + _menu?.Populate(crayonDecals); + } + + public override void OnProtoReload(PrototypesReloadedEventArgs args) + { + base.OnProtoReload(args); + + if (!args.WasModified()) + return; + + PopulateCrayons(); + } + protected override void UpdateState(BoundUserInterfaceState state) { base.UpdateState(state); @@ -43,16 +60,5 @@ public void SelectColor(Color color) { SendMessage(new CrayonColorMessage(color)); } - - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - - if (disposing) - { - _menu?.Close(); - _menu = null; - } - } } } diff --git a/Content.Client/Crayon/UI/CrayonWindow.xaml.cs b/Content.Client/Crayon/UI/CrayonWindow.xaml.cs index 2a5801ccf2d..b97786cd41a 100644 --- a/Content.Client/Crayon/UI/CrayonWindow.xaml.cs +++ b/Content.Client/Crayon/UI/CrayonWindow.xaml.cs @@ -18,18 +18,17 @@ namespace Content.Client.Crayon.UI [GenerateTypedNameReferences] public sealed partial class CrayonWindow : DefaultWindow { - public CrayonBoundUserInterface Owner { get; } - private Dictionary? _decals; private string? _selected; private Color _color; - public CrayonWindow(CrayonBoundUserInterface owner) + public event Action? OnColorSelected; + public event Action? OnSelected; + + public CrayonWindow() { RobustXamlLoader.Load(this); - Owner = owner; - Search.OnTextChanged += _ => RefreshList(); ColorSelector.OnColorChanged += SelectColor; } @@ -38,16 +37,16 @@ private void SelectColor(Color color) { _color = color; - Owner.SelectColor(color); - + OnColorSelected?.Invoke(color); RefreshList(); } private void RefreshList() { // Clear - Grid.RemoveAllChildren(); - if (_decals == null) return; + Grid.DisposeAllChildren(); + if (_decals == null) + return; var filter = Search.Text; foreach (var (decal, tex) in _decals) @@ -89,7 +88,6 @@ private void ButtonOnPressed(ButtonEventArgs obj) { if (obj.Button.Name == null) return; - Owner.Select(obj.Button.Name); _selected = obj.Button.Name; RefreshList(); } diff --git a/Content.Client/Disposal/UI/DisposalRouterBoundUserInterface.cs b/Content.Client/Disposal/UI/DisposalRouterBoundUserInterface.cs index e8e77217ea5..296e71d3a95 100644 --- a/Content.Client/Disposal/UI/DisposalRouterBoundUserInterface.cs +++ b/Content.Client/Disposal/UI/DisposalRouterBoundUserInterface.cs @@ -1,5 +1,6 @@ using JetBrains.Annotations; using Robust.Client.GameObjects; +using Robust.Client.UserInterface; using static Content.Shared.Disposal.Components.SharedDisposalRouterComponent; namespace Content.Client.Disposal.UI @@ -21,20 +22,16 @@ protected override void Open() { base.Open(); - _window = new DisposalRouterWindow(); - - _window.OpenCentered(); - _window.OnClose += Close; + _window = this.CreateWindow(); _window.Confirm.OnPressed += _ => ButtonPressed(UiAction.Ok, _window.TagInput.Text); _window.TagInput.OnTextEntered += args => ButtonPressed(UiAction.Ok, args.Text); - } private void ButtonPressed(UiAction action, string tag) { SendMessage(new UiActionMessage(action, tag)); - _window?.Close(); + Close(); } protected override void UpdateState(BoundUserInterfaceState state) @@ -48,18 +45,5 @@ protected override void UpdateState(BoundUserInterfaceState state) _window?.UpdateState(cast); } - - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - - if (disposing) - { - _window?.Dispose(); - } - } - - } - } diff --git a/Content.Client/Disposal/UI/DisposalTaggerBoundUserInterface.cs b/Content.Client/Disposal/UI/DisposalTaggerBoundUserInterface.cs index 3aeed8dc802..7fc0eb85401 100644 --- a/Content.Client/Disposal/UI/DisposalTaggerBoundUserInterface.cs +++ b/Content.Client/Disposal/UI/DisposalTaggerBoundUserInterface.cs @@ -1,5 +1,6 @@ using JetBrains.Annotations; using Robust.Client.GameObjects; +using Robust.Client.UserInterface; using static Content.Shared.Disposal.Components.SharedDisposalTaggerComponent; namespace Content.Client.Disposal.UI @@ -21,20 +22,17 @@ protected override void Open() { base.Open(); - _window = new DisposalTaggerWindow(); - - _window.OpenCentered(); - _window.OnClose += Close; + _window = this.CreateWindow(); _window.Confirm.OnPressed += _ => ButtonPressed(UiAction.Ok, _window.TagInput.Text); _window.TagInput.OnTextEntered += args => ButtonPressed(UiAction.Ok, args.Text); - } private void ButtonPressed(UiAction action, string tag) { + // TODO: This looks copy-pasted with the other mailing stuff... SendMessage(new UiActionMessage(action, tag)); - _window?.Close(); + Close(); } protected override void UpdateState(BoundUserInterfaceState state) @@ -48,18 +46,5 @@ protected override void UpdateState(BoundUserInterfaceState state) _window?.UpdateState(cast); } - - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - - if (disposing) - { - _window?.Dispose(); - } - } - - } - } diff --git a/Content.Client/Doors/Electronics/DoorElectronicsBoundUserInterface.cs b/Content.Client/Doors/Electronics/DoorElectronicsBoundUserInterface.cs index cd7ea717ce3..9b7e23c03aa 100644 --- a/Content.Client/Doors/Electronics/DoorElectronicsBoundUserInterface.cs +++ b/Content.Client/Doors/Electronics/DoorElectronicsBoundUserInterface.cs @@ -1,6 +1,7 @@ using Content.Shared.Access; using Content.Shared.Doors.Electronics; using Robust.Client.GameObjects; +using Robust.Client.UserInterface; using Robust.Shared.Prototypes; namespace Content.Client.Doors.Electronics; @@ -18,6 +19,23 @@ public DoorElectronicsBoundUserInterface(EntityUid owner, Enum uiKey) : base(own protected override void Open() { base.Open(); + _window = this.CreateWindow(); + _window.OnAccessChanged += UpdateConfiguration; + Reset(); + } + + public override void OnProtoReload(PrototypesReloadedEventArgs args) + { + base.OnProtoReload(args); + + if (!args.WasModified()) + return; + + Reset(); + } + + private void Reset() + { List> accessLevels = new(); foreach (var accessLevel in _prototypeManager.EnumeratePrototypes()) @@ -29,10 +47,7 @@ protected override void Open() } accessLevels.Sort(); - - _window = new DoorElectronicsConfigurationMenu(this, accessLevels, _prototypeManager); - _window.OnClose += Close; - _window.OpenCentered(); + _window?.Reset(_prototypeManager, accessLevels); } protected override void UpdateState(BoundUserInterfaceState state) @@ -44,14 +59,6 @@ protected override void UpdateState(BoundUserInterfaceState state) _window?.UpdateState(castState); } - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - if (!disposing) return; - - _window?.Dispose(); - } - public void UpdateConfiguration(List> newAccessList) { SendMessage(new DoorElectronicsUpdateConfigurationMessage(newAccessList)); diff --git a/Content.Client/Doors/Electronics/DoorElectronicsConfigurationMenu.xaml.cs b/Content.Client/Doors/Electronics/DoorElectronicsConfigurationMenu.xaml.cs index c01f13a462e..2112a562971 100644 --- a/Content.Client/Doors/Electronics/DoorElectronicsConfigurationMenu.xaml.cs +++ b/Content.Client/Doors/Electronics/DoorElectronicsConfigurationMenu.xaml.cs @@ -15,22 +15,23 @@ namespace Content.Client.Doors.Electronics; [GenerateTypedNameReferences] public sealed partial class DoorElectronicsConfigurationMenu : FancyWindow { - private readonly DoorElectronicsBoundUserInterface _owner; - private AccessLevelControl _buttonsList = new(); + private readonly AccessLevelControl _buttonsList = new(); - public DoorElectronicsConfigurationMenu(DoorElectronicsBoundUserInterface ui, List> accessLevels, IPrototypeManager prototypeManager) + public event Action>>? OnAccessChanged; + + public DoorElectronicsConfigurationMenu() { RobustXamlLoader.Load(this); - - _owner = ui; - - _buttonsList.Populate(accessLevels, prototypeManager); AccessLevelControlContainer.AddChild(_buttonsList); + } + + public void Reset(IPrototypeManager protoManager, List> accessLevels) + { + _buttonsList.Populate(accessLevels, protoManager); - foreach (var (id, button) in _buttonsList.ButtonsList) + foreach (var button in _buttonsList.ButtonsList.Values) { - button.OnPressed += _ => _owner.UpdateConfiguration( - _buttonsList.ButtonsList.Where(x => x.Value.Pressed).Select(x => x.Key).ToList()); + button.OnPressed += _ => OnAccessChanged?.Invoke(_buttonsList.ButtonsList.Where(x => x.Value.Pressed).Select(x => x.Key).ToList()); } } diff --git a/Content.Client/Fax/UI/FaxBoundUi.cs b/Content.Client/Fax/UI/FaxBoundUi.cs index a95066a3b58..ca2e834b4fe 100644 --- a/Content.Client/Fax/UI/FaxBoundUi.cs +++ b/Content.Client/Fax/UI/FaxBoundUi.cs @@ -25,10 +25,7 @@ protected override void Open() { base.Open(); - _window = new FaxWindow(); - _window.OpenCentered(); - - _window.OnClose += Close; + _window = this.CreateWindow(); _window.FileButtonPressed += OnFileButtonPressed; _window.CopyButtonPressed += OnCopyButtonPressed; _window.SendButtonPressed += OnSendButtonPressed; @@ -104,11 +101,4 @@ protected override void UpdateState(BoundUserInterfaceState state) _window.UpdateState(cast); } - - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - if (disposing) - _window?.Dispose(); - } } diff --git a/Content.Client/Forensics/ForensicScannerBoundUserInterface.cs b/Content.Client/Forensics/ForensicScannerBoundUserInterface.cs index ba49f11ea0f..08596b04e6e 100644 --- a/Content.Client/Forensics/ForensicScannerBoundUserInterface.cs +++ b/Content.Client/Forensics/ForensicScannerBoundUserInterface.cs @@ -1,6 +1,7 @@ using Robust.Client.GameObjects; using Robust.Shared.Timing; using Content.Shared.Forensics; +using Robust.Client.UserInterface; namespace Content.Client.Forensics { @@ -21,11 +22,9 @@ public ForensicScannerBoundUserInterface(EntityUid owner, Enum uiKey) : base(own protected override void Open() { base.Open(); - _window = new ForensicScannerMenu(); - _window.OnClose += Close; + _window = this.CreateWindow(); _window.Print.OnPressed += _ => Print(); _window.Clear.OnPressed += _ => Clear(); - _window.OpenCentered(); } private void Print() @@ -62,6 +61,7 @@ protected override void UpdateState(BoundUserInterfaceState state) _printCooldown = cast.PrintCooldown; + // TODO: Fix this if (cast.PrintReadyAt > _gameTiming.CurTime) Timer.Spawn(cast.PrintReadyAt - _gameTiming.CurTime, () => { @@ -71,14 +71,5 @@ protected override void UpdateState(BoundUserInterfaceState state) _window.UpdateState(cast); } - - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - if (!disposing) - return; - - _window?.Dispose(); - } } } diff --git a/Content.Client/Gateway/UI/GatewayBoundUserInterface.cs b/Content.Client/Gateway/UI/GatewayBoundUserInterface.cs index fdb3cdbc010..457b70ca7ca 100644 --- a/Content.Client/Gateway/UI/GatewayBoundUserInterface.cs +++ b/Content.Client/Gateway/UI/GatewayBoundUserInterface.cs @@ -1,6 +1,7 @@ using Content.Shared.Gateway; using JetBrains.Annotations; using Robust.Client.GameObjects; +using Robust.Client.UserInterface; namespace Content.Client.Gateway.UI; @@ -17,24 +18,13 @@ protected override void Open() { base.Open(); - _window = new GatewayWindow(EntMan.GetNetEntity(Owner)); + _window = this.CreateWindow(); + _window.SetEntity(EntMan.GetNetEntity(Owner)); _window.OpenPortal += destination => { SendMessage(new GatewayOpenPortalMessage(destination)); }; - _window.OnClose += Close; - _window?.OpenCentered(); - } - - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - if (disposing) - { - _window?.Dispose(); - _window = null; - } } protected override void UpdateState(BoundUserInterfaceState state) diff --git a/Content.Client/Gateway/UI/GatewayWindow.xaml.cs b/Content.Client/Gateway/UI/GatewayWindow.xaml.cs index 889dd6e1759..1c779b2b350 100644 --- a/Content.Client/Gateway/UI/GatewayWindow.xaml.cs +++ b/Content.Client/Gateway/UI/GatewayWindow.xaml.cs @@ -22,7 +22,7 @@ public sealed partial class GatewayWindow : FancyWindow, public event Action? OpenPortal; private List _destinations = new(); - public readonly NetEntity Owner; + public NetEntity Owner; private NetEntity? _current; private TimeSpan _nextReady; @@ -46,16 +46,20 @@ public sealed partial class GatewayWindow : FancyWindow, /// private bool _isCooldownPending = true; - public GatewayWindow(NetEntity netEntity) + public GatewayWindow() { RobustXamlLoader.Load(this); var dependencies = IoCManager.Instance!; _timing = dependencies.Resolve(); - Owner = netEntity; NextUnlockBar.ForegroundStyleBoxOverride = new StyleBoxFlat(Color.FromHex("#C74EBD")); } + public void SetEntity(NetEntity entity) + { + + } + public void UpdateState(GatewayBoundUserInterfaceState state) { _destinations = state.Destinations; diff --git a/Content.Client/Gravity/UI/GravityGeneratorBoundUserInterface.cs b/Content.Client/Gravity/UI/GravityGeneratorBoundUserInterface.cs index d72da3e8120..32b40747d55 100644 --- a/Content.Client/Gravity/UI/GravityGeneratorBoundUserInterface.cs +++ b/Content.Client/Gravity/UI/GravityGeneratorBoundUserInterface.cs @@ -1,6 +1,6 @@ using Content.Shared.Gravity; using JetBrains.Annotations; -using Robust.Client.GameObjects; +using Robust.Client.UserInterface; namespace Content.Client.Gravity.UI { @@ -18,17 +18,8 @@ protected override void Open() { base.Open(); - _window = new GravityGeneratorWindow(this); - - /* - _window.Switch.OnPressed += _ => - { - SendMessage(new SharedGravityGeneratorComponent.SwitchGeneratorMessage(!IsOn)); - }; - */ - - _window.OpenCentered(); - _window.OnClose += Close; + _window = this.CreateWindow(); + _window.SetEntity(Owner); } protected override void UpdateState(BoundUserInterfaceState state) @@ -39,14 +30,6 @@ protected override void UpdateState(BoundUserInterfaceState state) _window?.UpdateState(castState); } - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - if (!disposing) return; - - _window?.Dispose(); - } - public void SetPowerSwitch(bool on) { SendMessage(new SharedGravityGeneratorComponent.SwitchGeneratorMessage(on)); diff --git a/Content.Client/Gravity/UI/GravityGeneratorWindow.xaml.cs b/Content.Client/Gravity/UI/GravityGeneratorWindow.xaml.cs index 75f8eb479b5..6f04133b594 100644 --- a/Content.Client/Gravity/UI/GravityGeneratorWindow.xaml.cs +++ b/Content.Client/Gravity/UI/GravityGeneratorWindow.xaml.cs @@ -12,22 +12,23 @@ public sealed partial class GravityGeneratorWindow : FancyWindow { private readonly ButtonGroup _buttonGroup = new(); - private readonly GravityGeneratorBoundUserInterface _owner; + public event Action? OnPowerSwitch; - public GravityGeneratorWindow(GravityGeneratorBoundUserInterface owner) + public GravityGeneratorWindow() { RobustXamlLoader.Load(this); IoCManager.InjectDependencies(this); - _owner = owner; - OnButton.Group = _buttonGroup; OffButton.Group = _buttonGroup; - OnButton.OnPressed += _ => _owner.SetPowerSwitch(true); - OffButton.OnPressed += _ => _owner.SetPowerSwitch(false); + OnButton.OnPressed += _ => OnPowerSwitch?.Invoke(true); + OffButton.OnPressed += _ => OnPowerSwitch?.Invoke(false); + } - EntityView.SetEntity(owner.Owner); + public void SetEntity(EntityUid uid) + { + EntityView.SetEntity(uid); } public void UpdateState(SharedGravityGeneratorComponent.GeneratorState state) diff --git a/Content.Client/HealthAnalyzer/UI/HealthAnalyzerBoundUserInterface.cs b/Content.Client/HealthAnalyzer/UI/HealthAnalyzerBoundUserInterface.cs index dc0a3e9fccd..38760f4aa3c 100644 --- a/Content.Client/HealthAnalyzer/UI/HealthAnalyzerBoundUserInterface.cs +++ b/Content.Client/HealthAnalyzer/UI/HealthAnalyzerBoundUserInterface.cs @@ -1,6 +1,6 @@ using Content.Shared.MedicalScanner; using JetBrains.Annotations; -using Robust.Client.GameObjects; +using Robust.Client.UserInterface; namespace Content.Client.HealthAnalyzer.UI { @@ -17,12 +17,9 @@ public HealthAnalyzerBoundUserInterface(EntityUid owner, Enum uiKey) : base(owne protected override void Open() { base.Open(); - _window = new HealthAnalyzerWindow - { - Title = EntMan.GetComponent(Owner).EntityName, - }; - _window.OnClose += Close; - _window.OpenCentered(); + _window = this.CreateWindow(); + + _window.Title = EntMan.GetComponent(Owner).EntityName; } protected override void ReceiveMessage(BoundUserInterfaceMessage message) @@ -35,17 +32,5 @@ protected override void ReceiveMessage(BoundUserInterfaceMessage message) _window.Populate(cast); } - - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - if (!disposing) - return; - - if (_window != null) - _window.OnClose -= Close; - - _window?.Dispose(); - } } } diff --git a/Content.Client/Humanoid/HumanoidMarkingModifierBoundUserInterface.cs b/Content.Client/Humanoid/HumanoidMarkingModifierBoundUserInterface.cs index a8872604a4c..53977eb636b 100644 --- a/Content.Client/Humanoid/HumanoidMarkingModifierBoundUserInterface.cs +++ b/Content.Client/Humanoid/HumanoidMarkingModifierBoundUserInterface.cs @@ -1,5 +1,6 @@ using Content.Shared.Humanoid; using Content.Shared.Humanoid.Markings; +using Robust.Client.UserInterface; namespace Content.Client.Humanoid; @@ -20,8 +21,7 @@ protected override void Open() { base.Open(); - _window = new(); - _window.OnClose += Close; + _window = this.CreateWindow(); _window.OnMarkingAdded += SendMarkingSet; _window.OnMarkingRemoved += SendMarkingSet; _window.OnMarkingColorChange += SendMarkingSetNoResend; diff --git a/Content.Client/Instruments/UI/BandMenu.xaml.cs b/Content.Client/Instruments/UI/BandMenu.xaml.cs index 5fb293a194d..26cd1369e55 100644 --- a/Content.Client/Instruments/UI/BandMenu.xaml.cs +++ b/Content.Client/Instruments/UI/BandMenu.xaml.cs @@ -11,7 +11,9 @@ public sealed partial class BandMenu : DefaultWindow { private readonly InstrumentBoundUserInterface _owner; - public BandMenu(InstrumentBoundUserInterface owner) : base() + public EntityUid? Master; + + public BandMenu(InstrumentBoundUserInterface owner) { RobustXamlLoader.Load(this); @@ -40,7 +42,7 @@ public void Populate((NetEntity, string)[] nearby, IEntityManager entManager) { var uid = entManager.GetEntity(nent); var item = BandList.AddItem(name, null, true, uid); - item.Selected = _owner.Instrument?.Master == uid; + item.Selected = Master == uid; } } } diff --git a/Content.Client/Instruments/UI/ChannelsMenu.xaml.cs b/Content.Client/Instruments/UI/ChannelsMenu.xaml.cs index 2814d415365..c175e67842f 100644 --- a/Content.Client/Instruments/UI/ChannelsMenu.xaml.cs +++ b/Content.Client/Instruments/UI/ChannelsMenu.xaml.cs @@ -51,7 +51,7 @@ private void OnClearPressed(BaseButton.ButtonEventArgs obj) } } - public void Populate() + public void Populate(InstrumentComponent? instrument) { ChannelList.Clear(); @@ -60,7 +60,8 @@ public void Populate() var item = ChannelList.AddItem(_owner.Loc.GetString("instrument-component-channel-name", ("number", i)), null, true, i); - item.Selected = !_owner.Instrument?.FilteredChannels[i] ?? false; + + item.Selected = !instrument?.FilteredChannels[i] ?? false; } } } diff --git a/Content.Client/Instruments/UI/InstrumentBoundUserInterface.cs b/Content.Client/Instruments/UI/InstrumentBoundUserInterface.cs index 0f5729f55b1..4816ce8c365 100644 --- a/Content.Client/Instruments/UI/InstrumentBoundUserInterface.cs +++ b/Content.Client/Instruments/UI/InstrumentBoundUserInterface.cs @@ -24,8 +24,6 @@ public sealed class InstrumentBoundUserInterface : BoundUserInterface [ViewVariables] private BandMenu? _bandMenu; [ViewVariables] private ChannelsMenu? _channelsMenu; - [ViewVariables] public InstrumentComponent? Instrument { get; private set; } - public InstrumentBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey) { IoCManager.InjectDependencies(this); @@ -43,14 +41,20 @@ protected override void ReceiveMessage(BoundUserInterfaceMessage message) protected override void Open() { - if (!EntMan.TryGetComponent(Owner, out InstrumentComponent? instrument)) - return; + _instrumentMenu = this.CreateWindow(); + _instrumentMenu.Title = EntMan.GetComponent(Owner).EntityName; - Instrument = instrument; - _instrumentMenu = new InstrumentMenu(this); - _instrumentMenu.OnClose += Close; + _instrumentMenu.OnOpenBand += OpenBandMenu; + _instrumentMenu.OnOpenChannels += OpenChannelsMenu; + _instrumentMenu.OnCloseChannels += CloseChannelsMenu; + _instrumentMenu.OnCloseBands += CloseBandMenu; - _instrumentMenu.OpenCentered(); + _instrumentMenu.SetMIDI(MidiManager.IsAvailable); + + if (EntMan.TryGetComponent(Owner, out InstrumentComponent? instrument)) + { + _instrumentMenu.SetInstrument((Owner, instrument)); + } } protected override void Dispose(bool disposing) @@ -58,7 +62,12 @@ protected override void Dispose(bool disposing) base.Dispose(disposing); if (!disposing) return; - _instrumentMenu?.Dispose(); + + if (EntMan.TryGetComponent(Owner, out InstrumentComponent? instrument)) + { + _instrumentMenu?.RemoveInstrument(instrument); + } + _bandMenu?.Dispose(); _channelsMenu?.Dispose(); } @@ -72,6 +81,11 @@ public void OpenBandMenu() { _bandMenu ??= new BandMenu(this); + if (EntMan.TryGetComponent(Owner, out InstrumentComponent? instrument)) + { + _bandMenu.Master = instrument.Master; + } + // Refresh cache... RefreshBands(); @@ -87,7 +101,9 @@ public void CloseBandMenu() public void OpenChannelsMenu() { _channelsMenu ??= new ChannelsMenu(this); - _channelsMenu.Populate(); + EntMan.TryGetComponent(Owner, out InstrumentComponent? instrument); + + _channelsMenu.Populate(instrument); _channelsMenu.OpenCenteredRight(); } diff --git a/Content.Client/Instruments/UI/InstrumentMenu.xaml.cs b/Content.Client/Instruments/UI/InstrumentMenu.xaml.cs index da443e3fb5b..fc863648d79 100644 --- a/Content.Client/Instruments/UI/InstrumentMenu.xaml.cs +++ b/Content.Client/Instruments/UI/InstrumentMenu.xaml.cs @@ -1,7 +1,10 @@ using System.IO; using System.Numerics; using System.Threading.Tasks; +using Content.Client.Interactable; +using Content.Shared.ActionBlocker; using Robust.Client.AutoGenerated; +using Robust.Client.Player; using Robust.Client.UserInterface; using Robust.Client.UserInterface.CustomControls; using Robust.Client.UserInterface.XAML; @@ -16,33 +19,23 @@ namespace Content.Client.Instruments.UI [GenerateTypedNameReferences] public sealed partial class InstrumentMenu : DefaultWindow { - private readonly InstrumentBoundUserInterface _owner; + [Dependency] private readonly IEntityManager _entManager = default!; + [Dependency] private readonly IFileDialogManager _dialogs = default!; + [Dependency] private readonly IPlayerManager _player = default!; private bool _isMidiFileDialogueWindowOpen; - public InstrumentMenu(InstrumentBoundUserInterface owner) - { - RobustXamlLoader.Load(this); - - _owner = owner; + public event Action? OnOpenBand; + public event Action? OnOpenChannels; + public event Action? OnCloseBands; + public event Action? OnCloseChannels; - if (_owner.Instrument != null) - { - _owner.Instrument.OnMidiPlaybackEnded += InstrumentOnMidiPlaybackEnded; - Title = _owner.Entities.GetComponent(_owner.Owner).EntityName; - LoopButton.Disabled = !_owner.Instrument.IsMidiOpen; - LoopButton.Pressed = _owner.Instrument.LoopMidi; - ChannelsButton.Disabled = !_owner.Instrument.IsRendererAlive; - StopButton.Disabled = !_owner.Instrument.IsMidiOpen; - PlaybackSlider.MouseFilter = _owner.Instrument.IsMidiOpen ? MouseFilterMode.Pass : MouseFilterMode.Ignore; - } + public EntityUid Entity; - if (!_owner.MidiManager.IsAvailable) - { - UnavailableOverlay.Visible = true; - // We return early as to not give the buttons behavior. - return; - } + public InstrumentMenu() + { + RobustXamlLoader.Load(this); + IoCManager.InjectDependencies(this); InputButton.OnToggled += MidiInputButtonOnOnToggled; BandButton.OnPressed += BandButtonOnPressed; @@ -57,12 +50,34 @@ public InstrumentMenu(InstrumentBoundUserInterface owner) MinSize = SetSize = new Vector2(400, 150); } + public void SetInstrument(Entity entity) + { + Entity = entity; + var component = entity.Comp; + component.OnMidiPlaybackEnded += InstrumentOnMidiPlaybackEnded; + LoopButton.Disabled = !component.IsMidiOpen; + LoopButton.Pressed = component.LoopMidi; + ChannelsButton.Disabled = !component.IsRendererAlive; + StopButton.Disabled = !component.IsMidiOpen; + PlaybackSlider.MouseFilter = component.IsMidiOpen ? MouseFilterMode.Pass : MouseFilterMode.Ignore; + } + + public void RemoveInstrument(InstrumentComponent component) + { + component.OnMidiPlaybackEnded -= InstrumentOnMidiPlaybackEnded; + } + + public void SetMIDI(bool available) + { + UnavailableOverlay.Visible = !available; + } + private void BandButtonOnPressed(ButtonEventArgs obj) { if (!PlayCheck()) return; - _owner.OpenBandMenu(); + OnOpenBand?.Invoke(); } private void BandButtonOnToggled(ButtonToggledEventArgs obj) @@ -70,12 +85,15 @@ private void BandButtonOnToggled(ButtonToggledEventArgs obj) if (obj.Pressed) return; - _owner.Instruments.SetMaster(_owner.Owner, null); + if (_entManager.TryGetComponent(Entity, out InstrumentComponent? instrument)) + { + _entManager.System().SetMaster(Entity, instrument.Master); + } } private void ChannelsButtonOnPressed(ButtonEventArgs obj) { - _owner.OpenChannelsMenu(); + OnOpenChannels?.Invoke(); } private void InstrumentOnMidiPlaybackEnded() @@ -85,8 +103,10 @@ private void InstrumentOnMidiPlaybackEnded() public void MidiPlaybackSetButtonsDisabled(bool disabled) { - if(disabled) - _owner.CloseChannelsMenu(); + if (disabled) + { + OnCloseChannels?.Invoke(); + } LoopButton.Disabled = disabled; StopButton.Disabled = disabled; @@ -100,7 +120,7 @@ private async void MidiFileButtonOnOnPressed(ButtonEventArgs obj) if (_isMidiFileDialogueWindowOpen) return; - _owner.CloseBandMenu(); + OnCloseBands?.Invoke(); var filters = new FileDialogFilters(new FileDialogFilters.Group("mid", "midi")); @@ -108,7 +128,7 @@ private async void MidiFileButtonOnOnPressed(ButtonEventArgs obj) // or focus the previously-opened window. _isMidiFileDialogueWindowOpen = true; - await using var file = await _owner.FileDialogManager.OpenFile(filters); + await using var file = await _dialogs.OpenFile(filters); _isMidiFileDialogueWindowOpen = false; @@ -129,9 +149,18 @@ private async void MidiFileButtonOnOnPressed(ButtonEventArgs obj) await file.CopyToAsync(memStream); - if (_owner.Instrument is not {} instrument - || !_owner.Instruments.OpenMidi(_owner.Owner, memStream.GetBuffer().AsSpan(0, (int) memStream.Length), instrument)) + if (!_entManager.TryGetComponent(Entity, out var instrument)) + { return; + } + + if (!_entManager.System() + .OpenMidi(Entity, + memStream.GetBuffer().AsSpan(0, (int) memStream.Length), + instrument)) + { + return; + } MidiPlaybackSetButtonsDisabled(false); if (InputButton.Pressed) @@ -140,7 +169,7 @@ private async void MidiFileButtonOnOnPressed(ButtonEventArgs obj) private void MidiInputButtonOnOnToggled(ButtonToggledEventArgs obj) { - _owner.CloseBandMenu(); + OnCloseBands?.Invoke(); if (obj.Pressed) { @@ -148,109 +177,99 @@ private void MidiInputButtonOnOnToggled(ButtonToggledEventArgs obj) return; MidiStopButtonOnPressed(null); - if(_owner.Instrument is {} instrument) - _owner.Instruments.OpenInput(_owner.Owner, instrument); + + if (_entManager.TryGetComponent(Entity, out InstrumentComponent? instrument)) + _entManager.System().OpenInput(Entity, instrument); } - else if (_owner.Instrument is { } instrument) + else { - _owner.Instruments.CloseInput(_owner.Owner, false, instrument); - _owner.CloseChannelsMenu(); + _entManager.System().CloseInput(Entity, false); + OnCloseChannels?.Invoke(); } } private bool PlayCheck() { // TODO all of these checks should also be done server-side. - - var instrumentEnt = _owner.Owner; - var instrument = _owner.Instrument; - - if (instrument == null) + if (!_entManager.TryGetComponent(Entity, out InstrumentComponent? instrument)) return false; - var localEntity = _owner.PlayerManager.LocalEntity; + var localEntity = _player.LocalEntity; // If we don't have a player or controlled entity, we return. if (localEntity == null) return false; // By default, allow an instrument to play itself and skip all other checks - if (localEntity == instrumentEnt) + if (localEntity == Entity) return true; - var container = _owner.Entities.System(); + var container = _entManager.System(); // If we're a handheld instrument, we might be in a container. Get it just in case. - container.TryGetContainingContainer(instrumentEnt, out var conMan); + container.TryGetContainingContainer(Entity, out var conMan); // If the instrument is handheld and we're not holding it, we return. - if ((instrument.Handheld && (conMan == null || conMan.Owner != localEntity))) + if (instrument.Handheld && (conMan == null || conMan.Owner != localEntity)) return false; - if (!_owner.ActionBlocker.CanInteract(localEntity.Value, instrumentEnt)) + if (!_entManager.System().CanInteract(localEntity.Value, Entity)) return false; // We check that we're in range unobstructed just in case. - return _owner.Interactions.InRangeUnobstructed(localEntity.Value, instrumentEnt); + return _entManager.System().InRangeUnobstructed(localEntity.Value, Entity); } private void MidiStopButtonOnPressed(ButtonEventArgs? obj) { MidiPlaybackSetButtonsDisabled(true); - if (_owner.Instrument is not {} instrument) - return; - - _owner.Instruments.CloseMidi(_owner.Owner, false, instrument); - _owner.CloseChannelsMenu(); + _entManager.System().CloseMidi(Entity, false); + OnCloseChannels?.Invoke(); } private void MidiLoopButtonOnOnToggled(ButtonToggledEventArgs obj) { - if (_owner.Instrument == null) - return; + var instrument = _entManager.System(); + + if (_entManager.TryGetComponent(Entity, out InstrumentComponent? instrumentComp)) + { + instrumentComp.LoopMidi = obj.Pressed; + } - _owner.Instrument.LoopMidi = obj.Pressed; - _owner.Instruments.UpdateRenderer(_owner.Owner, _owner.Instrument); + instrument.UpdateRenderer(Entity); } private void PlaybackSliderSeek(Range _) { // Do not seek while still grabbing. - if (PlaybackSlider.Grabbed || _owner.Instrument is not {} instrument) + if (PlaybackSlider.Grabbed) return; - _owner.Instruments.SetPlayerTick(_owner.Owner, (int)Math.Ceiling(PlaybackSlider.Value), instrument); + _entManager.System().SetPlayerTick(Entity, (int)Math.Ceiling(PlaybackSlider.Value)); } private void PlaybackSliderKeyUp(GUIBoundKeyEventArgs args) { - if (args.Function != EngineKeyFunctions.UIClick || _owner.Instrument is not {} instrument) + if (args.Function != EngineKeyFunctions.UIClick) return; - _owner.Instruments.SetPlayerTick(_owner.Owner, (int)Math.Ceiling(PlaybackSlider.Value), instrument); - } - - public override void Close() - { - base.Close(); - _owner.CloseBandMenu(); - _owner.CloseChannelsMenu(); + _entManager.System().SetPlayerTick(Entity, (int)Math.Ceiling(PlaybackSlider.Value)); } protected override void FrameUpdate(FrameEventArgs args) { base.FrameUpdate(args); - if (_owner.Instrument == null) + if (!_entManager.TryGetComponent(Entity, out InstrumentComponent? instrument)) return; - var hasMaster = _owner.Instrument.Master != null; + var hasMaster = instrument.Master != null; BandButton.ToggleMode = hasMaster; BandButton.Pressed = hasMaster; - BandButton.Disabled = _owner.Instrument.IsMidiOpen || _owner.Instrument.IsInputOpen; - ChannelsButton.Disabled = !_owner.Instrument.IsRendererAlive; + BandButton.Disabled = instrument.IsMidiOpen || instrument.IsInputOpen; + ChannelsButton.Disabled = !instrument.IsRendererAlive; - if (!_owner.Instrument.IsMidiOpen) + if (!instrument.IsMidiOpen) { PlaybackSlider.MaxValue = 1; PlaybackSlider.SetValueWithoutEvent(0); @@ -260,8 +279,8 @@ protected override void FrameUpdate(FrameEventArgs args) if (PlaybackSlider.Grabbed) return; - PlaybackSlider.MaxValue = _owner.Instrument.PlayerTotalTick; - PlaybackSlider.SetValueWithoutEvent(_owner.Instrument.PlayerTick); + PlaybackSlider.MaxValue = instrument.PlayerTotalTick; + PlaybackSlider.SetValueWithoutEvent(instrument.PlayerTick); } } } diff --git a/Content.Client/Inventory/StrippableBoundUserInterface.cs b/Content.Client/Inventory/StrippableBoundUserInterface.cs index 7e50eb1c68a..132c5ed654c 100644 --- a/Content.Client/Inventory/StrippableBoundUserInterface.cs +++ b/Content.Client/Inventory/StrippableBoundUserInterface.cs @@ -41,7 +41,7 @@ public sealed class StrippableBoundUserInterface : BoundUserInterface public const string HiddenPocketEntityId = "StrippingHiddenEntity"; [ViewVariables] - private readonly StrippingMenu? _strippingMenu; + private StrippingMenu? _strippingMenu; [ViewVariables] private readonly EntityUid _virtualHiddenEntity; @@ -51,33 +51,30 @@ public StrippableBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, u _examine = EntMan.System(); _inv = EntMan.System(); _cuffable = EntMan.System(); - - // TODO update name when identity changes - var title = Loc.GetString("strippable-bound-user-interface-stripping-menu-title", ("ownerName", Identity.Name(Owner, EntMan))); - _strippingMenu = new StrippingMenu(title, this); - _strippingMenu.OnClose += Close; - - // TODO use global entity - // BUIs are opened and closed while applying comp sates, so spawning entities here is probably not the best idea. _virtualHiddenEntity = EntMan.SpawnEntity(HiddenPocketEntityId, MapCoordinates.Nullspace); } protected override void Open() { base.Open(); + + _strippingMenu = this.CreateWindow(); + _strippingMenu.OnDirty += UpdateMenu; + _strippingMenu.Title = Loc.GetString("strippable-bound-user-interface-stripping-menu-title", ("ownerName", Identity.Name(Owner, EntMan))); + _strippingMenu?.OpenCenteredLeft(); } protected override void Dispose(bool disposing) { - base.Dispose(disposing); - - EntMan.DeleteEntity(_virtualHiddenEntity); - if (!disposing) return; - _strippingMenu?.Dispose(); + if (_strippingMenu != null) + _strippingMenu.OnDirty -= UpdateMenu; + + EntMan.DeleteEntity(_virtualHiddenEntity); + base.Dispose(disposing); } public void DirtyMenu() diff --git a/Content.Client/Kitchen/UI/GrinderMenu.xaml.cs b/Content.Client/Kitchen/UI/GrinderMenu.xaml.cs index f97d8a73302..7884268c428 100644 --- a/Content.Client/Kitchen/UI/GrinderMenu.xaml.cs +++ b/Content.Client/Kitchen/UI/GrinderMenu.xaml.cs @@ -12,42 +12,34 @@ namespace Content.Client.Kitchen.UI [GenerateTypedNameReferences] public sealed partial class GrinderMenu : FancyWindow { - private readonly IEntityManager _entityManager; - private readonly IPrototypeManager _prototypeManager; - private readonly ReagentGrinderBoundUserInterface _owner; + [Dependency] private readonly IEntityManager _entityManager = default!; + [Dependency] private readonly IPrototypeManager _prototypeManager = default!; private readonly Dictionary _chamberVisualContents = new(); - public GrinderMenu(ReagentGrinderBoundUserInterface owner, IEntityManager entityManager, IPrototypeManager prototypeManager) + public event Action? OnToggleAuto; + public event Action? OnGrind; + public event Action? OnJuice; + public event Action? OnEjectAll; + public event Action? OnEjectBeaker; + public event Action? OnEjectChamber; + + public GrinderMenu() { RobustXamlLoader.Load(this); - _entityManager = entityManager; - _prototypeManager = prototypeManager; - _owner = owner; - AutoModeButton.OnPressed += owner.ToggleAutoMode; - GrindButton.OnPressed += owner.StartGrinding; - JuiceButton.OnPressed += owner.StartJuicing; - ChamberContentBox.EjectButton.OnPressed += owner.EjectAll; - BeakerContentBox.EjectButton.OnPressed += owner.EjectBeaker; + IoCManager.InjectDependencies(this); + AutoModeButton.OnPressed += _ => OnToggleAuto?.Invoke(); + GrindButton.OnPressed += _ => OnGrind?.Invoke(); + JuiceButton.OnPressed += _ => OnJuice?.Invoke(); + ChamberContentBox.EjectButton.OnPressed += _ => OnEjectAll?.Invoke(); + BeakerContentBox.EjectButton.OnPressed += _ => OnEjectBeaker?.Invoke(); ChamberContentBox.BoxContents.OnItemSelected += OnChamberBoxContentsItemSelected; BeakerContentBox.BoxContents.SelectMode = ItemList.ItemListSelectMode.None; } private void OnChamberBoxContentsItemSelected(ItemList.ItemListSelectedEventArgs args) { - _owner.EjectChamberContent(_chamberVisualContents[args.ItemIndex]); - } - - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - - _chamberVisualContents.Clear(); - GrindButton.OnPressed -= _owner.StartGrinding; - JuiceButton.OnPressed -= _owner.StartJuicing; - ChamberContentBox.EjectButton.OnPressed -= _owner.EjectAll; - BeakerContentBox.EjectButton.OnPressed -= _owner.EjectBeaker; - ChamberContentBox.BoxContents.OnItemSelected -= OnChamberBoxContentsItemSelected; + OnEjectChamber?.Invoke(_chamberVisualContents[args.ItemIndex]); } public void UpdateState(ReagentGrinderInterfaceState state) diff --git a/Content.Client/Kitchen/UI/MicrowaveBoundUserInterface.cs b/Content.Client/Kitchen/UI/MicrowaveBoundUserInterface.cs index 7e7dd2d6935..643ac47054b 100644 --- a/Content.Client/Kitchen/UI/MicrowaveBoundUserInterface.cs +++ b/Content.Client/Kitchen/UI/MicrowaveBoundUserInterface.cs @@ -3,6 +3,7 @@ using JetBrains.Annotations; using Robust.Client.GameObjects; using Robust.Client.Graphics; +using Robust.Client.UserInterface; using Robust.Client.UserInterface.Controls; using Robust.Shared.Timing; @@ -19,28 +20,15 @@ public sealed class MicrowaveBoundUserInterface : BoundUserInterface [ViewVariables] private readonly Dictionary _reagents = new(); - [Dependency] private readonly IGameTiming _gameTiming = default!; - - public MicrowaveUpdateUserInterfaceState currentState = default!; - - private IEntityManager _entManager; public MicrowaveBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey) { - _entManager = IoCManager.Resolve(); - } - - public TimeSpan GetCurrentTime() - { - return _gameTiming.CurTime; } protected override void Open() { base.Open(); - _menu = new MicrowaveMenu(this); - _menu.OpenCentered(); - _menu.OnClose += Close; + _menu = this.CreateWindow(); _menu.StartButton.OnPressed += _ => SendPredictedMessage(new MicrowaveStartCookMessage()); _menu.EjectButton.OnPressed += _ => SendPredictedMessage(new MicrowaveEjectMessage()); _menu.IngredientsList.OnItemSelected += args => @@ -74,38 +62,23 @@ protected override void Open() }; } - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - - if (!disposing) - { - return; - } - - _solids.Clear(); - _menu?.Dispose(); - } - protected override void UpdateState(BoundUserInterfaceState state) { base.UpdateState(state); - if (state is not MicrowaveUpdateUserInterfaceState cState) + if (state is not MicrowaveUpdateUserInterfaceState cState || _menu == null) { return; } + _menu.IsBusy = cState.IsMicrowaveBusy; + _menu.CurrentCooktimeEnd = cState.CurrentCookTimeEnd; - _menu?.ToggleBusyDisableOverlayPanel(cState.IsMicrowaveBusy || cState.ContainedSolids.Length == 0); - currentState = cState; - + _menu.ToggleBusyDisableOverlayPanel(cState.IsMicrowaveBusy || cState.ContainedSolids.Length == 0); // TODO move this to a component state and ensure the net ids. - RefreshContentsDisplay(_entManager.GetEntityArray(cState.ContainedSolids)); - - if (_menu == null) return; + RefreshContentsDisplay(EntMan.GetEntityArray(cState.ContainedSolids)); //Set the cook time info label - var cookTime = cState.ActiveButtonIndex == 0 + var cookTime = cState.ActiveButtonIndex == 0 ? Loc.GetString("microwave-menu-instant-button") : cState.CurrentCookTime.ToString(); diff --git a/Content.Client/Kitchen/UI/MicrowaveMenu.xaml.cs b/Content.Client/Kitchen/UI/MicrowaveMenu.xaml.cs index b292e9f1465..7565075f86f 100644 --- a/Content.Client/Kitchen/UI/MicrowaveMenu.xaml.cs +++ b/Content.Client/Kitchen/UI/MicrowaveMenu.xaml.cs @@ -9,22 +9,20 @@ namespace Content.Client.Kitchen.UI [GenerateTypedNameReferences] public sealed partial class MicrowaveMenu : FancyWindow { - public sealed class MicrowaveCookTimeButton : Button - { - public uint CookTime; - } + [Dependency] private readonly IGameTiming _timing = default!; public event Action? OnCookTimeSelected; public ButtonGroup CookTimeButtonGroup { get; } - private readonly MicrowaveBoundUserInterface _owner; - public MicrowaveMenu(MicrowaveBoundUserInterface owner) + public bool IsBusy; + public TimeSpan CurrentCooktimeEnd; + + public MicrowaveMenu() { RobustXamlLoader.Load(this); CookTimeButtonGroup = new ButtonGroup(); InstantCookButton.Group = CookTimeButtonGroup; - _owner = owner; InstantCookButton.OnPressed += args => { OnCookTimeSelected?.Invoke(args, 0); @@ -65,14 +63,20 @@ public void ToggleBusyDisableOverlayPanel(bool shouldDisable) protected override void FrameUpdate(FrameEventArgs args) { base.FrameUpdate(args); - if(!_owner.currentState.IsMicrowaveBusy) + + if (!IsBusy) return; - if(_owner.currentState.CurrentCookTimeEnd > _owner.GetCurrentTime()) + if (CurrentCooktimeEnd > _timing.CurTime) { CookTimeInfoLabel.Text = Loc.GetString("microwave-bound-user-interface-cook-time-label", - ("time",_owner.currentState.CurrentCookTimeEnd.Subtract(_owner.GetCurrentTime()).Seconds)); + ("time", CurrentCooktimeEnd.Subtract(_timing.CurTime).Seconds)); } } + + public sealed class MicrowaveCookTimeButton : Button + { + public uint CookTime; + } } } diff --git a/Content.Client/Kitchen/UI/ReagentGrinderBoundUserInterface.cs b/Content.Client/Kitchen/UI/ReagentGrinderBoundUserInterface.cs index e6f108b3050..bc4cc75b4d1 100644 --- a/Content.Client/Kitchen/UI/ReagentGrinderBoundUserInterface.cs +++ b/Content.Client/Kitchen/UI/ReagentGrinderBoundUserInterface.cs @@ -1,6 +1,7 @@ using Content.Shared.Containers.ItemSlots; using Content.Shared.Kitchen; using Robust.Client.GameObjects; +using Robust.Client.UserInterface; using Robust.Client.UserInterface.Controls; using Robust.Shared.Prototypes; @@ -8,8 +9,6 @@ namespace Content.Client.Kitchen.UI { public sealed class ReagentGrinderBoundUserInterface : BoundUserInterface { - [Dependency] private readonly IPrototypeManager _prototypeManager = default!; - [ViewVariables] private GrinderMenu? _menu; @@ -21,20 +20,13 @@ protected override void Open() { base.Open(); - _menu = new GrinderMenu(this, EntMan, _prototypeManager); - _menu.OpenCentered(); - _menu.OnClose += Close; - } - - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - if (!disposing) - { - return; - } - - _menu?.Dispose(); + _menu = this.CreateWindow(); + _menu.OnToggleAuto += ToggleAutoMode; + _menu.OnGrind += StartGrinding; + _menu.OnJuice += StartJuicing; + _menu.OnEjectAll += EjectAll; + _menu.OnEjectBeaker += EjectBeaker; + _menu.OnEjectChamber += EjectChamberContent; } protected override void UpdateState(BoundUserInterfaceState state) @@ -52,27 +44,27 @@ protected override void ReceiveMessage(BoundUserInterfaceMessage message) _menu?.HandleMessage(message); } - public void ToggleAutoMode(BaseButton.ButtonEventArgs args) + public void ToggleAutoMode() { SendMessage(new ReagentGrinderToggleAutoModeMessage()); } - public void StartGrinding(BaseButton.ButtonEventArgs? _ = null) + public void StartGrinding() { SendMessage(new ReagentGrinderStartMessage(GrinderProgram.Grind)); } - public void StartJuicing(BaseButton.ButtonEventArgs? _ = null) + public void StartJuicing() { SendMessage(new ReagentGrinderStartMessage(GrinderProgram.Juice)); } - public void EjectAll(BaseButton.ButtonEventArgs? _ = null) + public void EjectAll() { SendMessage(new ReagentGrinderEjectChamberAllMessage()); } - public void EjectBeaker(BaseButton.ButtonEventArgs? _ = null) + public void EjectBeaker() { SendMessage(new ItemSlotButtonPressedEvent(SharedReagentGrinder.BeakerSlotId)); } diff --git a/Content.Client/Labels/UI/HandLabelerBoundUserInterface.cs b/Content.Client/Labels/UI/HandLabelerBoundUserInterface.cs index 555f1ff09e6..6b656123412 100644 --- a/Content.Client/Labels/UI/HandLabelerBoundUserInterface.cs +++ b/Content.Client/Labels/UI/HandLabelerBoundUserInterface.cs @@ -1,6 +1,7 @@ using Content.Shared.Labels; using Content.Shared.Labels.Components; using Robust.Client.GameObjects; +using Robust.Client.UserInterface; namespace Content.Client.Labels.UI { @@ -23,13 +24,8 @@ protected override void Open() { base.Open(); - _window = new HandLabelerWindow(); - if (State != null) - UpdateState(State); + _window = this.CreateWindow(); - _window.OpenCentered(); - - _window.OnClose += Close; _window.OnLabelChanged += OnLabelChanged; Reload(); } @@ -51,13 +47,5 @@ public void Reload() _window.SetCurrentLabel(component.AssignedLabel); } - - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - if (!disposing) return; - _window?.Dispose(); - } } - } diff --git a/Content.Client/Lathe/UI/LatheBoundUserInterface.cs b/Content.Client/Lathe/UI/LatheBoundUserInterface.cs index 6e6d1b91761..a599f79152e 100644 --- a/Content.Client/Lathe/UI/LatheBoundUserInterface.cs +++ b/Content.Client/Lathe/UI/LatheBoundUserInterface.cs @@ -1,6 +1,7 @@ using Content.Shared.Lathe; using Content.Shared.Research.Components; using JetBrains.Annotations; +using Robust.Client.UserInterface; namespace Content.Client.Lathe.UI { @@ -17,9 +18,9 @@ protected override void Open() { base.Open(); - _menu = new LatheMenu(this); - _menu.OnClose += Close; - + _menu = this.CreateWindow(); + _menu.SetEntity(Owner); + _menu.OpenCenteredRight(); _menu.OnServerListButtonPressed += _ => { @@ -30,8 +31,6 @@ protected override void Open() { SendMessage(new LatheQueueRecipeMessage(recipe, amount)); }; - - _menu.OpenCenteredRight(); } protected override void UpdateState(BoundUserInterfaceState state) @@ -50,13 +49,5 @@ protected override void UpdateState(BoundUserInterfaceState state) break; } } - - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - if (!disposing) - return; - _menu?.Dispose(); - } } } diff --git a/Content.Client/Lathe/UI/LatheMenu.xaml.cs b/Content.Client/Lathe/UI/LatheMenu.xaml.cs index b7ec8791f5b..bfbcd94ed6c 100644 --- a/Content.Client/Lathe/UI/LatheMenu.xaml.cs +++ b/Content.Client/Lathe/UI/LatheMenu.xaml.cs @@ -1,3 +1,4 @@ +using System.Buffers; using System.Linq; using System.Text; using Content.Client.Materials; @@ -20,7 +21,6 @@ public sealed partial class LatheMenu : DefaultWindow [Dependency] private readonly IEntityManager _entityManager = default!; [Dependency] private readonly IPrototypeManager _prototypeManager = default!; - private EntityUid _owner; private readonly SpriteSystem _spriteSystem; private readonly LatheSystem _lathe; private readonly MaterialStorageSystem _materialStorage; @@ -34,9 +34,10 @@ public sealed partial class LatheMenu : DefaultWindow public ProtoId? CurrentCategory; - public LatheMenu(LatheBoundUserInterface owner) + public EntityUid Entity; + + public LatheMenu() { - _owner = owner.Owner; RobustXamlLoader.Load(this); IoCManager.InjectDependencies(this); @@ -44,8 +45,6 @@ public LatheMenu(LatheBoundUserInterface owner) _lathe = _entityManager.System(); _materialStorage = _entityManager.System(); - Title = _entityManager.GetComponent(owner.Owner).EntityName; - SearchBar.OnTextChanged += _ => { PopulateRecipes(); @@ -58,8 +57,13 @@ public LatheMenu(LatheBoundUserInterface owner) FilterOption.OnItemSelected += OnItemSelected; ServerListButton.OnPressed += a => OnServerListButtonPressed?.Invoke(a); + } - if (_entityManager.TryGetComponent(owner.Owner, out var latheComponent)) + public void SetEntity(EntityUid uid) + { + Entity = uid; + + if (_entityManager.TryGetComponent(Entity, out var latheComponent)) { if (!latheComponent.DynamicRecipes.Any()) { @@ -67,7 +71,7 @@ public LatheMenu(LatheBoundUserInterface owner) } } - MaterialsList.SetOwner(owner.Owner); + MaterialsList.SetOwner(Entity); } /// @@ -100,12 +104,15 @@ public void PopulateRecipes() var sortedRecipesToShow = recipesToShow.OrderBy(p => p.Name); RecipeList.Children.Clear(); + _entityManager.TryGetComponent(Entity, out LatheComponent? lathe); + foreach (var prototype in sortedRecipesToShow) { - var icon = prototype.Icon == null - ? _spriteSystem.GetPrototypeIcon(prototype.Result).Default - : _spriteSystem.Frame0(prototype.Icon); - var canProduce = _lathe.CanProduce(_owner, prototype, quantity); + EntityPrototype? recipeProto = null; + if (_prototypeManager.TryIndex(prototype.Result, out EntityPrototype? entityProto)) + recipeProto = entityProto; + + var canProduce = _lathe.CanProduce(Entity, prototype, quantity, component: lathe); var control = new RecipeControl(prototype, () => GenerateTooltipText(prototype), canProduce, icon); control.OnButtonPressed += s => @@ -121,19 +128,20 @@ public void PopulateRecipes() private string GenerateTooltipText(LatheRecipePrototype prototype) { StringBuilder sb = new(); + var multiplier = _entityManager.GetComponent(Entity).MaterialUseMultiplier; foreach (var (id, amount) in prototype.RequiredMaterials) { if (!_prototypeManager.TryIndex(id, out var proto)) continue; - var adjustedAmount = SharedLatheSystem.AdjustMaterial(amount, prototype.ApplyMaterialDiscount, _entityManager.GetComponent(_owner).MaterialUseMultiplier); + var adjustedAmount = SharedLatheSystem.AdjustMaterial(amount, prototype.ApplyMaterialDiscount, multiplier); var sheetVolume = _materialStorage.GetSheetVolume(proto); var unit = Loc.GetString(proto.Unit); var sheets = adjustedAmount / (float) sheetVolume; - var availableAmount = _materialStorage.GetMaterialAmount(_owner, id); + var availableAmount = _materialStorage.GetMaterialAmount(Entity, id); var missingAmount = Math.Max(0, adjustedAmount - availableAmount); var missingSheets = missingAmount / (float) sheetVolume; diff --git a/Content.Client/MachineLinking/UI/SignalTimerBoundUserInterface.cs b/Content.Client/MachineLinking/UI/SignalTimerBoundUserInterface.cs index 09bdedfd94c..11abe8c2451 100644 --- a/Content.Client/MachineLinking/UI/SignalTimerBoundUserInterface.cs +++ b/Content.Client/MachineLinking/UI/SignalTimerBoundUserInterface.cs @@ -1,5 +1,6 @@ using Content.Shared.MachineLinking; using Robust.Client.GameObjects; +using Robust.Client.UserInterface; using Robust.Shared.Timing; namespace Content.Client.MachineLinking.UI; @@ -19,19 +20,14 @@ protected override void Open() { base.Open(); - _window = new SignalTimerWindow(this); - - if (State != null) - UpdateState(State); - - _window.OpenCentered(); - _window.OnClose += Close; + _window = this.CreateWindow(); + _window.OnStartTimer += StartTimer; _window.OnCurrentTextChanged += OnTextChanged; _window.OnCurrentDelayMinutesChanged += OnDelayChanged; _window.OnCurrentDelaySecondsChanged += OnDelayChanged; } - public void OnStartTimer() + public void StartTimer() { SendMessage(new SignalTimerStartMessage()); } @@ -48,11 +44,6 @@ private void OnDelayChanged(string newDelay) SendMessage(new SignalTimerDelayChangedMessage(_window.GetDelay())); } - public TimeSpan GetCurrentTime() - { - return _gameTiming.CurTime; - } - /// /// Update the UI state based on server-sent info /// @@ -72,11 +63,4 @@ protected override void UpdateState(BoundUserInterfaceState state) _window.SetTimerStarted(cast.TimerStarted); _window.SetHasAccess(cast.HasAccess); } - - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - if (!disposing) return; - _window?.Dispose(); - } } diff --git a/Content.Client/MachineLinking/UI/SignalTimerWindow.xaml.cs b/Content.Client/MachineLinking/UI/SignalTimerWindow.xaml.cs index b62595595e5..6133abfcb70 100644 --- a/Content.Client/MachineLinking/UI/SignalTimerWindow.xaml.cs +++ b/Content.Client/MachineLinking/UI/SignalTimerWindow.xaml.cs @@ -9,42 +9,44 @@ namespace Content.Client.MachineLinking.UI; [GenerateTypedNameReferences] public sealed partial class SignalTimerWindow : DefaultWindow { + [Dependency] private readonly IGameTiming _timing = default!; + private const int MaxTextLength = 5; public event Action? OnCurrentTextChanged; public event Action? OnCurrentDelayMinutesChanged; public event Action? OnCurrentDelaySecondsChanged; - private readonly SignalTimerBoundUserInterface _owner; - private TimeSpan? _triggerTime; private bool _timerStarted; - public SignalTimerWindow(SignalTimerBoundUserInterface owner) + public event Action? OnStartTimer; + + public SignalTimerWindow() { RobustXamlLoader.Load(this); - - _owner = owner; + IoCManager.InjectDependencies(this); CurrentTextEdit.OnTextChanged += e => OnCurrentTextChange(e.Text); CurrentDelayEditMinutes.OnTextChanged += e => OnCurrentDelayMinutesChange(e.Text); CurrentDelayEditSeconds.OnTextChanged += e => OnCurrentDelaySecondsChange(e.Text); - StartTimer.OnPressed += _ => OnStartTimer(); + StartTimer.OnPressed += _ => StartTimerWeh(); } - public void OnStartTimer() + private void StartTimerWeh() { if (!_timerStarted) { _timerStarted = true; - _triggerTime = _owner.GetCurrentTime() + GetDelay(); + _triggerTime = _timing.CurTime + GetDelay(); } else { SetTimerStarted(false); } - _owner.OnStartTimer(); + + OnStartTimer?.Invoke(); } protected override void FrameUpdate(FrameEventArgs args) @@ -54,9 +56,9 @@ protected override void FrameUpdate(FrameEventArgs args) if (!_timerStarted || _triggerTime == null) return; - if (_owner.GetCurrentTime() < _triggerTime.Value) + if (_timing.CurTime < _triggerTime.Value) { - StartTimer.Text = TextScreenSystem.TimeToString(_triggerTime.Value - _owner.GetCurrentTime()); + StartTimer.Text = TextScreenSystem.TimeToString(_triggerTime.Value - _timing.CurTime); } else { diff --git a/Content.Client/MagicMirror/MagicMirrorBoundUserInterface.cs b/Content.Client/MagicMirror/MagicMirrorBoundUserInterface.cs index f6979bf8d7b..0a87948ff62 100644 --- a/Content.Client/MagicMirror/MagicMirrorBoundUserInterface.cs +++ b/Content.Client/MagicMirror/MagicMirrorBoundUserInterface.cs @@ -1,6 +1,7 @@ using Content.Shared.Humanoid.Markings; using Content.Shared.MagicMirror; using Robust.Client.GameObjects; +using Robust.Client.UserInterface; namespace Content.Client.MagicMirror; @@ -17,7 +18,7 @@ protected override void Open() { base.Open(); - _window = new(); + _window = this.CreateWindow(); _window.OnHairSelected += tuple => SelectHair(MagicMirrorCategory.Hair, tuple.id, tuple.slot); _window.OnHairColorChanged += args => ChangeColor(MagicMirrorCategory.Hair, args.marking, args.slot); @@ -29,9 +30,6 @@ protected override void Open() args => ChangeColor(MagicMirrorCategory.FacialHair, args.marking, args.slot); _window.OnFacialHairSlotAdded += delegate () { AddSlot(MagicMirrorCategory.FacialHair); }; _window.OnFacialHairSlotRemoved += args => RemoveSlot(MagicMirrorCategory.FacialHair, args); - - _window.OnClose += Close; - _window.OpenCentered(); } private void SelectHair(MagicMirrorCategory category, string marking, int slot) @@ -65,14 +63,5 @@ protected override void UpdateState(BoundUserInterfaceState state) _window.UpdateState(data); } - - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - if (!disposing) - return; - - _window?.Dispose(); - } } diff --git a/Content.Client/MassMedia/Ui/NewsWriterBoundUserInterface.cs b/Content.Client/MassMedia/Ui/NewsWriterBoundUserInterface.cs index 80eca82e324..22e5bc452a0 100644 --- a/Content.Client/MassMedia/Ui/NewsWriterBoundUserInterface.cs +++ b/Content.Client/MassMedia/Ui/NewsWriterBoundUserInterface.cs @@ -1,6 +1,7 @@ using JetBrains.Annotations; using Content.Shared.MassMedia.Systems; using Content.Shared.MassMedia.Components; +using Robust.Client.UserInterface; using Robust.Shared.Timing; using Robust.Shared.Utility; @@ -9,8 +10,6 @@ namespace Content.Client.MassMedia.Ui; [UsedImplicitly] public sealed class NewsWriterBoundUserInterface : BoundUserInterface { - [Dependency] private readonly IGameTiming _gameTiming = default!; - [ViewVariables] private NewsWriterMenu? _menu; @@ -21,10 +20,7 @@ public NewsWriterBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, u protected override void Open() { - _menu = new NewsWriterMenu(_gameTiming); - - _menu.OpenCentered(); - _menu.OnClose += Close; + _menu = this.CreateWindow(); _menu.ArticleEditorPanel.PublishButtonPressed += OnPublishButtonPressed; _menu.DeleteButtonPressed += OnDeleteButtonPressed; @@ -32,16 +28,6 @@ protected override void Open() SendMessage(new NewsWriterArticlesRequestMessage()); } - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - if (!disposing) - return; - - _menu?.Close(); - _menu?.Dispose(); - } - protected override void UpdateState(BoundUserInterfaceState state) { base.UpdateState(state); diff --git a/Content.Client/MassMedia/Ui/NewsWriterMenu.xaml.cs b/Content.Client/MassMedia/Ui/NewsWriterMenu.xaml.cs index e2d57935e3a..c059ce785af 100644 --- a/Content.Client/MassMedia/Ui/NewsWriterMenu.xaml.cs +++ b/Content.Client/MassMedia/Ui/NewsWriterMenu.xaml.cs @@ -10,17 +10,17 @@ namespace Content.Client.MassMedia.Ui; [GenerateTypedNameReferences] public sealed partial class NewsWriterMenu : FancyWindow { - private readonly IGameTiming _gameTiming; + [Dependency] private readonly IGameTiming _gameTiming = default!; private TimeSpan? _nextPublish; public event Action? DeleteButtonPressed; - public NewsWriterMenu(IGameTiming gameTiming) + public NewsWriterMenu() { RobustXamlLoader.Load(this); + IoCManager.InjectDependencies(this); - _gameTiming = gameTiming; ContentsContainer.RectClipContent = false; // Customize scrollbar width and margin. This is not possible in xaml diff --git a/Content.Client/Mech/Ui/MechBoundUserInterface.cs b/Content.Client/Mech/Ui/MechBoundUserInterface.cs index 4172bdc90f1..2130a8c6099 100644 --- a/Content.Client/Mech/Ui/MechBoundUserInterface.cs +++ b/Content.Client/Mech/Ui/MechBoundUserInterface.cs @@ -3,6 +3,7 @@ using Content.Shared.Mech.Components; using JetBrains.Annotations; using Robust.Client.GameObjects; +using Robust.Client.UserInterface; namespace Content.Client.Mech.Ui; @@ -20,9 +21,8 @@ protected override void Open() { base.Open(); - _menu = new(Owner); - - _menu.OnClose += Close; + _menu = this.CreateWindow(); + _menu.SetEntity(Owner); _menu.OpenCenteredLeft(); _menu.OnRemoveButtonPressed += uid => @@ -60,16 +60,6 @@ public void UpdateEquipmentControls(MechBoundUiState state) } } - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - - if (!disposing) - return; - - _menu?.Close(); - } - public UIFragment? GetEquipmentUi(EntityUid? uid) { var component = EntMan.GetComponentOrNull(uid); diff --git a/Content.Client/Mech/Ui/MechMenu.xaml.cs b/Content.Client/Mech/Ui/MechMenu.xaml.cs index fad76488086..6f39bc386ee 100644 --- a/Content.Client/Mech/Ui/MechMenu.xaml.cs +++ b/Content.Client/Mech/Ui/MechMenu.xaml.cs @@ -16,14 +16,15 @@ public sealed partial class MechMenu : FancyWindow public event Action? OnRemoveButtonPressed; - public MechMenu(EntityUid mech) + public MechMenu() { RobustXamlLoader.Load(this); IoCManager.InjectDependencies(this); + } - _mech = mech; - - MechView.SetEntity(mech); + public void SetEntity(EntityUid uid) + { + MechView.SetEntity(uid); } public void UpdateMechStats() diff --git a/Content.Client/Medical/CrewMonitoring/CrewMonitoringBoundUserInterface.cs b/Content.Client/Medical/CrewMonitoring/CrewMonitoringBoundUserInterface.cs index 39788809871..b1f239cd78e 100644 --- a/Content.Client/Medical/CrewMonitoring/CrewMonitoringBoundUserInterface.cs +++ b/Content.Client/Medical/CrewMonitoring/CrewMonitoringBoundUserInterface.cs @@ -1,4 +1,5 @@ using Content.Shared.Medical.CrewMonitoring; +using Robust.Client.UserInterface; namespace Content.Client.Medical.CrewMonitoring; @@ -14,7 +15,7 @@ public CrewMonitoringBoundUserInterface(EntityUid owner, Enum uiKey) : base(owne protected override void Open() { EntityUid? gridUid = null; - string stationName = string.Empty; + var stationName = string.Empty; if (EntMan.TryGetComponent(Owner, out var xform)) { @@ -26,10 +27,8 @@ protected override void Open() } } - _menu = new CrewMonitoringWindow(stationName, gridUid); - - _menu.OpenCentered(); - _menu.OnClose += Close; + _menu = this.CreateWindow(); + _menu.Set(stationName, gridUid); } protected override void UpdateState(BoundUserInterfaceState state) @@ -44,13 +43,4 @@ protected override void UpdateState(BoundUserInterfaceState state) break; } } - - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - if (!disposing) - return; - - _menu?.Dispose(); - } } diff --git a/Content.Client/Medical/CrewMonitoring/CrewMonitoringWindow.xaml.cs b/Content.Client/Medical/CrewMonitoring/CrewMonitoringWindow.xaml.cs index 863412e5532..e861864c144 100644 --- a/Content.Client/Medical/CrewMonitoring/CrewMonitoringWindow.xaml.cs +++ b/Content.Client/Medical/CrewMonitoring/CrewMonitoringWindow.xaml.cs @@ -23,22 +23,27 @@ namespace Content.Client.Medical.CrewMonitoring; [GenerateTypedNameReferences] public sealed partial class CrewMonitoringWindow : FancyWindow { - private readonly IEntityManager _entManager; - private readonly IPrototypeManager _prototypeManager; + [Dependency] private readonly IEntityManager _entManager = default!; + [Dependency] private readonly IPrototypeManager _prototypeManager = default!; private readonly SpriteSystem _spriteSystem; private NetEntity? _trackedEntity; private bool _tryToScrollToListFocus; private Texture? _blipTexture; - public CrewMonitoringWindow(string stationName, EntityUid? mapUid) + public CrewMonitoringWindow() { RobustXamlLoader.Load(this); + IoCManager.InjectDependencies(this); - _entManager = IoCManager.Resolve(); - _prototypeManager = IoCManager.Resolve(); _spriteSystem = _entManager.System(); + NavMap.TrackedEntitySelectedAction += SetTrackedEntityFromNavMap; + + } + + public void Set(string stationName, EntityUid? mapUid) + { _blipTexture = _spriteSystem.Frame0(new SpriteSpecifier.Texture(new ResPath("/Textures/Interface/NavMap/beveled_circle.png"))); if (_entManager.TryGetComponent(mapUid, out var xform)) @@ -49,8 +54,6 @@ public CrewMonitoringWindow(string stationName, EntityUid? mapUid) StationName.AddStyleClass("LabelBig"); StationName.Text = stationName; - - NavMap.TrackedEntitySelectedAction += SetTrackedEntityFromNavMap; NavMap.ForceNavMapUpdate(); } diff --git a/Content.Client/NetworkConfigurator/NetworkConfiguratorBoundUserInterface.cs b/Content.Client/NetworkConfigurator/NetworkConfiguratorBoundUserInterface.cs index 80c98f143b9..f85220a9266 100644 --- a/Content.Client/NetworkConfigurator/NetworkConfiguratorBoundUserInterface.cs +++ b/Content.Client/NetworkConfigurator/NetworkConfiguratorBoundUserInterface.cs @@ -1,6 +1,7 @@ using Content.Client.NetworkConfigurator.Systems; using Content.Shared.DeviceNetwork; using Robust.Client.GameObjects; +using Robust.Client.UserInterface; using Robust.Client.UserInterface.Controls; namespace Content.Client.NetworkConfigurator; @@ -35,14 +36,12 @@ protected override void Open() switch (UiKey) { case NetworkConfiguratorUiKey.List: - _listMenu = new NetworkConfiguratorListMenu(this); - _listMenu.OnClose += Close; + _listMenu = this.CreateWindow(); _listMenu.ClearButton.OnPressed += _ => OnClearButtonPressed(); - _listMenu.OpenCenteredRight(); + _listMenu.OnRemoveAddress += OnRemoveButtonPressed; break; case NetworkConfiguratorUiKey.Configure: - _configurationMenu = new NetworkConfiguratorConfigurationMenu(); - _configurationMenu.OnClose += Close; + _configurationMenu = this.CreateWindow(); _configurationMenu.Set.OnPressed += _ => OnConfigButtonPressed(NetworkConfiguratorButtonKey.Set); _configurationMenu.Add.OnPressed += _ => OnConfigButtonPressed(NetworkConfiguratorButtonKey.Add); //_configurationMenu.Edit.OnPressed += _ => OnConfigButtonPressed(NetworkConfiguratorButtonKey.Edit); @@ -50,12 +49,24 @@ protected override void Open() _configurationMenu.Copy.OnPressed += _ => OnConfigButtonPressed(NetworkConfiguratorButtonKey.Copy); _configurationMenu.Show.OnPressed += OnShowPressed; _configurationMenu.Show.Pressed = _netConfig.ConfiguredListIsTracked(Owner); - _configurationMenu.OpenCentered(); + _configurationMenu.OnRemoveAddress += OnRemoveButtonPressed; break; case NetworkConfiguratorUiKey.Link: - _linkMenu = new NetworkConfiguratorLinkMenu(this); - _linkMenu.OnClose += Close; - _linkMenu.OpenCentered(); + _linkMenu = this.CreateWindow(); + _linkMenu.OnLinkDefaults += args => + { + SendMessage(new NetworkConfiguratorLinksSaveMessage(args)); + }; + + _linkMenu.OnToggleLink += (left, right) => + { + SendMessage(new NetworkConfiguratorToggleLinkMessage(left, right)); + }; + + _linkMenu.OnClearLinks += () => + { + SendMessage(new NetworkConfiguratorClearLinksMessage()); + }; break; } } @@ -83,16 +94,6 @@ protected override void UpdateState(BoundUserInterfaceState state) } } - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - if (!disposing) return; - - _linkMenu?.Dispose(); - _listMenu?.Dispose(); - _configurationMenu?.Dispose(); - } - private void OnClearButtonPressed() { SendMessage(new NetworkConfiguratorClearDevicesMessage()); diff --git a/Content.Client/NetworkConfigurator/NetworkConfiguratorConfigurationMenu.xaml.cs b/Content.Client/NetworkConfigurator/NetworkConfiguratorConfigurationMenu.xaml.cs index 19d04cd3464..fcd2f759187 100644 --- a/Content.Client/NetworkConfigurator/NetworkConfiguratorConfigurationMenu.xaml.cs +++ b/Content.Client/NetworkConfigurator/NetworkConfiguratorConfigurationMenu.xaml.cs @@ -9,17 +9,23 @@ namespace Content.Client.NetworkConfigurator; [GenerateTypedNameReferences] public sealed partial class NetworkConfiguratorConfigurationMenu : FancyWindow { + public event Action? OnRemoveAddress; + public NetworkConfiguratorConfigurationMenu() { RobustXamlLoader.Load(this); Clear.StyleClasses.Add(StyleBase.ButtonOpenLeft); Clear.StyleClasses.Add(StyleNano.StyleClassButtonColorRed); + DeviceList.OnRemoveAddress += args => + { + OnRemoveAddress?.Invoke(args); + }; } public void UpdateState(DeviceListUserInterfaceState state) { - DeviceList.UpdateState(null, state.DeviceList); + DeviceList.UpdateState(state.DeviceList, false); Count.Text = Loc.GetString("network-configurator-ui-count-label", ("count", state.DeviceList.Count)); } diff --git a/Content.Client/NetworkConfigurator/NetworkConfiguratorDeviceList.xaml.cs b/Content.Client/NetworkConfigurator/NetworkConfiguratorDeviceList.xaml.cs index 8cfa97dc6c2..e75c60058cb 100644 --- a/Content.Client/NetworkConfigurator/NetworkConfiguratorDeviceList.xaml.cs +++ b/Content.Client/NetworkConfigurator/NetworkConfiguratorDeviceList.xaml.cs @@ -7,17 +7,19 @@ namespace Content.Client.NetworkConfigurator; [GenerateTypedNameReferences] public sealed partial class NetworkConfiguratorDeviceList : ScrollContainer { - public void UpdateState(NetworkConfiguratorBoundUserInterface? ui, HashSet<(string address, string name)> devices) + public event Action? OnRemoveAddress; + + public void UpdateState(HashSet<(string address, string name)> devices, bool ui) { DeviceList.RemoveAllChildren(); foreach (var device in devices) { - DeviceList.AddChild(BuildDeviceListRow(ui, device)); + DeviceList.AddChild(BuildDeviceListRow(device, ui)); } } - private static BoxContainer BuildDeviceListRow(NetworkConfiguratorBoundUserInterface? ui, (string address, string name) savedDevice) + private BoxContainer BuildDeviceListRow((string address, string name) savedDevice, bool ui) { var row = new BoxContainer() { @@ -48,10 +50,10 @@ private static BoxContainer BuildDeviceListRow(NetworkConfiguratorBoundUserInter row.AddChild(name); row.AddChild(address); - if (ui != null) + if (ui) { row.AddChild(removeButton); - removeButton.OnPressed += _ => ui.OnRemoveButtonPressed(savedDevice.address); + removeButton.OnPressed += _ => OnRemoveAddress?.Invoke(savedDevice.address); } return row; diff --git a/Content.Client/NetworkConfigurator/NetworkConfiguratorLinkMenu.xaml.cs b/Content.Client/NetworkConfigurator/NetworkConfiguratorLinkMenu.xaml.cs index c04b42f249b..8cdffd16af6 100644 --- a/Content.Client/NetworkConfigurator/NetworkConfiguratorLinkMenu.xaml.cs +++ b/Content.Client/NetworkConfigurator/NetworkConfiguratorLinkMenu.xaml.cs @@ -18,20 +18,20 @@ public sealed partial class NetworkConfiguratorLinkMenu : FancyWindow private readonly LinksRender _links; - private readonly List _sources = new(); private readonly List _sinks = new(); - private readonly NetworkConfiguratorBoundUserInterface _userInterface; - private (ButtonPosition position, string id, int index)? _selectedButton; private List<(string left, string right)>? _defaults; - public NetworkConfiguratorLinkMenu(NetworkConfiguratorBoundUserInterface userInterface) + public event Action? OnClearLinks; + public event Action? OnToggleLink; + public event Action>? OnLinkDefaults; + + public NetworkConfiguratorLinkMenu() { - _userInterface = userInterface; RobustXamlLoader.Load(this); var footerStyleBox = new StyleBoxFlat() @@ -52,7 +52,7 @@ public NetworkConfiguratorLinkMenu(NetworkConfiguratorBoundUserInterface userInt ButtonOk.OnPressed += _ => Close(); ButtonLinkDefault.OnPressed += _ => LinkDefaults(); - ButtonClear.OnPressed += _ => _userInterface.SendMessage(new NetworkConfiguratorClearLinksMessage()); + ButtonClear.OnPressed += _ => OnClearLinks?.Invoke(); } public void UpdateState(DeviceLinkUserInterfaceState linkState) @@ -98,7 +98,7 @@ private void LinkDefaults() if (_defaults == default) return; - _userInterface.SendMessage(new NetworkConfiguratorLinksSaveMessage(_defaults)); + OnLinkDefaults?.Invoke(_defaults); } private Button CreateButton(ButtonPosition position, string name, string description, string id, int index) @@ -138,7 +138,7 @@ private void OnButtonPressed(BaseButton.ButtonEventArgs args, ButtonPosition pos var left = _selectedButton.Value.position == ButtonPosition.Left ? _selectedButton.Value.id : id; var right = _selectedButton.Value.position == ButtonPosition.Left ? id : _selectedButton.Value.id; - _userInterface.SendMessage(new NetworkConfiguratorToggleLinkMessage(left, right)); + OnToggleLink?.Invoke(left, right); args.Button.Pressed = false; diff --git a/Content.Client/NetworkConfigurator/NetworkConfiguratorListMenu.xaml.cs b/Content.Client/NetworkConfigurator/NetworkConfiguratorListMenu.xaml.cs index fb4aec1974b..6294facaeed 100644 --- a/Content.Client/NetworkConfigurator/NetworkConfiguratorListMenu.xaml.cs +++ b/Content.Client/NetworkConfigurator/NetworkConfiguratorListMenu.xaml.cs @@ -9,17 +9,20 @@ namespace Content.Client.NetworkConfigurator; [GenerateTypedNameReferences] public sealed partial class NetworkConfiguratorListMenu : FancyWindow { - private readonly NetworkConfiguratorBoundUserInterface _ui; - public NetworkConfiguratorListMenu(NetworkConfiguratorBoundUserInterface ui) + public event Action? OnRemoveAddress; + + public NetworkConfiguratorListMenu() { RobustXamlLoader.Load(this); - - _ui = ui; + DeviceList.OnRemoveAddress += args => + { + OnRemoveAddress?.Invoke(args); + }; } public void UpdateState(NetworkConfiguratorUserInterfaceState state) { DeviceCountLabel.Text = Loc.GetString("network-configurator-ui-count-label", ("count", state.DeviceList.Count)); - DeviceList.UpdateState(_ui, state.DeviceList); + DeviceList.UpdateState(state.DeviceList, true); } } diff --git a/Content.Client/Nuke/NukeBoundUserInterface.cs b/Content.Client/Nuke/NukeBoundUserInterface.cs index 59fbc5b319b..2e150423734 100644 --- a/Content.Client/Nuke/NukeBoundUserInterface.cs +++ b/Content.Client/Nuke/NukeBoundUserInterface.cs @@ -2,6 +2,7 @@ using Content.Shared.Nuke; using JetBrains.Annotations; using Robust.Client.GameObjects; +using Robust.Client.UserInterface; namespace Content.Client.Nuke { @@ -11,15 +12,13 @@ public sealed class NukeBoundUserInterface : BoundUserInterface [ViewVariables] private NukeMenu? _menu; - public NukeBoundUserInterface([NotNull] EntityUid owner, [NotNull] Enum uiKey) : base(owner, uiKey) + public NukeBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey) { } protected override void Open() { - _menu = new NukeMenu(); - _menu.OpenCentered(); - _menu.OnClose += Close; + _menu = this.CreateWindow(); _menu.OnKeypadButtonPressed += i => { @@ -62,15 +61,5 @@ protected override void UpdateState(BoundUserInterfaceState state) break; } } - - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - if (!disposing) - return; - - _menu?.Close(); - _menu?.Dispose(); - } } } diff --git a/Content.Client/NukeOps/WarDeclaratorBoundUserInterface.cs b/Content.Client/NukeOps/WarDeclaratorBoundUserInterface.cs index ec055b3240c..ad4f1a75d47 100644 --- a/Content.Client/NukeOps/WarDeclaratorBoundUserInterface.cs +++ b/Content.Client/NukeOps/WarDeclaratorBoundUserInterface.cs @@ -2,6 +2,7 @@ using Content.Shared.Chat; using Content.Shared.NukeOps; using JetBrains.Annotations; +using Robust.Client.UserInterface; using Robust.Shared.Configuration; using Robust.Shared.Timing; @@ -11,8 +12,6 @@ namespace Content.Client.NukeOps; public sealed class WarDeclaratorBoundUserInterface : BoundUserInterface { [Dependency] private readonly IConfigurationManager _cfg = default!; - [Dependency] private readonly IGameTiming _gameTiming = default!; - [Dependency] private readonly ILocalizationManager _localizationManager = default!; [ViewVariables] private WarDeclaratorWindow? _window; @@ -23,13 +22,7 @@ protected override void Open() { base.Open(); - _window = new WarDeclaratorWindow(_gameTiming, _localizationManager); - if (State != null) - UpdateState(State); - - _window.OpenCentered(); - - _window.OnClose += Close; + _window = this.CreateWindow(); _window.OnActivated += OnWarDeclaratorActivated; } @@ -42,13 +35,6 @@ protected override void UpdateState(BoundUserInterfaceState state) _window?.UpdateState(cast); } - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - if (disposing) - _window?.Dispose(); - } - private void OnWarDeclaratorActivated(string message) { var maxLength = _cfg.GetCVar(CCVars.ChatMaxAnnouncementLength); diff --git a/Content.Client/NukeOps/WarDeclaratorWindow.xaml.cs b/Content.Client/NukeOps/WarDeclaratorWindow.xaml.cs index b4a3f1c7fa5..aeceae13275 100644 --- a/Content.Client/NukeOps/WarDeclaratorWindow.xaml.cs +++ b/Content.Client/NukeOps/WarDeclaratorWindow.xaml.cs @@ -11,7 +11,8 @@ namespace Content.Client.NukeOps; [GenerateTypedNameReferences] public sealed partial class WarDeclaratorWindow : FancyWindow { - private readonly IGameTiming _gameTiming; + [Dependency] private readonly IGameTiming _gameTiming = default!; + [Dependency] private readonly ILocalizationManager _localizationManager = default!; public event Action? OnActivated; @@ -19,15 +20,13 @@ public sealed partial class WarDeclaratorWindow : FancyWindow private TimeSpan _shuttleDisabledTime; private WarConditionStatus _status; - public WarDeclaratorWindow(IGameTiming gameTiming, ILocalizationManager localizationManager) + public WarDeclaratorWindow() { RobustXamlLoader.Load(this); - _gameTiming = gameTiming; - WarButton.OnPressed += (_) => OnActivated?.Invoke(Rope.Collapse(MessageEdit.TextRope)); - MessageEdit.Placeholder = new Rope.Leaf(localizationManager.GetString("war-declarator-message-placeholder")); + MessageEdit.Placeholder = new Rope.Leaf(_localizationManager.GetString("war-declarator-message-placeholder")); } protected override void FrameUpdate(FrameEventArgs args) diff --git a/Content.Client/PDA/PdaBoundUserInterface.cs b/Content.Client/PDA/PdaBoundUserInterface.cs index f8f4c67076c..37ce9c4280f 100644 --- a/Content.Client/PDA/PdaBoundUserInterface.cs +++ b/Content.Client/PDA/PdaBoundUserInterface.cs @@ -24,14 +24,13 @@ protected override void Open() if (_menu == null) CreateMenu(); - - _menu?.OpenCenteredLeft(); } private void CreateMenu() { - _menu = new PdaMenu(); - _menu.OnClose += Close; + _menu = this.CreateWindow(); + _menu.OpenCenteredLeft(); + _menu.FlashLightToggleButton.OnToggled += _ => { SendMessage(new PdaToggleFlashlightMessage()); @@ -96,7 +95,6 @@ protected override void UpdateState(BoundUserInterfaceState state) _menu?.UpdateState(updateState); } - protected override void AttachCartridgeUI(Control cartridgeUIFragment, string? title) { _menu?.ProgramView.AddChild(cartridgeUIFragment); @@ -118,15 +116,6 @@ protected override void UpdateAvailablePrograms(List<(EntityUid, CartridgeCompon _menu?.UpdateAvailablePrograms(programs); } - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - if (!disposing) - return; - - _menu?.Dispose(); - } - private PdaBorderColorComponent? GetBorderColorComponent() { return EntMan.GetComponentOrNull(Owner); diff --git a/Content.Client/PDA/Ringer/RingerBoundUserInterface.cs b/Content.Client/PDA/Ringer/RingerBoundUserInterface.cs index a0688523f1e..170a296ac2e 100644 --- a/Content.Client/PDA/Ringer/RingerBoundUserInterface.cs +++ b/Content.Client/PDA/Ringer/RingerBoundUserInterface.cs @@ -1,6 +1,7 @@ using Content.Shared.PDA; using Content.Shared.PDA.Ringer; using JetBrains.Annotations; +using Robust.Client.UserInterface; using Robust.Shared.Timing; namespace Content.Client.PDA.Ringer @@ -18,9 +19,8 @@ public RingerBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey protected override void Open() { base.Open(); - _menu = new RingtoneMenu(); + _menu = this.CreateWindow(); _menu.OpenToLeft(); - _menu.OnClose += Close; _menu.TestRingerButton.OnPressed += _ => { diff --git a/Content.Client/Paper/UI/PaperBoundUserInterface.cs b/Content.Client/Paper/UI/PaperBoundUserInterface.cs index 4b0ac868f01..f3ad1e347e7 100644 --- a/Content.Client/Paper/UI/PaperBoundUserInterface.cs +++ b/Content.Client/Paper/UI/PaperBoundUserInterface.cs @@ -1,4 +1,5 @@ using JetBrains.Annotations; +using Robust.Client.UserInterface; using Robust.Client.UserInterface.Controls; using Robust.Shared.Utility; using static Content.Shared.Paper.SharedPaperComponent; @@ -19,16 +20,13 @@ protected override void Open() { base.Open(); - _window = new PaperWindow(); - _window.OnClose += Close; - _window.OnSaved += Input_OnTextEntered; + _window = this.CreateWindow(); + _window.OnSaved += InputOnTextEntered; if (EntMan.TryGetComponent(Owner, out var visuals)) { _window.InitVisuals(Owner, visuals); } - - _window.OpenCentered(); } protected override void UpdateState(BoundUserInterfaceState state) @@ -37,7 +35,7 @@ protected override void UpdateState(BoundUserInterfaceState state) _window?.Populate((PaperBoundUserInterfaceState) state); } - private void Input_OnTextEntered(string text) + private void InputOnTextEntered(string text) { SendMessage(new PaperInputTextMessage(text)); @@ -47,11 +45,4 @@ private void Input_OnTextEntered(string text) _window.Input.CursorPosition = new TextEdit.CursorPos(0, TextEdit.LineBreakBias.Top); } } - - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - if (!disposing) return; - _window?.Dispose(); - } } diff --git a/Content.Client/Paper/UI/PaperWindow.xaml.cs b/Content.Client/Paper/UI/PaperWindow.xaml.cs index 7a5fd652643..f7cace642ce 100644 --- a/Content.Client/Paper/UI/PaperWindow.xaml.cs +++ b/Content.Client/Paper/UI/PaperWindow.xaml.cs @@ -17,6 +17,7 @@ namespace Content.Client.Paper.UI public sealed partial class PaperWindow : BaseWindow { [Dependency] private readonly IInputManager _inputManager = default!; + [Dependency] private readonly IResourceCache _resCache = default!; private static Color DefaultTextColor = new(25, 25, 25); @@ -85,11 +86,10 @@ public void InitVisuals(EntityUid entity, PaperVisualsComponent visuals) // Randomize the placement of any stamps based on the entity UID // so that there's some variety in different papers. StampDisplay.PlacementSeed = (int)entity; - var resCache = IoCManager.Resolve(); // Initialize the background: PaperBackground.ModulateSelfOverride = visuals.BackgroundModulate; - var backgroundImage = visuals.BackgroundImagePath != null? resCache.GetResource(visuals.BackgroundImagePath) : null; + var backgroundImage = visuals.BackgroundImagePath != null? _resCache.GetResource(visuals.BackgroundImagePath) : null; if (backgroundImage != null) { var backgroundImageMode = visuals.BackgroundImageTile ? StyleBoxTexture.StretchMode.Tile : StyleBoxTexture.StretchMode.Stretch; @@ -127,7 +127,7 @@ public void InitVisuals(EntityUid entity, PaperVisualsComponent visuals) PaperContent.ModulateSelfOverride = visuals.ContentImageModulate; WrittenTextLabel.ModulateSelfOverride = visuals.FontAccentColor; - var contentImage = visuals.ContentImagePath != null ? resCache.GetResource(visuals.ContentImagePath) : null; + var contentImage = visuals.ContentImagePath != null ? _resCache.GetResource(visuals.ContentImagePath) : null; if (contentImage != null) { // Setup the paper content texture, but keep a reference to it, as we can't set diff --git a/Content.Client/ParticleAccelerator/UI/ParticleAcceleratorBoundUserInterface.cs b/Content.Client/ParticleAccelerator/UI/ParticleAcceleratorBoundUserInterface.cs index cde5ba9ef79..ff1eae36f55 100644 --- a/Content.Client/ParticleAccelerator/UI/ParticleAcceleratorBoundUserInterface.cs +++ b/Content.Client/ParticleAccelerator/UI/ParticleAcceleratorBoundUserInterface.cs @@ -1,5 +1,6 @@ using Content.Shared.Singularity.Components; using Robust.Client.GameObjects; +using Robust.Client.UserInterface; namespace Content.Client.ParticleAccelerator.UI { @@ -16,9 +17,10 @@ protected override void Open() { base.Open(); - _menu = new ParticleAcceleratorControlMenu(this); - _menu.OnClose += Close; - _menu.OpenCentered(); + _menu = this.CreateWindow(); + _menu.OnOverallState += SendEnableMessage; + _menu.OnPowerState += SendPowerStateMessage; + _menu.OnScanPartsRequested += SendScanPartsMessage; } public void SendEnableMessage(bool enable) @@ -40,13 +42,5 @@ protected override void UpdateState(BoundUserInterfaceState state) { _menu?.DataUpdate((ParticleAcceleratorUIState) state); } - - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - - _menu?.Dispose(); - _menu = null; - } } } diff --git a/Content.Client/ParticleAccelerator/UI/ParticleAcceleratorControlMenu.cs b/Content.Client/ParticleAccelerator/UI/ParticleAcceleratorControlMenu.cs index c69e0271372..85a5f476293 100644 --- a/Content.Client/ParticleAccelerator/UI/ParticleAcceleratorControlMenu.cs +++ b/Content.Client/ParticleAccelerator/UI/ParticleAcceleratorControlMenu.cs @@ -18,9 +18,10 @@ namespace Content.Client.ParticleAccelerator.UI { public sealed class ParticleAcceleratorControlMenu : BaseWindow { - private readonly ShaderInstance _greyScaleShader; + [Dependency] private readonly IPrototypeManager _protoManager = default!; + [Dependency] private readonly IResourceCache _cache = default!; - private readonly ParticleAcceleratorBoundUserInterface _owner; + private readonly ShaderInstance _greyScaleShader; private readonly Label _drawLabel; private readonly FastNoiseLite _drawNoiseGenerator; @@ -50,19 +51,21 @@ public sealed class ParticleAcceleratorControlMenu : BaseWindow private bool _shouldContinueAnimating; private int _maxStrength = 3; - public ParticleAcceleratorControlMenu(ParticleAcceleratorBoundUserInterface owner) + public event Action? OnOverallState; + public event Action? OnPowerState; + public event Action? OnScanPartsRequested; + + public ParticleAcceleratorControlMenu() { SetSize = new Vector2(400, 320); - _greyScaleShader = IoCManager.Resolve().Index("Greyscale").Instance(); + _greyScaleShader = _protoManager.Index("Greyscale").Instance(); - _owner = owner; _drawNoiseGenerator = new(); _drawNoiseGenerator.SetFractalType(FastNoiseLite.FractalType.FBm); _drawNoiseGenerator.SetFrequency(0.5f); - var resourceCache = IoCManager.Resolve(); - var font = resourceCache.GetFont("/Fonts/Boxfont-round/Boxfont Round.ttf", 13); - var panelTex = resourceCache.GetTexture("/Textures/Interface/Nano/button.svg.96dpi.png"); + var font = _cache.GetFont("/Fonts/Boxfont-round/Boxfont Round.ttf", 13); + var panelTex = _cache.GetTexture("/Textures/Interface/Nano/button.svg.96dpi.png"); MouseFilter = MouseFilterMode.Stop; @@ -112,7 +115,8 @@ public ParticleAcceleratorControlMenu(ParticleAcceleratorBoundUserInterface owne Text = Loc.GetString("particle-accelerator-control-menu-off-button"), StyleClasses = { StyleBase.ButtonOpenRight }, }; - _offButton.OnPressed += args => owner.SendEnableMessage(false); + + _offButton.OnPressed += args => OnOverallState?.Invoke(false); _onButton = new Button { @@ -120,7 +124,7 @@ public ParticleAcceleratorControlMenu(ParticleAcceleratorBoundUserInterface owne Text = Loc.GetString("particle-accelerator-control-menu-on-button"), StyleClasses = { StyleBase.ButtonOpenLeft }, }; - _onButton.OnPressed += args => owner.SendEnableMessage(true); + _onButton.OnPressed += args => OnOverallState?.Invoke(true); var closeButton = new TextureButton { @@ -316,7 +320,7 @@ public ParticleAcceleratorControlMenu(ParticleAcceleratorBoundUserInterface owne } }); - _scanButton.OnPressed += args => _owner.SendScanPartsMessage(); + _scanButton.OnPressed += args => OnScanPartsRequested?.Invoke(); _alarmControl.AnimationCompleted += s => { @@ -332,7 +336,7 @@ public ParticleAcceleratorControlMenu(ParticleAcceleratorBoundUserInterface owne PASegmentControl Segment(string name) { - return new(this, resourceCache, name); + return new(this, _cache, name); } UpdateUI(false, false, false, false); @@ -368,7 +372,7 @@ private void PowerStateChanged(ValueChangedEventArgs e) } _stateSpinBox.SetButtonDisabled(true); - _owner.SendPowerStateMessage(newState); + OnPowerState?.Invoke(newState); } protected override DragMode GetDragModeFor(Vector2 relativeMousePos) diff --git a/Content.Client/Pinpointer/UI/NavMapBeaconBoundUserInterface.cs b/Content.Client/Pinpointer/UI/NavMapBeaconBoundUserInterface.cs index 3ebcf7cbced..0df6787170a 100644 --- a/Content.Client/Pinpointer/UI/NavMapBeaconBoundUserInterface.cs +++ b/Content.Client/Pinpointer/UI/NavMapBeaconBoundUserInterface.cs @@ -1,5 +1,6 @@ using Content.Shared.Pinpointer; using JetBrains.Annotations; +using Robust.Client.UserInterface; namespace Content.Client.Pinpointer.UI; @@ -16,19 +17,16 @@ public NavMapBeaconBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, protected override void Open() { base.Open(); - _window = new NavMapBeaconWindow(Owner); - _window.OpenCentered(); - _window.OnClose += Close; + _window = this.CreateWindow(); + + if (EntMan.TryGetComponent(Owner, out NavMapBeaconComponent? beacon)) + { + _window.SetEntity(Owner, beacon); + } _window.OnApplyButtonPressed += (label, enabled, color) => { SendMessage(new NavMapBeaconConfigureBuiMessage(label, enabled, color)); }; } - - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - _window?.Dispose(); - } } diff --git a/Content.Client/Pinpointer/UI/NavMapBeaconWindow.xaml.cs b/Content.Client/Pinpointer/UI/NavMapBeaconWindow.xaml.cs index 968fe188f75..b77f1af0472 100644 --- a/Content.Client/Pinpointer/UI/NavMapBeaconWindow.xaml.cs +++ b/Content.Client/Pinpointer/UI/NavMapBeaconWindow.xaml.cs @@ -10,38 +10,37 @@ namespace Content.Client.Pinpointer.UI; [GenerateTypedNameReferences] public sealed partial class NavMapBeaconWindow : FancyWindow { - [Dependency] private readonly IEntityManager _entityManager = default!; - private string? _defaultLabel; private bool _defaultEnabled; private Color _defaultColor; public event Action? OnApplyButtonPressed; - public NavMapBeaconWindow(EntityUid beaconEntity) + public NavMapBeaconWindow() { RobustXamlLoader.Load(this); IoCManager.InjectDependencies(this); - if (!_entityManager.TryGetComponent(beaconEntity, out var navMap)) - return; - _defaultLabel = navMap.Text; - _defaultEnabled = navMap.Enabled; - _defaultColor = navMap.Color; - UpdateVisibleButton(navMap.Enabled); VisibleButton.OnPressed += args => UpdateVisibleButton(args.Button.Pressed); - - LabelLineEdit.Text = navMap.Text ?? string.Empty; LabelLineEdit.OnTextChanged += OnTextChanged; - - ColorSelector.Color = navMap.Color; ColorSelector.OnColorChanged += _ => TryEnableApplyButton(); TryEnableApplyButton(); ApplyButton.OnPressed += OnApplyPressed; } + public void SetEntity(EntityUid uid, NavMapBeaconComponent navMap) + { + _defaultLabel = navMap.Text; + _defaultEnabled = navMap.Enabled; + _defaultColor = navMap.Color; + + UpdateVisibleButton(navMap.Enabled); + LabelLineEdit.Text = navMap.Text ?? string.Empty; + ColorSelector.Color = navMap.Color; + } + private void UpdateVisibleButton(bool value) { VisibleButton.Pressed = value; diff --git a/Content.Client/Pinpointer/UI/StationMapBoundUserInterface.cs b/Content.Client/Pinpointer/UI/StationMapBoundUserInterface.cs index 1483e75e732..7417fafede5 100644 --- a/Content.Client/Pinpointer/UI/StationMapBoundUserInterface.cs +++ b/Content.Client/Pinpointer/UI/StationMapBoundUserInterface.cs @@ -1,4 +1,4 @@ -using Robust.Client.GameObjects; +using Robust.Client.UserInterface; namespace Content.Client.Pinpointer.UI; @@ -14,7 +14,6 @@ public StationMapBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, u protected override void Open() { base.Open(); - _window?.Close(); EntityUid? gridUid = null; if (EntMan.TryGetComponent(Owner, out var xform)) @@ -22,14 +21,8 @@ protected override void Open() gridUid = xform.GridUid; } - _window = new StationMapWindow(gridUid, Owner); - _window.OpenCentered(); - _window.OnClose += Close; - } - - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - _window?.Dispose(); + _window = this.CreateWindow(); + _window.Title = EntMan.GetComponent(Owner).EntityName; + _window.Set(gridUid, Owner); } } diff --git a/Content.Client/Pinpointer/UI/StationMapWindow.xaml.cs b/Content.Client/Pinpointer/UI/StationMapWindow.xaml.cs index 1b01fe4e304..7cbb8b7d0db 100644 --- a/Content.Client/Pinpointer/UI/StationMapWindow.xaml.cs +++ b/Content.Client/Pinpointer/UI/StationMapWindow.xaml.cs @@ -9,19 +9,18 @@ namespace Content.Client.Pinpointer.UI; [GenerateTypedNameReferences] public sealed partial class StationMapWindow : FancyWindow { - public StationMapWindow(EntityUid? mapUid, EntityUid? trackedEntity) + public StationMapWindow() { RobustXamlLoader.Load(this); + } + + public void Set(EntityUid? mapUid, EntityUid? trackedEntity) + { NavMapScreen.MapUid = mapUid; if (trackedEntity != null) NavMapScreen.TrackedCoordinates.Add(new EntityCoordinates(trackedEntity.Value, Vector2.Zero), (true, Color.Cyan)); - if (IoCManager.Resolve().TryGetComponent(mapUid, out var metadata)) - { - Title = metadata.EntityName; - } - NavMapScreen.ForceNavMapUpdate(); } } diff --git a/Content.Client/Pinpointer/UI/UntrackedMapBoundUserInterface.cs b/Content.Client/Pinpointer/UI/UntrackedMapBoundUserInterface.cs index 57965b030a2..a3ca6f65da2 100644 --- a/Content.Client/Pinpointer/UI/UntrackedMapBoundUserInterface.cs +++ b/Content.Client/Pinpointer/UI/UntrackedMapBoundUserInterface.cs @@ -1,4 +1,4 @@ -using Robust.Client.GameObjects; +using Robust.Client.UserInterface; namespace Content.Client.Pinpointer.UI; @@ -14,22 +14,15 @@ public UntrackedStationMapBoundUserInterface(EntityUid owner, Enum uiKey) : base protected override void Open() { base.Open(); - _window?.Close(); EntityUid? gridUid = null; + // TODO: What this just looks like it's been copy-pasted wholesale from StationMapBoundUserInterface? if (EntMan.TryGetComponent(Owner, out var xform)) { gridUid = xform.GridUid; } - _window = new StationMapWindow(gridUid, null); - _window.OpenCentered(); - _window.OnClose += Close; - } - - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - _window?.Dispose(); + _window = this.CreateWindow(); + _window.Set(gridUid, Owner); } } diff --git a/Content.Client/Power/APC/ApcBoundUserInterface.cs b/Content.Client/Power/APC/ApcBoundUserInterface.cs index fbcbf011569..759a5949ba6 100644 --- a/Content.Client/Power/APC/ApcBoundUserInterface.cs +++ b/Content.Client/Power/APC/ApcBoundUserInterface.cs @@ -2,6 +2,7 @@ using Content.Shared.APC; using JetBrains.Annotations; using Robust.Client.GameObjects; +using Robust.Client.UserInterface; namespace Content.Client.Power.APC { @@ -19,9 +20,8 @@ protected override void Open() { base.Open(); - _menu = new ApcMenu(this); - _menu.OnClose += Close; - _menu.OpenCentered(); + _menu = this.CreateWindow(); + _menu.OnBreaker += BreakerPressed; } protected override void UpdateState(BoundUserInterfaceState state) @@ -36,15 +36,5 @@ public void BreakerPressed() { SendMessage(new ApcToggleMainBreakerMessage()); } - - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - - if (disposing) - { - _menu?.Dispose(); - } - } } } diff --git a/Content.Client/Power/APC/UI/ApcMenu.xaml.cs b/Content.Client/Power/APC/UI/ApcMenu.xaml.cs index dbf68ea07b0..2f61ea63a86 100644 --- a/Content.Client/Power/APC/UI/ApcMenu.xaml.cs +++ b/Content.Client/Power/APC/UI/ApcMenu.xaml.cs @@ -17,13 +17,19 @@ namespace Content.Client.Power.APC.UI [GenerateTypedNameReferences] public sealed partial class ApcMenu : FancyWindow { - public ApcMenu(ApcBoundUserInterface owner) + public event Action? OnBreaker; + + public ApcMenu() { IoCManager.InjectDependencies(this); RobustXamlLoader.Load(this); - EntityView.SetEntity(owner.Owner); - BreakerButton.OnPressed += _ => owner.BreakerPressed(); + BreakerButton.OnPressed += _ => OnBreaker?.Invoke(); + } + + public void SetEntity(EntityUid entity) + { + EntityView.SetEntity(entity); } public void UpdateState(BoundUserInterfaceState state) diff --git a/Content.Client/Power/Generator/GeneratorWindow.xaml.cs b/Content.Client/Power/Generator/GeneratorWindow.xaml.cs index bd5b75de1da..e975e5d466e 100644 --- a/Content.Client/Power/Generator/GeneratorWindow.xaml.cs +++ b/Content.Client/Power/Generator/GeneratorWindow.xaml.cs @@ -9,35 +9,39 @@ namespace Content.Client.Power.Generator; [GenerateTypedNameReferences] public sealed partial class GeneratorWindow : FancyWindow { - private readonly EntityUid _entity; - [Dependency] private readonly IEntityManager _entityManager = default!; [Dependency] private readonly ILocalizationManager _loc = default!; - private readonly SharedPowerSwitchableSystem _switchable; - private readonly FuelGeneratorComponent? _component; - private PortableGeneratorComponentBuiState? _lastState; + private EntityUid _entity; + + public float? MaximumPower; + + public event Action? OnPower; + public event Action? OnState; + public event Action? OnSwitchOutput; + public event Action? OnEjectFuel; - public GeneratorWindow(PortableGeneratorBoundUserInterface bui, EntityUid entity) + public GeneratorWindow() { - _entity = entity; RobustXamlLoader.Load(this); IoCManager.InjectDependencies(this); - _entityManager.TryGetComponent(entity, out _component); - _switchable = _entityManager.System(); - - EntityView.SetEntity(entity); TargetPower.IsValid += IsValid; TargetPower.ValueChanged += (args) => { - bui.SetTargetPower(args.Value); + OnPower?.Invoke(args.Value); }; - StartButton.OnPressed += _ => bui.Start(); - StopButton.OnPressed += _ => bui.Stop(); - OutputSwitchButton.OnPressed += _ => bui.SwitchOutput(); - FuelEject.OnPressed += _ => bui.EjectFuel(); + StartButton.OnPressed += _ => OnState?.Invoke(true); + StopButton.OnPressed += _ => OnState?.Invoke(false); + OutputSwitchButton.OnPressed += _ => OnSwitchOutput?.Invoke(); + FuelEject.OnPressed += _ => OnEjectFuel?.Invoke(); + } + + public void SetEntity(EntityUid entity) + { + _entity = entity; + EntityView.SetEntity(entity); } private bool IsValid(int arg) @@ -45,7 +49,7 @@ private bool IsValid(int arg) if (arg < 0) return false; - if (arg > (_lastState?.MaximumPower / 1000.0f ?? 0)) + if (arg > (MaximumPower / 1000.0f ?? 0)) return false; return true; @@ -53,16 +57,17 @@ private bool IsValid(int arg) public void Update(PortableGeneratorComponentBuiState state) { - if (_component == null) + MaximumPower = state.MaximumPower; + + if (!_entityManager.TryGetComponent(_entity, out FuelGeneratorComponent? component)) return; - _lastState = state; if (!TargetPower.LineEditControl.HasKeyboardFocus()) TargetPower.OverrideValue((int)(state.TargetPower / 1000.0f)); - var efficiency = SharedGeneratorSystem.CalcFuelEfficiency(state.TargetPower, state.OptimalPower, _component); + var efficiency = SharedGeneratorSystem.CalcFuelEfficiency(state.TargetPower, state.OptimalPower, component); Efficiency.Text = efficiency.ToString("P1"); - var burnRate = _component.OptimalBurnRate / efficiency; + var burnRate = component.OptimalBurnRate / efficiency; var left = state.RemainingFuel / burnRate; Eta.Text = Loc.GetString( @@ -102,14 +107,15 @@ public void Update(PortableGeneratorComponentBuiState state) } var canSwitch = _entityManager.TryGetComponent(_entity, out PowerSwitchableComponent? switchable); + var switcher = _entityManager.System(); OutputSwitchLabel.Visible = canSwitch; OutputSwitchButton.Visible = canSwitch; if (switchable != null) { - var voltage = _switchable.VoltageString(_switchable.GetVoltage(_entity, switchable)); + var voltage = switcher.VoltageString(switcher.GetVoltage(_entity, switchable)); OutputSwitchLabel.Text = Loc.GetString("portable-generator-ui-current-output", ("voltage", voltage)); - var nextVoltage = _switchable.VoltageString(_switchable.GetNextVoltage(_entity, switchable)); + var nextVoltage = switcher.VoltageString(switcher.GetNextVoltage(_entity, switchable)); OutputSwitchButton.Text = Loc.GetString("power-switchable-switch-voltage", ("voltage", nextVoltage)); OutputSwitchButton.Disabled = state.On; } diff --git a/Content.Client/Power/Generator/PortableGeneratorBoundUserInterface.cs b/Content.Client/Power/Generator/PortableGeneratorBoundUserInterface.cs index 30679d71fd6..550e1041b62 100644 --- a/Content.Client/Power/Generator/PortableGeneratorBoundUserInterface.cs +++ b/Content.Client/Power/Generator/PortableGeneratorBoundUserInterface.cs @@ -1,6 +1,7 @@ using Content.Shared.Power.Generator; using JetBrains.Annotations; using Robust.Client.GameObjects; +using Robust.Client.UserInterface; namespace Content.Client.Power.Generator; @@ -16,10 +17,25 @@ public PortableGeneratorBoundUserInterface(EntityUid owner, Enum uiKey) : base(o protected override void Open() { base.Open(); - _window = new GeneratorWindow(this, Owner); + _window = this.CreateWindow(); + _window.SetEntity(Owner); + _window.OnState += args => + { + if (args) + { + Start(); + } + else + { + Stop(); + } + }; + + _window.OnPower += SetTargetPower; + _window.OnEjectFuel += EjectFuel; + _window.OnSwitchOutput += SwitchOutput; _window.OpenCenteredLeft(); - _window.OnClose += Close; } protected override void UpdateState(BoundUserInterfaceState state) @@ -30,11 +46,6 @@ protected override void UpdateState(BoundUserInterfaceState state) _window?.Update(msg); } - protected override void Dispose(bool disposing) - { - _window?.Dispose(); - } - public void SetTargetPower(int target) { SendMessage(new PortableGeneratorSetTargetPowerMessage(target)); diff --git a/Content.Client/Power/PowerMonitoringConsoleBoundUserInterface.cs b/Content.Client/Power/PowerMonitoringConsoleBoundUserInterface.cs index dc1dcd03ef1..cbc343c06c6 100644 --- a/Content.Client/Power/PowerMonitoringConsoleBoundUserInterface.cs +++ b/Content.Client/Power/PowerMonitoringConsoleBoundUserInterface.cs @@ -1,4 +1,5 @@ using Content.Shared.Power; +using Robust.Client.UserInterface; namespace Content.Client.Power; @@ -11,9 +12,9 @@ public PowerMonitoringConsoleBoundUserInterface(EntityUid owner, Enum uiKey) : b protected override void Open() { - _menu = new PowerMonitoringWindow(this, Owner); - _menu.OpenCentered(); - _menu.OnClose += Close; + _menu = this.CreateWindow(); + _menu.SetEntity(Owner); + _menu.SendPowerMonitoringConsoleMessageAction += SendPowerMonitoringConsoleMessage; } protected override void UpdateState(BoundUserInterfaceState state) @@ -22,9 +23,6 @@ protected override void UpdateState(BoundUserInterfaceState state) var castState = (PowerMonitoringConsoleBoundInterfaceState) state; - if (castState == null) - return; - EntMan.TryGetComponent(Owner, out var xform); _menu?.ShowEntites (castState.TotalSources, @@ -40,13 +38,4 @@ public void SendPowerMonitoringConsoleMessage(NetEntity? netEntity, PowerMonitor { SendMessage(new PowerMonitoringConsoleMessage(netEntity, group)); } - - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - if (!disposing) - return; - - _menu?.Dispose(); - } } diff --git a/Content.Client/Power/PowerMonitoringWindow.xaml.Widgets.cs b/Content.Client/Power/PowerMonitoringWindow.xaml.Widgets.cs index 74752ddc534..d9952992070 100644 --- a/Content.Client/Power/PowerMonitoringWindow.xaml.Widgets.cs +++ b/Content.Client/Power/PowerMonitoringWindow.xaml.Widgets.cs @@ -32,7 +32,7 @@ private void UpdateWindowConsoleEntry if (windowEntry == null) return; - // Update sources and loads + // Update sources and loads UpdateEntrySourcesOrLoads(masterContainer, windowEntry.SourcesContainer, focusSources, _sourceIcon); UpdateEntrySourcesOrLoads(masterContainer, windowEntry.LoadsContainer, focusLoads, _loadIconPath); @@ -134,7 +134,7 @@ private void UpdateEntrySourcesOrLoads(BoxContainer masterContainer, BoxContaine subEntry.Button.OnButtonUp += args => { ButtonAction(subEntry, masterContainer); }; } - if (!_entManager.TryGetComponent(_owner, out var console)) + if (!_entManager.TryGetComponent(Entity, out var console)) return; // Update all children @@ -379,7 +379,7 @@ public PowerMonitoringWindowEntry(PowerMonitoringConsoleEntry entry) : base(entr AddChild(MainContainer); - // Grid container to hold the list of sources when selected + // Grid container to hold the list of sources when selected SourcesContainer = new BoxContainer() { Orientation = LayoutOrientation.Vertical, diff --git a/Content.Client/Power/PowerMonitoringWindow.xaml.cs b/Content.Client/Power/PowerMonitoringWindow.xaml.cs index 81fe1f4d047..e3043252486 100644 --- a/Content.Client/Power/PowerMonitoringWindow.xaml.cs +++ b/Content.Client/Power/PowerMonitoringWindow.xaml.cs @@ -15,13 +15,12 @@ namespace Content.Client.Power; [GenerateTypedNameReferences] public sealed partial class PowerMonitoringWindow : FancyWindow { - private readonly IEntityManager _entManager; + [Dependency] private IEntityManager _entManager = default!; private readonly SpriteSystem _spriteSystem; - private readonly IGameTiming _gameTiming; + [Dependency] private IGameTiming _gameTiming = default!; private const float BlinkFrequency = 1f; - private EntityUid? _owner; private NetEntity? _focusEntity; public event Action? SendPowerMonitoringConsoleMessageAction; @@ -34,31 +33,56 @@ public sealed partial class PowerMonitoringWindow : FancyWindow { PowerMonitoringConsoleGroup.APC, (new SpriteSpecifier.Texture(new ResPath("/Textures/Interface/NavMap/beveled_triangle.png")), Color.LimeGreen) }, }; - public PowerMonitoringWindow(PowerMonitoringConsoleBoundUserInterface userInterface, EntityUid? owner) + public EntityUid Entity; + + public PowerMonitoringWindow() { RobustXamlLoader.Load(this); - _entManager = IoCManager.Resolve(); - _gameTiming = IoCManager.Resolve(); + IoCManager.InjectDependencies(this); _spriteSystem = _entManager.System(); - _owner = owner; + + // Set trackable entity selected action + NavMap.TrackedEntitySelectedAction += SetTrackedEntityFromNavMap; + + // Update nav map + NavMap.ForceNavMapUpdate(); + + // Set UI tab titles + MasterTabContainer.SetTabTitle(0, Loc.GetString("power-monitoring-window-label-sources")); + MasterTabContainer.SetTabTitle(1, Loc.GetString("power-monitoring-window-label-smes")); + MasterTabContainer.SetTabTitle(2, Loc.GetString("power-monitoring-window-label-substation")); + MasterTabContainer.SetTabTitle(3, Loc.GetString("power-monitoring-window-label-apc")); + + // Track when the MasterTabContainer changes its tab + MasterTabContainer.OnTabChanged += OnTabChanged; + + // Set UI toggles + ShowHVCable.OnToggled += _ => OnShowCableToggled(PowerMonitoringConsoleLineGroup.HighVoltage); + ShowMVCable.OnToggled += _ => OnShowCableToggled(PowerMonitoringConsoleLineGroup.MediumVoltage); + ShowLVCable.OnToggled += _ => OnShowCableToggled(PowerMonitoringConsoleLineGroup.Apc); + } + + public void SetEntity(EntityUid uid) + { + Entity = uid; // Pass owner to nav map - NavMap.Owner = _owner; + NavMap.Owner = uid; // Set nav map grid uid var stationName = Loc.GetString("power-monitoring-window-unknown-location"); - if (_entManager.TryGetComponent(owner, out var xform)) + if (_entManager.TryGetComponent(uid, out var xform)) { NavMap.MapUid = xform.GridUid; - // Assign station name + // Assign station name if (_entManager.TryGetComponent(xform.GridUid, out var stationMetaData)) stationName = stationMetaData.EntityName; var msg = new FormattedMessage(); - msg.AddMarkup(Loc.GetString("power-monitoring-window-station-name", ("stationName", stationName))); + msg.AddMarkupOrThrow(Loc.GetString("power-monitoring-window-station-name", ("stationName", stationName))); StationName.SetMessage(msg); } @@ -68,29 +92,6 @@ public PowerMonitoringWindow(PowerMonitoringConsoleBoundUserInterface userInterf StationName.SetMessage(stationName); NavMap.Visible = false; } - - // Set trackable entity selected action - NavMap.TrackedEntitySelectedAction += SetTrackedEntityFromNavMap; - - // Update nav map - NavMap.ForceNavMapUpdate(); - - // Set UI tab titles - MasterTabContainer.SetTabTitle(0, Loc.GetString("power-monitoring-window-label-sources")); - MasterTabContainer.SetTabTitle(1, Loc.GetString("power-monitoring-window-label-smes")); - MasterTabContainer.SetTabTitle(2, Loc.GetString("power-monitoring-window-label-substation")); - MasterTabContainer.SetTabTitle(3, Loc.GetString("power-monitoring-window-label-apc")); - - // Track when the MasterTabContainer changes its tab - MasterTabContainer.OnTabChanged += OnTabChanged; - - // Set UI toggles - ShowHVCable.OnToggled += _ => OnShowCableToggled(PowerMonitoringConsoleLineGroup.HighVoltage); - ShowMVCable.OnToggled += _ => OnShowCableToggled(PowerMonitoringConsoleLineGroup.MediumVoltage); - ShowLVCable.OnToggled += _ => OnShowCableToggled(PowerMonitoringConsoleLineGroup.Apc); - - // Set power monitoring message action - SendPowerMonitoringConsoleMessageAction += userInterface.SendPowerMonitoringConsoleMessage; } private void OnTabChanged(int tab) @@ -113,10 +114,7 @@ public void ShowEntites PowerMonitoringConsoleEntry[] focusLoads, EntityCoordinates? monitorCoords) { - if (_owner == null) - return; - - if (!_entManager.TryGetComponent(_owner.Value, out var console)) + if (!_entManager.TryGetComponent(Entity, out var console)) return; // Update power status text @@ -161,13 +159,13 @@ public void ShowEntites } // Show monitor location - var mon = _entManager.GetNetEntity(_owner); + var mon = _entManager.GetNetEntity(Entity); - if (monitorCoords != null && mon != null) + if (monitorCoords != null && mon.IsValid()) { var texture = _spriteSystem.Frame0(new SpriteSpecifier.Texture(new ResPath("/Textures/Interface/NavMap/beveled_circle.png"))); var blip = new NavMapBlip(monitorCoords.Value, texture, Color.Cyan, true, false); - NavMap.TrackedEntities[mon.Value] = blip; + NavMap.TrackedEntities[mon] = blip; } // If the entry group doesn't match the current tab, the data is out dated, do not use it @@ -239,7 +237,7 @@ private void SetTrackedEntityFromNavMap(NetEntity? netEntity) if (netEntity == null) return; - if (!_entManager.TryGetComponent(_owner, out var console)) + if (!_entManager.TryGetComponent(Entity, out var console)) return; if (!console.PowerMonitoringDeviceMetaData.TryGetValue(netEntity.Value, out var metaData)) @@ -266,7 +264,7 @@ protected override void FrameUpdate(FrameEventArgs args) { AutoScrollToFocus(); - // Warning sign pulse + // Warning sign pulse var lit = _gameTiming.RealTime.TotalSeconds % BlinkFrequency > BlinkFrequency / 2f; SystemWarningPanel.Modulate = lit ? Color.White : new Color(178, 178, 178); } diff --git a/Content.Client/RCD/RCDMenu.xaml.cs b/Content.Client/RCD/RCDMenu.xaml.cs index 3eb0397a690..aefb3191812 100644 --- a/Content.Client/RCD/RCDMenu.xaml.cs +++ b/Content.Client/RCD/RCDMenu.xaml.cs @@ -20,31 +20,36 @@ public sealed partial class RCDMenu : RadialMenu [Dependency] private readonly IPrototypeManager _protoManager = default!; [Dependency] private readonly IPlayerManager _playerManager = default!; - private readonly SpriteSystem _spriteSystem; - private readonly SharedPopupSystem _popup; + private SharedPopupSystem _popup; + private SpriteSystem _sprites; public event Action>? SendRCDSystemMessageAction; private EntityUid _owner; - public RCDMenu(EntityUid owner, RCDMenuBoundUserInterface bui) + public RCDMenu() { IoCManager.InjectDependencies(this); RobustXamlLoader.Load(this); - _spriteSystem = _entManager.System(); _popup = _entManager.System(); + _sprites = _entManager.System(); - _owner = owner; + OnChildAdded += AddRCDMenuButtonOnClickActions; + } + + public void SetEntity(EntityUid uid) + { + _owner = uid; + } + public void Refresh() + { // Find the main radial container var main = FindControl("Main"); - if (main == null) - return; - // Populate secondary radial containers - if (!_entManager.TryGetComponent(owner, out var rcd)) + if (!_entManager.TryGetComponent(_owner, out var rcd)) return; foreach (var protoId in rcd.AvailablePrototypes) @@ -56,10 +61,6 @@ public RCDMenu(EntityUid owner, RCDMenuBoundUserInterface bui) continue; var parent = FindControl(proto.Category); - - if (parent == null) - continue; - var tooltip = Loc.GetString(proto.SetName); if ((proto.Mode == RcdMode.ConstructTile || proto.Mode == RcdMode.ConstructObject) && @@ -84,7 +85,7 @@ public RCDMenu(EntityUid owner, RCDMenuBoundUserInterface bui) { VerticalAlignment = VAlignment.Center, HorizontalAlignment = HAlignment.Center, - Texture = _spriteSystem.Frame0(proto.Sprite), + Texture = _sprites.Frame0(proto.Sprite), TextureScale = new Vector2(2f, 2f), }; @@ -112,11 +113,9 @@ public RCDMenu(EntityUid owner, RCDMenuBoundUserInterface bui) // Set up menu actions foreach (var child in Children) + { AddRCDMenuButtonOnClickActions(child); - - OnChildAdded += AddRCDMenuButtonOnClickActions; - - SendRCDSystemMessageAction += bui.SendRCDSystemMessage; + } } private static string OopsConcat(string a, string b) diff --git a/Content.Client/RCD/RCDMenuBoundUserInterface.cs b/Content.Client/RCD/RCDMenuBoundUserInterface.cs index a37dbcecf8c..1dd03626ae6 100644 --- a/Content.Client/RCD/RCDMenuBoundUserInterface.cs +++ b/Content.Client/RCD/RCDMenuBoundUserInterface.cs @@ -3,6 +3,7 @@ using JetBrains.Annotations; using Robust.Client.Graphics; using Robust.Client.Input; +using Robust.Client.UserInterface; using Robust.Shared.Prototypes; namespace Content.Client.RCD; @@ -24,8 +25,9 @@ protected override void Open() { base.Open(); - _menu = new(Owner, this); - _menu.OnClose += Close; + _menu = this.CreateWindow(); + _menu.SetEntity(Owner); + _menu.SendRCDSystemMessageAction += SendRCDSystemMessage; // Open the menu, centered on the mouse var vpSize = _displayManager.ScreenSize; @@ -34,16 +36,8 @@ protected override void Open() public void SendRCDSystemMessage(ProtoId protoId) { - // A predicted message cannot be used here as the RCD UI is closed immediately + // A predicted message cannot be used here as the RCD UI is closed immediately // after this message is sent, which will stop the server from receiving it SendMessage(new RCDSystemMessage(protoId)); } - - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - if (!disposing) return; - - _menu?.Dispose(); - } } diff --git a/Content.Client/Radio/Ui/IntercomBoundUserInterface.cs b/Content.Client/Radio/Ui/IntercomBoundUserInterface.cs index 7b3e39aa084..401e7edd44a 100644 --- a/Content.Client/Radio/Ui/IntercomBoundUserInterface.cs +++ b/Content.Client/Radio/Ui/IntercomBoundUserInterface.cs @@ -1,6 +1,8 @@ using Content.Shared.Radio; using Content.Shared.Radio.Components; using JetBrains.Annotations; +using Robust.Client.GameObjects; +using Robust.Client.UserInterface; namespace Content.Client.Radio.Ui; @@ -19,9 +21,12 @@ protected override void Open() { base.Open(); - var comp = EntMan.GetComponent(Owner); + _menu = this.CreateWindow(); - _menu = new((Owner, comp)); + if (EntMan.TryGetComponent(Owner, out IntercomComponent? intercom)) + { + _menu.Update((Owner, intercom)); + } _menu.OnMicPressed += enabled => { @@ -35,17 +40,6 @@ protected override void Open() { SendMessage(new SelectIntercomChannelMessage(channel)); }; - - _menu.OnClose += Close; - _menu.OpenCentered(); - } - - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - if (!disposing) - return; - _menu?.Close(); } public void Update(Entity ent) diff --git a/Content.Client/Radio/Ui/IntercomMenu.xaml.cs b/Content.Client/Radio/Ui/IntercomMenu.xaml.cs index 2e08913051c..20d2e4a3e54 100644 --- a/Content.Client/Radio/Ui/IntercomMenu.xaml.cs +++ b/Content.Client/Radio/Ui/IntercomMenu.xaml.cs @@ -18,15 +18,13 @@ public sealed partial class IntercomMenu : FancyWindow private readonly List _channels = new(); - public IntercomMenu(Entity entity) + public IntercomMenu() { RobustXamlLoader.Load(this); IoCManager.InjectDependencies(this); MicButton.OnPressed += args => OnMicPressed?.Invoke(args.Button.Pressed); SpeakerButton.OnPressed += args => OnSpeakerPressed?.Invoke(args.Button.Pressed); - - Update(entity); } public void Update(Entity entity) diff --git a/Content.Client/Research/UI/DiskConsoleBoundUserInterface.cs b/Content.Client/Research/UI/DiskConsoleBoundUserInterface.cs index c14a8c5bd05..9641adb5b2d 100644 --- a/Content.Client/Research/UI/DiskConsoleBoundUserInterface.cs +++ b/Content.Client/Research/UI/DiskConsoleBoundUserInterface.cs @@ -1,5 +1,7 @@ using Content.Shared.Research; using Content.Shared.Research.Components; +using Robust.Client.GameObjects; +using Robust.Client.UserInterface; namespace Content.Client.Research.UI { @@ -16,10 +18,7 @@ protected override void Open() { base.Open(); - _menu = new(); - - _menu.OnClose += Close; - _menu.OpenCentered(); + _menu = this.CreateWindow(); _menu.OnServerButtonPressed += () => { @@ -31,14 +30,6 @@ protected override void Open() }; } - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - if (!disposing) - return; - _menu?.Close(); - } - protected override void UpdateState(BoundUserInterfaceState state) { base.UpdateState(state); diff --git a/Content.Client/Research/UI/ResearchClientBoundUserInterface.cs b/Content.Client/Research/UI/ResearchClientBoundUserInterface.cs index a0a2b58e889..288445e4dea 100644 --- a/Content.Client/Research/UI/ResearchClientBoundUserInterface.cs +++ b/Content.Client/Research/UI/ResearchClientBoundUserInterface.cs @@ -1,4 +1,6 @@ using Content.Shared.Research.Components; +using Robust.Client.GameObjects; +using Robust.Client.UserInterface; namespace Content.Client.Research.UI { @@ -15,10 +17,9 @@ public ResearchClientBoundUserInterface(EntityUid owner, Enum uiKey) : base(owne protected override void Open() { base.Open(); - - _menu = new ResearchClientServerSelectionMenu(this); - _menu.OnClose += Close; - _menu.OpenCentered(); + _menu = this.CreateWindow(); + _menu.OnServerSelected += SelectServer; + _menu.OnServerDeselected += DeselectServer; } public void SelectServer(int serverId) @@ -37,12 +38,5 @@ protected override void UpdateState(BoundUserInterfaceState state) if (state is not ResearchClientBoundInterfaceState rState) return; _menu?.Populate(rState.ServerCount, rState.ServerNames, rState.ServerIds, rState.SelectedServerId); } - - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - if (!disposing) return; - _menu?.Dispose(); - } } } diff --git a/Content.Client/Research/UI/ResearchClientServerSelectionMenu.xaml.cs b/Content.Client/Research/UI/ResearchClientServerSelectionMenu.xaml.cs index ceaa965e59f..d10f8b39f48 100644 --- a/Content.Client/Research/UI/ResearchClientServerSelectionMenu.xaml.cs +++ b/Content.Client/Research/UI/ResearchClientServerSelectionMenu.xaml.cs @@ -13,27 +13,26 @@ public sealed partial class ResearchClientServerSelectionMenu : DefaultWindow private int[] _serverIds = Array.Empty(); private int _selectedServerId = -1; - private ResearchClientBoundUserInterface Owner { get; } + public event Action? OnServerSelected; + public event Action? OnServerDeselected; - public ResearchClientServerSelectionMenu(ResearchClientBoundUserInterface owner) + public ResearchClientServerSelectionMenu() { RobustXamlLoader.Load(this); IoCManager.InjectDependencies(this); - Owner = owner; - Servers.OnItemSelected += OnItemSelected; Servers.OnItemDeselected += OnItemDeselected; } public void OnItemSelected(ItemList.ItemListSelectedEventArgs itemListSelectedEventArgs) { - Owner.SelectServer(_serverIds[itemListSelectedEventArgs.ItemIndex]); + OnServerSelected?.Invoke(_serverIds[itemListSelectedEventArgs.ItemIndex]); } public void OnItemDeselected(ItemList.ItemListDeselectedEventArgs itemListDeselectedEventArgs) { - Owner.DeselectServer(); + OnServerDeselected?.Invoke(); } public void Populate(int serverCount, string[] serverNames, int[] serverIds, int selectedServerId) diff --git a/Content.Client/Research/UI/ResearchConsoleBoundUserInterface.cs b/Content.Client/Research/UI/ResearchConsoleBoundUserInterface.cs index 2a9782045b8..2895ada61fb 100644 --- a/Content.Client/Research/UI/ResearchConsoleBoundUserInterface.cs +++ b/Content.Client/Research/UI/ResearchConsoleBoundUserInterface.cs @@ -1,5 +1,8 @@ using Content.Shared.Research.Components; +using Content.Shared.Research.Prototypes; using JetBrains.Annotations; +using Robust.Client.UserInterface; +using Robust.Shared.Prototypes; namespace Content.Client.Research.UI; @@ -19,7 +22,8 @@ protected override void Open() var owner = Owner; - _consoleMenu = new ResearchConsoleMenu(owner); + _consoleMenu = this.CreateWindow(); + _consoleMenu.SetEntity(owner); _consoleMenu.OnTechnologyCardPressed += id => { @@ -30,10 +34,20 @@ protected override void Open() { SendMessage(new ConsoleServerSelectionMessage()); }; + } + + public override void OnProtoReload(PrototypesReloadedEventArgs args) + { + base.OnProtoReload(args); + + if (!args.WasModified()) + return; - _consoleMenu.OnClose += Close; + if (State is not ResearchConsoleBoundInterfaceState rState) + return; - _consoleMenu.OpenCentered(); + _consoleMenu?.UpdatePanels(rState); + _consoleMenu?.UpdateInformationPanel(rState); } protected override void UpdateState(BoundUserInterfaceState state) @@ -45,12 +59,4 @@ protected override void UpdateState(BoundUserInterfaceState state) _consoleMenu?.UpdatePanels(castState); _consoleMenu?.UpdateInformationPanel(castState); } - - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - if (!disposing) - return; - _consoleMenu?.Dispose(); - } } diff --git a/Content.Client/Research/UI/ResearchConsoleMenu.xaml.cs b/Content.Client/Research/UI/ResearchConsoleMenu.xaml.cs index 77ebe6740c5..eafbe75fbb9 100644 --- a/Content.Client/Research/UI/ResearchConsoleMenu.xaml.cs +++ b/Content.Client/Research/UI/ResearchConsoleMenu.xaml.cs @@ -25,14 +25,13 @@ public sealed partial class ResearchConsoleMenu : FancyWindow [Dependency] private readonly IEntityManager _entity = default!; [Dependency] private readonly IPrototypeManager _prototype = default!; [Dependency] private readonly IPlayerManager _player = default!; - private readonly TechnologyDatabaseComponent? _technologyDatabase; private readonly ResearchSystem _research; private readonly SpriteSystem _sprite; private readonly AccessReaderSystem _accessReader; - public readonly EntityUid Entity; + public EntityUid Entity; - public ResearchConsoleMenu(EntityUid entity) + public ResearchConsoleMenu() { RobustXamlLoader.Load(this); IoCManager.InjectDependencies(this); @@ -40,21 +39,23 @@ public ResearchConsoleMenu(EntityUid entity) _research = _entity.System(); _sprite = _entity.System(); _accessReader = _entity.System(); - Entity = entity; ServerButton.OnPressed += _ => OnServerButtonPressed?.Invoke(); + } - _entity.TryGetComponent(entity, out _technologyDatabase); + public void SetEntity(EntityUid entity) + { + Entity = entity; } - public void UpdatePanels(ResearchConsoleBoundInterfaceState state) + public void UpdatePanels(ResearchConsoleBoundInterfaceState state) { TechnologyCardsContainer.Children.Clear(); var availableTech = _research.GetAvailableTechnologies(Entity); SyncTechnologyList(AvailableCardsContainer, availableTech); - if (_technologyDatabase == null) + if (!_entity.TryGetComponent(Entity, out TechnologyDatabaseComponent? database)) return; // i can't figure out the spacing so here you go @@ -66,7 +67,7 @@ public void UpdatePanels(ResearchConsoleBoundInterfaceState state) var hasAccess = _player.LocalEntity is not { } local || !_entity.TryGetComponent(Entity, out var access) || _accessReader.IsAllowed(local, Entity, access); - foreach (var techId in _technologyDatabase.CurrentTechnologyCards) + foreach (var techId in database.CurrentTechnologyCards) { var tech = _prototype.Index(techId); var cardControl = new TechnologyCardControl(tech, _prototype, _sprite, _research.GetTechnologyDescription(tech, includeTier: false), state.Points, hasAccess); @@ -74,7 +75,7 @@ public void UpdatePanels(ResearchConsoleBoundInterfaceState state) TechnologyCardsContainer.AddChild(cardControl); } - var unlockedTech = _technologyDatabase.UnlockedTechnologies.Select(x => _prototype.Index(x)); + var unlockedTech = database.UnlockedTechnologies.Select(x => _prototype.Index(x)); SyncTechnologyList(UnlockedCardsContainer, unlockedTech); } @@ -85,14 +86,14 @@ public void UpdateInformationPanel(ResearchConsoleBoundInterfaceState state) ("points", state.Points))); ResearchAmountLabel.SetMessage(amountMsg); - if (_technologyDatabase == null) + if (!_entity.TryGetComponent(Entity, out TechnologyDatabaseComponent? database)) return; var disciplineText = Loc.GetString("research-discipline-none"); var disciplineColor = Color.Gray; - if (_technologyDatabase.MainDiscipline != null) + if (database.MainDiscipline != null) { - var discipline = _prototype.Index(_technologyDatabase.MainDiscipline); + var discipline = _prototype.Index(database.MainDiscipline); disciplineText = Loc.GetString(discipline.Name); disciplineColor = discipline.Color; } @@ -103,10 +104,10 @@ public void UpdateInformationPanel(ResearchConsoleBoundInterfaceState state) MainDisciplineLabel.SetMessage(msg); TierDisplayContainer.Children.Clear(); - foreach (var disciplineId in _technologyDatabase.SupportedDisciplines) + foreach (var disciplineId in database.SupportedDisciplines) { var discipline = _prototype.Index(disciplineId); - var tier = _research.GetHighestDisciplineTier(_technologyDatabase, discipline); + var tier = _research.GetHighestDisciplineTier(database, discipline); // don't show tiers with no available tech if (tier == 0) diff --git a/Content.Client/Robotics/UI/RoboticsConsoleBoundUserInterface.cs b/Content.Client/Robotics/UI/RoboticsConsoleBoundUserInterface.cs index 6185979eee6..9a5159880f9 100644 --- a/Content.Client/Robotics/UI/RoboticsConsoleBoundUserInterface.cs +++ b/Content.Client/Robotics/UI/RoboticsConsoleBoundUserInterface.cs @@ -1,5 +1,6 @@ using Content.Shared.Robotics; using Robust.Client.GameObjects; +using Robust.Client.UserInterface; namespace Content.Client.Robotics.UI; @@ -16,7 +17,9 @@ protected override void Open() { base.Open(); - _window = new RoboticsConsoleWindow(Owner); + _window = this.CreateWindow(); + _window.SetEntity(Owner); + _window.OnDisablePressed += address => { SendMessage(new RoboticsConsoleDisableMessage(address)); @@ -25,9 +28,6 @@ protected override void Open() { SendMessage(new RoboticsConsoleDestroyMessage(address)); }; - _window.OnClose += Close; - - _window.OpenCentered(); } protected override void UpdateState(BoundUserInterfaceState state) @@ -37,14 +37,6 @@ protected override void UpdateState(BoundUserInterfaceState state) if (state is not RoboticsConsoleState cast) return; - _window?.UpdateState(cast); - } - - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - - if (disposing) - _window?.Dispose(); + _window.UpdateState(cast); } } diff --git a/Content.Client/Robotics/UI/RoboticsConsoleWindow.xaml.cs b/Content.Client/Robotics/UI/RoboticsConsoleWindow.xaml.cs index fc7b234bccc..87d7e62c392 100644 --- a/Content.Client/Robotics/UI/RoboticsConsoleWindow.xaml.cs +++ b/Content.Client/Robotics/UI/RoboticsConsoleWindow.xaml.cs @@ -23,11 +23,12 @@ public sealed partial class RoboticsConsoleWindow : FancyWindow public Action? OnDisablePressed; public Action? OnDestroyPressed; - private Entity _console; private string? _selected; private Dictionary _cyborgs = new(); - public RoboticsConsoleWindow(EntityUid console) + public EntityUid Entity; + + public RoboticsConsoleWindow() { RobustXamlLoader.Load(this); IoCManager.InjectDependencies(this); @@ -35,9 +36,6 @@ public RoboticsConsoleWindow(EntityUid console) _lock = _entMan.System(); _sprite = _entMan.System(); - _console = (console, _entMan.GetComponent(console), null); - _entMan.TryGetComponent(_console, out _console.Comp2); - Cyborgs.OnItemSelected += args => { if (Cyborgs[args.ItemIndex].Metadata is not string address) @@ -66,6 +64,11 @@ public RoboticsConsoleWindow(EntityUid console) DestroyButton.StyleClasses.Add(StyleBase.ButtonCaution); } + public void SetEntity(EntityUid uid) + { + Entity = uid; + } + public void UpdateState(RoboticsConsoleState state) { _cyborgs = state.Cyborgs; @@ -81,7 +84,7 @@ public void UpdateState(RoboticsConsoleState state) PopulateData(); - var locked = _lock.IsLocked((_console, _console.Comp2)); + var locked = _lock.IsLocked(Entity); DangerZone.Visible = !locked; LockedMessage.Visible = locked; } @@ -135,13 +138,19 @@ private void PopulateData() // how the turntables DisableButton.Disabled = !(data.HasBrain && data.CanDisable); - DestroyButton.Disabled = _timing.CurTime < _console.Comp1.NextDestroy; } protected override void FrameUpdate(FrameEventArgs args) { base.FrameUpdate(args); - DestroyButton.Disabled = _timing.CurTime < _console.Comp1.NextDestroy; + if (_entMan.TryGetComponent(Entity, out RoboticsConsoleComponent? console)) + { + DestroyButton.Disabled = _timing.CurTime < console.NextDestroy; + } + else + { + DestroyButton.Disabled = true; + } } } diff --git a/Content.Client/Salvage/UI/SalvageExpeditionConsoleBoundUserInterface.cs b/Content.Client/Salvage/UI/SalvageExpeditionConsoleBoundUserInterface.cs index 8f1723d1f22..663bde15b0d 100644 --- a/Content.Client/Salvage/UI/SalvageExpeditionConsoleBoundUserInterface.cs +++ b/Content.Client/Salvage/UI/SalvageExpeditionConsoleBoundUserInterface.cs @@ -30,17 +30,9 @@ public SalvageExpeditionConsoleBoundUserInterface(EntityUid owner, Enum uiKey) : protected override void Open() { base.Open(); - _window = new OfferingWindow(); + _window = this.CreateWindow(); _window.Title = Loc.GetString("salvage-expedition-window-title"); - _window.OnClose += Close; - _window?.OpenCenteredLeft(); - } - - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - _window?.Dispose(); - _window = null; + _window.OpenCenteredLeft(); } protected override void UpdateState(BoundUserInterfaceState state) diff --git a/Content.Client/Salvage/UI/SalvageMagnetBoundUserInterface.cs b/Content.Client/Salvage/UI/SalvageMagnetBoundUserInterface.cs index be3ba0e046e..bee8092ea8e 100644 --- a/Content.Client/Salvage/UI/SalvageMagnetBoundUserInterface.cs +++ b/Content.Client/Salvage/UI/SalvageMagnetBoundUserInterface.cs @@ -21,13 +21,9 @@ protected override void Open() { base.Open(); - if (_window is null) - { - _window = new OfferingWindow(); - _window.Title = Loc.GetString("salvage-magnet-window-title"); - _window.OnClose += Close; - _window.OpenCenteredLeft(); - } + _window = this.CreateWindow(); + _window.Title = Loc.GetString("salvage-magnet-window-title"); + _window.OpenCenteredLeft(); } protected override void UpdateState(BoundUserInterfaceState state) @@ -112,15 +108,4 @@ protected override void UpdateState(BoundUserInterfaceState state) _window.AddOption(option); } } - - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - - if (disposing) - { - _window?.Close(); - _window?.Dispose(); - } - } } diff --git a/Content.Client/Shuttles/BUI/IFFConsoleBoundUserInterface.cs b/Content.Client/Shuttles/BUI/IFFConsoleBoundUserInterface.cs index 086369aa264..b8b4fb8a746 100644 --- a/Content.Client/Shuttles/BUI/IFFConsoleBoundUserInterface.cs +++ b/Content.Client/Shuttles/BUI/IFFConsoleBoundUserInterface.cs @@ -3,6 +3,7 @@ using Content.Shared.Shuttles.Events; using JetBrains.Annotations; using Robust.Client.GameObjects; +using Robust.Client.UserInterface; namespace Content.Client.Shuttles.BUI; @@ -20,8 +21,7 @@ protected override void Open() { base.Open(); - _window = new IFFConsoleWindow(); - _window.OnClose += Close; + _window = this.CreateWindow(); _window.ShowIFF += SendIFFMessage; _window.ShowVessel += SendVesselMessage; _window.OpenCenteredLeft(); diff --git a/Content.Client/Shuttles/BUI/RadarConsoleBoundUserInterface.cs b/Content.Client/Shuttles/BUI/RadarConsoleBoundUserInterface.cs index 4bd44a47a8e..f75759b042f 100644 --- a/Content.Client/Shuttles/BUI/RadarConsoleBoundUserInterface.cs +++ b/Content.Client/Shuttles/BUI/RadarConsoleBoundUserInterface.cs @@ -2,6 +2,7 @@ using Content.Shared.Shuttles.BUIStates; using JetBrains.Annotations; using Robust.Client.GameObjects; +using Robust.Client.UserInterface; using RadarConsoleWindow = Content.Client.Shuttles.UI.RadarConsoleWindow; namespace Content.Client.Shuttles.BUI; @@ -20,18 +21,7 @@ protected override void Open() { base.Open(); - _window = new RadarConsoleWindow(); - _window.OnClose += Close; - _window.OpenCentered(); - } - - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - if (disposing) - { - _window?.Dispose(); - } + _window = this.CreateWindow(); } protected override void UpdateState(BoundUserInterfaceState state) diff --git a/Content.Client/Shuttles/BUI/ShuttleConsoleBoundUserInterface.cs b/Content.Client/Shuttles/BUI/ShuttleConsoleBoundUserInterface.cs index af7b6055c80..e677181419e 100644 --- a/Content.Client/Shuttles/BUI/ShuttleConsoleBoundUserInterface.cs +++ b/Content.Client/Shuttles/BUI/ShuttleConsoleBoundUserInterface.cs @@ -2,6 +2,7 @@ using Content.Shared.Shuttles.BUIStates; using Content.Shared.Shuttles.Events; using JetBrains.Annotations; +using Robust.Client.UserInterface; using Robust.Shared.Map; namespace Content.Client.Shuttles.BUI; @@ -19,9 +20,7 @@ public ShuttleConsoleBoundUserInterface(EntityUid owner, Enum uiKey) : base(owne protected override void Open() { base.Open(); - _window = new ShuttleConsoleWindow(); - _window.OpenCentered(); - _window.OnClose += Close; + _window = this.CreateWindow(); _window.RequestFTL += OnFTLRequest; _window.RequestBeaconFTL += OnFTLBeaconRequest; diff --git a/Content.Client/Silicons/Borgs/BorgBoundUserInterface.cs b/Content.Client/Silicons/Borgs/BorgBoundUserInterface.cs index 3cc2a35d795..ed9bf40a481 100644 --- a/Content.Client/Silicons/Borgs/BorgBoundUserInterface.cs +++ b/Content.Client/Silicons/Borgs/BorgBoundUserInterface.cs @@ -1,6 +1,7 @@ using Content.Shared.Silicons.Borgs; using JetBrains.Annotations; using Robust.Client.GameObjects; +using Robust.Client.UserInterface; namespace Content.Client.Silicons.Borgs; @@ -18,9 +19,8 @@ protected override void Open() { base.Open(); - var owner = Owner; - - _menu = new BorgMenu(owner); + _menu = this.CreateWindow(); + _menu.SetEntity(Owner); _menu.BrainButtonPressed += () => { @@ -41,10 +41,6 @@ protected override void Open() { SendMessage(new BorgRemoveModuleBuiMessage(EntMan.GetNetEntity(module))); }; - - _menu.OnClose += Close; - - _menu.OpenCentered(); } protected override void UpdateState(BoundUserInterfaceState state) @@ -55,12 +51,4 @@ protected override void UpdateState(BoundUserInterfaceState state) return; _menu?.UpdateState(msg); } - - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - if (!disposing) - return; - _menu?.Dispose(); - } } diff --git a/Content.Client/Silicons/Borgs/BorgMenu.xaml b/Content.Client/Silicons/Borgs/BorgMenu.xaml index 7d8fd9fe57d..4cc2e41a8fb 100644 --- a/Content.Client/Silicons/Borgs/BorgMenu.xaml +++ b/Content.Client/Silicons/Borgs/BorgMenu.xaml @@ -10,7 +10,7 @@ VerticalExpand="True"> - + diff --git a/Content.Client/Silicons/Borgs/BorgMenu.xaml.cs b/Content.Client/Silicons/Borgs/BorgMenu.xaml.cs index 474a83b4530..f6a861aa057 100644 --- a/Content.Client/Silicons/Borgs/BorgMenu.xaml.cs +++ b/Content.Client/Silicons/Borgs/BorgMenu.xaml.cs @@ -21,25 +21,33 @@ public sealed partial class BorgMenu : FancyWindow public Action? NameChanged; public Action? RemoveModuleButtonPressed; - private readonly BorgChassisComponent? _chassis; - public readonly EntityUid Entity; public float AccumulatedTime; private string _lastValidName; private List _modules = new(); - public BorgMenu(EntityUid entity) + public EntityUid Entity; + + public BorgMenu() { RobustXamlLoader.Load(this); IoCManager.InjectDependencies(this); - Entity = entity; + _lastValidName = NameLineEdit.Text; - if (_entity.TryGetComponent(Entity, out var chassis)) - _chassis = chassis; + EjectBatteryButton.OnPressed += _ => EjectBatteryButtonPressed?.Invoke(); + BrainButton.OnPressed += _ => BrainButtonPressed?.Invoke(); + NameLineEdit.OnTextChanged += OnNameChanged; + NameLineEdit.OnTextEntered += OnNameEntered; + NameLineEdit.OnFocusExit += OnNameFocusExit; + + UpdateBrainButton(); + } + + public void SetEntity(EntityUid entity) + { + Entity = entity; BorgSprite.SetEntity(entity); - ChargeBar.MaxValue = 1f; - ChargeBar.Value = 1f; if (_entity.TryGetComponent(Entity, out var nameIdentifierComponent)) { @@ -55,17 +63,6 @@ public BorgMenu(EntityUid entity) NameIdentifierLabel.Visible = false; NameLineEdit.Text = _entity.GetComponent(Entity).EntityName; } - - _lastValidName = NameLineEdit.Text; - - EjectBatteryButton.OnPressed += _ => EjectBatteryButtonPressed?.Invoke(); - BrainButton.OnPressed += _ => BrainButtonPressed?.Invoke(); - - NameLineEdit.OnTextChanged += OnNameChanged; - NameLineEdit.OnTextEntered += OnNameEntered; - NameLineEdit.OnFocusExit += OnNameFocusExit; - - UpdateBrainButton(); } protected override void FrameUpdate(FrameEventArgs args) @@ -89,7 +86,7 @@ public void UpdateState(BorgBuiState state) private void UpdateBrainButton() { - if (_chassis?.BrainEntity is { } brain) + if (_entity.TryGetComponent(Entity, out BorgChassisComponent? chassis) && chassis.BrainEntity is { } brain) { BrainButton.Text = _entity.GetComponent(brain).EntityName; BrainView.Visible = true; @@ -108,17 +105,17 @@ private void UpdateBrainButton() private void UpdateModulePanel() { - if (_chassis == null) + if (!_entity.TryGetComponent(Entity, out BorgChassisComponent? chassis)) return; ModuleCounter.Text = Loc.GetString("borg-ui-module-counter", - ("actual", _chassis.ModuleCount), - ("max", _chassis.MaxModules)); + ("actual", chassis.ModuleCount), + ("max", chassis.MaxModules)); - if (_chassis.ModuleContainer.Count == _modules.Count) + if (chassis.ModuleContainer.Count == _modules.Count) { var isSame = true; - foreach (var module in _chassis.ModuleContainer.ContainedEntities) + foreach (var module in chassis.ModuleContainer.ContainedEntities) { if (_modules.Contains(module)) continue; @@ -132,7 +129,7 @@ private void UpdateModulePanel() ModuleContainer.Children.Clear(); _modules.Clear(); - foreach (var module in _chassis.ModuleContainer.ContainedEntities) + foreach (var module in chassis.ModuleContainer.ContainedEntities) { var control = new BorgModuleControl(module, _entity); control.RemoveButtonPressed += () => diff --git a/Content.Client/Silicons/Laws/Ui/SiliconLawBoundUserInterface.cs b/Content.Client/Silicons/Laws/Ui/SiliconLawBoundUserInterface.cs index d150735fa11..56216b91847 100644 --- a/Content.Client/Silicons/Laws/Ui/SiliconLawBoundUserInterface.cs +++ b/Content.Client/Silicons/Laws/Ui/SiliconLawBoundUserInterface.cs @@ -2,6 +2,7 @@ using Content.Shared.Silicons.Laws; using Content.Shared.Silicons.Laws.Components; using JetBrains.Annotations; +using Robust.Client.UserInterface; namespace Content.Client.Silicons.Laws.Ui; @@ -22,18 +23,7 @@ protected override void Open() { base.Open(); - _menu = new(); - - _menu.OnClose += Close; - _menu.OpenCentered(); - } - - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - if (!disposing) - return; - _menu?.Close(); + _menu = this.CreateWindow(); } protected override void UpdateState(BoundUserInterfaceState state) diff --git a/Content.Client/SprayPainter/UI/SprayPainterBoundUserInterface.cs b/Content.Client/SprayPainter/UI/SprayPainterBoundUserInterface.cs index e8442d23908..7d6a6cf2a5a 100644 --- a/Content.Client/SprayPainter/UI/SprayPainterBoundUserInterface.cs +++ b/Content.Client/SprayPainter/UI/SprayPainterBoundUserInterface.cs @@ -1,6 +1,6 @@ using Content.Shared.SprayPainter; using Content.Shared.SprayPainter.Components; -using Robust.Client.GameObjects; +using Robust.Client.UserInterface; using Robust.Client.UserInterface.Controls; namespace Content.Client.SprayPainter.UI; @@ -10,9 +10,6 @@ public sealed class SprayPainterBoundUserInterface : BoundUserInterface [ViewVariables] private SprayPainterWindow? _window; - [ViewVariables] - private SprayPainterSystem? _painter; - public SprayPainterBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey) { } @@ -21,27 +18,15 @@ protected override void Open() { base.Open(); - if (!EntMan.TryGetComponent(Owner, out var comp)) - return; - - _window = new SprayPainterWindow(); + _window = this.CreateWindow(); - _painter = EntMan.System(); - - _window.OnClose += Close; _window.OnSpritePicked = OnSpritePicked; _window.OnColorPicked = OnColorPicked; - _window.Populate(_painter.Entries, comp.Index, comp.PickedColor, comp.ColorPalette); - - _window.OpenCentered(); - } - - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - - _window?.Dispose(); + if (EntMan.TryGetComponent(Owner, out SprayPainterComponent? comp)) + { + _window.Populate(EntMan.System().Entries, comp.Index, comp.PickedColor, comp.ColorPalette); + } } private void OnSpritePicked(ItemList.ItemListSelectedEventArgs args) diff --git a/Content.Client/StationRecords/GeneralStationRecordConsoleBoundUserInterface.cs b/Content.Client/StationRecords/GeneralStationRecordConsoleBoundUserInterface.cs index 720a2efb9dd..e7bab71e38e 100644 --- a/Content.Client/StationRecords/GeneralStationRecordConsoleBoundUserInterface.cs +++ b/Content.Client/StationRecords/GeneralStationRecordConsoleBoundUserInterface.cs @@ -1,4 +1,5 @@ using Content.Shared.StationRecords; +using Robust.Client.UserInterface; namespace Content.Client.StationRecords; @@ -15,15 +16,12 @@ protected override void Open() { base.Open(); - _window = new(); + _window = this.CreateWindow(); _window.OnKeySelected += key => SendMessage(new SelectStationRecord(key)); _window.OnFiltersChanged += (type, filterValue) => SendMessage(new SetStationRecordFilter(type, filterValue)); _window.OnDeleted += id => SendMessage(new DeleteStationRecord(id)); - _window.OnClose += Close; - - _window.OpenCentered(); } protected override void UpdateState(BoundUserInterfaceState state) @@ -35,11 +33,4 @@ protected override void UpdateState(BoundUserInterfaceState state) _window?.UpdateState(cast); } - - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - - _window?.Close(); - } } diff --git a/Content.Client/Store/Ui/StoreBoundUserInterface.cs b/Content.Client/Store/Ui/StoreBoundUserInterface.cs index 0010aedd964..7ed67f7b5dd 100644 --- a/Content.Client/Store/Ui/StoreBoundUserInterface.cs +++ b/Content.Client/Store/Ui/StoreBoundUserInterface.cs @@ -2,6 +2,7 @@ using JetBrains.Annotations; using System.Linq; using Content.Shared.Store.Components; +using Robust.Client.UserInterface; using Robust.Shared.Prototypes; namespace Content.Client.Store.Ui; @@ -26,13 +27,10 @@ public StoreBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey) protected override void Open() { - _menu = new StoreMenu(); + _menu = this.CreateWindow(); if (EntMan.TryGetComponent(Owner, out var store)) _menu.Title = Loc.GetString(store.Name); - _menu.OpenCentered(); - _menu.OnClose += Close; - _menu.OnListingButtonPressed += (_, listing) => { SendMessage(new StoreBuyListingMessage(listing)); @@ -77,15 +75,6 @@ protected override void UpdateState(BoundUserInterfaceState state) } } - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - if (!disposing) - return; - _menu?.Close(); - _menu?.Dispose(); - } - private void UpdateListingsWithSearchFilter() { if (_menu == null) diff --git a/Content.Client/Strip/StrippingMenu.cs b/Content.Client/Strip/StrippingMenu.cs index eea867b7948..1c46b4be35c 100644 --- a/Content.Client/Strip/StrippingMenu.cs +++ b/Content.Client/Strip/StrippingMenu.cs @@ -1,4 +1,3 @@ -using Content.Client.Inventory; using Robust.Client.UserInterface.Controls; using Robust.Client.UserInterface.CustomControls; using Robust.Shared.Timing; @@ -11,14 +10,12 @@ public sealed class StrippingMenu : DefaultWindow public LayoutContainer InventoryContainer = new(); public BoxContainer HandsContainer = new() { Orientation = LayoutOrientation.Horizontal }; public BoxContainer SnareContainer = new(); - private StrippableBoundUserInterface _bui; public bool Dirty = true; - public StrippingMenu(string title, StrippableBoundUserInterface bui) - { - Title = title; - _bui = bui; + public event Action? OnDirty; + public StrippingMenu() + { var box = new BoxContainer() { Orientation = LayoutOrientation.Vertical, Margin = new Thickness(0, 8) }; Contents.AddChild(box); box.AddChild(SnareContainer); @@ -39,7 +36,7 @@ protected override void FrameUpdate(FrameEventArgs args) return; Dirty = false; - _bui.UpdateMenu(); + OnDirty?.Invoke(); } } } diff --git a/Content.Client/SurveillanceCamera/UI/SurveillanceCameraMonitorBoundUi.cs b/Content.Client/SurveillanceCamera/UI/SurveillanceCameraMonitorBoundUi.cs index 9132dd6ed5f..e3646c00cc3 100644 --- a/Content.Client/SurveillanceCamera/UI/SurveillanceCameraMonitorBoundUi.cs +++ b/Content.Client/SurveillanceCamera/UI/SurveillanceCameraMonitorBoundUi.cs @@ -1,6 +1,7 @@ using Content.Client.Eye; using Content.Shared.SurveillanceCamera; using Robust.Client.GameObjects; +using Robust.Client.UserInterface; namespace Content.Client.SurveillanceCamera.UI; @@ -25,20 +26,12 @@ protected override void Open() { base.Open(); - _window = new SurveillanceCameraMonitorWindow(); - - if (State != null) - { - UpdateState(State); - } - - _window.OpenCentered(); + _window = this.CreateWindow(); _window.CameraSelected += OnCameraSelected; _window.SubnetOpened += OnSubnetRequest; _window.CameraRefresh += OnCameraRefresh; _window.SubnetRefresh += OnSubnetRefresh; - _window.OnClose += Close; _window.CameraSwitchTimer += OnCameraSwitchTimer; _window.CameraDisconnect += OnCameraDisconnect; } diff --git a/Content.Client/Thief/ThiefBackpackBoundUserInterface.cs b/Content.Client/Thief/ThiefBackpackBoundUserInterface.cs index 37384daafef..0631d98993a 100644 --- a/Content.Client/Thief/ThiefBackpackBoundUserInterface.cs +++ b/Content.Client/Thief/ThiefBackpackBoundUserInterface.cs @@ -1,6 +1,7 @@ using Content.Shared.Thief; using JetBrains.Annotations; using Robust.Client.GameObjects; +using Robust.Client.UserInterface; namespace Content.Client.Thief; @@ -15,21 +16,9 @@ protected override void Open() { base.Open(); - _window = new ThiefBackpackMenu(this); - _window.OnClose += Close; - _window.OpenCentered(); - } - - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - if (!disposing) - return; - - if (_window != null) - _window.OnClose -= Close; - - _window?.Dispose(); + _window = this.CreateWindow(); + _window.OnApprove += SendApprove; + _window.OnSetChange += SendChangeSelected; } protected override void UpdateState(BoundUserInterfaceState state) diff --git a/Content.Client/Thief/ThiefBackpackMenu.xaml.cs b/Content.Client/Thief/ThiefBackpackMenu.xaml.cs index 543772c704c..aaee3576174 100644 --- a/Content.Client/Thief/ThiefBackpackMenu.xaml.cs +++ b/Content.Client/Thief/ThiefBackpackMenu.xaml.cs @@ -12,46 +12,42 @@ public sealed partial class ThiefBackpackMenu : FancyWindow [Dependency] private readonly IEntitySystemManager _sysMan = default!; private readonly SpriteSystem _spriteSystem; - private readonly ThiefBackpackBoundUserInterface _owner; + public event Action? OnApprove; + public event Action? OnSetChange; - public ThiefBackpackMenu(ThiefBackpackBoundUserInterface owner) + public ThiefBackpackMenu() { RobustXamlLoader.Load(this); IoCManager.InjectDependencies(this); _spriteSystem = _sysMan.GetEntitySystem(); - _owner = owner; - - ApproveButton.OnButtonDown += (args) => + ApproveButton.OnPressed += args => { - _owner.SendApprove(); + OnApprove?.Invoke(); }; } public void UpdateState(ThiefBackpackBoundUserInterfaceState state) { - SetsGrid.RemoveAllChildren(); - int count = 0; - int selectedNumber = 0; - foreach (var set in state.Sets) + SetsGrid.DisposeAllChildren(); + var selectedNumber = 0; + foreach (var (set, info) in state.Sets) { - var child = new ThiefBackpackSet(set.Value, _spriteSystem); + var child = new ThiefBackpackSet(info, _spriteSystem); child.SetButton.OnButtonDown += (args) => { - _owner.SendChangeSelected(set.Key); + OnSetChange?.Invoke(set); }; SetsGrid.AddChild(child); - count++; - - if (set.Value.Selected) + if (info.Selected) selectedNumber++; } Description.Text = Loc.GetString("thief-backpack-window-description", ("maxCount", state.MaxSelectedSets)); SelectedSets.Text = Loc.GetString("thief-backpack-window-selected", ("selectedCount", selectedNumber), ("maxCount", state.MaxSelectedSets)); - ApproveButton.Disabled = selectedNumber == state.MaxSelectedSets ? false : true; + ApproveButton.Disabled = selectedNumber != state.MaxSelectedSets; } } diff --git a/Content.Client/UserInterface/Systems/Atmos/GasTank/GasTankBoundUserInterface.cs b/Content.Client/UserInterface/Systems/Atmos/GasTank/GasTankBoundUserInterface.cs index 4702f8f3659..4ae74a5d65e 100644 --- a/Content.Client/UserInterface/Systems/Atmos/GasTank/GasTankBoundUserInterface.cs +++ b/Content.Client/UserInterface/Systems/Atmos/GasTank/GasTankBoundUserInterface.cs @@ -1,5 +1,7 @@ using Content.Shared.Atmos.Components; using JetBrains.Annotations; +using Robust.Client.GameObjects; +using Robust.Client.UserInterface; namespace Content.Client.UserInterface.Systems.Atmos.GasTank { @@ -13,7 +15,7 @@ public GasTankBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKe { } - public void SetOutputPressure(in float value) + public void SetOutputPressure(float value) { SendMessage(new GasTankSetPressureMessage { @@ -29,9 +31,10 @@ public void ToggleInternals() protected override void Open() { base.Open(); - _window = new GasTankWindow(this, EntMan.GetComponent(Owner).EntityName); - _window.OnClose += Close; - _window.OpenCentered(); + _window = this.CreateWindow(); + _window.SetTitle(EntMan.GetComponent(Owner).EntityName); + _window.OnOutputPressure += SetOutputPressure; + _window.OnToggleInternals += ToggleInternals; } protected override void UpdateState(BoundUserInterfaceState state) diff --git a/Content.Client/UserInterface/Systems/Atmos/GasTank/GasTankWindow.cs b/Content.Client/UserInterface/Systems/Atmos/GasTank/GasTankWindow.cs index c23850a6503..12eeaa55de9 100644 --- a/Content.Client/UserInterface/Systems/Atmos/GasTank/GasTankWindow.cs +++ b/Content.Client/UserInterface/Systems/Atmos/GasTank/GasTankWindow.cs @@ -15,23 +15,28 @@ namespace Content.Client.UserInterface.Systems.Atmos.GasTank; public sealed class GasTankWindow : BaseWindow { + [Dependency] private readonly IResourceCache _cache = default!; + private readonly RichTextLabel _lblPressure; private readonly FloatSpinBox _spbPressure; private readonly RichTextLabel _lblInternals; private readonly Button _btnInternals; + private readonly Label _topLabel; + + public event Action? OnOutputPressure; + public event Action? OnToggleInternals; - public GasTankWindow(GasTankBoundUserInterface owner, string uidName) + public GasTankWindow() { Control contentContainer; BoxContainer topContainer; TextureButton btnClose; - var resourceCache = IoCManager.Resolve(); var rootContainer = new LayoutContainer { Name = "GasTankRoot" }; AddChild(rootContainer); MouseFilter = MouseFilterMode.Stop; - var panelTex = resourceCache.GetTexture("/Textures/Interface/Nano/button.svg.96dpi.png"); + var panelTex = _cache.GetTexture("/Textures/Interface/Nano/button.svg.96dpi.png"); var back = new StyleBoxTexture { Texture = panelTex, @@ -78,7 +83,17 @@ public GasTankWindow(GasTankBoundUserInterface owner, string uidName) LayoutContainer.SetAnchorPreset(topContainerWrap, LayoutContainer.LayoutPreset.Wide); - var font = resourceCache.GetFont("/Fonts/Boxfont-round/Boxfont Round.ttf", 13); + var font = _cache.GetFont("/Fonts/Boxfont-round/Boxfont Round.ttf", 13); + + _topLabel = new Label + { + FontOverride = font, + FontColorOverride = StyleNano.NanoGold, + VerticalAlignment = VAlignment.Center, + HorizontalExpand = true, + HorizontalAlignment = HAlignment.Left, + Margin = new Thickness(0, 0, 20, 0), + }; var topRow = new BoxContainer { @@ -86,16 +101,7 @@ public GasTankWindow(GasTankBoundUserInterface owner, string uidName) Margin = new Thickness(4, 2, 12, 2), Children = { - (new Label - { - Text = uidName, - FontOverride = font, - FontColorOverride = StyleNano.NanoGold, - VerticalAlignment = VAlignment.Center, - HorizontalExpand = true, - HorizontalAlignment = HAlignment.Left, - Margin = new Thickness(0, 0, 20, 0), - }), + _topLabel, (btnClose = new TextureButton { StyleClasses = {DefaultWindow.StyleClassWindowCloseButton}, @@ -168,17 +174,22 @@ public GasTankWindow(GasTankBoundUserInterface owner, string uidName) // Handlers _spbPressure.OnValueChanged += args => { - owner.SetOutputPressure(args.Value); + OnOutputPressure?.Invoke(args.Value); }; _btnInternals.OnPressed += args => { - owner.ToggleInternals(); + OnToggleInternals?.Invoke(); }; btnClose.OnPressed += _ => Close(); } + public void SetTitle(string name) + { + _topLabel.Text = name; + } + public void UpdateState(GasTankBoundUserInterfaceState state) { _lblPressure.SetMarkup(Loc.GetString("gas-tank-window-tank-pressure-text", ("tankPressure", $"{state.TankPressure:0.##}"))); diff --git a/Content.Client/VendingMachines/VendingMachineBoundUserInterface.cs b/Content.Client/VendingMachines/VendingMachineBoundUserInterface.cs index 17ddba77ffc..eafab84ed63 100644 --- a/Content.Client/VendingMachines/VendingMachineBoundUserInterface.cs +++ b/Content.Client/VendingMachines/VendingMachineBoundUserInterface.cs @@ -2,6 +2,7 @@ using Content.Shared.VendingMachines; using Robust.Client.UserInterface.Controls; using System.Linq; +using Robust.Client.UserInterface; namespace Content.Client.VendingMachines { @@ -28,15 +29,14 @@ protected override void Open() _cachedInventory = vendingMachineSys.GetAllInventory(Owner); - _menu = new VendingMachineMenu { Title = EntMan.GetComponent(Owner).EntityName }; + _menu = this.CreateWindow(); + _menu.OpenCenteredLeft(); + _menu.Title = EntMan.GetComponent(Owner).EntityName; - _menu.OnClose += Close; _menu.OnItemSelected += OnItemSelected; _menu.OnSearchChanged += OnSearchChanged; _menu.Populate(_cachedInventory, out _cachedFilteredIndex); - - _menu.OpenCenteredLeft(); } protected override void UpdateState(BoundUserInterfaceState state) diff --git a/Content.Client/VoiceMask/VoiceMaskBoundUserInterface.cs b/Content.Client/VoiceMask/VoiceMaskBoundUserInterface.cs index f700c6663b9..891804674d3 100644 --- a/Content.Client/VoiceMask/VoiceMaskBoundUserInterface.cs +++ b/Content.Client/VoiceMask/VoiceMaskBoundUserInterface.cs @@ -1,12 +1,13 @@ using Content.Shared.VoiceMask; using Robust.Client.GameObjects; +using Robust.Client.UserInterface; using Robust.Shared.Prototypes; namespace Content.Client.VoiceMask; public sealed class VoiceMaskBoundUserInterface : BoundUserInterface { - [Dependency] private readonly IPrototypeManager _proto = default!; + [Dependency] private readonly IPrototypeManager _protomanager = default!; [ViewVariables] private VoiceMaskNameChangeWindow? _window; @@ -19,12 +20,11 @@ protected override void Open() { base.Open(); - _window = new(_proto); + _window = this.CreateWindow(); + _window.ReloadVerbs(_protomanager); - _window.OpenCentered(); _window.OnNameChange += OnNameSelected; _window.OnVerbChange += verb => SendMessage(new VoiceMaskChangeVerbMessage(verb)); - _window.OnClose += Close; } private void OnNameSelected(string name) diff --git a/Content.Client/VoiceMask/VoiceMaskNameChangeWindow.xaml.cs b/Content.Client/VoiceMask/VoiceMaskNameChangeWindow.xaml.cs index 16a28f9d9b3..0dc41f807ab 100644 --- a/Content.Client/VoiceMask/VoiceMaskNameChangeWindow.xaml.cs +++ b/Content.Client/VoiceMask/VoiceMaskNameChangeWindow.xaml.cs @@ -17,7 +17,7 @@ public sealed partial class VoiceMaskNameChangeWindow : FancyWindow private string? _verb; - public VoiceMaskNameChangeWindow(IPrototypeManager proto) + public VoiceMaskNameChangeWindow() { RobustXamlLoader.Load(this); @@ -32,12 +32,10 @@ public VoiceMaskNameChangeWindow(IPrototypeManager proto) SpeechVerbSelector.SelectId(args.Id); }; - ReloadVerbs(proto); - AddVerbs(); } - private void ReloadVerbs(IPrototypeManager proto) + public void ReloadVerbs(IPrototypeManager proto) { foreach (var verb in proto.EnumeratePrototypes()) { diff --git a/Content.Client/Weapons/Melee/UI/MeleeSpeechBoundUserInterface.cs b/Content.Client/Weapons/Melee/UI/MeleeSpeechBoundUserInterface.cs index f3e0c0a539a..3f01808c422 100644 --- a/Content.Client/Weapons/Melee/UI/MeleeSpeechBoundUserInterface.cs +++ b/Content.Client/Weapons/Melee/UI/MeleeSpeechBoundUserInterface.cs @@ -1,5 +1,6 @@ using Robust.Client.GameObjects; using Content.Shared.Speech.Components; +using Robust.Client.UserInterface; namespace Content.Client.Weapons.Melee.UI; @@ -19,17 +20,10 @@ protected override void Open() { base.Open(); - _window = new MeleeSpeechWindow(); - if (State != null) - UpdateState(State); - - _window.OpenCentered(); - - _window.OnClose += Close; + _window = this.CreateWindow(); _window.OnBattlecryEntered += OnBattlecryChanged; } - private void OnBattlecryChanged(string newBattlecry) { SendMessage(new MeleeSpeechBattlecryChangedMessage(newBattlecry)); diff --git a/Content.Client/Wires/UI/WiresBoundUserInterface.cs b/Content.Client/Wires/UI/WiresBoundUserInterface.cs index 5a8869a204e..edf1a2d3770 100644 --- a/Content.Client/Wires/UI/WiresBoundUserInterface.cs +++ b/Content.Client/Wires/UI/WiresBoundUserInterface.cs @@ -1,5 +1,6 @@ using Content.Shared.Wires; using Robust.Client.GameObjects; +using Robust.Client.UserInterface; namespace Content.Client.Wires.UI { @@ -15,10 +16,8 @@ public WiresBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey) protected override void Open() { base.Open(); - - _menu = new WiresMenu(this); - _menu.OnClose += Close; - _menu.OpenCenteredLeft(); + _menu = this.CreateWindow(); + _menu.OnAction += PerformAction; } protected override void UpdateState(BoundUserInterfaceState state) diff --git a/Content.Client/Wires/UI/WiresMenu.cs b/Content.Client/Wires/UI/WiresMenu.cs index 7bccc208616..eccc548297c 100644 --- a/Content.Client/Wires/UI/WiresMenu.cs +++ b/Content.Client/Wires/UI/WiresMenu.cs @@ -1,4 +1,3 @@ -using System; using System.Numerics; using Content.Client.Examine; using Content.Client.Resources; @@ -12,10 +11,6 @@ using Robust.Client.UserInterface.CustomControls; using Robust.Shared.Animations; using Robust.Shared.Input; -using Robust.Shared.IoC; -using Robust.Shared.Localization; -using Robust.Shared.Maths; -using Robust.Shared.Random; using static Robust.Client.UserInterface.Controls.BoxContainer; namespace Content.Client.Wires.UI @@ -24,8 +19,6 @@ public sealed class WiresMenu : BaseWindow { [Dependency] private readonly IResourceCache _resourceCache = default!; - public WiresBoundUserInterface Owner { get; } - private readonly Control _wiresHBox; private readonly Control _topContainer; private readonly Control _statusContainer; @@ -35,11 +28,12 @@ public sealed class WiresMenu : BaseWindow public TextureButton CloseButton { get; set; } - public WiresMenu(WiresBoundUserInterface owner) + public event Action? OnAction; + + public WiresMenu() { IoCManager.InjectDependencies(this); - Owner = owner; var rootContainer = new LayoutContainer {Name = "WireRoot"}; AddChild(rootContainer); @@ -257,12 +251,12 @@ public void Populate(WiresBoundUserInterfaceState state) control.WireClicked += () => { - Owner.PerformAction(wire.Id, wire.IsCut ? WiresAction.Mend : WiresAction.Cut); + OnAction?.Invoke(wire.Id, wire.IsCut ? WiresAction.Mend : WiresAction.Cut); }; control.ContactsClicked += () => { - Owner.PerformAction(wire.Id, WiresAction.Pulse); + OnAction?.Invoke(wire.Id, WiresAction.Pulse); }; } diff --git a/Content.Client/Xenoarchaeology/Ui/AnalysisConsoleBoundUserInterface.cs b/Content.Client/Xenoarchaeology/Ui/AnalysisConsoleBoundUserInterface.cs index 2538caf6eb8..c7a74815b6b 100644 --- a/Content.Client/Xenoarchaeology/Ui/AnalysisConsoleBoundUserInterface.cs +++ b/Content.Client/Xenoarchaeology/Ui/AnalysisConsoleBoundUserInterface.cs @@ -1,6 +1,7 @@ using Content.Shared.Xenoarchaeology.Equipment; using JetBrains.Annotations; using Robust.Client.GameObjects; +using Robust.Client.UserInterface; namespace Content.Client.Xenoarchaeology.Ui; @@ -18,10 +19,7 @@ protected override void Open() { base.Open(); - _consoleMenu = new AnalysisConsoleMenu(); - - _consoleMenu.OnClose += Close; - _consoleMenu.OpenCentered(); + _consoleMenu = this.CreateWindow(); _consoleMenu.OnServerSelectionButtonPressed += () => { From 83c71ab23714153edf5a1d099e3655305c8193fd Mon Sep 17 00:00:00 2001 From: Aiden Date: Sat, 20 Jul 2024 00:53:57 -0500 Subject: [PATCH 296/765] MassHallucinationsRule Minor Refactor (#28748) * Update MassHallucinationsRule. * Update Content.Server/StationEvents/Events/MassHallucinationsRule.cs Co-authored-by: Ed <96445749+TheShuEd@users.noreply.github.com> * Update Content.Server/StationEvents/Events/MassHallucinationsRule.cs Co-authored-by: Ed <96445749+TheShuEd@users.noreply.github.com> * Update Content.Server/StationEvents/Events/MassHallucinationsRule.cs Co-authored-by: Ed <96445749+TheShuEd@users.noreply.github.com> * MGS Change * Update Content.Server/StationEvents/Events/MassHallucinationsRule.cs Co-authored-by: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com> * Update Content.Server/StationEvents/Events/MassHallucinationsRule.cs Co-authored-by: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com> * Move affectedentities to component, remove masshallucinationscomponent as its no longer needed to track entities. * Apply suggested changes. * No double checks --------- Co-authored-by: Ed <96445749+TheShuEd@users.noreply.github.com> Co-authored-by: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com> --- .../Components/MassHallucinationsComponent.cs | 11 ---------- .../MassHallucinationsRuleComponent.cs | 4 ++++ .../Events/MassHallucinationsRule.cs | 20 ++++++++++++------- 3 files changed, 17 insertions(+), 18 deletions(-) delete mode 100644 Content.Server/StationEvents/Components/MassHallucinationsComponent.cs diff --git a/Content.Server/StationEvents/Components/MassHallucinationsComponent.cs b/Content.Server/StationEvents/Components/MassHallucinationsComponent.cs deleted file mode 100644 index 99b893cad51..00000000000 --- a/Content.Server/StationEvents/Components/MassHallucinationsComponent.cs +++ /dev/null @@ -1,11 +0,0 @@ -using Content.Server.StationEvents.Events; - -namespace Content.Server.StationEvents.Components; - -/// -/// This is used to keep track of hallucinated entities to remove effects when event ends -/// -[RegisterComponent, Access(typeof(MassHallucinationsRule))] -public sealed partial class MassHallucinationsComponent : Component -{ -} diff --git a/Content.Server/StationEvents/Components/MassHallucinationsRuleComponent.cs b/Content.Server/StationEvents/Components/MassHallucinationsRuleComponent.cs index 63a1f872513..a5268f97a62 100644 --- a/Content.Server/StationEvents/Components/MassHallucinationsRuleComponent.cs +++ b/Content.Server/StationEvents/Components/MassHallucinationsRuleComponent.cs @@ -1,5 +1,6 @@ using Content.Server.StationEvents.Events; using Robust.Shared.Audio; +using Robust.Shared.Collections; namespace Content.Server.StationEvents.Components; @@ -23,4 +24,7 @@ public sealed partial class MassHallucinationsRuleComponent : Component [DataField("sounds", required: true)] public SoundSpecifier Sounds = default!; + + [DataField, ViewVariables(VVAccess.ReadOnly)] + public List AffectedEntities = new(); } diff --git a/Content.Server/StationEvents/Events/MassHallucinationsRule.cs b/Content.Server/StationEvents/Events/MassHallucinationsRule.cs index d6f609bee1d..b46f1ed4b43 100644 --- a/Content.Server/StationEvents/Events/MassHallucinationsRule.cs +++ b/Content.Server/StationEvents/Events/MassHallucinationsRule.cs @@ -2,9 +2,12 @@ using Content.Server.GameTicking.Rules.Components; using Content.Server.StationEvents.Components; using Content.Server.Traits.Assorted; +using Content.Shared.GameTicking.Components; +using Content.Shared.Humanoid; using Content.Shared.Mind.Components; using Content.Shared.Traits.Assorted; + namespace Content.Server.StationEvents.Events; public sealed class MassHallucinationsRule : StationEventSystem @@ -14,16 +17,17 @@ public sealed class MassHallucinationsRule : StationEventSystem(); - while (query.MoveNext(out var ent, out _)) + + var query = EntityQueryEnumerator(); + while (query.MoveNext(out var ent, out _, out _)) { - if (!HasComp(ent)) + if (!EnsureComp(ent, out var paracusia)) { - EnsureComp(ent); - var paracusia = EnsureComp(ent); _paracusia.SetSounds(ent, component.Sounds, paracusia); _paracusia.SetTime(ent, component.MinTimeBetweenIncidents, component.MaxTimeBetweenIncidents, paracusia); _paracusia.SetDistance(ent, component.MaxSoundDistance); + + component.AffectedEntities.Add(ent); } } } @@ -31,10 +35,12 @@ protected override void Started(EntityUid uid, MassHallucinationsRuleComponent c protected override void Ended(EntityUid uid, MassHallucinationsRuleComponent component, GameRuleComponent gameRule, GameRuleEndedEvent args) { base.Ended(uid, component, gameRule, args); - var query = EntityQueryEnumerator(); - while (query.MoveNext(out var ent, out _)) + + foreach (var ent in component.AffectedEntities) { RemComp(ent); } + + component.AffectedEntities.Clear(); } } From 5a503cff1aee442608fc1545cdcfe2f0983163e1 Mon Sep 17 00:00:00 2001 From: PJBot Date: Sat, 20 Jul 2024 05:55:05 +0000 Subject: [PATCH 297/765] Automatic changelog update --- Resources/Changelog/Changelog.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 09ab407edd9..ed8f51b7865 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,11 +1,4 @@ Entries: -- author: Boaz1111 - changes: - - message: Refactored Cluster's medbay, including cryo in the bottom left room - type: Tweak - id: 6442 - time: '2024-04-26T08:01:21.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/27293 - author: metalgearsloth changes: - message: Add predicted UI opening for storage and PDAs. @@ -3798,3 +3791,10 @@ id: 6941 time: '2024-07-20T03:00:28.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/30156 +- author: Aidenkrz + changes: + - message: The mass hallucinations event no longer affects non-humanoids. + type: Fix + id: 6942 + time: '2024-07-20T05:53:58.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/28748 From b3605cea36fe6a5ad29f6a77c2aec066d9428eeb Mon Sep 17 00:00:00 2001 From: lzk <124214523+lzk228@users.noreply.github.com> Date: Sat, 20 Jul 2024 07:56:21 +0200 Subject: [PATCH 298/765] Remove HighImpassable from TableTopLayer (#29455) * uhmm * Update CollisionGroup.cs --- Content.Shared/Physics/CollisionGroup.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Content.Shared/Physics/CollisionGroup.cs b/Content.Shared/Physics/CollisionGroup.cs index 775ccb7c446..9f8c5ad9bef 100644 --- a/Content.Shared/Physics/CollisionGroup.cs +++ b/Content.Shared/Physics/CollisionGroup.cs @@ -58,7 +58,7 @@ public enum CollisionGroup // Tabletop machines, windoors, firelocks TabletopMachineMask = Impassable | HighImpassable, // Tabletop machines - TabletopMachineLayer = Opaque | HighImpassable | BulletImpassable, + TabletopMachineLayer = Opaque | BulletImpassable, // Airlocks, windoors, firelocks GlassAirlockLayer = HighImpassable | MidImpassable | BulletImpassable | InteractImpassable, From 81de880e075eb2c5a5b2f947ff9557803f05852c Mon Sep 17 00:00:00 2001 From: JIPDawg <51352440+JIPDawg@users.noreply.github.com> Date: Sat, 20 Jul 2024 01:23:07 -0500 Subject: [PATCH 299/765] Added missing builld components to RCD [empty] (#30177) * Added missing stuff to rcd[empty] * do the smart thing --------- Co-authored-by: JIP --- .../Prototypes/Entities/Objects/Tools/tools.yml | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/Resources/Prototypes/Entities/Objects/Tools/tools.yml b/Resources/Prototypes/Entities/Objects/Tools/tools.yml index b5ab18b2386..4d6f33fe21b 100644 --- a/Resources/Prototypes/Entities/Objects/Tools/tools.yml +++ b/Resources/Prototypes/Entities/Objects/Tools/tools.yml @@ -407,20 +407,6 @@ components: - type: LimitedCharges charges: 0 - - type: RCD - availablePrototypes: - - WallSolid - - FloorSteel - - Plating - - Catwalk - - Grille - - Window - - WindowDirectional - - WindowReinforcedDirectional - - ReinforcedWindow - - Airlock - - AirlockGlass - - Firelock - type: entity id: RCDRecharging From 4951d6ad9fb263f33838079436f24902cb95802b Mon Sep 17 00:00:00 2001 From: DrSmugleaf <10968691+DrSmugleaf@users.noreply.github.com> Date: Sat, 20 Jul 2024 01:06:52 -0700 Subject: [PATCH 300/765] Add user to AttemptMeleeEvent, add ThrowItemAttemptEvent (#30193) * Add user to AttemptMeleeEvent, add ThrowItemAttemptEvent * Add xmldoc --- Content.Shared/ActionBlocker/ActionBlockerSystem.cs | 8 +++++++- Content.Shared/Throwing/ThrowAttemptEvent.cs | 8 ++++++++ Content.Shared/Weapons/Melee/Events/AttemptMeleeEvent.cs | 2 +- 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/Content.Shared/ActionBlocker/ActionBlockerSystem.cs b/Content.Shared/ActionBlocker/ActionBlockerSystem.cs index 005c7dc78ec..afa1e19eade 100644 --- a/Content.Shared/ActionBlocker/ActionBlockerSystem.cs +++ b/Content.Shared/ActionBlocker/ActionBlockerSystem.cs @@ -120,7 +120,13 @@ public bool CanThrow(EntityUid user, EntityUid itemUid) var ev = new ThrowAttemptEvent(user, itemUid); RaiseLocalEvent(user, ev); - return !ev.Cancelled; + if (ev.Cancelled) + return false; + + var itemEv = new ThrowItemAttemptEvent(user); + RaiseLocalEvent(itemUid, ref itemEv); + + return !itemEv.Cancelled; } public bool CanSpeak(EntityUid uid) diff --git a/Content.Shared/Throwing/ThrowAttemptEvent.cs b/Content.Shared/Throwing/ThrowAttemptEvent.cs index bf8cad6c746..dfb3dca5c7d 100644 --- a/Content.Shared/Throwing/ThrowAttemptEvent.cs +++ b/Content.Shared/Throwing/ThrowAttemptEvent.cs @@ -13,6 +13,14 @@ public ThrowAttemptEvent(EntityUid uid, EntityUid itemUid) public EntityUid ItemUid { get; } } + /// + /// Raised on the item entity that is thrown. + /// + /// The user that threw this entity. + /// Whether or not the throw should be cancelled. + [ByRefEvent] + public record struct ThrowItemAttemptEvent(EntityUid User, bool Cancelled = false); + /// /// Raised when we try to pushback an entity from throwing /// diff --git a/Content.Shared/Weapons/Melee/Events/AttemptMeleeEvent.cs b/Content.Shared/Weapons/Melee/Events/AttemptMeleeEvent.cs index 2800e3b34da..cbcadcd19f9 100644 --- a/Content.Shared/Weapons/Melee/Events/AttemptMeleeEvent.cs +++ b/Content.Shared/Weapons/Melee/Events/AttemptMeleeEvent.cs @@ -4,4 +4,4 @@ namespace Content.Shared.Weapons.Melee.Events; /// Raised directed on a weapon when attempt a melee attack. /// [ByRefEvent] -public record struct AttemptMeleeEvent(bool Cancelled, string? Message); +public record struct AttemptMeleeEvent(EntityUid User, bool Cancelled = false, string? Message = null); From d746da2f9928026bc41a89df69fd09e2904817e4 Mon Sep 17 00:00:00 2001 From: chavonadelal <156101927+chavonadelal@users.noreply.github.com> Date: Sat, 20 Jul 2024 19:14:41 +0300 Subject: [PATCH 301/765] Localization of encryption keys (#30172) * Localization of encryption keys * Localization of encryption keys update --- Content.Shared/Radio/EntitySystems/EncryptionKeySystem.cs | 4 ++-- Content.Shared/Radio/RadioChannelPrototype.cs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Content.Shared/Radio/EntitySystems/EncryptionKeySystem.cs b/Content.Shared/Radio/EntitySystems/EncryptionKeySystem.cs index cfa553661a3..7b050273db6 100644 --- a/Content.Shared/Radio/EntitySystems/EncryptionKeySystem.cs +++ b/Content.Shared/Radio/EntitySystems/EncryptionKeySystem.cs @@ -239,14 +239,14 @@ public void AddChannelsExamine(HashSet channels, string? defaultChannel, { var msg = Loc.GetString("examine-headset-default-channel", ("prefix", SharedChatSystem.DefaultChannelPrefix), - ("channel", defaultChannel), + ("channel", proto.LocalizedName), ("color", proto.Color)); examineEvent.PushMarkup(msg); } if (HasComp(examineEvent.Examined)) { var msg = Loc.GetString("examine-encryption-default-channel", - ("channel", defaultChannel), + ("channel", proto.LocalizedName), ("color", proto.Color)); examineEvent.PushMarkup(msg); } diff --git a/Content.Shared/Radio/RadioChannelPrototype.cs b/Content.Shared/Radio/RadioChannelPrototype.cs index cc65f885375..166db0577ea 100644 --- a/Content.Shared/Radio/RadioChannelPrototype.cs +++ b/Content.Shared/Radio/RadioChannelPrototype.cs @@ -9,7 +9,7 @@ public sealed partial class RadioChannelPrototype : IPrototype /// Human-readable name for the channel. /// [DataField("name")] - public string Name { get; private set; } = string.Empty; + public LocId Name { get; private set; } = string.Empty; [ViewVariables(VVAccess.ReadOnly)] public string LocalizedName => Loc.GetString(Name); From 0c17e4e7643b398a621330b3d1f1bee8cbccb7ca Mon Sep 17 00:00:00 2001 From: Chief-Engineer <119664036+Chief-Engineer@users.noreply.github.com> Date: Sat, 20 Jul 2024 18:28:43 -0500 Subject: [PATCH 302/765] Add debug logs to baby jail and fix playtime logic (#30158) * add debug logs * Update Model.cs * fix playtime logic for null playtime * remove unnecessary condition * either me or the compiler is having a C# skill issue --- Content.Server.Database/Model.cs | 3 +++ Content.Server/Connection/ConnectionManager.cs | 13 ++++++++++++- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/Content.Server.Database/Model.cs b/Content.Server.Database/Model.cs index dea8f9558ab..d195201c29c 100644 --- a/Content.Server.Database/Model.cs +++ b/Content.Server.Database/Model.cs @@ -903,6 +903,9 @@ public enum ConnectionDenyReason : byte Panic = 3, /* * TODO: Remove baby jail code once a more mature gateway process is established. This code is only being issued as a stopgap to help with potential tiding in the immediate future. + * + * If baby jail is removed, please reserve this value for as long as can reasonably be done to prevent causing ambiguity in connection denial reasons. + * Reservation by commenting out the value is likely sufficient for this purpose, but may impact projects which depend on SS14 like SS14.Admin. */ BabyJail = 4, } diff --git a/Content.Server/Connection/ConnectionManager.cs b/Content.Server/Connection/ConnectionManager.cs index 516b884369a..e609b513341 100644 --- a/Content.Server/Connection/ConnectionManager.cs +++ b/Content.Server/Connection/ConnectionManager.cs @@ -335,6 +335,12 @@ session.Status is SessionStatus.Connected or SessionStatus.InGame return (false, ""); var isAccountAgeInvalid = record.FirstSeenTime.CompareTo(DateTimeOffset.Now - TimeSpan.FromMinutes(maxAccountAgeMinutes)) <= 0; + + if (isAccountAgeInvalid) + { + _sawmill.Debug($"Baby jail will deny {userId} for account age {record.FirstSeenTime}"); // Remove on or after 2024-09 + } + if (isAccountAgeInvalid && showReason) { var locAccountReason = reason != string.Empty @@ -349,7 +355,12 @@ session.Status is SessionStatus.Connected or SessionStatus.InGame } var overallTime = ( await _db.GetPlayTimes(e.UserId)).Find(p => p.Tracker == PlayTimeTrackingShared.TrackerOverall); - var isTotalPlaytimeInvalid = overallTime == null || overallTime.TimeSpent.TotalMinutes >= maxPlaytimeMinutes; + var isTotalPlaytimeInvalid = overallTime != null && overallTime.TimeSpent.TotalMinutes >= maxPlaytimeMinutes; + + if (isTotalPlaytimeInvalid) + { + _sawmill.Debug($"Baby jail will deny {userId} for playtime {overallTime!.TimeSpent}"); // Remove on or after 2024-09 + } if (isTotalPlaytimeInvalid && showReason) { From ac0a73c03991d6dbefe3f054b838fd8ec7d63f4d Mon Sep 17 00:00:00 2001 From: Nemanja <98561806+EmoGarbage404@users.noreply.github.com> Date: Sat, 20 Jul 2024 20:42:27 -0400 Subject: [PATCH 303/765] Revert "Remove some BUI boilerplate" (#30214) Revert "Remove some BUI boilerplate (#28399)" This reverts commit cbf329a82d77eed2bb5e51666dab5d8a21fd3fff. --- .../UI/AccessOverriderBoundUserInterface.cs | 45 ++--- .../Access/UI/AccessOverriderWindow.xaml.cs | 41 +++-- .../UI/AgentIDCardBoundUserInterface.cs | 19 +- .../Access/UI/AgentIDCardWindow.xaml.cs | 10 +- .../Ame/UI/AmeControllerBoundUserInterface.cs | 16 +- Content.Client/Ame/UI/AmeWindow.xaml.cs | 19 +- .../Ui/AnomalyGeneratorBoundUserInterface.cs | 20 +- .../Anomaly/Ui/AnomalyGeneratorWindow.xaml.cs | 8 +- Content.Client/Arcade/BlockGameMenu.cs | 45 ++--- .../Arcade/SpaceVillainArcadeMenu.cs | 45 +++-- .../Arcade/UI/BlockGameBoundUserInterface.cs | 5 +- .../SpaceVillainArcadeBoundUserInterface.cs | 16 +- .../Monitor/UI/AirAlarmBoundUserInterface.cs | 12 +- .../Atmos/Monitor/UI/AirAlarmWindow.xaml.cs | 7 +- .../Atmos/UI/GasCanisterBoundUserInterface.cs | 9 +- .../Atmos/UI/GasFilterBoundUserInterface.cs | 11 +- .../Atmos/UI/GasFilterWindow.xaml.cs | 7 +- .../Atmos/UI/GasMixerBoundUserInteface.cs | 18 +- .../UI/GasPressurePumpBoundUserInterface.cs | 17 +- .../UI/GasThermomachineBoundUserInterface.cs | 17 +- .../UI/GasVolumePumpBoundUserInterface.cs | 19 +- .../Atmos/UI/SpaceHeaterBoundUserInterface.cs | 10 +- .../Jukebox/JukeboxBoundUserInterface.cs | 21 ++- .../CryostorageBoundUserInterface.cs | 15 +- .../CargoBountyConsoleBoundUserInterface.cs | 17 +- .../CargoPalletConsoleBoundUserInterface.cs | 15 +- .../CargoShuttleConsoleBoundUserInterface.cs | 24 ++- .../Cargo/UI/CargoShuttleMenu.xaml.cs | 13 +- .../UI/ChemMasterBoundUserInterface.cs | 20 +- .../UI/ReagentDispenserBoundUserInterface.cs | 27 ++- .../UI/TransferAmountBoundUserInterface.cs | 12 +- .../UI/CloningConsoleBoundUserInterface.cs | 25 ++- .../UI/ChameleonBoundUserInterface.cs | 16 +- ...CommunicationsConsoleBoundUserInterface.cs | 72 +++++--- .../UI/CommunicationsConsoleMenu.xaml.cs | 81 ++++----- .../Computer/ComputerBoundUserInterface.cs | 15 +- .../UI/ConfigurationBoundUserInterface.cs | 28 ++- .../Configurable/UI/ConfigurationMenu.cs | 18 +- .../UI/FlatpackCreatorBoundUserInterface.cs | 14 +- .../UI/FlatpackCreatorMenu.xaml.cs | 13 +- .../Crayon/UI/CrayonBoundUserInterface.cs | 40 ++-- Content.Client/Crayon/UI/CrayonWindow.xaml.cs | 18 +- .../UI/DisposalRouterBoundUserInterface.cs | 22 ++- .../UI/DisposalTaggerBoundUserInterface.cs | 23 ++- .../DoorElectronicsBoundUserInterface.cs | 31 ++-- .../DoorElectronicsConfigurationMenu.xaml.cs | 21 +-- Content.Client/Fax/UI/FaxBoundUi.cs | 12 +- .../ForensicScannerBoundUserInterface.cs | 15 +- .../Gateway/UI/GatewayBoundUserInterface.cs | 16 +- .../Gateway/UI/GatewayWindow.xaml.cs | 10 +- .../UI/GravityGeneratorBoundUserInterface.cs | 23 ++- .../Gravity/UI/GravityGeneratorWindow.xaml.cs | 15 +- .../UI/HealthAnalyzerBoundUserInterface.cs | 23 ++- ...manoidMarkingModifierBoundUserInterface.cs | 4 +- .../Instruments/UI/BandMenu.xaml.cs | 6 +- .../Instruments/UI/ChannelsMenu.xaml.cs | 5 +- .../UI/InstrumentBoundUserInterface.cs | 36 +--- .../Instruments/UI/InstrumentMenu.xaml.cs | 171 ++++++++---------- .../Inventory/StrippableBoundUserInterface.cs | 25 +-- Content.Client/Kitchen/UI/GrinderMenu.xaml.cs | 42 +++-- .../Kitchen/UI/MicrowaveBoundUserInterface.cs | 43 ++++- .../Kitchen/UI/MicrowaveMenu.xaml.cs | 24 +-- .../UI/ReagentGrinderBoundUserInterface.cs | 34 ++-- .../UI/HandLabelerBoundUserInterface.cs | 16 +- .../Lathe/UI/LatheBoundUserInterface.cs | 17 +- Content.Client/Lathe/UI/LatheMenu.xaml.cs | 29 ++- .../UI/SignalTimerBoundUserInterface.cs | 24 ++- .../UI/SignalTimerWindow.xaml.cs | 24 ++- .../MagicMirrorBoundUserInterface.cs | 15 +- .../Ui/NewsWriterBoundUserInterface.cs | 18 +- .../MassMedia/Ui/NewsWriterMenu.xaml.cs | 6 +- .../Mech/Ui/MechBoundUserInterface.cs | 16 +- Content.Client/Mech/Ui/MechMenu.xaml.cs | 9 +- .../CrewMonitoringBoundUserInterface.cs | 18 +- .../CrewMonitoringWindow.xaml.cs | 17 +- .../NetworkConfiguratorBoundUserInterface.cs | 39 ++-- ...tworkConfiguratorConfigurationMenu.xaml.cs | 8 +- .../NetworkConfiguratorDeviceList.xaml.cs | 12 +- .../NetworkConfiguratorLinkMenu.xaml.cs | 16 +- .../NetworkConfiguratorListMenu.xaml.cs | 13 +- Content.Client/Nuke/NukeBoundUserInterface.cs | 17 +- .../WarDeclaratorBoundUserInterface.cs | 18 +- .../NukeOps/WarDeclaratorWindow.xaml.cs | 9 +- Content.Client/PDA/PdaBoundUserInterface.cs | 17 +- .../PDA/Ringer/RingerBoundUserInterface.cs | 4 +- .../Paper/UI/PaperBoundUserInterface.cs | 17 +- Content.Client/Paper/UI/PaperWindow.xaml.cs | 6 +- .../ParticleAcceleratorBoundUserInterface.cs | 16 +- .../UI/ParticleAcceleratorControlMenu.cs | 30 ++- .../UI/NavMapBeaconBoundUserInterface.cs | 16 +- .../Pinpointer/UI/NavMapBeaconWindow.xaml.cs | 25 +-- .../UI/StationMapBoundUserInterface.cs | 15 +- .../Pinpointer/UI/StationMapWindow.xaml.cs | 11 +- .../UI/UntrackedMapBoundUserInterface.cs | 15 +- .../Power/APC/ApcBoundUserInterface.cs | 16 +- Content.Client/Power/APC/UI/ApcMenu.xaml.cs | 12 +- .../Power/Generator/GeneratorWindow.xaml.cs | 52 +++--- .../PortableGeneratorBoundUserInterface.cs | 25 +-- ...owerMonitoringConsoleBoundUserInterface.cs | 19 +- .../PowerMonitoringWindow.xaml.Widgets.cs | 6 +- .../Power/PowerMonitoringWindow.xaml.cs | 84 ++++----- Content.Client/RCD/RCDMenu.xaml.cs | 35 ++-- .../RCD/RCDMenuBoundUserInterface.cs | 16 +- .../Radio/Ui/IntercomBoundUserInterface.cs | 20 +- Content.Client/Radio/Ui/IntercomMenu.xaml.cs | 4 +- .../UI/DiskConsoleBoundUserInterface.cs | 15 +- .../UI/ResearchClientBoundUserInterface.cs | 16 +- .../ResearchClientServerSelectionMenu.xaml.cs | 11 +- .../UI/ResearchConsoleBoundUserInterface.cs | 28 ++- .../Research/UI/ResearchConsoleMenu.xaml.cs | 29 ++- .../UI/RoboticsConsoleBoundUserInterface.cs | 18 +- .../Robotics/UI/RoboticsConsoleWindow.xaml.cs | 25 +-- ...vageExpeditionConsoleBoundUserInterface.cs | 12 +- .../UI/SalvageMagnetBoundUserInterface.cs | 21 ++- .../BUI/IFFConsoleBoundUserInterface.cs | 4 +- .../BUI/RadarConsoleBoundUserInterface.cs | 14 +- .../BUI/ShuttleConsoleBoundUserInterface.cs | 5 +- .../Silicons/Borgs/BorgBoundUserInterface.cs | 18 +- Content.Client/Silicons/Borgs/BorgMenu.xaml | 2 +- .../Silicons/Borgs/BorgMenu.xaml.cs | 49 ++--- .../Laws/Ui/SiliconLawBoundUserInterface.cs | 14 +- .../UI/SprayPainterBoundUserInterface.cs | 27 ++- ...lStationRecordConsoleBoundUserInterface.cs | 13 +- .../Store/Ui/StoreBoundUserInterface.cs | 15 +- Content.Client/Strip/StrippingMenu.cs | 11 +- .../UI/SurveillanceCameraMonitorBoundUi.cs | 11 +- .../Thief/ThiefBackpackBoundUserInterface.cs | 19 +- .../Thief/ThiefBackpackMenu.xaml.cs | 28 +-- .../GasTank/GasTankBoundUserInterface.cs | 11 +- .../Systems/Atmos/GasTank/GasTankWindow.cs | 43 ++--- .../VendingMachineBoundUserInterface.cs | 8 +- .../VoiceMask/VoiceMaskBoundUserInterface.cs | 8 +- .../VoiceMaskNameChangeWindow.xaml.cs | 6 +- .../Melee/UI/MeleeSpeechBoundUserInterface.cs | 10 +- .../Wires/UI/WiresBoundUserInterface.cs | 7 +- Content.Client/Wires/UI/WiresMenu.cs | 16 +- .../Ui/AnalysisConsoleBoundUserInterface.cs | 6 +- 137 files changed, 1751 insertions(+), 1092 deletions(-) diff --git a/Content.Client/Access/UI/AccessOverriderBoundUserInterface.cs b/Content.Client/Access/UI/AccessOverriderBoundUserInterface.cs index d80c600c03e..c1b63dc4d05 100644 --- a/Content.Client/Access/UI/AccessOverriderBoundUserInterface.cs +++ b/Content.Client/Access/UI/AccessOverriderBoundUserInterface.cs @@ -2,7 +2,6 @@ using Content.Shared.Access.Components; using Content.Shared.Access.Systems; using Content.Shared.Containers.ItemSlots; -using Robust.Client.UserInterface; using Robust.Shared.Prototypes; using static Content.Shared.Access.Components.AccessOverriderComponent; @@ -24,28 +23,6 @@ protected override void Open() { base.Open(); - _window = this.CreateWindow(); - RefreshAccess(); - _window.Title = EntMan.GetComponent(Owner).EntityName; - _window.OnSubmit += SubmitData; - - _window.PrivilegedIdButton.OnPressed += _ => SendMessage(new ItemSlotButtonPressedEvent(PrivilegedIdCardSlotId)); - } - - public override void OnProtoReload(PrototypesReloadedEventArgs args) - { - base.OnProtoReload(args); - if (!args.WasModified()) - return; - - RefreshAccess(); - - if (State != null) - _window?.UpdateState(_prototypeManager, (AccessOverriderBoundUserInterfaceState) State); - } - - private void RefreshAccess() - { List> accessLevels; if (EntMan.TryGetComponent(Owner, out var accessOverrider)) @@ -53,20 +30,38 @@ private void RefreshAccess() accessLevels = accessOverrider.AccessLevels; accessLevels.Sort(); } + else { accessLevels = new List>(); _accessOverriderSystem.Log.Error($"No AccessOverrider component found for {EntMan.ToPrettyString(Owner)}!"); } - _window?.SetAccessLevels(_prototypeManager, accessLevels); + _window = new AccessOverriderWindow(this, _prototypeManager, accessLevels) + { + Title = EntMan.GetComponent(Owner).EntityName + }; + + _window.PrivilegedIdButton.OnPressed += _ => SendMessage(new ItemSlotButtonPressedEvent(PrivilegedIdCardSlotId)); + + _window.OnClose += Close; + _window.OpenCentered(); + } + + protected override void Dispose(bool disposing) + { + base.Dispose(disposing); + if (!disposing) + return; + + _window?.Dispose(); } protected override void UpdateState(BoundUserInterfaceState state) { base.UpdateState(state); var castState = (AccessOverriderBoundUserInterfaceState) state; - _window?.UpdateState(_prototypeManager, castState); + _window?.UpdateState(castState); } public void SubmitData(List> newAccessList) diff --git a/Content.Client/Access/UI/AccessOverriderWindow.xaml.cs b/Content.Client/Access/UI/AccessOverriderWindow.xaml.cs index ba087718583..6025c3b551f 100644 --- a/Content.Client/Access/UI/AccessOverriderWindow.xaml.cs +++ b/Content.Client/Access/UI/AccessOverriderWindow.xaml.cs @@ -13,24 +13,26 @@ namespace Content.Client.Access.UI [GenerateTypedNameReferences] public sealed partial class AccessOverriderWindow : DefaultWindow { - private readonly Dictionary _accessButtons = new(); + [Dependency] private readonly ILogManager _logManager = default!; + [Dependency] private readonly IPrototypeManager _prototypeManager = default!; - public event Action>>? OnSubmit; + private readonly AccessOverriderBoundUserInterface _owner; + private readonly Dictionary _accessButtons = new(); - public AccessOverriderWindow() + public AccessOverriderWindow(AccessOverriderBoundUserInterface owner, IPrototypeManager prototypeManager, + List> accessLevels) { RobustXamlLoader.Load(this); - } + IoCManager.InjectDependencies(this); + var logMill = _logManager.GetSawmill(SharedAccessOverriderSystem.Sawmill); - public void SetAccessLevels(IPrototypeManager protoManager, List> accessLevels) - { - _accessButtons.Clear(); - AccessLevelGrid.DisposeAllChildren(); + _owner = owner; foreach (var access in accessLevels) { - if (!protoManager.TryIndex(access, out var accessLevel)) + if (!prototypeManager.TryIndex(access, out var accessLevel)) { + logMill.Error($"Unable to find accesslevel for {access}"); continue; } @@ -42,16 +44,11 @@ public void SetAccessLevels(IPrototypeManager protoManager, List - { - OnSubmit?.Invoke( - // Iterate over the buttons dictionary, filter by `Pressed`, only get key from the key/value pair - _accessButtons.Where(x => x.Value.Pressed).Select(x => new ProtoId(x.Key)).ToList()); - }; + newButton.OnPressed += _ => SubmitData(); } } - public void UpdateState(IPrototypeManager protoManager, AccessOverriderBoundUserInterfaceState state) + public void UpdateState(AccessOverriderBoundUserInterfaceState state) { PrivilegedIdLabel.Text = state.PrivilegedIdName; PrivilegedIdButton.Text = state.IsPrivilegedIdPresent @@ -69,11 +66,11 @@ public void UpdateState(IPrototypeManager protoManager, AccessOverriderBoundUser if (state.MissingPrivilegesList != null && state.MissingPrivilegesList.Any()) { - var missingPrivileges = new List(); + List missingPrivileges = new List(); foreach (string tag in state.MissingPrivilegesList) { - var privilege = Loc.GetString(protoManager.Index(tag)?.Name ?? "generic-unknown"); + string privilege = Loc.GetString(_prototypeManager.Index(tag)?.Name ?? "generic-unknown"); missingPrivileges.Add(privilege); } @@ -93,5 +90,13 @@ public void UpdateState(IPrototypeManager protoManager, AccessOverriderBoundUser } } } + + private void SubmitData() + { + _owner.SubmitData( + + // Iterate over the buttons dictionary, filter by `Pressed`, only get key from the key/value pair + _accessButtons.Where(x => x.Value.Pressed).Select(x => new ProtoId(x.Key)).ToList()); + } } } diff --git a/Content.Client/Access/UI/AgentIDCardBoundUserInterface.cs b/Content.Client/Access/UI/AgentIDCardBoundUserInterface.cs index 50add43dc91..761f52988a9 100644 --- a/Content.Client/Access/UI/AgentIDCardBoundUserInterface.cs +++ b/Content.Client/Access/UI/AgentIDCardBoundUserInterface.cs @@ -1,7 +1,6 @@ using Content.Shared.Access.Systems; using Content.Shared.StatusIcon; using Robust.Client.GameObjects; -using Robust.Client.UserInterface; using Robust.Shared.Prototypes; namespace Content.Client.Access.UI @@ -21,11 +20,16 @@ protected override void Open() { base.Open(); - _window = this.CreateWindow(); + _window?.Dispose(); + _window = new AgentIDCardWindow(this); + if (State != null) + UpdateState(State); + _window.OpenCentered(); + + _window.OnClose += Close; _window.OnNameChanged += OnNameChanged; _window.OnJobChanged += OnJobChanged; - _window.OnJobIconChanged += OnJobIconChanged; } private void OnNameChanged(string newName) @@ -57,5 +61,14 @@ protected override void UpdateState(BoundUserInterfaceState state) _window.SetCurrentJob(cast.CurrentJob); _window.SetAllowedIcons(cast.Icons, cast.CurrentJobIconId); } + + protected override void Dispose(bool disposing) + { + base.Dispose(disposing); + if (!disposing) + return; + + _window?.Dispose(); + } } } diff --git a/Content.Client/Access/UI/AgentIDCardWindow.xaml.cs b/Content.Client/Access/UI/AgentIDCardWindow.xaml.cs index 071ce41a069..6d0b2a184f4 100644 --- a/Content.Client/Access/UI/AgentIDCardWindow.xaml.cs +++ b/Content.Client/Access/UI/AgentIDCardWindow.xaml.cs @@ -17,19 +17,19 @@ public sealed partial class AgentIDCardWindow : DefaultWindow [Dependency] private readonly IPrototypeManager _prototypeManager = default!; [Dependency] private readonly IEntitySystemManager _entitySystem = default!; private readonly SpriteSystem _spriteSystem; + private readonly AgentIDCardBoundUserInterface _bui; private const int JobIconColumnCount = 10; public event Action? OnNameChanged; public event Action? OnJobChanged; - public event Action>? OnJobIconChanged; - - public AgentIDCardWindow() + public AgentIDCardWindow(AgentIDCardBoundUserInterface bui) { RobustXamlLoader.Load(this); IoCManager.InjectDependencies(this); _spriteSystem = _entitySystem.GetEntitySystem(); + _bui = bui; NameLineEdit.OnTextEntered += e => OnNameChanged?.Invoke(e.Text); NameLineEdit.OnFocusExit += e => OnNameChanged?.Invoke(e.Text); @@ -67,7 +67,7 @@ public void SetAllowedIcons(HashSet> icons, string }; // Generate buttons textures - var jobIconTexture = new TextureRect + TextureRect jobIconTexture = new TextureRect { Texture = _spriteSystem.Frame0(jobIcon.Icon), TextureScale = new Vector2(2.5f, 2.5f), @@ -75,7 +75,7 @@ public void SetAllowedIcons(HashSet> icons, string }; jobIconButton.AddChild(jobIconTexture); - jobIconButton.OnPressed += _ => OnJobIconChanged?.Invoke(jobIcon.ID); + jobIconButton.OnPressed += _ => _bui.OnJobIconChanged(jobIconId); IconGrid.AddChild(jobIconButton); if (jobIconId.Equals(currentJobIconId)) diff --git a/Content.Client/Ame/UI/AmeControllerBoundUserInterface.cs b/Content.Client/Ame/UI/AmeControllerBoundUserInterface.cs index 3d65f751899..e84cf5d34de 100644 --- a/Content.Client/Ame/UI/AmeControllerBoundUserInterface.cs +++ b/Content.Client/Ame/UI/AmeControllerBoundUserInterface.cs @@ -1,6 +1,5 @@ using Content.Shared.Ame.Components; using JetBrains.Annotations; -using Robust.Client.UserInterface; namespace Content.Client.Ame.UI { @@ -17,8 +16,9 @@ protected override void Open() { base.Open(); - _window = this.CreateWindow(); - _window.OnAmeButton += ButtonPressed; + _window = new AmeWindow(this); + _window.OnClose += Close; + _window.OpenCentered(); } /// @@ -40,5 +40,15 @@ public void ButtonPressed(UiButton button) { SendMessage(new UiButtonPressedMessage(button)); } + + protected override void Dispose(bool disposing) + { + base.Dispose(disposing); + + if (disposing) + { + _window?.Dispose(); + } + } } } diff --git a/Content.Client/Ame/UI/AmeWindow.xaml.cs b/Content.Client/Ame/UI/AmeWindow.xaml.cs index d6d580bcdaf..8b91ec59660 100644 --- a/Content.Client/Ame/UI/AmeWindow.xaml.cs +++ b/Content.Client/Ame/UI/AmeWindow.xaml.cs @@ -1,4 +1,3 @@ -using System.Linq; using Content.Client.UserInterface; using Content.Shared.Ame.Components; using Robust.Client.AutoGenerated; @@ -10,17 +9,15 @@ namespace Content.Client.Ame.UI [GenerateTypedNameReferences] public sealed partial class AmeWindow : DefaultWindow { - public event Action? OnAmeButton; - - public AmeWindow() + public AmeWindow(AmeControllerBoundUserInterface ui) { RobustXamlLoader.Load(this); IoCManager.InjectDependencies(this); - EjectButton.OnPressed += _ => OnAmeButton?.Invoke(UiButton.Eject); - ToggleInjection.OnPressed += _ => OnAmeButton?.Invoke(UiButton.ToggleInjection); - IncreaseFuelButton.OnPressed += _ => OnAmeButton?.Invoke(UiButton.IncreaseFuel); - DecreaseFuelButton.OnPressed += _ => OnAmeButton?.Invoke(UiButton.DecreaseFuel); + EjectButton.OnPressed += _ => ui.ButtonPressed(UiButton.Eject); + ToggleInjection.OnPressed += _ => ui.ButtonPressed(UiButton.ToggleInjection); + IncreaseFuelButton.OnPressed += _ => ui.ButtonPressed(UiButton.IncreaseFuel); + DecreaseFuelButton.OnPressed += _ => ui.ButtonPressed(UiButton.DecreaseFuel); } /// @@ -32,7 +29,7 @@ public void UpdateState(BoundUserInterfaceState state) var castState = (AmeControllerBoundUserInterfaceState) state; // Disable all buttons if not powered - if (Contents.Children.Any()) + if (Contents.Children != null) { ButtonHelpers.SetButtonDisabledRecursive(Contents, !castState.HasPower); EjectButton.Disabled = false; @@ -68,8 +65,8 @@ public void UpdateState(BoundUserInterfaceState state) CoreCount.Text = $"{castState.CoreCount}"; InjectionAmount.Text = $"{castState.InjectionAmount}"; // format power statistics to pretty numbers - CurrentPowerSupply.Text = $"{castState.CurrentPowerSupply:N1}"; - TargetedPowerSupply.Text = $"{castState.TargetedPowerSupply:N1}"; + CurrentPowerSupply.Text = $"{castState.CurrentPowerSupply.ToString("N1")}"; + TargetedPowerSupply.Text = $"{castState.TargetedPowerSupply.ToString("N1")}"; } } } diff --git a/Content.Client/Anomaly/Ui/AnomalyGeneratorBoundUserInterface.cs b/Content.Client/Anomaly/Ui/AnomalyGeneratorBoundUserInterface.cs index 5d1985485c4..5764d0a097d 100644 --- a/Content.Client/Anomaly/Ui/AnomalyGeneratorBoundUserInterface.cs +++ b/Content.Client/Anomaly/Ui/AnomalyGeneratorBoundUserInterface.cs @@ -2,7 +2,6 @@ using Content.Shared.Gravity; using JetBrains.Annotations; using Robust.Client.GameObjects; -using Robust.Client.UserInterface; namespace Content.Client.Anomaly.Ui; @@ -19,8 +18,10 @@ protected override void Open() { base.Open(); - _window = this.CreateWindow(); - _window.SetEntity(Owner); + _window = new(Owner); + + _window.OpenCentered(); + _window.OnClose += Close; _window.OnGenerateButtonPressed += () => { @@ -36,5 +37,18 @@ protected override void UpdateState(BoundUserInterfaceState state) return; _window?.UpdateState(msg); } + + protected override void Dispose(bool disposing) + { + base.Dispose(disposing); + if (!disposing) return; + + _window?.Dispose(); + } + + public void SetPowerSwitch(bool on) + { + SendMessage(new SharedGravityGeneratorComponent.SwitchGeneratorMessage(on)); + } } diff --git a/Content.Client/Anomaly/Ui/AnomalyGeneratorWindow.xaml.cs b/Content.Client/Anomaly/Ui/AnomalyGeneratorWindow.xaml.cs index 82d41192dd0..08438e2a1b2 100644 --- a/Content.Client/Anomaly/Ui/AnomalyGeneratorWindow.xaml.cs +++ b/Content.Client/Anomaly/Ui/AnomalyGeneratorWindow.xaml.cs @@ -18,21 +18,17 @@ public sealed partial class AnomalyGeneratorWindow : FancyWindow public Action? OnGenerateButtonPressed; - public AnomalyGeneratorWindow() + public AnomalyGeneratorWindow(EntityUid gen) { RobustXamlLoader.Load(this); IoCManager.InjectDependencies(this); + EntityView.SetEntity(gen); EntityView.SpriteOffset = false; GenerateButton.OnPressed += _ => OnGenerateButtonPressed?.Invoke(); } - public void SetEntity(EntityUid uid) - { - EntityView.SetEntity(uid); - } - public void UpdateState(AnomalyGeneratorUserInterfaceState state) { _cooldownEnd = state.CooldownEndTime; diff --git a/Content.Client/Arcade/BlockGameMenu.cs b/Content.Client/Arcade/BlockGameMenu.cs index 4a579fc4bf4..eeda2a31020 100644 --- a/Content.Client/Arcade/BlockGameMenu.cs +++ b/Content.Client/Arcade/BlockGameMenu.cs @@ -28,6 +28,8 @@ public sealed class BlockGameMenu : DefaultWindow private static readonly Vector2 BlockSize = new(15, 15); + private readonly BlockGameBoundUserInterface _owner; + private readonly PanelContainer _mainPanel; private readonly BoxContainer _gameRootContainer; @@ -56,11 +58,10 @@ public sealed class BlockGameMenu : DefaultWindow private bool _isPlayer = false; private bool _gameOver = false; - public event Action? OnAction; - - public BlockGameMenu() + public BlockGameMenu(BlockGameBoundUserInterface owner) { Title = Loc.GetString("blockgame-menu-title"); + _owner = owner; MinSize = SetSize = new Vector2(410, 490); @@ -175,7 +176,7 @@ public BlockGameMenu() }; _newGameButton.OnPressed += (e) => { - OnAction?.Invoke(BlockGamePlayerAction.NewGame); + _owner.SendAction(BlockGamePlayerAction.NewGame); }; pauseMenuContainer.AddChild(_newGameButton); pauseMenuContainer.AddChild(new Control { MinSize = new Vector2(1, 10) }); @@ -185,10 +186,7 @@ public BlockGameMenu() Text = Loc.GetString("blockgame-menu-button-scoreboard"), TextAlign = Label.AlignMode.Center }; - _scoreBoardButton.OnPressed += (e) => - { - OnAction?.Invoke(BlockGamePlayerAction.ShowHighscores); - }; + _scoreBoardButton.OnPressed += (e) => _owner.SendAction(BlockGamePlayerAction.ShowHighscores); pauseMenuContainer.AddChild(_scoreBoardButton); _unpauseButtonMargin = new Control { MinSize = new Vector2(1, 10), Visible = false }; pauseMenuContainer.AddChild(_unpauseButtonMargin); @@ -201,7 +199,7 @@ public BlockGameMenu() }; _unpauseButton.OnPressed += (e) => { - OnAction?.Invoke(BlockGamePlayerAction.Unpause); + _owner.SendAction(BlockGamePlayerAction.Unpause); }; pauseMenuContainer.AddChild(_unpauseButton); @@ -259,7 +257,7 @@ public BlockGameMenu() }; _finalNewGameButton.OnPressed += (e) => { - OnAction?.Invoke(BlockGamePlayerAction.NewGame); + _owner.SendAction(BlockGamePlayerAction.NewGame); }; gameOverMenuContainer.AddChild(_finalNewGameButton); @@ -329,10 +327,7 @@ public BlockGameMenu() Text = Loc.GetString("blockgame-menu-button-back"), TextAlign = Label.AlignMode.Center }; - _highscoreBackButton.OnPressed += (e) => - { - OnAction?.Invoke(BlockGamePlayerAction.Pause); - }; + _highscoreBackButton.OnPressed += (e) => _owner.SendAction(BlockGamePlayerAction.Pause); menuContainer.AddChild(_highscoreBackButton); menuInnerPanel.AddChild(menuContainer); @@ -478,7 +473,7 @@ protected override void KeyboardFocusExited() private void TryPause() { - OnAction?.Invoke(BlockGamePlayerAction.Pause); + _owner.SendAction(BlockGamePlayerAction.Pause); } public void SetStarted() @@ -581,19 +576,19 @@ protected override void KeyBindDown(GUIBoundKeyEventArgs args) return; else if (args.Function == ContentKeyFunctions.ArcadeLeft) - OnAction?.Invoke(BlockGamePlayerAction.StartLeft); + _owner.SendAction(BlockGamePlayerAction.StartLeft); else if (args.Function == ContentKeyFunctions.ArcadeRight) - OnAction?.Invoke(BlockGamePlayerAction.StartRight); + _owner.SendAction(BlockGamePlayerAction.StartRight); else if (args.Function == ContentKeyFunctions.ArcadeUp) - OnAction?.Invoke(BlockGamePlayerAction.Rotate); + _owner.SendAction(BlockGamePlayerAction.Rotate); else if (args.Function == ContentKeyFunctions.Arcade3) - OnAction?.Invoke(BlockGamePlayerAction.CounterRotate); + _owner.SendAction(BlockGamePlayerAction.CounterRotate); else if (args.Function == ContentKeyFunctions.ArcadeDown) - OnAction?.Invoke(BlockGamePlayerAction.SoftdropStart); + _owner.SendAction(BlockGamePlayerAction.SoftdropStart); else if (args.Function == ContentKeyFunctions.Arcade2) - OnAction?.Invoke(BlockGamePlayerAction.Hold); + _owner.SendAction(BlockGamePlayerAction.Hold); else if (args.Function == ContentKeyFunctions.Arcade1) - OnAction?.Invoke(BlockGamePlayerAction.Harddrop); + _owner.SendAction(BlockGamePlayerAction.Harddrop); } protected override void KeyBindUp(GUIBoundKeyEventArgs args) @@ -604,11 +599,11 @@ protected override void KeyBindUp(GUIBoundKeyEventArgs args) return; else if (args.Function == ContentKeyFunctions.ArcadeLeft) - OnAction?.Invoke(BlockGamePlayerAction.EndLeft); + _owner.SendAction(BlockGamePlayerAction.EndLeft); else if (args.Function == ContentKeyFunctions.ArcadeRight) - OnAction?.Invoke(BlockGamePlayerAction.EndRight); + _owner.SendAction(BlockGamePlayerAction.EndRight); else if (args.Function == ContentKeyFunctions.ArcadeDown) - OnAction?.Invoke(BlockGamePlayerAction.SoftdropEnd); + _owner.SendAction(BlockGamePlayerAction.SoftdropEnd); } public void UpdateNextBlock(BlockGameBlock[] blocks) diff --git a/Content.Client/Arcade/SpaceVillainArcadeMenu.cs b/Content.Client/Arcade/SpaceVillainArcadeMenu.cs index 1ee4c268184..e5542a5848e 100644 --- a/Content.Client/Arcade/SpaceVillainArcadeMenu.cs +++ b/Content.Client/Arcade/SpaceVillainArcadeMenu.cs @@ -8,6 +8,8 @@ namespace Content.Client.Arcade { public sealed class SpaceVillainArcadeMenu : DefaultWindow { + public SpaceVillainArcadeBoundUserInterface Owner { get; set; } + private readonly Label _enemyNameLabel; private readonly Label _playerInfoLabel; private readonly Label _enemyInfoLabel; @@ -15,13 +17,11 @@ public sealed class SpaceVillainArcadeMenu : DefaultWindow private readonly Label _enemyActionLabel; private readonly Button[] _gameButtons = new Button[3]; //used to disable/enable all game buttons - - public event Action? OnPlayerAction; - - public SpaceVillainArcadeMenu() + public SpaceVillainArcadeMenu(SpaceVillainArcadeBoundUserInterface owner) { MinSize = SetSize = new Vector2(300, 225); Title = Loc.GetString("spacevillain-menu-title"); + Owner = owner; var grid = new GridContainer { Columns = 1 }; @@ -47,43 +47,32 @@ public SpaceVillainArcadeMenu() grid.AddChild(_enemyActionLabel); var buttonGrid = new GridContainer { Columns = 3 }; - _gameButtons[0] = new Button() + _gameButtons[0] = new ActionButton(Owner, SharedSpaceVillainArcadeComponent.PlayerAction.Attack) { Text = Loc.GetString("spacevillain-menu-button-attack") }; - - _gameButtons[0].OnPressed += - _ => OnPlayerAction?.Invoke(SharedSpaceVillainArcadeComponent.PlayerAction.Attack); buttonGrid.AddChild(_gameButtons[0]); - _gameButtons[1] = new Button() + _gameButtons[1] = new ActionButton(Owner, SharedSpaceVillainArcadeComponent.PlayerAction.Heal) { Text = Loc.GetString("spacevillain-menu-button-heal") }; - - _gameButtons[1].OnPressed += - _ => OnPlayerAction?.Invoke(SharedSpaceVillainArcadeComponent.PlayerAction.Heal); buttonGrid.AddChild(_gameButtons[1]); - _gameButtons[2] = new Button() + _gameButtons[2] = new ActionButton(Owner, SharedSpaceVillainArcadeComponent.PlayerAction.Recharge) { Text = Loc.GetString("spacevillain-menu-button-recharge") }; - - _gameButtons[2].OnPressed += - _ => OnPlayerAction?.Invoke(SharedSpaceVillainArcadeComponent.PlayerAction.Recharge); buttonGrid.AddChild(_gameButtons[2]); centerContainer = new CenterContainer(); centerContainer.AddChild(buttonGrid); grid.AddChild(centerContainer); - var newGame = new Button() + var newGame = new ActionButton(Owner, SharedSpaceVillainArcadeComponent.PlayerAction.NewGame) { Text = Loc.GetString("spacevillain-menu-button-new-game") }; - - newGame.OnPressed += _ => OnPlayerAction?.Invoke(SharedSpaceVillainArcadeComponent.PlayerAction.NewGame); grid.AddChild(newGame); Contents.AddChild(grid); @@ -110,5 +99,23 @@ public void UpdateInfo(SharedSpaceVillainArcadeComponent.SpaceVillainArcadeDataU _playerActionLabel.Text = message.PlayerActionMessage; _enemyActionLabel.Text = message.EnemyActionMessage; } + + private sealed class ActionButton : Button + { + private readonly SpaceVillainArcadeBoundUserInterface _owner; + private readonly SharedSpaceVillainArcadeComponent.PlayerAction _playerAction; + + public ActionButton(SpaceVillainArcadeBoundUserInterface owner, SharedSpaceVillainArcadeComponent.PlayerAction playerAction) + { + _owner = owner; + _playerAction = playerAction; + OnPressed += Clicked; + } + + private void Clicked(ButtonEventArgs e) + { + _owner.SendAction(_playerAction); + } + } } } diff --git a/Content.Client/Arcade/UI/BlockGameBoundUserInterface.cs b/Content.Client/Arcade/UI/BlockGameBoundUserInterface.cs index 8fa8035afd6..1a3422dec0f 100644 --- a/Content.Client/Arcade/UI/BlockGameBoundUserInterface.cs +++ b/Content.Client/Arcade/UI/BlockGameBoundUserInterface.cs @@ -1,6 +1,5 @@ using Content.Shared.Arcade; using Robust.Client.GameObjects; -using Robust.Client.UserInterface; namespace Content.Client.Arcade.UI; @@ -16,7 +15,9 @@ protected override void Open() { base.Open(); - _menu = this.CreateWindow(); + _menu = new BlockGameMenu(this); + _menu.OnClose += Close; + _menu.OpenCentered(); } protected override void ReceiveMessage(BoundUserInterfaceMessage message) diff --git a/Content.Client/Arcade/UI/SpaceVillainArcadeBoundUserInterface.cs b/Content.Client/Arcade/UI/SpaceVillainArcadeBoundUserInterface.cs index c0704530de2..40bbe8b2d8c 100644 --- a/Content.Client/Arcade/UI/SpaceVillainArcadeBoundUserInterface.cs +++ b/Content.Client/Arcade/UI/SpaceVillainArcadeBoundUserInterface.cs @@ -1,5 +1,4 @@ using Robust.Client.GameObjects; -using Robust.Client.UserInterface; using Robust.Shared.GameObjects; using Robust.Shared.ViewVariables; using static Content.Shared.Arcade.SharedSpaceVillainArcadeComponent; @@ -10,6 +9,8 @@ public sealed class SpaceVillainArcadeBoundUserInterface : BoundUserInterface { [ViewVariables] private SpaceVillainArcadeMenu? _menu; + //public SharedSpaceVillainArcadeComponent SpaceVillainArcade; + public SpaceVillainArcadeBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey) { SendAction(PlayerAction.RequestData); @@ -24,7 +25,10 @@ protected override void Open() { base.Open(); - _menu = this.CreateWindow(); + _menu = new SpaceVillainArcadeMenu(this); + + _menu.OnClose += Close; + _menu.OpenCentered(); } protected override void ReceiveMessage(BoundUserInterfaceMessage message) @@ -32,4 +36,12 @@ protected override void ReceiveMessage(BoundUserInterfaceMessage message) if (message is SpaceVillainArcadeDataUpdateMessage msg) _menu?.UpdateInfo(msg); } + + protected override void Dispose(bool disposing) + { + base.Dispose(disposing); + + if (disposing) + _menu?.Dispose(); + } } diff --git a/Content.Client/Atmos/Monitor/UI/AirAlarmBoundUserInterface.cs b/Content.Client/Atmos/Monitor/UI/AirAlarmBoundUserInterface.cs index 2ae15188355..8f3b507c806 100644 --- a/Content.Client/Atmos/Monitor/UI/AirAlarmBoundUserInterface.cs +++ b/Content.Client/Atmos/Monitor/UI/AirAlarmBoundUserInterface.cs @@ -2,7 +2,6 @@ using Content.Shared.Atmos.Monitor; using Content.Shared.Atmos.Monitor.Components; using Robust.Client.GameObjects; -using Robust.Client.UserInterface; using Robust.Shared.GameObjects; using Robust.Shared.IoC; using Robust.Shared.Log; @@ -21,9 +20,16 @@ protected override void Open() { base.Open(); - _window = this.CreateWindow(); - _window.SetEntity(Owner); + _window = new AirAlarmWindow(this); + if (State != null) + { + UpdateState(State); + } + + _window.OpenCentered(); + + _window.OnClose += Close; _window.AtmosDeviceDataChanged += OnDeviceDataChanged; _window.AtmosDeviceDataCopied += OnDeviceDataCopied; _window.AtmosAlarmThresholdChanged += OnThresholdChanged; diff --git a/Content.Client/Atmos/Monitor/UI/AirAlarmWindow.xaml.cs b/Content.Client/Atmos/Monitor/UI/AirAlarmWindow.xaml.cs index eeec11c7660..43be67c9d6b 100644 --- a/Content.Client/Atmos/Monitor/UI/AirAlarmWindow.xaml.cs +++ b/Content.Client/Atmos/Monitor/UI/AirAlarmWindow.xaml.cs @@ -47,7 +47,7 @@ public sealed partial class AirAlarmWindow : FancyWindow private CheckBox _autoMode => AutoModeCheckBox; - public AirAlarmWindow() + public AirAlarmWindow(BoundUserInterface owner) { RobustXamlLoader.Load(this); @@ -95,11 +95,8 @@ public AirAlarmWindow() _sensors.Clear(); ResyncAllRequested!.Invoke(); }; - } - public void SetEntity(EntityUid uid) - { - EntityView.SetEntity(uid); + EntityView.SetEntity(owner.Owner); } public void UpdateState(AirAlarmUIState state) diff --git a/Content.Client/Atmos/UI/GasCanisterBoundUserInterface.cs b/Content.Client/Atmos/UI/GasCanisterBoundUserInterface.cs index 7bf9b396d5e..a5e316a8def 100644 --- a/Content.Client/Atmos/UI/GasCanisterBoundUserInterface.cs +++ b/Content.Client/Atmos/UI/GasCanisterBoundUserInterface.cs @@ -1,7 +1,6 @@ using Content.Shared.Atmos.Piping.Binary.Components; using JetBrains.Annotations; using Robust.Client.GameObjects; -using Robust.Client.UserInterface; namespace Content.Client.Atmos.UI { @@ -22,8 +21,14 @@ protected override void Open() { base.Open(); - _window = this.CreateWindow(); + _window = new GasCanisterWindow(); + if (State != null) + UpdateState(State); + + _window.OpenCentered(); + + _window.OnClose += Close; _window.ReleaseValveCloseButtonPressed += OnReleaseValveClosePressed; _window.ReleaseValveOpenButtonPressed += OnReleaseValveOpenPressed; _window.ReleasePressureSet += OnReleasePressureSet; diff --git a/Content.Client/Atmos/UI/GasFilterBoundUserInterface.cs b/Content.Client/Atmos/UI/GasFilterBoundUserInterface.cs index 2b8020924cf..1904e2b3402 100644 --- a/Content.Client/Atmos/UI/GasFilterBoundUserInterface.cs +++ b/Content.Client/Atmos/UI/GasFilterBoundUserInterface.cs @@ -3,7 +3,6 @@ using Content.Shared.Atmos.Piping.Trinary.Components; using Content.Shared.Localizations; using JetBrains.Annotations; -using Robust.Client.UserInterface; namespace Content.Client.Atmos.UI { @@ -29,8 +28,14 @@ protected override void Open() var atmosSystem = EntMan.System(); - _window = this.CreateWindow(); - _window.PopulateGasList(atmosSystem.Gases); + _window = new GasFilterWindow(atmosSystem.Gases); + + if (State != null) + UpdateState(State); + + _window.OpenCentered(); + + _window.OnClose += Close; _window.ToggleStatusButtonPressed += OnToggleStatusButtonPressed; _window.FilterTransferRateChanged += OnFilterTransferRatePressed; diff --git a/Content.Client/Atmos/UI/GasFilterWindow.xaml.cs b/Content.Client/Atmos/UI/GasFilterWindow.xaml.cs index 62748b52592..28766c688a0 100644 --- a/Content.Client/Atmos/UI/GasFilterWindow.xaml.cs +++ b/Content.Client/Atmos/UI/GasFilterWindow.xaml.cs @@ -26,9 +26,10 @@ public sealed partial class GasFilterWindow : DefaultWindow public event Action? FilterTransferRateChanged; public event Action? SelectGasPressed; - public GasFilterWindow() + public GasFilterWindow(IEnumerable gases) { RobustXamlLoader.Load(this); + PopulateGasList(gases); ToggleStatusButton.OnPressed += _ => SetFilterStatus(!FilterStatus); ToggleStatusButton.OnPressed += _ => ToggleStatusButtonPressed?.Invoke(); @@ -72,7 +73,7 @@ public void SetGasFiltered(string? id, string name) SelectGasButton.Disabled = true; } - public void PopulateGasList(IEnumerable gases) + private void PopulateGasList(IEnumerable gases) { GasList.Add(new ItemList.Item(GasList) { @@ -80,7 +81,7 @@ public void PopulateGasList(IEnumerable gases) Text = Loc.GetString("comp-gas-filter-ui-filter-gas-none") }); - foreach (var gas in gases) + foreach (GasPrototype gas in gases) { var gasName = Loc.GetString(gas.Name); GasList.Add(GetGasItem(gas.ID, gasName, GasList)); diff --git a/Content.Client/Atmos/UI/GasMixerBoundUserInteface.cs b/Content.Client/Atmos/UI/GasMixerBoundUserInteface.cs index 392fbf1cd9a..709c06517cb 100644 --- a/Content.Client/Atmos/UI/GasMixerBoundUserInteface.cs +++ b/Content.Client/Atmos/UI/GasMixerBoundUserInteface.cs @@ -2,7 +2,7 @@ using Content.Shared.Atmos.Piping.Trinary.Components; using Content.Shared.Localizations; using JetBrains.Annotations; -using Robust.Client.UserInterface; +using Robust.Client.GameObjects; namespace Content.Client.Atmos.UI { @@ -26,7 +26,14 @@ protected override void Open() { base.Open(); - _window = this.CreateWindow(); + _window = new GasMixerWindow(); + + if (State != null) + UpdateState(State); + + _window.OpenCentered(); + + _window.OnClose += Close; _window.ToggleStatusButtonPressed += OnToggleStatusButtonPressed; _window.MixerOutputPressureChanged += OnMixerOutputPressurePressed; @@ -76,5 +83,12 @@ protected override void UpdateState(BoundUserInterfaceState state) _window.SetOutputPressure(cast.OutputPressure); _window.SetNodePercentages(cast.NodeOne); } + + protected override void Dispose(bool disposing) + { + base.Dispose(disposing); + if (!disposing) return; + _window?.Dispose(); + } } } diff --git a/Content.Client/Atmos/UI/GasPressurePumpBoundUserInterface.cs b/Content.Client/Atmos/UI/GasPressurePumpBoundUserInterface.cs index 220fdbe875c..6eba2e0d215 100644 --- a/Content.Client/Atmos/UI/GasPressurePumpBoundUserInterface.cs +++ b/Content.Client/Atmos/UI/GasPressurePumpBoundUserInterface.cs @@ -3,7 +3,6 @@ using Content.Shared.Localizations; using JetBrains.Annotations; using Robust.Client.GameObjects; -using Robust.Client.UserInterface; namespace Content.Client.Atmos.UI { @@ -27,7 +26,14 @@ protected override void Open() { base.Open(); - _window = this.CreateWindow(); + _window = new GasPressurePumpWindow(); + + if (State != null) + UpdateState(State); + + _window.OpenCentered(); + + _window.OnClose += Close; _window.ToggleStatusButtonPressed += OnToggleStatusButtonPressed; _window.PumpOutputPressureChanged += OnPumpOutputPressurePressed; @@ -61,5 +67,12 @@ protected override void UpdateState(BoundUserInterfaceState state) _window.SetPumpStatus(cast.Enabled); _window.SetOutputPressure(cast.OutputPressure); } + + protected override void Dispose(bool disposing) + { + base.Dispose(disposing); + if (!disposing) return; + _window?.Dispose(); + } } } diff --git a/Content.Client/Atmos/UI/GasThermomachineBoundUserInterface.cs b/Content.Client/Atmos/UI/GasThermomachineBoundUserInterface.cs index d62be8f4bb4..1664c8b9d75 100644 --- a/Content.Client/Atmos/UI/GasThermomachineBoundUserInterface.cs +++ b/Content.Client/Atmos/UI/GasThermomachineBoundUserInterface.cs @@ -2,7 +2,6 @@ using Content.Shared.Atmos.Piping.Unary.Components; using JetBrains.Annotations; using Robust.Client.GameObjects; -using Robust.Client.UserInterface; namespace Content.Client.Atmos.UI { @@ -32,7 +31,14 @@ protected override void Open() { base.Open(); - _window = this.CreateWindow(); + _window = new GasThermomachineWindow(); + + if (State != null) + UpdateState(State); + + _window.OpenCentered(); + + _window.OnClose += Close; _window.ToggleStatusButton.OnPressed += _ => OnToggleStatusButtonPressed(); _window.TemperatureSpinbox.OnValueChanged += _ => OnTemperatureChanged(_window.TemperatureSpinbox.Value); @@ -85,5 +91,12 @@ protected override void UpdateState(BoundUserInterfaceState state) true => Loc.GetString("comp-gas-thermomachine-ui-title-heater") }; } + + protected override void Dispose(bool disposing) + { + base.Dispose(disposing); + if (!disposing) return; + _window?.Dispose(); + } } } diff --git a/Content.Client/Atmos/UI/GasVolumePumpBoundUserInterface.cs b/Content.Client/Atmos/UI/GasVolumePumpBoundUserInterface.cs index 642f34c2f92..1b39306181a 100644 --- a/Content.Client/Atmos/UI/GasVolumePumpBoundUserInterface.cs +++ b/Content.Client/Atmos/UI/GasVolumePumpBoundUserInterface.cs @@ -3,7 +3,6 @@ using Content.Shared.Localizations; using JetBrains.Annotations; using Robust.Client.GameObjects; -using Robust.Client.UserInterface; namespace Content.Client.Atmos.UI { @@ -27,7 +26,14 @@ protected override void Open() { base.Open(); - _window = this.CreateWindow(); + _window = new GasVolumePumpWindow(); + + if (State != null) + UpdateState(State); + + _window.OpenCentered(); + + _window.OnClose += Close; _window.ToggleStatusButtonPressed += OnToggleStatusButtonPressed; _window.PumpTransferRateChanged += OnPumpTransferRatePressed; @@ -58,9 +64,16 @@ protected override void UpdateState(BoundUserInterfaceState state) if (_window == null || state is not GasVolumePumpBoundUserInterfaceState cast) return; - _window.Title = cast.PumpLabel; + _window.Title = (cast.PumpLabel); _window.SetPumpStatus(cast.Enabled); _window.SetTransferRate(cast.TransferRate); } + + protected override void Dispose(bool disposing) + { + base.Dispose(disposing); + if (!disposing) return; + _window?.Dispose(); + } } } diff --git a/Content.Client/Atmos/UI/SpaceHeaterBoundUserInterface.cs b/Content.Client/Atmos/UI/SpaceHeaterBoundUserInterface.cs index e70426575d4..4d8d1191e91 100644 --- a/Content.Client/Atmos/UI/SpaceHeaterBoundUserInterface.cs +++ b/Content.Client/Atmos/UI/SpaceHeaterBoundUserInterface.cs @@ -1,6 +1,5 @@ using Content.Shared.Atmos.Piping.Portable.Components; using JetBrains.Annotations; -using Robust.Client.UserInterface; using Robust.Client.UserInterface.Controls; namespace Content.Client.Atmos.UI; @@ -22,7 +21,14 @@ protected override void Open() { base.Open(); - _window = this.CreateWindow(); + _window = new SpaceHeaterWindow(); + + if (State != null) + UpdateState(State); + + _window.OpenCentered(); + + _window.OnClose += Close; _window.ToggleStatusButton.OnPressed += _ => OnToggleStatusButtonPressed(); _window.IncreaseTempRange.OnPressed += _ => OnTemperatureRangeChanged(_window.TemperatureChangeDelta); diff --git a/Content.Client/Audio/Jukebox/JukeboxBoundUserInterface.cs b/Content.Client/Audio/Jukebox/JukeboxBoundUserInterface.cs index 865dfc478d0..60fe339069a 100644 --- a/Content.Client/Audio/Jukebox/JukeboxBoundUserInterface.cs +++ b/Content.Client/Audio/Jukebox/JukeboxBoundUserInterface.cs @@ -1,7 +1,8 @@ using Content.Shared.Audio.Jukebox; using Robust.Client.Audio; -using Robust.Client.UserInterface; +using Robust.Client.Player; using Robust.Shared.Audio.Components; +using Robust.Shared.Player; using Robust.Shared.Prototypes; namespace Content.Client.Audio.Jukebox; @@ -22,7 +23,9 @@ protected override void Open() { base.Open(); - _menu = this.CreateWindow(); + _menu = new JukeboxMenu(); + _menu.OnClose += Close; + _menu.OpenCentered(); _menu.OnPlayPressed += args => { @@ -97,5 +100,19 @@ public void SetTime(float time) SendMessage(new JukeboxSetTimeMessage(sentTime)); } + + protected override void Dispose(bool disposing) + { + base.Dispose(disposing); + if (!disposing) + return; + + if (_menu == null) + return; + + _menu.OnClose -= Close; + _menu.Dispose(); + _menu = null; + } } diff --git a/Content.Client/Bed/Cryostorage/CryostorageBoundUserInterface.cs b/Content.Client/Bed/Cryostorage/CryostorageBoundUserInterface.cs index 09f3cec8fbf..ffab1625483 100644 --- a/Content.Client/Bed/Cryostorage/CryostorageBoundUserInterface.cs +++ b/Content.Client/Bed/Cryostorage/CryostorageBoundUserInterface.cs @@ -1,6 +1,5 @@ using Content.Shared.Bed.Cryostorage; using JetBrains.Annotations; -using Robust.Client.UserInterface; namespace Content.Client.Bed.Cryostorage; @@ -18,7 +17,9 @@ protected override void Open() { base.Open(); - _menu = this.CreateWindow(); + _menu = new(); + + _menu.OnClose += Close; _menu.SlotRemoveButtonPressed += (ent, slot) => { @@ -29,6 +30,8 @@ protected override void Open() { SendMessage(new CryostorageRemoveItemBuiMessage(ent, hand, CryostorageRemoveItemBuiMessage.RemovalType.Hand)); }; + + _menu.OpenCentered(); } protected override void UpdateState(BoundUserInterfaceState state) @@ -42,4 +45,12 @@ protected override void UpdateState(BoundUserInterfaceState state) break; } } + + protected override void Dispose(bool disposing) + { + base.Dispose(disposing); + if (!disposing) + return; + _menu?.Dispose(); + } } diff --git a/Content.Client/Cargo/BUI/CargoBountyConsoleBoundUserInterface.cs b/Content.Client/Cargo/BUI/CargoBountyConsoleBoundUserInterface.cs index 44c40143d83..d3365702bcf 100644 --- a/Content.Client/Cargo/BUI/CargoBountyConsoleBoundUserInterface.cs +++ b/Content.Client/Cargo/BUI/CargoBountyConsoleBoundUserInterface.cs @@ -1,7 +1,6 @@ using Content.Client.Cargo.UI; using Content.Shared.Cargo.Components; using JetBrains.Annotations; -using Robust.Client.UserInterface; namespace Content.Client.Cargo.BUI; @@ -19,7 +18,9 @@ protected override void Open() { base.Open(); - _menu = this.CreateWindow(); + _menu = new(); + + _menu.OnClose += Close; _menu.OnLabelButtonPressed += id => { @@ -30,6 +31,8 @@ protected override void Open() { SendMessage(new BountySkipMessage(id)); }; + + _menu.OpenCentered(); } protected override void UpdateState(BoundUserInterfaceState message) @@ -41,4 +44,14 @@ protected override void UpdateState(BoundUserInterfaceState message) _menu?.UpdateEntries(state.Bounties, state.UntilNextSkip); } + + protected override void Dispose(bool disposing) + { + base.Dispose(disposing); + + if (!disposing) + return; + + _menu?.Dispose(); + } } diff --git a/Content.Client/Cargo/BUI/CargoPalletConsoleBoundUserInterface.cs b/Content.Client/Cargo/BUI/CargoPalletConsoleBoundUserInterface.cs index 2461dafb5f3..20c23a48a0d 100644 --- a/Content.Client/Cargo/BUI/CargoPalletConsoleBoundUserInterface.cs +++ b/Content.Client/Cargo/BUI/CargoPalletConsoleBoundUserInterface.cs @@ -2,7 +2,6 @@ using Content.Shared.Cargo.BUI; using Content.Shared.Cargo.Events; using Robust.Client.GameObjects; -using Robust.Client.UserInterface; namespace Content.Client.Cargo.BUI; @@ -19,9 +18,21 @@ protected override void Open() { base.Open(); - _menu = this.CreateWindow(); + _menu = new CargoPalletMenu(); _menu.AppraiseRequested += OnAppraisal; _menu.SellRequested += OnSell; + _menu.OnClose += Close; + + _menu.OpenCentered(); + } + + protected override void Dispose(bool disposing) + { + base.Dispose(disposing); + if (disposing) + { + _menu?.Dispose(); + } } private void OnAppraisal() diff --git a/Content.Client/Cargo/BUI/CargoShuttleConsoleBoundUserInterface.cs b/Content.Client/Cargo/BUI/CargoShuttleConsoleBoundUserInterface.cs index 02b721b9020..422d03707a0 100644 --- a/Content.Client/Cargo/BUI/CargoShuttleConsoleBoundUserInterface.cs +++ b/Content.Client/Cargo/BUI/CargoShuttleConsoleBoundUserInterface.cs @@ -2,7 +2,6 @@ using Content.Shared.Cargo.BUI; using JetBrains.Annotations; using Robust.Client.GameObjects; -using Robust.Client.UserInterface; using Robust.Shared.Prototypes; namespace Content.Client.Cargo.BUI; @@ -10,8 +9,6 @@ namespace Content.Client.Cargo.BUI; [UsedImplicitly] public sealed class CargoShuttleConsoleBoundUserInterface : BoundUserInterface { - [Dependency] private readonly IPrototypeManager _protoManager = default!; - [ViewVariables] private CargoShuttleMenu? _menu; @@ -22,7 +19,24 @@ public CargoShuttleConsoleBoundUserInterface(EntityUid owner, Enum uiKey) : base protected override void Open() { base.Open(); - _menu = this.CreateWindow(); + var collection = IoCManager.Instance; + + if (collection == null) + return; + + _menu = new CargoShuttleMenu(collection.Resolve(), collection.Resolve().GetEntitySystem()); + _menu.OnClose += Close; + + _menu.OpenCentered(); + } + + protected override void Dispose(bool disposing) + { + base.Dispose(disposing); + if (disposing) + { + _menu?.Dispose(); + } } protected override void UpdateState(BoundUserInterfaceState state) @@ -31,6 +45,6 @@ protected override void UpdateState(BoundUserInterfaceState state) if (state is not CargoShuttleConsoleBoundUserInterfaceState cargoState) return; _menu?.SetAccountName(cargoState.AccountName); _menu?.SetShuttleName(cargoState.ShuttleName); - _menu?.SetOrders(EntMan.System(), _protoManager, cargoState.Orders); + _menu?.SetOrders(cargoState.Orders); } } diff --git a/Content.Client/Cargo/UI/CargoShuttleMenu.xaml.cs b/Content.Client/Cargo/UI/CargoShuttleMenu.xaml.cs index 43b00089e16..c591f917da3 100644 --- a/Content.Client/Cargo/UI/CargoShuttleMenu.xaml.cs +++ b/Content.Client/Cargo/UI/CargoShuttleMenu.xaml.cs @@ -12,9 +12,14 @@ namespace Content.Client.Cargo.UI [GenerateTypedNameReferences] public sealed partial class CargoShuttleMenu : FancyWindow { - public CargoShuttleMenu() + private readonly IPrototypeManager _protoManager; + private readonly SpriteSystem _spriteSystem; + + public CargoShuttleMenu(IPrototypeManager protoManager, SpriteSystem spriteSystem) { RobustXamlLoader.Load(this); + _protoManager = protoManager; + _spriteSystem = spriteSystem; Title = Loc.GetString("cargo-shuttle-console-menu-title"); } @@ -28,19 +33,19 @@ public void SetShuttleName(string name) ShuttleNameLabel.Text = name; } - public void SetOrders(SpriteSystem sprites, IPrototypeManager protoManager, List orders) + public void SetOrders(List orders) { Orders.DisposeAllChildren(); foreach (var order in orders) { - var product = protoManager.Index(order.ProductId); + var product = _protoManager.Index(order.ProductId); var productName = product.Name; var row = new CargoOrderRow { Order = order, - Icon = { Texture = sprites.Frame0(product) }, + Icon = { Texture = _spriteSystem.Frame0(product) }, ProductName = { Text = Loc.GetString( diff --git a/Content.Client/Chemistry/UI/ChemMasterBoundUserInterface.cs b/Content.Client/Chemistry/UI/ChemMasterBoundUserInterface.cs index 3ef7f0ae73e..988fea7978b 100644 --- a/Content.Client/Chemistry/UI/ChemMasterBoundUserInterface.cs +++ b/Content.Client/Chemistry/UI/ChemMasterBoundUserInterface.cs @@ -2,7 +2,6 @@ using Content.Shared.Containers.ItemSlots; using JetBrains.Annotations; using Robust.Client.GameObjects; -using Robust.Client.UserInterface; namespace Content.Client.Chemistry.UI { @@ -28,8 +27,13 @@ protected override void Open() base.Open(); // Setup window layout/elements - _window = this.CreateWindow(); - _window.Title = EntMan.GetComponent(Owner).EntityName; + _window = new ChemMasterWindow + { + Title = EntMan.GetComponent(Owner).EntityName, + }; + + _window.OpenCentered(); + _window.OnClose += Close; // Setup static button actions. _window.InputEjectButton.OnPressed += _ => SendMessage( @@ -71,5 +75,15 @@ protected override void UpdateState(BoundUserInterfaceState state) _window?.UpdateState(castState); // Update window state } + + protected override void Dispose(bool disposing) + { + base.Dispose(disposing); + + if (disposing) + { + _window?.Dispose(); + } + } } } diff --git a/Content.Client/Chemistry/UI/ReagentDispenserBoundUserInterface.cs b/Content.Client/Chemistry/UI/ReagentDispenserBoundUserInterface.cs index 2ad1b718887..99e5a3d3953 100644 --- a/Content.Client/Chemistry/UI/ReagentDispenserBoundUserInterface.cs +++ b/Content.Client/Chemistry/UI/ReagentDispenserBoundUserInterface.cs @@ -3,7 +3,6 @@ using Content.Shared.Containers.ItemSlots; using JetBrains.Annotations; using Robust.Client.GameObjects; -using Robust.Client.UserInterface; namespace Content.Client.Chemistry.UI { @@ -16,6 +15,9 @@ public sealed class ReagentDispenserBoundUserInterface : BoundUserInterface [ViewVariables] private ReagentDispenserWindow? _window; + [ViewVariables] + private ReagentDispenserBoundUserInterfaceState? _lastState; + public ReagentDispenserBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey) { } @@ -30,9 +32,14 @@ protected override void Open() base.Open(); // Setup window layout/elements - _window = this.CreateWindow(); - _window.Title = EntMan.GetComponent(Owner).EntityName; - _window.HelpGuidebookIds = EntMan.GetComponent(Owner).Guides; + _window = new() + { + Title = EntMan.GetComponent(Owner).EntityName, + HelpGuidebookIds = EntMan.GetComponent(Owner).Guides + }; + + _window.OpenCentered(); + _window.OnClose += Close; // Setup static button actions. _window.EjectButton.OnPressed += _ => SendMessage(new ItemSlotButtonPressedEvent(SharedReagentDispenser.OutputSlotName)); @@ -56,7 +63,19 @@ protected override void UpdateState(BoundUserInterfaceState state) base.UpdateState(state); var castState = (ReagentDispenserBoundUserInterfaceState) state; + _lastState = castState; + _window?.UpdateState(castState); //Update window state } + + protected override void Dispose(bool disposing) + { + base.Dispose(disposing); + + if (disposing) + { + _window?.Dispose(); + } + } } } diff --git a/Content.Client/Chemistry/UI/TransferAmountBoundUserInterface.cs b/Content.Client/Chemistry/UI/TransferAmountBoundUserInterface.cs index f1cb27a62a4..35df131312d 100644 --- a/Content.Client/Chemistry/UI/TransferAmountBoundUserInterface.cs +++ b/Content.Client/Chemistry/UI/TransferAmountBoundUserInterface.cs @@ -2,7 +2,6 @@ using Content.Shared.FixedPoint; using JetBrains.Annotations; using Robust.Client.GameObjects; -using Robust.Client.UserInterface; namespace Content.Client.Chemistry.UI { @@ -19,7 +18,7 @@ public TransferAmountBoundUserInterface(EntityUid owner, Enum uiKey) : base(owne protected override void Open() { base.Open(); - _window = this.CreateWindow(); + _window = new TransferAmountWindow(); _window.ApplyButton.OnPressed += _ => { @@ -29,6 +28,15 @@ protected override void Open() _window.Close(); } }; + _window.OnClose += Close; + _window.OpenCentered(); + } + + protected override void Dispose(bool disposing) + { + base.Dispose(disposing); + if (!disposing) return; + _window?.Dispose(); } } } diff --git a/Content.Client/CloningConsole/UI/CloningConsoleBoundUserInterface.cs b/Content.Client/CloningConsole/UI/CloningConsoleBoundUserInterface.cs index 62a02f37186..26f0994701e 100644 --- a/Content.Client/CloningConsole/UI/CloningConsoleBoundUserInterface.cs +++ b/Content.Client/CloningConsole/UI/CloningConsoleBoundUserInterface.cs @@ -1,7 +1,6 @@ using JetBrains.Annotations; using Robust.Client.GameObjects; using Content.Shared.Cloning.CloningConsole; -using Robust.Client.UserInterface; namespace Content.Client.CloningConsole.UI { @@ -18,11 +17,13 @@ public CloningConsoleBoundUserInterface(EntityUid owner, Enum uiKey) : base(owne protected override void Open() { base.Open(); - - _window = this.CreateWindow(); - _window.Title = Loc.GetString("cloning-console-window-title"); - + _window = new CloningConsoleWindow + { + Title = Loc.GetString("cloning-console-window-title") + }; + _window.OnClose += Close; _window.CloneButton.OnPressed += _ => SendMessage(new UiButtonPressedMessage(UiButton.Clone)); + _window.OpenCentered(); } protected override void UpdateState(BoundUserInterfaceState state) @@ -31,5 +32,19 @@ protected override void UpdateState(BoundUserInterfaceState state) _window?.Populate((CloningConsoleBoundUserInterfaceState) state); } + + protected override void Dispose(bool disposing) + { + base.Dispose(disposing); + if (!disposing) + return; + + if (_window != null) + { + _window.OnClose -= Close; + _window.CloneButton.OnPressed -= _ => SendMessage(new UiButtonPressedMessage(UiButton.Clone)); + } + _window?.Dispose(); + } } } diff --git a/Content.Client/Clothing/UI/ChameleonBoundUserInterface.cs b/Content.Client/Clothing/UI/ChameleonBoundUserInterface.cs index 83f6ba15662..5b0d5fcf21f 100644 --- a/Content.Client/Clothing/UI/ChameleonBoundUserInterface.cs +++ b/Content.Client/Clothing/UI/ChameleonBoundUserInterface.cs @@ -2,7 +2,6 @@ using Content.Shared.Clothing.Components; using JetBrains.Annotations; using Robust.Client.GameObjects; -using Robust.Client.UserInterface; namespace Content.Client.Clothing.UI; @@ -23,8 +22,10 @@ protected override void Open() { base.Open(); - _menu = this.CreateWindow(); + _menu = new ChameleonMenu(); + _menu.OnClose += Close; _menu.OnIdSelected += OnIdSelected; + _menu.OpenCentered(); } protected override void UpdateState(BoundUserInterfaceState state) @@ -41,4 +42,15 @@ private void OnIdSelected(string selectedId) { SendMessage(new ChameleonPrototypeSelectedMessage(selectedId)); } + + protected override void Dispose(bool disposing) + { + base.Dispose(disposing); + + if (disposing) + { + _menu?.Close(); + _menu = null; + } + } } diff --git a/Content.Client/Communications/UI/CommunicationsConsoleBoundUserInterface.cs b/Content.Client/Communications/UI/CommunicationsConsoleBoundUserInterface.cs index 0310e91eeb0..1c94d32bf8d 100644 --- a/Content.Client/Communications/UI/CommunicationsConsoleBoundUserInterface.cs +++ b/Content.Client/Communications/UI/CommunicationsConsoleBoundUserInterface.cs @@ -1,7 +1,6 @@ using Content.Shared.CCVar; using Content.Shared.Chat; using Content.Shared.Communications; -using Robust.Client.UserInterface; using Robust.Shared.Configuration; using Robust.Shared.Timing; @@ -9,11 +8,34 @@ namespace Content.Client.Communications.UI { public sealed class CommunicationsConsoleBoundUserInterface : BoundUserInterface { + [Dependency] private readonly IGameTiming _gameTiming = default!; [Dependency] private readonly IConfigurationManager _cfg = default!; [ViewVariables] private CommunicationsConsoleMenu? _menu; + [ViewVariables] + public bool CanAnnounce { get; private set; } + [ViewVariables] + public bool CanBroadcast { get; private set; } + + [ViewVariables] + public bool CanCall { get; private set; } + + [ViewVariables] + public bool CountdownStarted { get; private set; } + + [ViewVariables] + public bool AlertLevelSelectable { get; private set; } + + [ViewVariables] + public string CurrentLevel { get; private set; } = default!; + + [ViewVariables] + private TimeSpan? _expectedCountdownTime; + + public int Countdown => _expectedCountdownTime == null ? 0 : Math.Max((int) _expectedCountdownTime.Value.Subtract(_gameTiming.CurTime).TotalSeconds, 0); + public CommunicationsConsoleBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey) { } @@ -22,25 +44,23 @@ protected override void Open() { base.Open(); - _menu = this.CreateWindow(); - _menu.OnAnnounce += AnnounceButtonPressed; - _menu.OnBroadcast += BroadcastButtonPressed; - _menu.OnAlertLevel += AlertLevelSelected; - _menu.OnEmergencyLevel += EmergencyShuttleButtonPressed; + _menu = new CommunicationsConsoleMenu(this); + _menu.OnClose += Close; + _menu.OpenCentered(); } public void AlertLevelSelected(string level) { - if (_menu!.AlertLevelSelectable) + if (AlertLevelSelectable) { - _menu.CurrentLevel = level; + CurrentLevel = level; SendMessage(new CommunicationsConsoleSelectAlertLevelMessage(level)); } } public void EmergencyShuttleButtonPressed() { - if (_menu!.CountdownStarted) + if (CountdownStarted) RecallShuttle(); else CallShuttle(); @@ -75,23 +95,31 @@ protected override void UpdateState(BoundUserInterfaceState state) if (state is not CommunicationsConsoleInterfaceState commsState) return; + CanAnnounce = commsState.CanAnnounce; + CanBroadcast = commsState.CanBroadcast; + CanCall = commsState.CanCall; + _expectedCountdownTime = commsState.ExpectedCountdownEnd; + CountdownStarted = commsState.CountdownStarted; + AlertLevelSelectable = commsState.AlertLevels != null && !float.IsNaN(commsState.CurrentAlertDelay) && commsState.CurrentAlertDelay <= 0; + CurrentLevel = commsState.CurrentAlert; + if (_menu != null) { - _menu.CanAnnounce = commsState.CanAnnounce; - _menu.CanBroadcast = commsState.CanBroadcast; - _menu.CanCall = commsState.CanCall; - _menu.CountdownStarted = commsState.CountdownStarted; - _menu.AlertLevelSelectable = commsState.AlertLevels != null && !float.IsNaN(commsState.CurrentAlertDelay) && commsState.CurrentAlertDelay <= 0; - _menu.CurrentLevel = commsState.CurrentAlert; - _menu.CountdownEnd = commsState.ExpectedCountdownEnd; - _menu.UpdateCountdown(); - _menu.UpdateAlertLevels(commsState.AlertLevels, _menu.CurrentLevel); - _menu.AlertLevelButton.Disabled = !_menu.AlertLevelSelectable; - _menu.EmergencyShuttleButton.Disabled = !_menu.CanCall; - _menu.AnnounceButton.Disabled = !_menu.CanAnnounce; - _menu.BroadcastButton.Disabled = !_menu.CanBroadcast; + _menu.UpdateAlertLevels(commsState.AlertLevels, CurrentLevel); + _menu.AlertLevelButton.Disabled = !AlertLevelSelectable; + _menu.EmergencyShuttleButton.Disabled = !CanCall; + _menu.AnnounceButton.Disabled = !CanAnnounce; + _menu.BroadcastButton.Disabled = !CanBroadcast; } } + + protected override void Dispose(bool disposing) + { + base.Dispose(disposing); + if (!disposing) return; + + _menu?.Dispose(); + } } } diff --git a/Content.Client/Communications/UI/CommunicationsConsoleMenu.xaml.cs b/Content.Client/Communications/UI/CommunicationsConsoleMenu.xaml.cs index cef68efd1f3..bbca06f5194 100644 --- a/Content.Client/Communications/UI/CommunicationsConsoleMenu.xaml.cs +++ b/Content.Client/Communications/UI/CommunicationsConsoleMenu.xaml.cs @@ -1,40 +1,31 @@ -using System.Globalization; -using Content.Client.UserInterface.Controls; +using Content.Client.UserInterface.Controls; +using System.Threading; using Content.Shared.CCVar; using Robust.Client.AutoGenerated; using Robust.Client.UserInterface.XAML; using Robust.Shared.Configuration; -using Robust.Shared.Timing; using Robust.Shared.Utility; +using Timer = Robust.Shared.Timing.Timer; namespace Content.Client.Communications.UI { [GenerateTypedNameReferences] public sealed partial class CommunicationsConsoleMenu : FancyWindow { + private CommunicationsConsoleBoundUserInterface Owner { get; set; } + private readonly CancellationTokenSource _timerCancelTokenSource = new(); + [Dependency] private readonly IConfigurationManager _cfg = default!; - [Dependency] private readonly IGameTiming _timing = default!; - [Dependency] private readonly ILocalizationManager _loc = default!; - - public bool CanAnnounce; - public bool CanBroadcast; - public bool CanCall; - public bool AlertLevelSelectable; - public bool CountdownStarted; - public string CurrentLevel = string.Empty; - public TimeSpan? CountdownEnd; - - public event Action? OnEmergencyLevel; - public event Action? OnAlertLevel; - public event Action? OnAnnounce; - public event Action? OnBroadcast; - - public CommunicationsConsoleMenu() + + public CommunicationsConsoleMenu(CommunicationsConsoleBoundUserInterface owner) { IoCManager.InjectDependencies(this); RobustXamlLoader.Load(this); - MessageInput.Placeholder = new Rope.Leaf(_loc.GetString("comms-console-menu-announcement-placeholder")); + Owner = owner; + + var loc = IoCManager.Resolve(); + MessageInput.Placeholder = new Rope.Leaf(loc.GetString("comms-console-menu-announcement-placeholder")); var maxAnnounceLength = _cfg.GetCVar(CCVars.ChatMaxAnnouncementLength); MessageInput.OnTextChanged += (args) => @@ -46,38 +37,33 @@ public CommunicationsConsoleMenu() } else { - AnnounceButton.Disabled = !CanAnnounce; + AnnounceButton.Disabled = !owner.CanAnnounce; AnnounceButton.ToolTip = null; } }; - AnnounceButton.OnPressed += _ => OnAnnounce?.Invoke(Rope.Collapse(MessageInput.TextRope)); - AnnounceButton.Disabled = !CanAnnounce; + AnnounceButton.OnPressed += (_) => Owner.AnnounceButtonPressed(Rope.Collapse(MessageInput.TextRope)); + AnnounceButton.Disabled = !owner.CanAnnounce; - BroadcastButton.OnPressed += _ => OnBroadcast?.Invoke(Rope.Collapse(MessageInput.TextRope)); - BroadcastButton.Disabled = !CanBroadcast; + BroadcastButton.OnPressed += (_) => Owner.BroadcastButtonPressed(Rope.Collapse(MessageInput.TextRope)); + BroadcastButton.Disabled = !owner.CanBroadcast; AlertLevelButton.OnItemSelected += args => { var metadata = AlertLevelButton.GetItemMetadata(args.Id); if (metadata != null && metadata is string cast) { - OnAlertLevel?.Invoke(cast); + Owner.AlertLevelSelected(cast); } }; + AlertLevelButton.Disabled = !owner.AlertLevelSelectable; + EmergencyShuttleButton.OnPressed += (_) => Owner.EmergencyShuttleButtonPressed(); + EmergencyShuttleButton.Disabled = !owner.CanCall; - AlertLevelButton.Disabled = !AlertLevelSelectable; - - EmergencyShuttleButton.OnPressed += _ => OnEmergencyLevel?.Invoke(); - EmergencyShuttleButton.Disabled = !CanCall; - } - - protected override void FrameUpdate(FrameEventArgs args) - { - base.FrameUpdate(args); UpdateCountdown(); + Timer.SpawnRepeating(1000, UpdateCountdown, _timerCancelTokenSource.Token); } // The current alert could make levels unselectable, so we need to ensure that the UI reacts properly. @@ -119,19 +105,32 @@ public void UpdateAlertLevels(List? alerts, string currentAlert) public void UpdateCountdown() { - if (!CountdownStarted) + if (!Owner.CountdownStarted) { - CountdownLabel.SetMessage(string.Empty); + CountdownLabel.SetMessage(""); EmergencyShuttleButton.Text = Loc.GetString("comms-console-menu-call-shuttle"); return; } - var diff = (CountdownEnd - _timing.CurTime) ?? TimeSpan.Zero; - EmergencyShuttleButton.Text = Loc.GetString("comms-console-menu-recall-shuttle"); var infoText = Loc.GetString($"comms-console-menu-time-remaining", - ("time", diff.TotalSeconds.ToString(CultureInfo.CurrentCulture))); + ("time", Owner.Countdown.ToString())); CountdownLabel.SetMessage(infoText); } + + public override void Close() + { + base.Close(); + + _timerCancelTokenSource.Cancel(); + } + + protected override void Dispose(bool disposing) + { + base.Dispose(disposing); + + if (disposing) + _timerCancelTokenSource.Cancel(); + } } } diff --git a/Content.Client/Computer/ComputerBoundUserInterface.cs b/Content.Client/Computer/ComputerBoundUserInterface.cs index 11c26b252e9..bdbfe03fa10 100644 --- a/Content.Client/Computer/ComputerBoundUserInterface.cs +++ b/Content.Client/Computer/ComputerBoundUserInterface.cs @@ -1,5 +1,4 @@ using Robust.Client.GameObjects; -using Robust.Client.UserInterface; using Robust.Client.UserInterface.CustomControls; namespace Content.Client.Computer @@ -20,8 +19,10 @@ protected override void Open() { base.Open(); - _window = this.CreateWindow(); + _window = (TWindow) _dynamicTypeFactory.CreateInstance(typeof(TWindow)); _window.SetupComputerWindow(this); + _window.OnClose += Close; + _window.OpenCentered(); } // Alas, this constructor has to be copied to the subclass. :( @@ -41,6 +42,16 @@ protected override void UpdateState(BoundUserInterfaceState state) _window.UpdateState((TState) state); } + protected override void Dispose(bool disposing) + { + base.Dispose(disposing); + + if (disposing) + { + _window?.Dispose(); + } + } + protected override void ReceiveMessage(BoundUserInterfaceMessage message) { _window?.ReceiveMessage(message); diff --git a/Content.Client/Configurable/UI/ConfigurationBoundUserInterface.cs b/Content.Client/Configurable/UI/ConfigurationBoundUserInterface.cs index e4966f1ec43..4fea44f2253 100644 --- a/Content.Client/Configurable/UI/ConfigurationBoundUserInterface.cs +++ b/Content.Client/Configurable/UI/ConfigurationBoundUserInterface.cs @@ -1,6 +1,5 @@ using System.Text.RegularExpressions; using Robust.Client.GameObjects; -using Robust.Client.UserInterface; using static Content.Shared.Configurable.ConfigurationComponent; namespace Content.Client.Configurable.UI @@ -10,6 +9,9 @@ public sealed class ConfigurationBoundUserInterface : BoundUserInterface [ViewVariables] private ConfigurationMenu? _menu; + [ViewVariables] + public Regex? Validation { get; internal set; } + public ConfigurationBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey) { } @@ -17,8 +19,10 @@ public ConfigurationBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner protected override void Open() { base.Open(); - _menu = this.CreateWindow(); - _menu.OnConfiguration += SendConfiguration; + _menu = new ConfigurationMenu(this); + + _menu.OnClose += Close; + _menu.OpenCentered(); } protected override void UpdateState(BoundUserInterfaceState state) @@ -26,7 +30,9 @@ protected override void UpdateState(BoundUserInterfaceState state) base.UpdateState(state); if (state is not ConfigurationBoundUserInterfaceState configurationState) + { return; + } _menu?.Populate(configurationState); } @@ -35,12 +41,9 @@ protected override void ReceiveMessage(BoundUserInterfaceMessage message) { base.ReceiveMessage(message); - if (_menu == null) - return; - if (message is ValidationUpdateMessage msg) { - _menu.Validation = new Regex(msg.ValidationString, RegexOptions.Compiled); + Validation = new Regex(msg.ValidationString, RegexOptions.Compiled); } } @@ -48,5 +51,16 @@ public void SendConfiguration(Dictionary config) { SendMessage(new ConfigurationUpdatedMessage(config)); } + + protected override void Dispose(bool disposing) + { + base.Dispose(disposing); + + if (disposing && _menu != null) + { + _menu.OnClose -= Close; + _menu.Close(); + } + } } } diff --git a/Content.Client/Configurable/UI/ConfigurationMenu.cs b/Content.Client/Configurable/UI/ConfigurationMenu.cs index 29217eef7be..cc24af28692 100644 --- a/Content.Client/Configurable/UI/ConfigurationMenu.cs +++ b/Content.Client/Configurable/UI/ConfigurationMenu.cs @@ -1,6 +1,5 @@ using System.Collections.Generic; using System.Numerics; -using System.Text.RegularExpressions; using Robust.Client.UserInterface; using Robust.Client.UserInterface.Controls; using Robust.Client.UserInterface.CustomControls; @@ -14,25 +13,23 @@ namespace Content.Client.Configurable.UI { public sealed class ConfigurationMenu : DefaultWindow { + public ConfigurationBoundUserInterface Owner { get; } + private readonly BoxContainer _column; private readonly BoxContainer _row; private readonly List<(string name, LineEdit input)> _inputs; - [ViewVariables] - public Regex? Validation { get; internal set; } - - public event Action>? OnConfiguration; - - public ConfigurationMenu() + public ConfigurationMenu(ConfigurationBoundUserInterface owner) { MinSize = SetSize = new Vector2(300, 250); + Owner = owner; _inputs = new List<(string name, LineEdit input)>(); Title = Loc.GetString("configuration-menu-device-title"); - var baseContainer = new BoxContainer + BoxContainer baseContainer = new BoxContainer { Orientation = LayoutOrientation.Vertical, VerticalExpand = true, @@ -119,13 +116,14 @@ public void Populate(ConfigurationBoundUserInterfaceState state) private void OnConfirm(ButtonEventArgs args) { var config = GenerateDictionary(_inputs, "Text"); - OnConfiguration?.Invoke(config); + + Owner.SendConfiguration(config); Close(); } private bool Validate(string value) { - return Validation?.IsMatch(value) != false; + return Owner.Validation == null || Owner.Validation.IsMatch(value); } private Dictionary GenerateDictionary(IEnumerable<(string name, LineEdit input)> inputs, string propertyName) diff --git a/Content.Client/Construction/UI/FlatpackCreatorBoundUserInterface.cs b/Content.Client/Construction/UI/FlatpackCreatorBoundUserInterface.cs index 887492955e9..86f1b8b83c7 100644 --- a/Content.Client/Construction/UI/FlatpackCreatorBoundUserInterface.cs +++ b/Content.Client/Construction/UI/FlatpackCreatorBoundUserInterface.cs @@ -1,6 +1,5 @@ using Content.Shared.Construction.Components; using JetBrains.Annotations; -using Robust.Client.UserInterface; namespace Content.Client.Construction.UI { @@ -18,8 +17,8 @@ protected override void Open() { base.Open(); - _menu = this.CreateWindow(); - _menu.SetEntity(Owner); + _menu = new FlatpackCreatorMenu(Owner); + _menu.OnClose += Close; _menu.PackButtonPressed += () => { @@ -28,5 +27,14 @@ protected override void Open() _menu.OpenCentered(); } + + protected override void Dispose(bool disposing) + { + base.Dispose(disposing); + if (!disposing) + return; + + _menu?.Dispose(); + } } } diff --git a/Content.Client/Construction/UI/FlatpackCreatorMenu.xaml.cs b/Content.Client/Construction/UI/FlatpackCreatorMenu.xaml.cs index 2a386a03de6..00261632378 100644 --- a/Content.Client/Construction/UI/FlatpackCreatorMenu.xaml.cs +++ b/Content.Client/Construction/UI/FlatpackCreatorMenu.xaml.cs @@ -25,7 +25,7 @@ public sealed partial class FlatpackCreatorMenu : FancyWindow private readonly MaterialStorageSystem _materialStorage; private readonly SpriteSystem _spriteSystem; - private EntityUid _owner; + private readonly EntityUid _owner; [ValidatePrototypeId] public const string NoBoardEffectId = "FlatpackerNoBoardEffect"; @@ -35,7 +35,7 @@ public sealed partial class FlatpackCreatorMenu : FancyWindow public event Action? PackButtonPressed; - public FlatpackCreatorMenu() + public FlatpackCreatorMenu(EntityUid uid) { RobustXamlLoader.Load(this); IoCManager.InjectDependencies(this); @@ -45,15 +45,12 @@ public FlatpackCreatorMenu() _materialStorage = _entityManager.System(); _spriteSystem = _entityManager.System(); - PackButton.OnPressed += _ => PackButtonPressed?.Invoke(); + _owner = uid; - InsertLabel.SetMarkup(Loc.GetString("flatpacker-ui-insert-board")); - } + PackButton.OnPressed += _ => PackButtonPressed?.Invoke(); - public void SetEntity(EntityUid uid) - { - _owner = uid; MaterialStorageControl.SetOwner(uid); + InsertLabel.SetMarkup(Loc.GetString("flatpacker-ui-insert-board")); } protected override void FrameUpdate(FrameEventArgs args) diff --git a/Content.Client/Crayon/UI/CrayonBoundUserInterface.cs b/Content.Client/Crayon/UI/CrayonBoundUserInterface.cs index e5be0b1811f..e2c4d51ecd1 100644 --- a/Content.Client/Crayon/UI/CrayonBoundUserInterface.cs +++ b/Content.Client/Crayon/UI/CrayonBoundUserInterface.cs @@ -2,15 +2,12 @@ using Content.Shared.Crayon; using Content.Shared.Decals; using Robust.Client.GameObjects; -using Robust.Client.UserInterface; using Robust.Shared.Prototypes; namespace Content.Client.Crayon.UI { public sealed class CrayonBoundUserInterface : BoundUserInterface { - [Dependency] private readonly IPrototypeManager _protoManager = default!; - [ViewVariables] private CrayonWindow? _menu; @@ -21,27 +18,13 @@ public CrayonBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey protected override void Open() { base.Open(); - _menu = this.CreateWindow(); - _menu.OnColorSelected += SelectColor; - _menu.OnSelected += Select; - PopulateCrayons(); - _menu.OpenCenteredLeft(); - } - - private void PopulateCrayons() - { - var crayonDecals = _protoManager.EnumeratePrototypes().Where(x => x.Tags.Contains("crayon")); - _menu?.Populate(crayonDecals); - } - - public override void OnProtoReload(PrototypesReloadedEventArgs args) - { - base.OnProtoReload(args); - - if (!args.WasModified()) - return; + _menu = new CrayonWindow(this); - PopulateCrayons(); + _menu.OnClose += Close; + var prototypeManager = IoCManager.Resolve(); + var crayonDecals = prototypeManager.EnumeratePrototypes().Where(x => x.Tags.Contains("crayon")); + _menu.Populate(crayonDecals); + _menu.OpenCenteredLeft(); } protected override void UpdateState(BoundUserInterfaceState state) @@ -60,5 +43,16 @@ public void SelectColor(Color color) { SendMessage(new CrayonColorMessage(color)); } + + protected override void Dispose(bool disposing) + { + base.Dispose(disposing); + + if (disposing) + { + _menu?.Close(); + _menu = null; + } + } } } diff --git a/Content.Client/Crayon/UI/CrayonWindow.xaml.cs b/Content.Client/Crayon/UI/CrayonWindow.xaml.cs index b97786cd41a..2a5801ccf2d 100644 --- a/Content.Client/Crayon/UI/CrayonWindow.xaml.cs +++ b/Content.Client/Crayon/UI/CrayonWindow.xaml.cs @@ -18,17 +18,18 @@ namespace Content.Client.Crayon.UI [GenerateTypedNameReferences] public sealed partial class CrayonWindow : DefaultWindow { + public CrayonBoundUserInterface Owner { get; } + private Dictionary? _decals; private string? _selected; private Color _color; - public event Action? OnColorSelected; - public event Action? OnSelected; - - public CrayonWindow() + public CrayonWindow(CrayonBoundUserInterface owner) { RobustXamlLoader.Load(this); + Owner = owner; + Search.OnTextChanged += _ => RefreshList(); ColorSelector.OnColorChanged += SelectColor; } @@ -37,16 +38,16 @@ private void SelectColor(Color color) { _color = color; - OnColorSelected?.Invoke(color); + Owner.SelectColor(color); + RefreshList(); } private void RefreshList() { // Clear - Grid.DisposeAllChildren(); - if (_decals == null) - return; + Grid.RemoveAllChildren(); + if (_decals == null) return; var filter = Search.Text; foreach (var (decal, tex) in _decals) @@ -88,6 +89,7 @@ private void ButtonOnPressed(ButtonEventArgs obj) { if (obj.Button.Name == null) return; + Owner.Select(obj.Button.Name); _selected = obj.Button.Name; RefreshList(); } diff --git a/Content.Client/Disposal/UI/DisposalRouterBoundUserInterface.cs b/Content.Client/Disposal/UI/DisposalRouterBoundUserInterface.cs index 296e71d3a95..e8e77217ea5 100644 --- a/Content.Client/Disposal/UI/DisposalRouterBoundUserInterface.cs +++ b/Content.Client/Disposal/UI/DisposalRouterBoundUserInterface.cs @@ -1,6 +1,5 @@ using JetBrains.Annotations; using Robust.Client.GameObjects; -using Robust.Client.UserInterface; using static Content.Shared.Disposal.Components.SharedDisposalRouterComponent; namespace Content.Client.Disposal.UI @@ -22,16 +21,20 @@ protected override void Open() { base.Open(); - _window = this.CreateWindow(); + _window = new DisposalRouterWindow(); + + _window.OpenCentered(); + _window.OnClose += Close; _window.Confirm.OnPressed += _ => ButtonPressed(UiAction.Ok, _window.TagInput.Text); _window.TagInput.OnTextEntered += args => ButtonPressed(UiAction.Ok, args.Text); + } private void ButtonPressed(UiAction action, string tag) { SendMessage(new UiActionMessage(action, tag)); - Close(); + _window?.Close(); } protected override void UpdateState(BoundUserInterfaceState state) @@ -45,5 +48,18 @@ protected override void UpdateState(BoundUserInterfaceState state) _window?.UpdateState(cast); } + + protected override void Dispose(bool disposing) + { + base.Dispose(disposing); + + if (disposing) + { + _window?.Dispose(); + } + } + + } + } diff --git a/Content.Client/Disposal/UI/DisposalTaggerBoundUserInterface.cs b/Content.Client/Disposal/UI/DisposalTaggerBoundUserInterface.cs index 7fc0eb85401..3aeed8dc802 100644 --- a/Content.Client/Disposal/UI/DisposalTaggerBoundUserInterface.cs +++ b/Content.Client/Disposal/UI/DisposalTaggerBoundUserInterface.cs @@ -1,6 +1,5 @@ using JetBrains.Annotations; using Robust.Client.GameObjects; -using Robust.Client.UserInterface; using static Content.Shared.Disposal.Components.SharedDisposalTaggerComponent; namespace Content.Client.Disposal.UI @@ -22,17 +21,20 @@ protected override void Open() { base.Open(); - _window = this.CreateWindow(); + _window = new DisposalTaggerWindow(); + + _window.OpenCentered(); + _window.OnClose += Close; _window.Confirm.OnPressed += _ => ButtonPressed(UiAction.Ok, _window.TagInput.Text); _window.TagInput.OnTextEntered += args => ButtonPressed(UiAction.Ok, args.Text); + } private void ButtonPressed(UiAction action, string tag) { - // TODO: This looks copy-pasted with the other mailing stuff... SendMessage(new UiActionMessage(action, tag)); - Close(); + _window?.Close(); } protected override void UpdateState(BoundUserInterfaceState state) @@ -46,5 +48,18 @@ protected override void UpdateState(BoundUserInterfaceState state) _window?.UpdateState(cast); } + + protected override void Dispose(bool disposing) + { + base.Dispose(disposing); + + if (disposing) + { + _window?.Dispose(); + } + } + + } + } diff --git a/Content.Client/Doors/Electronics/DoorElectronicsBoundUserInterface.cs b/Content.Client/Doors/Electronics/DoorElectronicsBoundUserInterface.cs index 9b7e23c03aa..cd7ea717ce3 100644 --- a/Content.Client/Doors/Electronics/DoorElectronicsBoundUserInterface.cs +++ b/Content.Client/Doors/Electronics/DoorElectronicsBoundUserInterface.cs @@ -1,7 +1,6 @@ using Content.Shared.Access; using Content.Shared.Doors.Electronics; using Robust.Client.GameObjects; -using Robust.Client.UserInterface; using Robust.Shared.Prototypes; namespace Content.Client.Doors.Electronics; @@ -19,23 +18,6 @@ public DoorElectronicsBoundUserInterface(EntityUid owner, Enum uiKey) : base(own protected override void Open() { base.Open(); - _window = this.CreateWindow(); - _window.OnAccessChanged += UpdateConfiguration; - Reset(); - } - - public override void OnProtoReload(PrototypesReloadedEventArgs args) - { - base.OnProtoReload(args); - - if (!args.WasModified()) - return; - - Reset(); - } - - private void Reset() - { List> accessLevels = new(); foreach (var accessLevel in _prototypeManager.EnumeratePrototypes()) @@ -47,7 +29,10 @@ private void Reset() } accessLevels.Sort(); - _window?.Reset(_prototypeManager, accessLevels); + + _window = new DoorElectronicsConfigurationMenu(this, accessLevels, _prototypeManager); + _window.OnClose += Close; + _window.OpenCentered(); } protected override void UpdateState(BoundUserInterfaceState state) @@ -59,6 +44,14 @@ protected override void UpdateState(BoundUserInterfaceState state) _window?.UpdateState(castState); } + protected override void Dispose(bool disposing) + { + base.Dispose(disposing); + if (!disposing) return; + + _window?.Dispose(); + } + public void UpdateConfiguration(List> newAccessList) { SendMessage(new DoorElectronicsUpdateConfigurationMessage(newAccessList)); diff --git a/Content.Client/Doors/Electronics/DoorElectronicsConfigurationMenu.xaml.cs b/Content.Client/Doors/Electronics/DoorElectronicsConfigurationMenu.xaml.cs index 2112a562971..c01f13a462e 100644 --- a/Content.Client/Doors/Electronics/DoorElectronicsConfigurationMenu.xaml.cs +++ b/Content.Client/Doors/Electronics/DoorElectronicsConfigurationMenu.xaml.cs @@ -15,23 +15,22 @@ namespace Content.Client.Doors.Electronics; [GenerateTypedNameReferences] public sealed partial class DoorElectronicsConfigurationMenu : FancyWindow { - private readonly AccessLevelControl _buttonsList = new(); + private readonly DoorElectronicsBoundUserInterface _owner; + private AccessLevelControl _buttonsList = new(); - public event Action>>? OnAccessChanged; - - public DoorElectronicsConfigurationMenu() + public DoorElectronicsConfigurationMenu(DoorElectronicsBoundUserInterface ui, List> accessLevels, IPrototypeManager prototypeManager) { RobustXamlLoader.Load(this); - AccessLevelControlContainer.AddChild(_buttonsList); - } - public void Reset(IPrototypeManager protoManager, List> accessLevels) - { - _buttonsList.Populate(accessLevels, protoManager); + _owner = ui; + + _buttonsList.Populate(accessLevels, prototypeManager); + AccessLevelControlContainer.AddChild(_buttonsList); - foreach (var button in _buttonsList.ButtonsList.Values) + foreach (var (id, button) in _buttonsList.ButtonsList) { - button.OnPressed += _ => OnAccessChanged?.Invoke(_buttonsList.ButtonsList.Where(x => x.Value.Pressed).Select(x => x.Key).ToList()); + button.OnPressed += _ => _owner.UpdateConfiguration( + _buttonsList.ButtonsList.Where(x => x.Value.Pressed).Select(x => x.Key).ToList()); } } diff --git a/Content.Client/Fax/UI/FaxBoundUi.cs b/Content.Client/Fax/UI/FaxBoundUi.cs index ca2e834b4fe..a95066a3b58 100644 --- a/Content.Client/Fax/UI/FaxBoundUi.cs +++ b/Content.Client/Fax/UI/FaxBoundUi.cs @@ -25,7 +25,10 @@ protected override void Open() { base.Open(); - _window = this.CreateWindow(); + _window = new FaxWindow(); + _window.OpenCentered(); + + _window.OnClose += Close; _window.FileButtonPressed += OnFileButtonPressed; _window.CopyButtonPressed += OnCopyButtonPressed; _window.SendButtonPressed += OnSendButtonPressed; @@ -101,4 +104,11 @@ protected override void UpdateState(BoundUserInterfaceState state) _window.UpdateState(cast); } + + protected override void Dispose(bool disposing) + { + base.Dispose(disposing); + if (disposing) + _window?.Dispose(); + } } diff --git a/Content.Client/Forensics/ForensicScannerBoundUserInterface.cs b/Content.Client/Forensics/ForensicScannerBoundUserInterface.cs index 08596b04e6e..ba49f11ea0f 100644 --- a/Content.Client/Forensics/ForensicScannerBoundUserInterface.cs +++ b/Content.Client/Forensics/ForensicScannerBoundUserInterface.cs @@ -1,7 +1,6 @@ using Robust.Client.GameObjects; using Robust.Shared.Timing; using Content.Shared.Forensics; -using Robust.Client.UserInterface; namespace Content.Client.Forensics { @@ -22,9 +21,11 @@ public ForensicScannerBoundUserInterface(EntityUid owner, Enum uiKey) : base(own protected override void Open() { base.Open(); - _window = this.CreateWindow(); + _window = new ForensicScannerMenu(); + _window.OnClose += Close; _window.Print.OnPressed += _ => Print(); _window.Clear.OnPressed += _ => Clear(); + _window.OpenCentered(); } private void Print() @@ -61,7 +62,6 @@ protected override void UpdateState(BoundUserInterfaceState state) _printCooldown = cast.PrintCooldown; - // TODO: Fix this if (cast.PrintReadyAt > _gameTiming.CurTime) Timer.Spawn(cast.PrintReadyAt - _gameTiming.CurTime, () => { @@ -71,5 +71,14 @@ protected override void UpdateState(BoundUserInterfaceState state) _window.UpdateState(cast); } + + protected override void Dispose(bool disposing) + { + base.Dispose(disposing); + if (!disposing) + return; + + _window?.Dispose(); + } } } diff --git a/Content.Client/Gateway/UI/GatewayBoundUserInterface.cs b/Content.Client/Gateway/UI/GatewayBoundUserInterface.cs index 457b70ca7ca..fdb3cdbc010 100644 --- a/Content.Client/Gateway/UI/GatewayBoundUserInterface.cs +++ b/Content.Client/Gateway/UI/GatewayBoundUserInterface.cs @@ -1,7 +1,6 @@ using Content.Shared.Gateway; using JetBrains.Annotations; using Robust.Client.GameObjects; -using Robust.Client.UserInterface; namespace Content.Client.Gateway.UI; @@ -18,13 +17,24 @@ protected override void Open() { base.Open(); - _window = this.CreateWindow(); - _window.SetEntity(EntMan.GetNetEntity(Owner)); + _window = new GatewayWindow(EntMan.GetNetEntity(Owner)); _window.OpenPortal += destination => { SendMessage(new GatewayOpenPortalMessage(destination)); }; + _window.OnClose += Close; + _window?.OpenCentered(); + } + + protected override void Dispose(bool disposing) + { + base.Dispose(disposing); + if (disposing) + { + _window?.Dispose(); + _window = null; + } } protected override void UpdateState(BoundUserInterfaceState state) diff --git a/Content.Client/Gateway/UI/GatewayWindow.xaml.cs b/Content.Client/Gateway/UI/GatewayWindow.xaml.cs index 1c779b2b350..889dd6e1759 100644 --- a/Content.Client/Gateway/UI/GatewayWindow.xaml.cs +++ b/Content.Client/Gateway/UI/GatewayWindow.xaml.cs @@ -22,7 +22,7 @@ public sealed partial class GatewayWindow : FancyWindow, public event Action? OpenPortal; private List _destinations = new(); - public NetEntity Owner; + public readonly NetEntity Owner; private NetEntity? _current; private TimeSpan _nextReady; @@ -46,20 +46,16 @@ public sealed partial class GatewayWindow : FancyWindow, /// private bool _isCooldownPending = true; - public GatewayWindow() + public GatewayWindow(NetEntity netEntity) { RobustXamlLoader.Load(this); var dependencies = IoCManager.Instance!; _timing = dependencies.Resolve(); + Owner = netEntity; NextUnlockBar.ForegroundStyleBoxOverride = new StyleBoxFlat(Color.FromHex("#C74EBD")); } - public void SetEntity(NetEntity entity) - { - - } - public void UpdateState(GatewayBoundUserInterfaceState state) { _destinations = state.Destinations; diff --git a/Content.Client/Gravity/UI/GravityGeneratorBoundUserInterface.cs b/Content.Client/Gravity/UI/GravityGeneratorBoundUserInterface.cs index 32b40747d55..d72da3e8120 100644 --- a/Content.Client/Gravity/UI/GravityGeneratorBoundUserInterface.cs +++ b/Content.Client/Gravity/UI/GravityGeneratorBoundUserInterface.cs @@ -1,6 +1,6 @@ using Content.Shared.Gravity; using JetBrains.Annotations; -using Robust.Client.UserInterface; +using Robust.Client.GameObjects; namespace Content.Client.Gravity.UI { @@ -18,8 +18,17 @@ protected override void Open() { base.Open(); - _window = this.CreateWindow(); - _window.SetEntity(Owner); + _window = new GravityGeneratorWindow(this); + + /* + _window.Switch.OnPressed += _ => + { + SendMessage(new SharedGravityGeneratorComponent.SwitchGeneratorMessage(!IsOn)); + }; + */ + + _window.OpenCentered(); + _window.OnClose += Close; } protected override void UpdateState(BoundUserInterfaceState state) @@ -30,6 +39,14 @@ protected override void UpdateState(BoundUserInterfaceState state) _window?.UpdateState(castState); } + protected override void Dispose(bool disposing) + { + base.Dispose(disposing); + if (!disposing) return; + + _window?.Dispose(); + } + public void SetPowerSwitch(bool on) { SendMessage(new SharedGravityGeneratorComponent.SwitchGeneratorMessage(on)); diff --git a/Content.Client/Gravity/UI/GravityGeneratorWindow.xaml.cs b/Content.Client/Gravity/UI/GravityGeneratorWindow.xaml.cs index 6f04133b594..75f8eb479b5 100644 --- a/Content.Client/Gravity/UI/GravityGeneratorWindow.xaml.cs +++ b/Content.Client/Gravity/UI/GravityGeneratorWindow.xaml.cs @@ -12,23 +12,22 @@ public sealed partial class GravityGeneratorWindow : FancyWindow { private readonly ButtonGroup _buttonGroup = new(); - public event Action? OnPowerSwitch; + private readonly GravityGeneratorBoundUserInterface _owner; - public GravityGeneratorWindow() + public GravityGeneratorWindow(GravityGeneratorBoundUserInterface owner) { RobustXamlLoader.Load(this); IoCManager.InjectDependencies(this); + _owner = owner; + OnButton.Group = _buttonGroup; OffButton.Group = _buttonGroup; - OnButton.OnPressed += _ => OnPowerSwitch?.Invoke(true); - OffButton.OnPressed += _ => OnPowerSwitch?.Invoke(false); - } + OnButton.OnPressed += _ => _owner.SetPowerSwitch(true); + OffButton.OnPressed += _ => _owner.SetPowerSwitch(false); - public void SetEntity(EntityUid uid) - { - EntityView.SetEntity(uid); + EntityView.SetEntity(owner.Owner); } public void UpdateState(SharedGravityGeneratorComponent.GeneratorState state) diff --git a/Content.Client/HealthAnalyzer/UI/HealthAnalyzerBoundUserInterface.cs b/Content.Client/HealthAnalyzer/UI/HealthAnalyzerBoundUserInterface.cs index 38760f4aa3c..dc0a3e9fccd 100644 --- a/Content.Client/HealthAnalyzer/UI/HealthAnalyzerBoundUserInterface.cs +++ b/Content.Client/HealthAnalyzer/UI/HealthAnalyzerBoundUserInterface.cs @@ -1,6 +1,6 @@ using Content.Shared.MedicalScanner; using JetBrains.Annotations; -using Robust.Client.UserInterface; +using Robust.Client.GameObjects; namespace Content.Client.HealthAnalyzer.UI { @@ -17,9 +17,12 @@ public HealthAnalyzerBoundUserInterface(EntityUid owner, Enum uiKey) : base(owne protected override void Open() { base.Open(); - _window = this.CreateWindow(); - - _window.Title = EntMan.GetComponent(Owner).EntityName; + _window = new HealthAnalyzerWindow + { + Title = EntMan.GetComponent(Owner).EntityName, + }; + _window.OnClose += Close; + _window.OpenCentered(); } protected override void ReceiveMessage(BoundUserInterfaceMessage message) @@ -32,5 +35,17 @@ protected override void ReceiveMessage(BoundUserInterfaceMessage message) _window.Populate(cast); } + + protected override void Dispose(bool disposing) + { + base.Dispose(disposing); + if (!disposing) + return; + + if (_window != null) + _window.OnClose -= Close; + + _window?.Dispose(); + } } } diff --git a/Content.Client/Humanoid/HumanoidMarkingModifierBoundUserInterface.cs b/Content.Client/Humanoid/HumanoidMarkingModifierBoundUserInterface.cs index 53977eb636b..a8872604a4c 100644 --- a/Content.Client/Humanoid/HumanoidMarkingModifierBoundUserInterface.cs +++ b/Content.Client/Humanoid/HumanoidMarkingModifierBoundUserInterface.cs @@ -1,6 +1,5 @@ using Content.Shared.Humanoid; using Content.Shared.Humanoid.Markings; -using Robust.Client.UserInterface; namespace Content.Client.Humanoid; @@ -21,7 +20,8 @@ protected override void Open() { base.Open(); - _window = this.CreateWindow(); + _window = new(); + _window.OnClose += Close; _window.OnMarkingAdded += SendMarkingSet; _window.OnMarkingRemoved += SendMarkingSet; _window.OnMarkingColorChange += SendMarkingSetNoResend; diff --git a/Content.Client/Instruments/UI/BandMenu.xaml.cs b/Content.Client/Instruments/UI/BandMenu.xaml.cs index 26cd1369e55..5fb293a194d 100644 --- a/Content.Client/Instruments/UI/BandMenu.xaml.cs +++ b/Content.Client/Instruments/UI/BandMenu.xaml.cs @@ -11,9 +11,7 @@ public sealed partial class BandMenu : DefaultWindow { private readonly InstrumentBoundUserInterface _owner; - public EntityUid? Master; - - public BandMenu(InstrumentBoundUserInterface owner) + public BandMenu(InstrumentBoundUserInterface owner) : base() { RobustXamlLoader.Load(this); @@ -42,7 +40,7 @@ public void Populate((NetEntity, string)[] nearby, IEntityManager entManager) { var uid = entManager.GetEntity(nent); var item = BandList.AddItem(name, null, true, uid); - item.Selected = Master == uid; + item.Selected = _owner.Instrument?.Master == uid; } } } diff --git a/Content.Client/Instruments/UI/ChannelsMenu.xaml.cs b/Content.Client/Instruments/UI/ChannelsMenu.xaml.cs index c175e67842f..2814d415365 100644 --- a/Content.Client/Instruments/UI/ChannelsMenu.xaml.cs +++ b/Content.Client/Instruments/UI/ChannelsMenu.xaml.cs @@ -51,7 +51,7 @@ private void OnClearPressed(BaseButton.ButtonEventArgs obj) } } - public void Populate(InstrumentComponent? instrument) + public void Populate() { ChannelList.Clear(); @@ -60,8 +60,7 @@ public void Populate(InstrumentComponent? instrument) var item = ChannelList.AddItem(_owner.Loc.GetString("instrument-component-channel-name", ("number", i)), null, true, i); - - item.Selected = !instrument?.FilteredChannels[i] ?? false; + item.Selected = !_owner.Instrument?.FilteredChannels[i] ?? false; } } } diff --git a/Content.Client/Instruments/UI/InstrumentBoundUserInterface.cs b/Content.Client/Instruments/UI/InstrumentBoundUserInterface.cs index 4816ce8c365..0f5729f55b1 100644 --- a/Content.Client/Instruments/UI/InstrumentBoundUserInterface.cs +++ b/Content.Client/Instruments/UI/InstrumentBoundUserInterface.cs @@ -24,6 +24,8 @@ public sealed class InstrumentBoundUserInterface : BoundUserInterface [ViewVariables] private BandMenu? _bandMenu; [ViewVariables] private ChannelsMenu? _channelsMenu; + [ViewVariables] public InstrumentComponent? Instrument { get; private set; } + public InstrumentBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey) { IoCManager.InjectDependencies(this); @@ -41,20 +43,14 @@ protected override void ReceiveMessage(BoundUserInterfaceMessage message) protected override void Open() { - _instrumentMenu = this.CreateWindow(); - _instrumentMenu.Title = EntMan.GetComponent(Owner).EntityName; - - _instrumentMenu.OnOpenBand += OpenBandMenu; - _instrumentMenu.OnOpenChannels += OpenChannelsMenu; - _instrumentMenu.OnCloseChannels += CloseChannelsMenu; - _instrumentMenu.OnCloseBands += CloseBandMenu; + if (!EntMan.TryGetComponent(Owner, out InstrumentComponent? instrument)) + return; - _instrumentMenu.SetMIDI(MidiManager.IsAvailable); + Instrument = instrument; + _instrumentMenu = new InstrumentMenu(this); + _instrumentMenu.OnClose += Close; - if (EntMan.TryGetComponent(Owner, out InstrumentComponent? instrument)) - { - _instrumentMenu.SetInstrument((Owner, instrument)); - } + _instrumentMenu.OpenCentered(); } protected override void Dispose(bool disposing) @@ -62,12 +58,7 @@ protected override void Dispose(bool disposing) base.Dispose(disposing); if (!disposing) return; - - if (EntMan.TryGetComponent(Owner, out InstrumentComponent? instrument)) - { - _instrumentMenu?.RemoveInstrument(instrument); - } - + _instrumentMenu?.Dispose(); _bandMenu?.Dispose(); _channelsMenu?.Dispose(); } @@ -81,11 +72,6 @@ public void OpenBandMenu() { _bandMenu ??= new BandMenu(this); - if (EntMan.TryGetComponent(Owner, out InstrumentComponent? instrument)) - { - _bandMenu.Master = instrument.Master; - } - // Refresh cache... RefreshBands(); @@ -101,9 +87,7 @@ public void CloseBandMenu() public void OpenChannelsMenu() { _channelsMenu ??= new ChannelsMenu(this); - EntMan.TryGetComponent(Owner, out InstrumentComponent? instrument); - - _channelsMenu.Populate(instrument); + _channelsMenu.Populate(); _channelsMenu.OpenCenteredRight(); } diff --git a/Content.Client/Instruments/UI/InstrumentMenu.xaml.cs b/Content.Client/Instruments/UI/InstrumentMenu.xaml.cs index fc863648d79..da443e3fb5b 100644 --- a/Content.Client/Instruments/UI/InstrumentMenu.xaml.cs +++ b/Content.Client/Instruments/UI/InstrumentMenu.xaml.cs @@ -1,10 +1,7 @@ using System.IO; using System.Numerics; using System.Threading.Tasks; -using Content.Client.Interactable; -using Content.Shared.ActionBlocker; using Robust.Client.AutoGenerated; -using Robust.Client.Player; using Robust.Client.UserInterface; using Robust.Client.UserInterface.CustomControls; using Robust.Client.UserInterface.XAML; @@ -19,23 +16,33 @@ namespace Content.Client.Instruments.UI [GenerateTypedNameReferences] public sealed partial class InstrumentMenu : DefaultWindow { - [Dependency] private readonly IEntityManager _entManager = default!; - [Dependency] private readonly IFileDialogManager _dialogs = default!; - [Dependency] private readonly IPlayerManager _player = default!; + private readonly InstrumentBoundUserInterface _owner; private bool _isMidiFileDialogueWindowOpen; - public event Action? OnOpenBand; - public event Action? OnOpenChannels; - public event Action? OnCloseBands; - public event Action? OnCloseChannels; - - public EntityUid Entity; - - public InstrumentMenu() + public InstrumentMenu(InstrumentBoundUserInterface owner) { RobustXamlLoader.Load(this); - IoCManager.InjectDependencies(this); + + _owner = owner; + + if (_owner.Instrument != null) + { + _owner.Instrument.OnMidiPlaybackEnded += InstrumentOnMidiPlaybackEnded; + Title = _owner.Entities.GetComponent(_owner.Owner).EntityName; + LoopButton.Disabled = !_owner.Instrument.IsMidiOpen; + LoopButton.Pressed = _owner.Instrument.LoopMidi; + ChannelsButton.Disabled = !_owner.Instrument.IsRendererAlive; + StopButton.Disabled = !_owner.Instrument.IsMidiOpen; + PlaybackSlider.MouseFilter = _owner.Instrument.IsMidiOpen ? MouseFilterMode.Pass : MouseFilterMode.Ignore; + } + + if (!_owner.MidiManager.IsAvailable) + { + UnavailableOverlay.Visible = true; + // We return early as to not give the buttons behavior. + return; + } InputButton.OnToggled += MidiInputButtonOnOnToggled; BandButton.OnPressed += BandButtonOnPressed; @@ -50,34 +57,12 @@ public InstrumentMenu() MinSize = SetSize = new Vector2(400, 150); } - public void SetInstrument(Entity entity) - { - Entity = entity; - var component = entity.Comp; - component.OnMidiPlaybackEnded += InstrumentOnMidiPlaybackEnded; - LoopButton.Disabled = !component.IsMidiOpen; - LoopButton.Pressed = component.LoopMidi; - ChannelsButton.Disabled = !component.IsRendererAlive; - StopButton.Disabled = !component.IsMidiOpen; - PlaybackSlider.MouseFilter = component.IsMidiOpen ? MouseFilterMode.Pass : MouseFilterMode.Ignore; - } - - public void RemoveInstrument(InstrumentComponent component) - { - component.OnMidiPlaybackEnded -= InstrumentOnMidiPlaybackEnded; - } - - public void SetMIDI(bool available) - { - UnavailableOverlay.Visible = !available; - } - private void BandButtonOnPressed(ButtonEventArgs obj) { if (!PlayCheck()) return; - OnOpenBand?.Invoke(); + _owner.OpenBandMenu(); } private void BandButtonOnToggled(ButtonToggledEventArgs obj) @@ -85,15 +70,12 @@ private void BandButtonOnToggled(ButtonToggledEventArgs obj) if (obj.Pressed) return; - if (_entManager.TryGetComponent(Entity, out InstrumentComponent? instrument)) - { - _entManager.System().SetMaster(Entity, instrument.Master); - } + _owner.Instruments.SetMaster(_owner.Owner, null); } private void ChannelsButtonOnPressed(ButtonEventArgs obj) { - OnOpenChannels?.Invoke(); + _owner.OpenChannelsMenu(); } private void InstrumentOnMidiPlaybackEnded() @@ -103,10 +85,8 @@ private void InstrumentOnMidiPlaybackEnded() public void MidiPlaybackSetButtonsDisabled(bool disabled) { - if (disabled) - { - OnCloseChannels?.Invoke(); - } + if(disabled) + _owner.CloseChannelsMenu(); LoopButton.Disabled = disabled; StopButton.Disabled = disabled; @@ -120,7 +100,7 @@ private async void MidiFileButtonOnOnPressed(ButtonEventArgs obj) if (_isMidiFileDialogueWindowOpen) return; - OnCloseBands?.Invoke(); + _owner.CloseBandMenu(); var filters = new FileDialogFilters(new FileDialogFilters.Group("mid", "midi")); @@ -128,7 +108,7 @@ private async void MidiFileButtonOnOnPressed(ButtonEventArgs obj) // or focus the previously-opened window. _isMidiFileDialogueWindowOpen = true; - await using var file = await _dialogs.OpenFile(filters); + await using var file = await _owner.FileDialogManager.OpenFile(filters); _isMidiFileDialogueWindowOpen = false; @@ -149,18 +129,9 @@ private async void MidiFileButtonOnOnPressed(ButtonEventArgs obj) await file.CopyToAsync(memStream); - if (!_entManager.TryGetComponent(Entity, out var instrument)) - { + if (_owner.Instrument is not {} instrument + || !_owner.Instruments.OpenMidi(_owner.Owner, memStream.GetBuffer().AsSpan(0, (int) memStream.Length), instrument)) return; - } - - if (!_entManager.System() - .OpenMidi(Entity, - memStream.GetBuffer().AsSpan(0, (int) memStream.Length), - instrument)) - { - return; - } MidiPlaybackSetButtonsDisabled(false); if (InputButton.Pressed) @@ -169,7 +140,7 @@ private async void MidiFileButtonOnOnPressed(ButtonEventArgs obj) private void MidiInputButtonOnOnToggled(ButtonToggledEventArgs obj) { - OnCloseBands?.Invoke(); + _owner.CloseBandMenu(); if (obj.Pressed) { @@ -177,99 +148,109 @@ private void MidiInputButtonOnOnToggled(ButtonToggledEventArgs obj) return; MidiStopButtonOnPressed(null); - - if (_entManager.TryGetComponent(Entity, out InstrumentComponent? instrument)) - _entManager.System().OpenInput(Entity, instrument); + if(_owner.Instrument is {} instrument) + _owner.Instruments.OpenInput(_owner.Owner, instrument); } - else + else if (_owner.Instrument is { } instrument) { - _entManager.System().CloseInput(Entity, false); - OnCloseChannels?.Invoke(); + _owner.Instruments.CloseInput(_owner.Owner, false, instrument); + _owner.CloseChannelsMenu(); } } private bool PlayCheck() { // TODO all of these checks should also be done server-side. - if (!_entManager.TryGetComponent(Entity, out InstrumentComponent? instrument)) + + var instrumentEnt = _owner.Owner; + var instrument = _owner.Instrument; + + if (instrument == null) return false; - var localEntity = _player.LocalEntity; + var localEntity = _owner.PlayerManager.LocalEntity; // If we don't have a player or controlled entity, we return. if (localEntity == null) return false; // By default, allow an instrument to play itself and skip all other checks - if (localEntity == Entity) + if (localEntity == instrumentEnt) return true; - var container = _entManager.System(); + var container = _owner.Entities.System(); // If we're a handheld instrument, we might be in a container. Get it just in case. - container.TryGetContainingContainer(Entity, out var conMan); + container.TryGetContainingContainer(instrumentEnt, out var conMan); // If the instrument is handheld and we're not holding it, we return. - if (instrument.Handheld && (conMan == null || conMan.Owner != localEntity)) + if ((instrument.Handheld && (conMan == null || conMan.Owner != localEntity))) return false; - if (!_entManager.System().CanInteract(localEntity.Value, Entity)) + if (!_owner.ActionBlocker.CanInteract(localEntity.Value, instrumentEnt)) return false; // We check that we're in range unobstructed just in case. - return _entManager.System().InRangeUnobstructed(localEntity.Value, Entity); + return _owner.Interactions.InRangeUnobstructed(localEntity.Value, instrumentEnt); } private void MidiStopButtonOnPressed(ButtonEventArgs? obj) { MidiPlaybackSetButtonsDisabled(true); - _entManager.System().CloseMidi(Entity, false); - OnCloseChannels?.Invoke(); + if (_owner.Instrument is not {} instrument) + return; + + _owner.Instruments.CloseMidi(_owner.Owner, false, instrument); + _owner.CloseChannelsMenu(); } private void MidiLoopButtonOnOnToggled(ButtonToggledEventArgs obj) { - var instrument = _entManager.System(); - - if (_entManager.TryGetComponent(Entity, out InstrumentComponent? instrumentComp)) - { - instrumentComp.LoopMidi = obj.Pressed; - } + if (_owner.Instrument == null) + return; - instrument.UpdateRenderer(Entity); + _owner.Instrument.LoopMidi = obj.Pressed; + _owner.Instruments.UpdateRenderer(_owner.Owner, _owner.Instrument); } private void PlaybackSliderSeek(Range _) { // Do not seek while still grabbing. - if (PlaybackSlider.Grabbed) + if (PlaybackSlider.Grabbed || _owner.Instrument is not {} instrument) return; - _entManager.System().SetPlayerTick(Entity, (int)Math.Ceiling(PlaybackSlider.Value)); + _owner.Instruments.SetPlayerTick(_owner.Owner, (int)Math.Ceiling(PlaybackSlider.Value), instrument); } private void PlaybackSliderKeyUp(GUIBoundKeyEventArgs args) { - if (args.Function != EngineKeyFunctions.UIClick) + if (args.Function != EngineKeyFunctions.UIClick || _owner.Instrument is not {} instrument) return; - _entManager.System().SetPlayerTick(Entity, (int)Math.Ceiling(PlaybackSlider.Value)); + _owner.Instruments.SetPlayerTick(_owner.Owner, (int)Math.Ceiling(PlaybackSlider.Value), instrument); + } + + public override void Close() + { + base.Close(); + _owner.CloseBandMenu(); + _owner.CloseChannelsMenu(); } protected override void FrameUpdate(FrameEventArgs args) { base.FrameUpdate(args); - if (!_entManager.TryGetComponent(Entity, out InstrumentComponent? instrument)) + if (_owner.Instrument == null) return; - var hasMaster = instrument.Master != null; + var hasMaster = _owner.Instrument.Master != null; BandButton.ToggleMode = hasMaster; BandButton.Pressed = hasMaster; - BandButton.Disabled = instrument.IsMidiOpen || instrument.IsInputOpen; - ChannelsButton.Disabled = !instrument.IsRendererAlive; + BandButton.Disabled = _owner.Instrument.IsMidiOpen || _owner.Instrument.IsInputOpen; + ChannelsButton.Disabled = !_owner.Instrument.IsRendererAlive; - if (!instrument.IsMidiOpen) + if (!_owner.Instrument.IsMidiOpen) { PlaybackSlider.MaxValue = 1; PlaybackSlider.SetValueWithoutEvent(0); @@ -279,8 +260,8 @@ protected override void FrameUpdate(FrameEventArgs args) if (PlaybackSlider.Grabbed) return; - PlaybackSlider.MaxValue = instrument.PlayerTotalTick; - PlaybackSlider.SetValueWithoutEvent(instrument.PlayerTick); + PlaybackSlider.MaxValue = _owner.Instrument.PlayerTotalTick; + PlaybackSlider.SetValueWithoutEvent(_owner.Instrument.PlayerTick); } } } diff --git a/Content.Client/Inventory/StrippableBoundUserInterface.cs b/Content.Client/Inventory/StrippableBoundUserInterface.cs index 132c5ed654c..7e50eb1c68a 100644 --- a/Content.Client/Inventory/StrippableBoundUserInterface.cs +++ b/Content.Client/Inventory/StrippableBoundUserInterface.cs @@ -41,7 +41,7 @@ public sealed class StrippableBoundUserInterface : BoundUserInterface public const string HiddenPocketEntityId = "StrippingHiddenEntity"; [ViewVariables] - private StrippingMenu? _strippingMenu; + private readonly StrippingMenu? _strippingMenu; [ViewVariables] private readonly EntityUid _virtualHiddenEntity; @@ -51,30 +51,33 @@ public StrippableBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, u _examine = EntMan.System(); _inv = EntMan.System(); _cuffable = EntMan.System(); + + // TODO update name when identity changes + var title = Loc.GetString("strippable-bound-user-interface-stripping-menu-title", ("ownerName", Identity.Name(Owner, EntMan))); + _strippingMenu = new StrippingMenu(title, this); + _strippingMenu.OnClose += Close; + + // TODO use global entity + // BUIs are opened and closed while applying comp sates, so spawning entities here is probably not the best idea. _virtualHiddenEntity = EntMan.SpawnEntity(HiddenPocketEntityId, MapCoordinates.Nullspace); } protected override void Open() { base.Open(); - - _strippingMenu = this.CreateWindow(); - _strippingMenu.OnDirty += UpdateMenu; - _strippingMenu.Title = Loc.GetString("strippable-bound-user-interface-stripping-menu-title", ("ownerName", Identity.Name(Owner, EntMan))); - _strippingMenu?.OpenCenteredLeft(); } protected override void Dispose(bool disposing) { + base.Dispose(disposing); + + EntMan.DeleteEntity(_virtualHiddenEntity); + if (!disposing) return; - if (_strippingMenu != null) - _strippingMenu.OnDirty -= UpdateMenu; - - EntMan.DeleteEntity(_virtualHiddenEntity); - base.Dispose(disposing); + _strippingMenu?.Dispose(); } public void DirtyMenu() diff --git a/Content.Client/Kitchen/UI/GrinderMenu.xaml.cs b/Content.Client/Kitchen/UI/GrinderMenu.xaml.cs index 7884268c428..f97d8a73302 100644 --- a/Content.Client/Kitchen/UI/GrinderMenu.xaml.cs +++ b/Content.Client/Kitchen/UI/GrinderMenu.xaml.cs @@ -12,34 +12,42 @@ namespace Content.Client.Kitchen.UI [GenerateTypedNameReferences] public sealed partial class GrinderMenu : FancyWindow { - [Dependency] private readonly IEntityManager _entityManager = default!; - [Dependency] private readonly IPrototypeManager _prototypeManager = default!; + private readonly IEntityManager _entityManager; + private readonly IPrototypeManager _prototypeManager; + private readonly ReagentGrinderBoundUserInterface _owner; private readonly Dictionary _chamberVisualContents = new(); - public event Action? OnToggleAuto; - public event Action? OnGrind; - public event Action? OnJuice; - public event Action? OnEjectAll; - public event Action? OnEjectBeaker; - public event Action? OnEjectChamber; - - public GrinderMenu() + public GrinderMenu(ReagentGrinderBoundUserInterface owner, IEntityManager entityManager, IPrototypeManager prototypeManager) { RobustXamlLoader.Load(this); - IoCManager.InjectDependencies(this); - AutoModeButton.OnPressed += _ => OnToggleAuto?.Invoke(); - GrindButton.OnPressed += _ => OnGrind?.Invoke(); - JuiceButton.OnPressed += _ => OnJuice?.Invoke(); - ChamberContentBox.EjectButton.OnPressed += _ => OnEjectAll?.Invoke(); - BeakerContentBox.EjectButton.OnPressed += _ => OnEjectBeaker?.Invoke(); + _entityManager = entityManager; + _prototypeManager = prototypeManager; + _owner = owner; + AutoModeButton.OnPressed += owner.ToggleAutoMode; + GrindButton.OnPressed += owner.StartGrinding; + JuiceButton.OnPressed += owner.StartJuicing; + ChamberContentBox.EjectButton.OnPressed += owner.EjectAll; + BeakerContentBox.EjectButton.OnPressed += owner.EjectBeaker; ChamberContentBox.BoxContents.OnItemSelected += OnChamberBoxContentsItemSelected; BeakerContentBox.BoxContents.SelectMode = ItemList.ItemListSelectMode.None; } private void OnChamberBoxContentsItemSelected(ItemList.ItemListSelectedEventArgs args) { - OnEjectChamber?.Invoke(_chamberVisualContents[args.ItemIndex]); + _owner.EjectChamberContent(_chamberVisualContents[args.ItemIndex]); + } + + protected override void Dispose(bool disposing) + { + base.Dispose(disposing); + + _chamberVisualContents.Clear(); + GrindButton.OnPressed -= _owner.StartGrinding; + JuiceButton.OnPressed -= _owner.StartJuicing; + ChamberContentBox.EjectButton.OnPressed -= _owner.EjectAll; + BeakerContentBox.EjectButton.OnPressed -= _owner.EjectBeaker; + ChamberContentBox.BoxContents.OnItemSelected -= OnChamberBoxContentsItemSelected; } public void UpdateState(ReagentGrinderInterfaceState state) diff --git a/Content.Client/Kitchen/UI/MicrowaveBoundUserInterface.cs b/Content.Client/Kitchen/UI/MicrowaveBoundUserInterface.cs index 643ac47054b..7e7dd2d6935 100644 --- a/Content.Client/Kitchen/UI/MicrowaveBoundUserInterface.cs +++ b/Content.Client/Kitchen/UI/MicrowaveBoundUserInterface.cs @@ -3,7 +3,6 @@ using JetBrains.Annotations; using Robust.Client.GameObjects; using Robust.Client.Graphics; -using Robust.Client.UserInterface; using Robust.Client.UserInterface.Controls; using Robust.Shared.Timing; @@ -20,15 +19,28 @@ public sealed class MicrowaveBoundUserInterface : BoundUserInterface [ViewVariables] private readonly Dictionary _reagents = new(); + [Dependency] private readonly IGameTiming _gameTiming = default!; + + public MicrowaveUpdateUserInterfaceState currentState = default!; + + private IEntityManager _entManager; public MicrowaveBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey) { + _entManager = IoCManager.Resolve(); + } + + public TimeSpan GetCurrentTime() + { + return _gameTiming.CurTime; } protected override void Open() { base.Open(); - _menu = this.CreateWindow(); + _menu = new MicrowaveMenu(this); + _menu.OpenCentered(); + _menu.OnClose += Close; _menu.StartButton.OnPressed += _ => SendPredictedMessage(new MicrowaveStartCookMessage()); _menu.EjectButton.OnPressed += _ => SendPredictedMessage(new MicrowaveEjectMessage()); _menu.IngredientsList.OnItemSelected += args => @@ -62,23 +74,38 @@ protected override void Open() }; } + protected override void Dispose(bool disposing) + { + base.Dispose(disposing); + + if (!disposing) + { + return; + } + + _solids.Clear(); + _menu?.Dispose(); + } + protected override void UpdateState(BoundUserInterfaceState state) { base.UpdateState(state); - if (state is not MicrowaveUpdateUserInterfaceState cState || _menu == null) + if (state is not MicrowaveUpdateUserInterfaceState cState) { return; } - _menu.IsBusy = cState.IsMicrowaveBusy; - _menu.CurrentCooktimeEnd = cState.CurrentCookTimeEnd; - _menu.ToggleBusyDisableOverlayPanel(cState.IsMicrowaveBusy || cState.ContainedSolids.Length == 0); + _menu?.ToggleBusyDisableOverlayPanel(cState.IsMicrowaveBusy || cState.ContainedSolids.Length == 0); + currentState = cState; + // TODO move this to a component state and ensure the net ids. - RefreshContentsDisplay(EntMan.GetEntityArray(cState.ContainedSolids)); + RefreshContentsDisplay(_entManager.GetEntityArray(cState.ContainedSolids)); + + if (_menu == null) return; //Set the cook time info label - var cookTime = cState.ActiveButtonIndex == 0 + var cookTime = cState.ActiveButtonIndex == 0 ? Loc.GetString("microwave-menu-instant-button") : cState.CurrentCookTime.ToString(); diff --git a/Content.Client/Kitchen/UI/MicrowaveMenu.xaml.cs b/Content.Client/Kitchen/UI/MicrowaveMenu.xaml.cs index 7565075f86f..b292e9f1465 100644 --- a/Content.Client/Kitchen/UI/MicrowaveMenu.xaml.cs +++ b/Content.Client/Kitchen/UI/MicrowaveMenu.xaml.cs @@ -9,20 +9,22 @@ namespace Content.Client.Kitchen.UI [GenerateTypedNameReferences] public sealed partial class MicrowaveMenu : FancyWindow { - [Dependency] private readonly IGameTiming _timing = default!; + public sealed class MicrowaveCookTimeButton : Button + { + public uint CookTime; + } public event Action? OnCookTimeSelected; public ButtonGroup CookTimeButtonGroup { get; } + private readonly MicrowaveBoundUserInterface _owner; - public bool IsBusy; - public TimeSpan CurrentCooktimeEnd; - - public MicrowaveMenu() + public MicrowaveMenu(MicrowaveBoundUserInterface owner) { RobustXamlLoader.Load(this); CookTimeButtonGroup = new ButtonGroup(); InstantCookButton.Group = CookTimeButtonGroup; + _owner = owner; InstantCookButton.OnPressed += args => { OnCookTimeSelected?.Invoke(args, 0); @@ -63,20 +65,14 @@ public void ToggleBusyDisableOverlayPanel(bool shouldDisable) protected override void FrameUpdate(FrameEventArgs args) { base.FrameUpdate(args); - - if (!IsBusy) + if(!_owner.currentState.IsMicrowaveBusy) return; - if (CurrentCooktimeEnd > _timing.CurTime) + if(_owner.currentState.CurrentCookTimeEnd > _owner.GetCurrentTime()) { CookTimeInfoLabel.Text = Loc.GetString("microwave-bound-user-interface-cook-time-label", - ("time", CurrentCooktimeEnd.Subtract(_timing.CurTime).Seconds)); + ("time",_owner.currentState.CurrentCookTimeEnd.Subtract(_owner.GetCurrentTime()).Seconds)); } } - - public sealed class MicrowaveCookTimeButton : Button - { - public uint CookTime; - } } } diff --git a/Content.Client/Kitchen/UI/ReagentGrinderBoundUserInterface.cs b/Content.Client/Kitchen/UI/ReagentGrinderBoundUserInterface.cs index bc4cc75b4d1..e6f108b3050 100644 --- a/Content.Client/Kitchen/UI/ReagentGrinderBoundUserInterface.cs +++ b/Content.Client/Kitchen/UI/ReagentGrinderBoundUserInterface.cs @@ -1,7 +1,6 @@ using Content.Shared.Containers.ItemSlots; using Content.Shared.Kitchen; using Robust.Client.GameObjects; -using Robust.Client.UserInterface; using Robust.Client.UserInterface.Controls; using Robust.Shared.Prototypes; @@ -9,6 +8,8 @@ namespace Content.Client.Kitchen.UI { public sealed class ReagentGrinderBoundUserInterface : BoundUserInterface { + [Dependency] private readonly IPrototypeManager _prototypeManager = default!; + [ViewVariables] private GrinderMenu? _menu; @@ -20,13 +21,20 @@ protected override void Open() { base.Open(); - _menu = this.CreateWindow(); - _menu.OnToggleAuto += ToggleAutoMode; - _menu.OnGrind += StartGrinding; - _menu.OnJuice += StartJuicing; - _menu.OnEjectAll += EjectAll; - _menu.OnEjectBeaker += EjectBeaker; - _menu.OnEjectChamber += EjectChamberContent; + _menu = new GrinderMenu(this, EntMan, _prototypeManager); + _menu.OpenCentered(); + _menu.OnClose += Close; + } + + protected override void Dispose(bool disposing) + { + base.Dispose(disposing); + if (!disposing) + { + return; + } + + _menu?.Dispose(); } protected override void UpdateState(BoundUserInterfaceState state) @@ -44,27 +52,27 @@ protected override void ReceiveMessage(BoundUserInterfaceMessage message) _menu?.HandleMessage(message); } - public void ToggleAutoMode() + public void ToggleAutoMode(BaseButton.ButtonEventArgs args) { SendMessage(new ReagentGrinderToggleAutoModeMessage()); } - public void StartGrinding() + public void StartGrinding(BaseButton.ButtonEventArgs? _ = null) { SendMessage(new ReagentGrinderStartMessage(GrinderProgram.Grind)); } - public void StartJuicing() + public void StartJuicing(BaseButton.ButtonEventArgs? _ = null) { SendMessage(new ReagentGrinderStartMessage(GrinderProgram.Juice)); } - public void EjectAll() + public void EjectAll(BaseButton.ButtonEventArgs? _ = null) { SendMessage(new ReagentGrinderEjectChamberAllMessage()); } - public void EjectBeaker() + public void EjectBeaker(BaseButton.ButtonEventArgs? _ = null) { SendMessage(new ItemSlotButtonPressedEvent(SharedReagentGrinder.BeakerSlotId)); } diff --git a/Content.Client/Labels/UI/HandLabelerBoundUserInterface.cs b/Content.Client/Labels/UI/HandLabelerBoundUserInterface.cs index 6b656123412..555f1ff09e6 100644 --- a/Content.Client/Labels/UI/HandLabelerBoundUserInterface.cs +++ b/Content.Client/Labels/UI/HandLabelerBoundUserInterface.cs @@ -1,7 +1,6 @@ using Content.Shared.Labels; using Content.Shared.Labels.Components; using Robust.Client.GameObjects; -using Robust.Client.UserInterface; namespace Content.Client.Labels.UI { @@ -24,8 +23,13 @@ protected override void Open() { base.Open(); - _window = this.CreateWindow(); + _window = new HandLabelerWindow(); + if (State != null) + UpdateState(State); + _window.OpenCentered(); + + _window.OnClose += Close; _window.OnLabelChanged += OnLabelChanged; Reload(); } @@ -47,5 +51,13 @@ public void Reload() _window.SetCurrentLabel(component.AssignedLabel); } + + protected override void Dispose(bool disposing) + { + base.Dispose(disposing); + if (!disposing) return; + _window?.Dispose(); + } } + } diff --git a/Content.Client/Lathe/UI/LatheBoundUserInterface.cs b/Content.Client/Lathe/UI/LatheBoundUserInterface.cs index a599f79152e..6e6d1b91761 100644 --- a/Content.Client/Lathe/UI/LatheBoundUserInterface.cs +++ b/Content.Client/Lathe/UI/LatheBoundUserInterface.cs @@ -1,7 +1,6 @@ using Content.Shared.Lathe; using Content.Shared.Research.Components; using JetBrains.Annotations; -using Robust.Client.UserInterface; namespace Content.Client.Lathe.UI { @@ -18,9 +17,9 @@ protected override void Open() { base.Open(); - _menu = this.CreateWindow(); - _menu.SetEntity(Owner); - _menu.OpenCenteredRight(); + _menu = new LatheMenu(this); + _menu.OnClose += Close; + _menu.OnServerListButtonPressed += _ => { @@ -31,6 +30,8 @@ protected override void Open() { SendMessage(new LatheQueueRecipeMessage(recipe, amount)); }; + + _menu.OpenCenteredRight(); } protected override void UpdateState(BoundUserInterfaceState state) @@ -49,5 +50,13 @@ protected override void UpdateState(BoundUserInterfaceState state) break; } } + + protected override void Dispose(bool disposing) + { + base.Dispose(disposing); + if (!disposing) + return; + _menu?.Dispose(); + } } } diff --git a/Content.Client/Lathe/UI/LatheMenu.xaml.cs b/Content.Client/Lathe/UI/LatheMenu.xaml.cs index bfbcd94ed6c..d597a7d432c 100644 --- a/Content.Client/Lathe/UI/LatheMenu.xaml.cs +++ b/Content.Client/Lathe/UI/LatheMenu.xaml.cs @@ -1,4 +1,3 @@ -using System.Buffers; using System.Linq; using System.Text; using Content.Client.Materials; @@ -21,6 +20,7 @@ public sealed partial class LatheMenu : DefaultWindow [Dependency] private readonly IEntityManager _entityManager = default!; [Dependency] private readonly IPrototypeManager _prototypeManager = default!; + private EntityUid _owner; private readonly SpriteSystem _spriteSystem; private readonly LatheSystem _lathe; private readonly MaterialStorageSystem _materialStorage; @@ -34,10 +34,9 @@ public sealed partial class LatheMenu : DefaultWindow public ProtoId? CurrentCategory; - public EntityUid Entity; - - public LatheMenu() + public LatheMenu(LatheBoundUserInterface owner) { + _owner = owner.Owner; RobustXamlLoader.Load(this); IoCManager.InjectDependencies(this); @@ -45,6 +44,8 @@ public LatheMenu() _lathe = _entityManager.System(); _materialStorage = _entityManager.System(); + Title = _entityManager.GetComponent(owner.Owner).EntityName; + SearchBar.OnTextChanged += _ => { PopulateRecipes(); @@ -57,13 +58,8 @@ public LatheMenu() FilterOption.OnItemSelected += OnItemSelected; ServerListButton.OnPressed += a => OnServerListButtonPressed?.Invoke(a); - } - public void SetEntity(EntityUid uid) - { - Entity = uid; - - if (_entityManager.TryGetComponent(Entity, out var latheComponent)) + if (_entityManager.TryGetComponent(owner.Owner, out var latheComponent)) { if (!latheComponent.DynamicRecipes.Any()) { @@ -71,7 +67,7 @@ public void SetEntity(EntityUid uid) } } - MaterialsList.SetOwner(Entity); + MaterialsList.SetOwner(owner.Owner); } /// @@ -104,15 +100,13 @@ public void PopulateRecipes() var sortedRecipesToShow = recipesToShow.OrderBy(p => p.Name); RecipeList.Children.Clear(); - _entityManager.TryGetComponent(Entity, out LatheComponent? lathe); - foreach (var prototype in sortedRecipesToShow) { EntityPrototype? recipeProto = null; - if (_prototypeManager.TryIndex(prototype.Result, out EntityPrototype? entityProto)) + if (_prototypeManager.TryIndex(prototype.Result, out EntityPrototype? entityProto) && entityProto != null) recipeProto = entityProto; - var canProduce = _lathe.CanProduce(Entity, prototype, quantity, component: lathe); + var canProduce = _lathe.CanProduce(_owner, prototype, quantity); var control = new RecipeControl(prototype, () => GenerateTooltipText(prototype), canProduce, icon); control.OnButtonPressed += s => @@ -128,20 +122,19 @@ public void PopulateRecipes() private string GenerateTooltipText(LatheRecipePrototype prototype) { StringBuilder sb = new(); - var multiplier = _entityManager.GetComponent(Entity).MaterialUseMultiplier; foreach (var (id, amount) in prototype.RequiredMaterials) { if (!_prototypeManager.TryIndex(id, out var proto)) continue; - var adjustedAmount = SharedLatheSystem.AdjustMaterial(amount, prototype.ApplyMaterialDiscount, multiplier); + var adjustedAmount = SharedLatheSystem.AdjustMaterial(amount, prototype.ApplyMaterialDiscount, _entityManager.GetComponent(_owner).MaterialUseMultiplier); var sheetVolume = _materialStorage.GetSheetVolume(proto); var unit = Loc.GetString(proto.Unit); var sheets = adjustedAmount / (float) sheetVolume; - var availableAmount = _materialStorage.GetMaterialAmount(Entity, id); + var availableAmount = _materialStorage.GetMaterialAmount(_owner, id); var missingAmount = Math.Max(0, adjustedAmount - availableAmount); var missingSheets = missingAmount / (float) sheetVolume; diff --git a/Content.Client/MachineLinking/UI/SignalTimerBoundUserInterface.cs b/Content.Client/MachineLinking/UI/SignalTimerBoundUserInterface.cs index 11abe8c2451..09bdedfd94c 100644 --- a/Content.Client/MachineLinking/UI/SignalTimerBoundUserInterface.cs +++ b/Content.Client/MachineLinking/UI/SignalTimerBoundUserInterface.cs @@ -1,6 +1,5 @@ using Content.Shared.MachineLinking; using Robust.Client.GameObjects; -using Robust.Client.UserInterface; using Robust.Shared.Timing; namespace Content.Client.MachineLinking.UI; @@ -20,14 +19,19 @@ protected override void Open() { base.Open(); - _window = this.CreateWindow(); - _window.OnStartTimer += StartTimer; + _window = new SignalTimerWindow(this); + + if (State != null) + UpdateState(State); + + _window.OpenCentered(); + _window.OnClose += Close; _window.OnCurrentTextChanged += OnTextChanged; _window.OnCurrentDelayMinutesChanged += OnDelayChanged; _window.OnCurrentDelaySecondsChanged += OnDelayChanged; } - public void StartTimer() + public void OnStartTimer() { SendMessage(new SignalTimerStartMessage()); } @@ -44,6 +48,11 @@ private void OnDelayChanged(string newDelay) SendMessage(new SignalTimerDelayChangedMessage(_window.GetDelay())); } + public TimeSpan GetCurrentTime() + { + return _gameTiming.CurTime; + } + /// /// Update the UI state based on server-sent info /// @@ -63,4 +72,11 @@ protected override void UpdateState(BoundUserInterfaceState state) _window.SetTimerStarted(cast.TimerStarted); _window.SetHasAccess(cast.HasAccess); } + + protected override void Dispose(bool disposing) + { + base.Dispose(disposing); + if (!disposing) return; + _window?.Dispose(); + } } diff --git a/Content.Client/MachineLinking/UI/SignalTimerWindow.xaml.cs b/Content.Client/MachineLinking/UI/SignalTimerWindow.xaml.cs index 6133abfcb70..b62595595e5 100644 --- a/Content.Client/MachineLinking/UI/SignalTimerWindow.xaml.cs +++ b/Content.Client/MachineLinking/UI/SignalTimerWindow.xaml.cs @@ -9,44 +9,42 @@ namespace Content.Client.MachineLinking.UI; [GenerateTypedNameReferences] public sealed partial class SignalTimerWindow : DefaultWindow { - [Dependency] private readonly IGameTiming _timing = default!; - private const int MaxTextLength = 5; public event Action? OnCurrentTextChanged; public event Action? OnCurrentDelayMinutesChanged; public event Action? OnCurrentDelaySecondsChanged; + private readonly SignalTimerBoundUserInterface _owner; + private TimeSpan? _triggerTime; private bool _timerStarted; - public event Action? OnStartTimer; - - public SignalTimerWindow() + public SignalTimerWindow(SignalTimerBoundUserInterface owner) { RobustXamlLoader.Load(this); - IoCManager.InjectDependencies(this); + + _owner = owner; CurrentTextEdit.OnTextChanged += e => OnCurrentTextChange(e.Text); CurrentDelayEditMinutes.OnTextChanged += e => OnCurrentDelayMinutesChange(e.Text); CurrentDelayEditSeconds.OnTextChanged += e => OnCurrentDelaySecondsChange(e.Text); - StartTimer.OnPressed += _ => StartTimerWeh(); + StartTimer.OnPressed += _ => OnStartTimer(); } - private void StartTimerWeh() + public void OnStartTimer() { if (!_timerStarted) { _timerStarted = true; - _triggerTime = _timing.CurTime + GetDelay(); + _triggerTime = _owner.GetCurrentTime() + GetDelay(); } else { SetTimerStarted(false); } - - OnStartTimer?.Invoke(); + _owner.OnStartTimer(); } protected override void FrameUpdate(FrameEventArgs args) @@ -56,9 +54,9 @@ protected override void FrameUpdate(FrameEventArgs args) if (!_timerStarted || _triggerTime == null) return; - if (_timing.CurTime < _triggerTime.Value) + if (_owner.GetCurrentTime() < _triggerTime.Value) { - StartTimer.Text = TextScreenSystem.TimeToString(_triggerTime.Value - _timing.CurTime); + StartTimer.Text = TextScreenSystem.TimeToString(_triggerTime.Value - _owner.GetCurrentTime()); } else { diff --git a/Content.Client/MagicMirror/MagicMirrorBoundUserInterface.cs b/Content.Client/MagicMirror/MagicMirrorBoundUserInterface.cs index 0a87948ff62..f6979bf8d7b 100644 --- a/Content.Client/MagicMirror/MagicMirrorBoundUserInterface.cs +++ b/Content.Client/MagicMirror/MagicMirrorBoundUserInterface.cs @@ -1,7 +1,6 @@ using Content.Shared.Humanoid.Markings; using Content.Shared.MagicMirror; using Robust.Client.GameObjects; -using Robust.Client.UserInterface; namespace Content.Client.MagicMirror; @@ -18,7 +17,7 @@ protected override void Open() { base.Open(); - _window = this.CreateWindow(); + _window = new(); _window.OnHairSelected += tuple => SelectHair(MagicMirrorCategory.Hair, tuple.id, tuple.slot); _window.OnHairColorChanged += args => ChangeColor(MagicMirrorCategory.Hair, args.marking, args.slot); @@ -30,6 +29,9 @@ protected override void Open() args => ChangeColor(MagicMirrorCategory.FacialHair, args.marking, args.slot); _window.OnFacialHairSlotAdded += delegate () { AddSlot(MagicMirrorCategory.FacialHair); }; _window.OnFacialHairSlotRemoved += args => RemoveSlot(MagicMirrorCategory.FacialHair, args); + + _window.OnClose += Close; + _window.OpenCentered(); } private void SelectHair(MagicMirrorCategory category, string marking, int slot) @@ -63,5 +65,14 @@ protected override void UpdateState(BoundUserInterfaceState state) _window.UpdateState(data); } + + protected override void Dispose(bool disposing) + { + base.Dispose(disposing); + if (!disposing) + return; + + _window?.Dispose(); + } } diff --git a/Content.Client/MassMedia/Ui/NewsWriterBoundUserInterface.cs b/Content.Client/MassMedia/Ui/NewsWriterBoundUserInterface.cs index 22e5bc452a0..80eca82e324 100644 --- a/Content.Client/MassMedia/Ui/NewsWriterBoundUserInterface.cs +++ b/Content.Client/MassMedia/Ui/NewsWriterBoundUserInterface.cs @@ -1,7 +1,6 @@ using JetBrains.Annotations; using Content.Shared.MassMedia.Systems; using Content.Shared.MassMedia.Components; -using Robust.Client.UserInterface; using Robust.Shared.Timing; using Robust.Shared.Utility; @@ -10,6 +9,8 @@ namespace Content.Client.MassMedia.Ui; [UsedImplicitly] public sealed class NewsWriterBoundUserInterface : BoundUserInterface { + [Dependency] private readonly IGameTiming _gameTiming = default!; + [ViewVariables] private NewsWriterMenu? _menu; @@ -20,7 +21,10 @@ public NewsWriterBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, u protected override void Open() { - _menu = this.CreateWindow(); + _menu = new NewsWriterMenu(_gameTiming); + + _menu.OpenCentered(); + _menu.OnClose += Close; _menu.ArticleEditorPanel.PublishButtonPressed += OnPublishButtonPressed; _menu.DeleteButtonPressed += OnDeleteButtonPressed; @@ -28,6 +32,16 @@ protected override void Open() SendMessage(new NewsWriterArticlesRequestMessage()); } + protected override void Dispose(bool disposing) + { + base.Dispose(disposing); + if (!disposing) + return; + + _menu?.Close(); + _menu?.Dispose(); + } + protected override void UpdateState(BoundUserInterfaceState state) { base.UpdateState(state); diff --git a/Content.Client/MassMedia/Ui/NewsWriterMenu.xaml.cs b/Content.Client/MassMedia/Ui/NewsWriterMenu.xaml.cs index c059ce785af..e2d57935e3a 100644 --- a/Content.Client/MassMedia/Ui/NewsWriterMenu.xaml.cs +++ b/Content.Client/MassMedia/Ui/NewsWriterMenu.xaml.cs @@ -10,17 +10,17 @@ namespace Content.Client.MassMedia.Ui; [GenerateTypedNameReferences] public sealed partial class NewsWriterMenu : FancyWindow { - [Dependency] private readonly IGameTiming _gameTiming = default!; + private readonly IGameTiming _gameTiming; private TimeSpan? _nextPublish; public event Action? DeleteButtonPressed; - public NewsWriterMenu() + public NewsWriterMenu(IGameTiming gameTiming) { RobustXamlLoader.Load(this); - IoCManager.InjectDependencies(this); + _gameTiming = gameTiming; ContentsContainer.RectClipContent = false; // Customize scrollbar width and margin. This is not possible in xaml diff --git a/Content.Client/Mech/Ui/MechBoundUserInterface.cs b/Content.Client/Mech/Ui/MechBoundUserInterface.cs index 2130a8c6099..4172bdc90f1 100644 --- a/Content.Client/Mech/Ui/MechBoundUserInterface.cs +++ b/Content.Client/Mech/Ui/MechBoundUserInterface.cs @@ -3,7 +3,6 @@ using Content.Shared.Mech.Components; using JetBrains.Annotations; using Robust.Client.GameObjects; -using Robust.Client.UserInterface; namespace Content.Client.Mech.Ui; @@ -21,8 +20,9 @@ protected override void Open() { base.Open(); - _menu = this.CreateWindow(); - _menu.SetEntity(Owner); + _menu = new(Owner); + + _menu.OnClose += Close; _menu.OpenCenteredLeft(); _menu.OnRemoveButtonPressed += uid => @@ -60,6 +60,16 @@ public void UpdateEquipmentControls(MechBoundUiState state) } } + protected override void Dispose(bool disposing) + { + base.Dispose(disposing); + + if (!disposing) + return; + + _menu?.Close(); + } + public UIFragment? GetEquipmentUi(EntityUid? uid) { var component = EntMan.GetComponentOrNull(uid); diff --git a/Content.Client/Mech/Ui/MechMenu.xaml.cs b/Content.Client/Mech/Ui/MechMenu.xaml.cs index 6f39bc386ee..fad76488086 100644 --- a/Content.Client/Mech/Ui/MechMenu.xaml.cs +++ b/Content.Client/Mech/Ui/MechMenu.xaml.cs @@ -16,15 +16,14 @@ public sealed partial class MechMenu : FancyWindow public event Action? OnRemoveButtonPressed; - public MechMenu() + public MechMenu(EntityUid mech) { RobustXamlLoader.Load(this); IoCManager.InjectDependencies(this); - } - public void SetEntity(EntityUid uid) - { - MechView.SetEntity(uid); + _mech = mech; + + MechView.SetEntity(mech); } public void UpdateMechStats() diff --git a/Content.Client/Medical/CrewMonitoring/CrewMonitoringBoundUserInterface.cs b/Content.Client/Medical/CrewMonitoring/CrewMonitoringBoundUserInterface.cs index b1f239cd78e..39788809871 100644 --- a/Content.Client/Medical/CrewMonitoring/CrewMonitoringBoundUserInterface.cs +++ b/Content.Client/Medical/CrewMonitoring/CrewMonitoringBoundUserInterface.cs @@ -1,5 +1,4 @@ using Content.Shared.Medical.CrewMonitoring; -using Robust.Client.UserInterface; namespace Content.Client.Medical.CrewMonitoring; @@ -15,7 +14,7 @@ public CrewMonitoringBoundUserInterface(EntityUid owner, Enum uiKey) : base(owne protected override void Open() { EntityUid? gridUid = null; - var stationName = string.Empty; + string stationName = string.Empty; if (EntMan.TryGetComponent(Owner, out var xform)) { @@ -27,8 +26,10 @@ protected override void Open() } } - _menu = this.CreateWindow(); - _menu.Set(stationName, gridUid); + _menu = new CrewMonitoringWindow(stationName, gridUid); + + _menu.OpenCentered(); + _menu.OnClose += Close; } protected override void UpdateState(BoundUserInterfaceState state) @@ -43,4 +44,13 @@ protected override void UpdateState(BoundUserInterfaceState state) break; } } + + protected override void Dispose(bool disposing) + { + base.Dispose(disposing); + if (!disposing) + return; + + _menu?.Dispose(); + } } diff --git a/Content.Client/Medical/CrewMonitoring/CrewMonitoringWindow.xaml.cs b/Content.Client/Medical/CrewMonitoring/CrewMonitoringWindow.xaml.cs index e861864c144..863412e5532 100644 --- a/Content.Client/Medical/CrewMonitoring/CrewMonitoringWindow.xaml.cs +++ b/Content.Client/Medical/CrewMonitoring/CrewMonitoringWindow.xaml.cs @@ -23,27 +23,22 @@ namespace Content.Client.Medical.CrewMonitoring; [GenerateTypedNameReferences] public sealed partial class CrewMonitoringWindow : FancyWindow { - [Dependency] private readonly IEntityManager _entManager = default!; - [Dependency] private readonly IPrototypeManager _prototypeManager = default!; + private readonly IEntityManager _entManager; + private readonly IPrototypeManager _prototypeManager; private readonly SpriteSystem _spriteSystem; private NetEntity? _trackedEntity; private bool _tryToScrollToListFocus; private Texture? _blipTexture; - public CrewMonitoringWindow() + public CrewMonitoringWindow(string stationName, EntityUid? mapUid) { RobustXamlLoader.Load(this); - IoCManager.InjectDependencies(this); + _entManager = IoCManager.Resolve(); + _prototypeManager = IoCManager.Resolve(); _spriteSystem = _entManager.System(); - NavMap.TrackedEntitySelectedAction += SetTrackedEntityFromNavMap; - - } - - public void Set(string stationName, EntityUid? mapUid) - { _blipTexture = _spriteSystem.Frame0(new SpriteSpecifier.Texture(new ResPath("/Textures/Interface/NavMap/beveled_circle.png"))); if (_entManager.TryGetComponent(mapUid, out var xform)) @@ -54,6 +49,8 @@ public void Set(string stationName, EntityUid? mapUid) StationName.AddStyleClass("LabelBig"); StationName.Text = stationName; + + NavMap.TrackedEntitySelectedAction += SetTrackedEntityFromNavMap; NavMap.ForceNavMapUpdate(); } diff --git a/Content.Client/NetworkConfigurator/NetworkConfiguratorBoundUserInterface.cs b/Content.Client/NetworkConfigurator/NetworkConfiguratorBoundUserInterface.cs index f85220a9266..80c98f143b9 100644 --- a/Content.Client/NetworkConfigurator/NetworkConfiguratorBoundUserInterface.cs +++ b/Content.Client/NetworkConfigurator/NetworkConfiguratorBoundUserInterface.cs @@ -1,7 +1,6 @@ using Content.Client.NetworkConfigurator.Systems; using Content.Shared.DeviceNetwork; using Robust.Client.GameObjects; -using Robust.Client.UserInterface; using Robust.Client.UserInterface.Controls; namespace Content.Client.NetworkConfigurator; @@ -36,12 +35,14 @@ protected override void Open() switch (UiKey) { case NetworkConfiguratorUiKey.List: - _listMenu = this.CreateWindow(); + _listMenu = new NetworkConfiguratorListMenu(this); + _listMenu.OnClose += Close; _listMenu.ClearButton.OnPressed += _ => OnClearButtonPressed(); - _listMenu.OnRemoveAddress += OnRemoveButtonPressed; + _listMenu.OpenCenteredRight(); break; case NetworkConfiguratorUiKey.Configure: - _configurationMenu = this.CreateWindow(); + _configurationMenu = new NetworkConfiguratorConfigurationMenu(); + _configurationMenu.OnClose += Close; _configurationMenu.Set.OnPressed += _ => OnConfigButtonPressed(NetworkConfiguratorButtonKey.Set); _configurationMenu.Add.OnPressed += _ => OnConfigButtonPressed(NetworkConfiguratorButtonKey.Add); //_configurationMenu.Edit.OnPressed += _ => OnConfigButtonPressed(NetworkConfiguratorButtonKey.Edit); @@ -49,24 +50,12 @@ protected override void Open() _configurationMenu.Copy.OnPressed += _ => OnConfigButtonPressed(NetworkConfiguratorButtonKey.Copy); _configurationMenu.Show.OnPressed += OnShowPressed; _configurationMenu.Show.Pressed = _netConfig.ConfiguredListIsTracked(Owner); - _configurationMenu.OnRemoveAddress += OnRemoveButtonPressed; + _configurationMenu.OpenCentered(); break; case NetworkConfiguratorUiKey.Link: - _linkMenu = this.CreateWindow(); - _linkMenu.OnLinkDefaults += args => - { - SendMessage(new NetworkConfiguratorLinksSaveMessage(args)); - }; - - _linkMenu.OnToggleLink += (left, right) => - { - SendMessage(new NetworkConfiguratorToggleLinkMessage(left, right)); - }; - - _linkMenu.OnClearLinks += () => - { - SendMessage(new NetworkConfiguratorClearLinksMessage()); - }; + _linkMenu = new NetworkConfiguratorLinkMenu(this); + _linkMenu.OnClose += Close; + _linkMenu.OpenCentered(); break; } } @@ -94,6 +83,16 @@ protected override void UpdateState(BoundUserInterfaceState state) } } + protected override void Dispose(bool disposing) + { + base.Dispose(disposing); + if (!disposing) return; + + _linkMenu?.Dispose(); + _listMenu?.Dispose(); + _configurationMenu?.Dispose(); + } + private void OnClearButtonPressed() { SendMessage(new NetworkConfiguratorClearDevicesMessage()); diff --git a/Content.Client/NetworkConfigurator/NetworkConfiguratorConfigurationMenu.xaml.cs b/Content.Client/NetworkConfigurator/NetworkConfiguratorConfigurationMenu.xaml.cs index fcd2f759187..19d04cd3464 100644 --- a/Content.Client/NetworkConfigurator/NetworkConfiguratorConfigurationMenu.xaml.cs +++ b/Content.Client/NetworkConfigurator/NetworkConfiguratorConfigurationMenu.xaml.cs @@ -9,23 +9,17 @@ namespace Content.Client.NetworkConfigurator; [GenerateTypedNameReferences] public sealed partial class NetworkConfiguratorConfigurationMenu : FancyWindow { - public event Action? OnRemoveAddress; - public NetworkConfiguratorConfigurationMenu() { RobustXamlLoader.Load(this); Clear.StyleClasses.Add(StyleBase.ButtonOpenLeft); Clear.StyleClasses.Add(StyleNano.StyleClassButtonColorRed); - DeviceList.OnRemoveAddress += args => - { - OnRemoveAddress?.Invoke(args); - }; } public void UpdateState(DeviceListUserInterfaceState state) { - DeviceList.UpdateState(state.DeviceList, false); + DeviceList.UpdateState(null, state.DeviceList); Count.Text = Loc.GetString("network-configurator-ui-count-label", ("count", state.DeviceList.Count)); } diff --git a/Content.Client/NetworkConfigurator/NetworkConfiguratorDeviceList.xaml.cs b/Content.Client/NetworkConfigurator/NetworkConfiguratorDeviceList.xaml.cs index e75c60058cb..8cfa97dc6c2 100644 --- a/Content.Client/NetworkConfigurator/NetworkConfiguratorDeviceList.xaml.cs +++ b/Content.Client/NetworkConfigurator/NetworkConfiguratorDeviceList.xaml.cs @@ -7,19 +7,17 @@ namespace Content.Client.NetworkConfigurator; [GenerateTypedNameReferences] public sealed partial class NetworkConfiguratorDeviceList : ScrollContainer { - public event Action? OnRemoveAddress; - - public void UpdateState(HashSet<(string address, string name)> devices, bool ui) + public void UpdateState(NetworkConfiguratorBoundUserInterface? ui, HashSet<(string address, string name)> devices) { DeviceList.RemoveAllChildren(); foreach (var device in devices) { - DeviceList.AddChild(BuildDeviceListRow(device, ui)); + DeviceList.AddChild(BuildDeviceListRow(ui, device)); } } - private BoxContainer BuildDeviceListRow((string address, string name) savedDevice, bool ui) + private static BoxContainer BuildDeviceListRow(NetworkConfiguratorBoundUserInterface? ui, (string address, string name) savedDevice) { var row = new BoxContainer() { @@ -50,10 +48,10 @@ private BoxContainer BuildDeviceListRow((string address, string name) savedDevic row.AddChild(name); row.AddChild(address); - if (ui) + if (ui != null) { row.AddChild(removeButton); - removeButton.OnPressed += _ => OnRemoveAddress?.Invoke(savedDevice.address); + removeButton.OnPressed += _ => ui.OnRemoveButtonPressed(savedDevice.address); } return row; diff --git a/Content.Client/NetworkConfigurator/NetworkConfiguratorLinkMenu.xaml.cs b/Content.Client/NetworkConfigurator/NetworkConfiguratorLinkMenu.xaml.cs index 8cdffd16af6..c04b42f249b 100644 --- a/Content.Client/NetworkConfigurator/NetworkConfiguratorLinkMenu.xaml.cs +++ b/Content.Client/NetworkConfigurator/NetworkConfiguratorLinkMenu.xaml.cs @@ -18,20 +18,20 @@ public sealed partial class NetworkConfiguratorLinkMenu : FancyWindow private readonly LinksRender _links; + private readonly List _sources = new(); private readonly List _sinks = new(); + private readonly NetworkConfiguratorBoundUserInterface _userInterface; + private (ButtonPosition position, string id, int index)? _selectedButton; private List<(string left, string right)>? _defaults; - public event Action? OnClearLinks; - public event Action? OnToggleLink; - public event Action>? OnLinkDefaults; - - public NetworkConfiguratorLinkMenu() + public NetworkConfiguratorLinkMenu(NetworkConfiguratorBoundUserInterface userInterface) { + _userInterface = userInterface; RobustXamlLoader.Load(this); var footerStyleBox = new StyleBoxFlat() @@ -52,7 +52,7 @@ public NetworkConfiguratorLinkMenu() ButtonOk.OnPressed += _ => Close(); ButtonLinkDefault.OnPressed += _ => LinkDefaults(); - ButtonClear.OnPressed += _ => OnClearLinks?.Invoke(); + ButtonClear.OnPressed += _ => _userInterface.SendMessage(new NetworkConfiguratorClearLinksMessage()); } public void UpdateState(DeviceLinkUserInterfaceState linkState) @@ -98,7 +98,7 @@ private void LinkDefaults() if (_defaults == default) return; - OnLinkDefaults?.Invoke(_defaults); + _userInterface.SendMessage(new NetworkConfiguratorLinksSaveMessage(_defaults)); } private Button CreateButton(ButtonPosition position, string name, string description, string id, int index) @@ -138,7 +138,7 @@ private void OnButtonPressed(BaseButton.ButtonEventArgs args, ButtonPosition pos var left = _selectedButton.Value.position == ButtonPosition.Left ? _selectedButton.Value.id : id; var right = _selectedButton.Value.position == ButtonPosition.Left ? id : _selectedButton.Value.id; - OnToggleLink?.Invoke(left, right); + _userInterface.SendMessage(new NetworkConfiguratorToggleLinkMessage(left, right)); args.Button.Pressed = false; diff --git a/Content.Client/NetworkConfigurator/NetworkConfiguratorListMenu.xaml.cs b/Content.Client/NetworkConfigurator/NetworkConfiguratorListMenu.xaml.cs index 6294facaeed..fb4aec1974b 100644 --- a/Content.Client/NetworkConfigurator/NetworkConfiguratorListMenu.xaml.cs +++ b/Content.Client/NetworkConfigurator/NetworkConfiguratorListMenu.xaml.cs @@ -9,20 +9,17 @@ namespace Content.Client.NetworkConfigurator; [GenerateTypedNameReferences] public sealed partial class NetworkConfiguratorListMenu : FancyWindow { - public event Action? OnRemoveAddress; - - public NetworkConfiguratorListMenu() + private readonly NetworkConfiguratorBoundUserInterface _ui; + public NetworkConfiguratorListMenu(NetworkConfiguratorBoundUserInterface ui) { RobustXamlLoader.Load(this); - DeviceList.OnRemoveAddress += args => - { - OnRemoveAddress?.Invoke(args); - }; + + _ui = ui; } public void UpdateState(NetworkConfiguratorUserInterfaceState state) { DeviceCountLabel.Text = Loc.GetString("network-configurator-ui-count-label", ("count", state.DeviceList.Count)); - DeviceList.UpdateState(state.DeviceList, true); + DeviceList.UpdateState(_ui, state.DeviceList); } } diff --git a/Content.Client/Nuke/NukeBoundUserInterface.cs b/Content.Client/Nuke/NukeBoundUserInterface.cs index 2e150423734..59fbc5b319b 100644 --- a/Content.Client/Nuke/NukeBoundUserInterface.cs +++ b/Content.Client/Nuke/NukeBoundUserInterface.cs @@ -2,7 +2,6 @@ using Content.Shared.Nuke; using JetBrains.Annotations; using Robust.Client.GameObjects; -using Robust.Client.UserInterface; namespace Content.Client.Nuke { @@ -12,13 +11,15 @@ public sealed class NukeBoundUserInterface : BoundUserInterface [ViewVariables] private NukeMenu? _menu; - public NukeBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey) + public NukeBoundUserInterface([NotNull] EntityUid owner, [NotNull] Enum uiKey) : base(owner, uiKey) { } protected override void Open() { - _menu = this.CreateWindow(); + _menu = new NukeMenu(); + _menu.OpenCentered(); + _menu.OnClose += Close; _menu.OnKeypadButtonPressed += i => { @@ -61,5 +62,15 @@ protected override void UpdateState(BoundUserInterfaceState state) break; } } + + protected override void Dispose(bool disposing) + { + base.Dispose(disposing); + if (!disposing) + return; + + _menu?.Close(); + _menu?.Dispose(); + } } } diff --git a/Content.Client/NukeOps/WarDeclaratorBoundUserInterface.cs b/Content.Client/NukeOps/WarDeclaratorBoundUserInterface.cs index ad4f1a75d47..ec055b3240c 100644 --- a/Content.Client/NukeOps/WarDeclaratorBoundUserInterface.cs +++ b/Content.Client/NukeOps/WarDeclaratorBoundUserInterface.cs @@ -2,7 +2,6 @@ using Content.Shared.Chat; using Content.Shared.NukeOps; using JetBrains.Annotations; -using Robust.Client.UserInterface; using Robust.Shared.Configuration; using Robust.Shared.Timing; @@ -12,6 +11,8 @@ namespace Content.Client.NukeOps; public sealed class WarDeclaratorBoundUserInterface : BoundUserInterface { [Dependency] private readonly IConfigurationManager _cfg = default!; + [Dependency] private readonly IGameTiming _gameTiming = default!; + [Dependency] private readonly ILocalizationManager _localizationManager = default!; [ViewVariables] private WarDeclaratorWindow? _window; @@ -22,7 +23,13 @@ protected override void Open() { base.Open(); - _window = this.CreateWindow(); + _window = new WarDeclaratorWindow(_gameTiming, _localizationManager); + if (State != null) + UpdateState(State); + + _window.OpenCentered(); + + _window.OnClose += Close; _window.OnActivated += OnWarDeclaratorActivated; } @@ -35,6 +42,13 @@ protected override void UpdateState(BoundUserInterfaceState state) _window?.UpdateState(cast); } + protected override void Dispose(bool disposing) + { + base.Dispose(disposing); + if (disposing) + _window?.Dispose(); + } + private void OnWarDeclaratorActivated(string message) { var maxLength = _cfg.GetCVar(CCVars.ChatMaxAnnouncementLength); diff --git a/Content.Client/NukeOps/WarDeclaratorWindow.xaml.cs b/Content.Client/NukeOps/WarDeclaratorWindow.xaml.cs index aeceae13275..b4a3f1c7fa5 100644 --- a/Content.Client/NukeOps/WarDeclaratorWindow.xaml.cs +++ b/Content.Client/NukeOps/WarDeclaratorWindow.xaml.cs @@ -11,8 +11,7 @@ namespace Content.Client.NukeOps; [GenerateTypedNameReferences] public sealed partial class WarDeclaratorWindow : FancyWindow { - [Dependency] private readonly IGameTiming _gameTiming = default!; - [Dependency] private readonly ILocalizationManager _localizationManager = default!; + private readonly IGameTiming _gameTiming; public event Action? OnActivated; @@ -20,13 +19,15 @@ public sealed partial class WarDeclaratorWindow : FancyWindow private TimeSpan _shuttleDisabledTime; private WarConditionStatus _status; - public WarDeclaratorWindow() + public WarDeclaratorWindow(IGameTiming gameTiming, ILocalizationManager localizationManager) { RobustXamlLoader.Load(this); + _gameTiming = gameTiming; + WarButton.OnPressed += (_) => OnActivated?.Invoke(Rope.Collapse(MessageEdit.TextRope)); - MessageEdit.Placeholder = new Rope.Leaf(_localizationManager.GetString("war-declarator-message-placeholder")); + MessageEdit.Placeholder = new Rope.Leaf(localizationManager.GetString("war-declarator-message-placeholder")); } protected override void FrameUpdate(FrameEventArgs args) diff --git a/Content.Client/PDA/PdaBoundUserInterface.cs b/Content.Client/PDA/PdaBoundUserInterface.cs index 37ce9c4280f..f8f4c67076c 100644 --- a/Content.Client/PDA/PdaBoundUserInterface.cs +++ b/Content.Client/PDA/PdaBoundUserInterface.cs @@ -24,13 +24,14 @@ protected override void Open() if (_menu == null) CreateMenu(); + + _menu?.OpenCenteredLeft(); } private void CreateMenu() { - _menu = this.CreateWindow(); - _menu.OpenCenteredLeft(); - + _menu = new PdaMenu(); + _menu.OnClose += Close; _menu.FlashLightToggleButton.OnToggled += _ => { SendMessage(new PdaToggleFlashlightMessage()); @@ -95,6 +96,7 @@ protected override void UpdateState(BoundUserInterfaceState state) _menu?.UpdateState(updateState); } + protected override void AttachCartridgeUI(Control cartridgeUIFragment, string? title) { _menu?.ProgramView.AddChild(cartridgeUIFragment); @@ -116,6 +118,15 @@ protected override void UpdateAvailablePrograms(List<(EntityUid, CartridgeCompon _menu?.UpdateAvailablePrograms(programs); } + protected override void Dispose(bool disposing) + { + base.Dispose(disposing); + if (!disposing) + return; + + _menu?.Dispose(); + } + private PdaBorderColorComponent? GetBorderColorComponent() { return EntMan.GetComponentOrNull(Owner); diff --git a/Content.Client/PDA/Ringer/RingerBoundUserInterface.cs b/Content.Client/PDA/Ringer/RingerBoundUserInterface.cs index 170a296ac2e..a0688523f1e 100644 --- a/Content.Client/PDA/Ringer/RingerBoundUserInterface.cs +++ b/Content.Client/PDA/Ringer/RingerBoundUserInterface.cs @@ -1,7 +1,6 @@ using Content.Shared.PDA; using Content.Shared.PDA.Ringer; using JetBrains.Annotations; -using Robust.Client.UserInterface; using Robust.Shared.Timing; namespace Content.Client.PDA.Ringer @@ -19,8 +18,9 @@ public RingerBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey protected override void Open() { base.Open(); - _menu = this.CreateWindow(); + _menu = new RingtoneMenu(); _menu.OpenToLeft(); + _menu.OnClose += Close; _menu.TestRingerButton.OnPressed += _ => { diff --git a/Content.Client/Paper/UI/PaperBoundUserInterface.cs b/Content.Client/Paper/UI/PaperBoundUserInterface.cs index f3ad1e347e7..4b0ac868f01 100644 --- a/Content.Client/Paper/UI/PaperBoundUserInterface.cs +++ b/Content.Client/Paper/UI/PaperBoundUserInterface.cs @@ -1,5 +1,4 @@ using JetBrains.Annotations; -using Robust.Client.UserInterface; using Robust.Client.UserInterface.Controls; using Robust.Shared.Utility; using static Content.Shared.Paper.SharedPaperComponent; @@ -20,13 +19,16 @@ protected override void Open() { base.Open(); - _window = this.CreateWindow(); - _window.OnSaved += InputOnTextEntered; + _window = new PaperWindow(); + _window.OnClose += Close; + _window.OnSaved += Input_OnTextEntered; if (EntMan.TryGetComponent(Owner, out var visuals)) { _window.InitVisuals(Owner, visuals); } + + _window.OpenCentered(); } protected override void UpdateState(BoundUserInterfaceState state) @@ -35,7 +37,7 @@ protected override void UpdateState(BoundUserInterfaceState state) _window?.Populate((PaperBoundUserInterfaceState) state); } - private void InputOnTextEntered(string text) + private void Input_OnTextEntered(string text) { SendMessage(new PaperInputTextMessage(text)); @@ -45,4 +47,11 @@ private void InputOnTextEntered(string text) _window.Input.CursorPosition = new TextEdit.CursorPos(0, TextEdit.LineBreakBias.Top); } } + + protected override void Dispose(bool disposing) + { + base.Dispose(disposing); + if (!disposing) return; + _window?.Dispose(); + } } diff --git a/Content.Client/Paper/UI/PaperWindow.xaml.cs b/Content.Client/Paper/UI/PaperWindow.xaml.cs index f7cace642ce..7a5fd652643 100644 --- a/Content.Client/Paper/UI/PaperWindow.xaml.cs +++ b/Content.Client/Paper/UI/PaperWindow.xaml.cs @@ -17,7 +17,6 @@ namespace Content.Client.Paper.UI public sealed partial class PaperWindow : BaseWindow { [Dependency] private readonly IInputManager _inputManager = default!; - [Dependency] private readonly IResourceCache _resCache = default!; private static Color DefaultTextColor = new(25, 25, 25); @@ -86,10 +85,11 @@ public void InitVisuals(EntityUid entity, PaperVisualsComponent visuals) // Randomize the placement of any stamps based on the entity UID // so that there's some variety in different papers. StampDisplay.PlacementSeed = (int)entity; + var resCache = IoCManager.Resolve(); // Initialize the background: PaperBackground.ModulateSelfOverride = visuals.BackgroundModulate; - var backgroundImage = visuals.BackgroundImagePath != null? _resCache.GetResource(visuals.BackgroundImagePath) : null; + var backgroundImage = visuals.BackgroundImagePath != null? resCache.GetResource(visuals.BackgroundImagePath) : null; if (backgroundImage != null) { var backgroundImageMode = visuals.BackgroundImageTile ? StyleBoxTexture.StretchMode.Tile : StyleBoxTexture.StretchMode.Stretch; @@ -127,7 +127,7 @@ public void InitVisuals(EntityUid entity, PaperVisualsComponent visuals) PaperContent.ModulateSelfOverride = visuals.ContentImageModulate; WrittenTextLabel.ModulateSelfOverride = visuals.FontAccentColor; - var contentImage = visuals.ContentImagePath != null ? _resCache.GetResource(visuals.ContentImagePath) : null; + var contentImage = visuals.ContentImagePath != null ? resCache.GetResource(visuals.ContentImagePath) : null; if (contentImage != null) { // Setup the paper content texture, but keep a reference to it, as we can't set diff --git a/Content.Client/ParticleAccelerator/UI/ParticleAcceleratorBoundUserInterface.cs b/Content.Client/ParticleAccelerator/UI/ParticleAcceleratorBoundUserInterface.cs index ff1eae36f55..cde5ba9ef79 100644 --- a/Content.Client/ParticleAccelerator/UI/ParticleAcceleratorBoundUserInterface.cs +++ b/Content.Client/ParticleAccelerator/UI/ParticleAcceleratorBoundUserInterface.cs @@ -1,6 +1,5 @@ using Content.Shared.Singularity.Components; using Robust.Client.GameObjects; -using Robust.Client.UserInterface; namespace Content.Client.ParticleAccelerator.UI { @@ -17,10 +16,9 @@ protected override void Open() { base.Open(); - _menu = this.CreateWindow(); - _menu.OnOverallState += SendEnableMessage; - _menu.OnPowerState += SendPowerStateMessage; - _menu.OnScanPartsRequested += SendScanPartsMessage; + _menu = new ParticleAcceleratorControlMenu(this); + _menu.OnClose += Close; + _menu.OpenCentered(); } public void SendEnableMessage(bool enable) @@ -42,5 +40,13 @@ protected override void UpdateState(BoundUserInterfaceState state) { _menu?.DataUpdate((ParticleAcceleratorUIState) state); } + + protected override void Dispose(bool disposing) + { + base.Dispose(disposing); + + _menu?.Dispose(); + _menu = null; + } } } diff --git a/Content.Client/ParticleAccelerator/UI/ParticleAcceleratorControlMenu.cs b/Content.Client/ParticleAccelerator/UI/ParticleAcceleratorControlMenu.cs index 85a5f476293..c69e0271372 100644 --- a/Content.Client/ParticleAccelerator/UI/ParticleAcceleratorControlMenu.cs +++ b/Content.Client/ParticleAccelerator/UI/ParticleAcceleratorControlMenu.cs @@ -18,11 +18,10 @@ namespace Content.Client.ParticleAccelerator.UI { public sealed class ParticleAcceleratorControlMenu : BaseWindow { - [Dependency] private readonly IPrototypeManager _protoManager = default!; - [Dependency] private readonly IResourceCache _cache = default!; - private readonly ShaderInstance _greyScaleShader; + private readonly ParticleAcceleratorBoundUserInterface _owner; + private readonly Label _drawLabel; private readonly FastNoiseLite _drawNoiseGenerator; private readonly Button _onButton; @@ -51,21 +50,19 @@ public sealed class ParticleAcceleratorControlMenu : BaseWindow private bool _shouldContinueAnimating; private int _maxStrength = 3; - public event Action? OnOverallState; - public event Action? OnPowerState; - public event Action? OnScanPartsRequested; - - public ParticleAcceleratorControlMenu() + public ParticleAcceleratorControlMenu(ParticleAcceleratorBoundUserInterface owner) { SetSize = new Vector2(400, 320); - _greyScaleShader = _protoManager.Index("Greyscale").Instance(); + _greyScaleShader = IoCManager.Resolve().Index("Greyscale").Instance(); + _owner = owner; _drawNoiseGenerator = new(); _drawNoiseGenerator.SetFractalType(FastNoiseLite.FractalType.FBm); _drawNoiseGenerator.SetFrequency(0.5f); - var font = _cache.GetFont("/Fonts/Boxfont-round/Boxfont Round.ttf", 13); - var panelTex = _cache.GetTexture("/Textures/Interface/Nano/button.svg.96dpi.png"); + var resourceCache = IoCManager.Resolve(); + var font = resourceCache.GetFont("/Fonts/Boxfont-round/Boxfont Round.ttf", 13); + var panelTex = resourceCache.GetTexture("/Textures/Interface/Nano/button.svg.96dpi.png"); MouseFilter = MouseFilterMode.Stop; @@ -115,8 +112,7 @@ public ParticleAcceleratorControlMenu() Text = Loc.GetString("particle-accelerator-control-menu-off-button"), StyleClasses = { StyleBase.ButtonOpenRight }, }; - - _offButton.OnPressed += args => OnOverallState?.Invoke(false); + _offButton.OnPressed += args => owner.SendEnableMessage(false); _onButton = new Button { @@ -124,7 +120,7 @@ public ParticleAcceleratorControlMenu() Text = Loc.GetString("particle-accelerator-control-menu-on-button"), StyleClasses = { StyleBase.ButtonOpenLeft }, }; - _onButton.OnPressed += args => OnOverallState?.Invoke(true); + _onButton.OnPressed += args => owner.SendEnableMessage(true); var closeButton = new TextureButton { @@ -320,7 +316,7 @@ public ParticleAcceleratorControlMenu() } }); - _scanButton.OnPressed += args => OnScanPartsRequested?.Invoke(); + _scanButton.OnPressed += args => _owner.SendScanPartsMessage(); _alarmControl.AnimationCompleted += s => { @@ -336,7 +332,7 @@ public ParticleAcceleratorControlMenu() PASegmentControl Segment(string name) { - return new(this, _cache, name); + return new(this, resourceCache, name); } UpdateUI(false, false, false, false); @@ -372,7 +368,7 @@ private void PowerStateChanged(ValueChangedEventArgs e) } _stateSpinBox.SetButtonDisabled(true); - OnPowerState?.Invoke(newState); + _owner.SendPowerStateMessage(newState); } protected override DragMode GetDragModeFor(Vector2 relativeMousePos) diff --git a/Content.Client/Pinpointer/UI/NavMapBeaconBoundUserInterface.cs b/Content.Client/Pinpointer/UI/NavMapBeaconBoundUserInterface.cs index 0df6787170a..3ebcf7cbced 100644 --- a/Content.Client/Pinpointer/UI/NavMapBeaconBoundUserInterface.cs +++ b/Content.Client/Pinpointer/UI/NavMapBeaconBoundUserInterface.cs @@ -1,6 +1,5 @@ using Content.Shared.Pinpointer; using JetBrains.Annotations; -using Robust.Client.UserInterface; namespace Content.Client.Pinpointer.UI; @@ -17,16 +16,19 @@ public NavMapBeaconBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, protected override void Open() { base.Open(); - _window = this.CreateWindow(); - - if (EntMan.TryGetComponent(Owner, out NavMapBeaconComponent? beacon)) - { - _window.SetEntity(Owner, beacon); - } + _window = new NavMapBeaconWindow(Owner); + _window.OpenCentered(); + _window.OnClose += Close; _window.OnApplyButtonPressed += (label, enabled, color) => { SendMessage(new NavMapBeaconConfigureBuiMessage(label, enabled, color)); }; } + + protected override void Dispose(bool disposing) + { + base.Dispose(disposing); + _window?.Dispose(); + } } diff --git a/Content.Client/Pinpointer/UI/NavMapBeaconWindow.xaml.cs b/Content.Client/Pinpointer/UI/NavMapBeaconWindow.xaml.cs index b77f1af0472..968fe188f75 100644 --- a/Content.Client/Pinpointer/UI/NavMapBeaconWindow.xaml.cs +++ b/Content.Client/Pinpointer/UI/NavMapBeaconWindow.xaml.cs @@ -10,35 +10,36 @@ namespace Content.Client.Pinpointer.UI; [GenerateTypedNameReferences] public sealed partial class NavMapBeaconWindow : FancyWindow { + [Dependency] private readonly IEntityManager _entityManager = default!; + private string? _defaultLabel; private bool _defaultEnabled; private Color _defaultColor; public event Action? OnApplyButtonPressed; - public NavMapBeaconWindow() + public NavMapBeaconWindow(EntityUid beaconEntity) { RobustXamlLoader.Load(this); IoCManager.InjectDependencies(this); - - VisibleButton.OnPressed += args => UpdateVisibleButton(args.Button.Pressed); - LabelLineEdit.OnTextChanged += OnTextChanged; - ColorSelector.OnColorChanged += _ => TryEnableApplyButton(); - - TryEnableApplyButton(); - ApplyButton.OnPressed += OnApplyPressed; - } - - public void SetEntity(EntityUid uid, NavMapBeaconComponent navMap) - { + if (!_entityManager.TryGetComponent(beaconEntity, out var navMap)) + return; _defaultLabel = navMap.Text; _defaultEnabled = navMap.Enabled; _defaultColor = navMap.Color; UpdateVisibleButton(navMap.Enabled); + VisibleButton.OnPressed += args => UpdateVisibleButton(args.Button.Pressed); + LabelLineEdit.Text = navMap.Text ?? string.Empty; + LabelLineEdit.OnTextChanged += OnTextChanged; + ColorSelector.Color = navMap.Color; + ColorSelector.OnColorChanged += _ => TryEnableApplyButton(); + + TryEnableApplyButton(); + ApplyButton.OnPressed += OnApplyPressed; } private void UpdateVisibleButton(bool value) diff --git a/Content.Client/Pinpointer/UI/StationMapBoundUserInterface.cs b/Content.Client/Pinpointer/UI/StationMapBoundUserInterface.cs index 7417fafede5..1483e75e732 100644 --- a/Content.Client/Pinpointer/UI/StationMapBoundUserInterface.cs +++ b/Content.Client/Pinpointer/UI/StationMapBoundUserInterface.cs @@ -1,4 +1,4 @@ -using Robust.Client.UserInterface; +using Robust.Client.GameObjects; namespace Content.Client.Pinpointer.UI; @@ -14,6 +14,7 @@ public StationMapBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, u protected override void Open() { base.Open(); + _window?.Close(); EntityUid? gridUid = null; if (EntMan.TryGetComponent(Owner, out var xform)) @@ -21,8 +22,14 @@ protected override void Open() gridUid = xform.GridUid; } - _window = this.CreateWindow(); - _window.Title = EntMan.GetComponent(Owner).EntityName; - _window.Set(gridUid, Owner); + _window = new StationMapWindow(gridUid, Owner); + _window.OpenCentered(); + _window.OnClose += Close; + } + + protected override void Dispose(bool disposing) + { + base.Dispose(disposing); + _window?.Dispose(); } } diff --git a/Content.Client/Pinpointer/UI/StationMapWindow.xaml.cs b/Content.Client/Pinpointer/UI/StationMapWindow.xaml.cs index 7cbb8b7d0db..1b01fe4e304 100644 --- a/Content.Client/Pinpointer/UI/StationMapWindow.xaml.cs +++ b/Content.Client/Pinpointer/UI/StationMapWindow.xaml.cs @@ -9,18 +9,19 @@ namespace Content.Client.Pinpointer.UI; [GenerateTypedNameReferences] public sealed partial class StationMapWindow : FancyWindow { - public StationMapWindow() + public StationMapWindow(EntityUid? mapUid, EntityUid? trackedEntity) { RobustXamlLoader.Load(this); - } - - public void Set(EntityUid? mapUid, EntityUid? trackedEntity) - { NavMapScreen.MapUid = mapUid; if (trackedEntity != null) NavMapScreen.TrackedCoordinates.Add(new EntityCoordinates(trackedEntity.Value, Vector2.Zero), (true, Color.Cyan)); + if (IoCManager.Resolve().TryGetComponent(mapUid, out var metadata)) + { + Title = metadata.EntityName; + } + NavMapScreen.ForceNavMapUpdate(); } } diff --git a/Content.Client/Pinpointer/UI/UntrackedMapBoundUserInterface.cs b/Content.Client/Pinpointer/UI/UntrackedMapBoundUserInterface.cs index a3ca6f65da2..57965b030a2 100644 --- a/Content.Client/Pinpointer/UI/UntrackedMapBoundUserInterface.cs +++ b/Content.Client/Pinpointer/UI/UntrackedMapBoundUserInterface.cs @@ -1,4 +1,4 @@ -using Robust.Client.UserInterface; +using Robust.Client.GameObjects; namespace Content.Client.Pinpointer.UI; @@ -14,15 +14,22 @@ public UntrackedStationMapBoundUserInterface(EntityUid owner, Enum uiKey) : base protected override void Open() { base.Open(); + _window?.Close(); EntityUid? gridUid = null; - // TODO: What this just looks like it's been copy-pasted wholesale from StationMapBoundUserInterface? if (EntMan.TryGetComponent(Owner, out var xform)) { gridUid = xform.GridUid; } - _window = this.CreateWindow(); - _window.Set(gridUid, Owner); + _window = new StationMapWindow(gridUid, null); + _window.OpenCentered(); + _window.OnClose += Close; + } + + protected override void Dispose(bool disposing) + { + base.Dispose(disposing); + _window?.Dispose(); } } diff --git a/Content.Client/Power/APC/ApcBoundUserInterface.cs b/Content.Client/Power/APC/ApcBoundUserInterface.cs index 759a5949ba6..fbcbf011569 100644 --- a/Content.Client/Power/APC/ApcBoundUserInterface.cs +++ b/Content.Client/Power/APC/ApcBoundUserInterface.cs @@ -2,7 +2,6 @@ using Content.Shared.APC; using JetBrains.Annotations; using Robust.Client.GameObjects; -using Robust.Client.UserInterface; namespace Content.Client.Power.APC { @@ -20,8 +19,9 @@ protected override void Open() { base.Open(); - _menu = this.CreateWindow(); - _menu.OnBreaker += BreakerPressed; + _menu = new ApcMenu(this); + _menu.OnClose += Close; + _menu.OpenCentered(); } protected override void UpdateState(BoundUserInterfaceState state) @@ -36,5 +36,15 @@ public void BreakerPressed() { SendMessage(new ApcToggleMainBreakerMessage()); } + + protected override void Dispose(bool disposing) + { + base.Dispose(disposing); + + if (disposing) + { + _menu?.Dispose(); + } + } } } diff --git a/Content.Client/Power/APC/UI/ApcMenu.xaml.cs b/Content.Client/Power/APC/UI/ApcMenu.xaml.cs index 2f61ea63a86..dbf68ea07b0 100644 --- a/Content.Client/Power/APC/UI/ApcMenu.xaml.cs +++ b/Content.Client/Power/APC/UI/ApcMenu.xaml.cs @@ -17,19 +17,13 @@ namespace Content.Client.Power.APC.UI [GenerateTypedNameReferences] public sealed partial class ApcMenu : FancyWindow { - public event Action? OnBreaker; - - public ApcMenu() + public ApcMenu(ApcBoundUserInterface owner) { IoCManager.InjectDependencies(this); RobustXamlLoader.Load(this); - BreakerButton.OnPressed += _ => OnBreaker?.Invoke(); - } - - public void SetEntity(EntityUid entity) - { - EntityView.SetEntity(entity); + EntityView.SetEntity(owner.Owner); + BreakerButton.OnPressed += _ => owner.BreakerPressed(); } public void UpdateState(BoundUserInterfaceState state) diff --git a/Content.Client/Power/Generator/GeneratorWindow.xaml.cs b/Content.Client/Power/Generator/GeneratorWindow.xaml.cs index e975e5d466e..bd5b75de1da 100644 --- a/Content.Client/Power/Generator/GeneratorWindow.xaml.cs +++ b/Content.Client/Power/Generator/GeneratorWindow.xaml.cs @@ -9,39 +9,35 @@ namespace Content.Client.Power.Generator; [GenerateTypedNameReferences] public sealed partial class GeneratorWindow : FancyWindow { + private readonly EntityUid _entity; + [Dependency] private readonly IEntityManager _entityManager = default!; [Dependency] private readonly ILocalizationManager _loc = default!; - private EntityUid _entity; - - public float? MaximumPower; - - public event Action? OnPower; - public event Action? OnState; - public event Action? OnSwitchOutput; - public event Action? OnEjectFuel; + private readonly SharedPowerSwitchableSystem _switchable; + private readonly FuelGeneratorComponent? _component; + private PortableGeneratorComponentBuiState? _lastState; - public GeneratorWindow() + public GeneratorWindow(PortableGeneratorBoundUserInterface bui, EntityUid entity) { + _entity = entity; RobustXamlLoader.Load(this); IoCManager.InjectDependencies(this); + _entityManager.TryGetComponent(entity, out _component); + _switchable = _entityManager.System(); + + EntityView.SetEntity(entity); TargetPower.IsValid += IsValid; TargetPower.ValueChanged += (args) => { - OnPower?.Invoke(args.Value); + bui.SetTargetPower(args.Value); }; - StartButton.OnPressed += _ => OnState?.Invoke(true); - StopButton.OnPressed += _ => OnState?.Invoke(false); - OutputSwitchButton.OnPressed += _ => OnSwitchOutput?.Invoke(); - FuelEject.OnPressed += _ => OnEjectFuel?.Invoke(); - } - - public void SetEntity(EntityUid entity) - { - _entity = entity; - EntityView.SetEntity(entity); + StartButton.OnPressed += _ => bui.Start(); + StopButton.OnPressed += _ => bui.Stop(); + OutputSwitchButton.OnPressed += _ => bui.SwitchOutput(); + FuelEject.OnPressed += _ => bui.EjectFuel(); } private bool IsValid(int arg) @@ -49,7 +45,7 @@ private bool IsValid(int arg) if (arg < 0) return false; - if (arg > (MaximumPower / 1000.0f ?? 0)) + if (arg > (_lastState?.MaximumPower / 1000.0f ?? 0)) return false; return true; @@ -57,17 +53,16 @@ private bool IsValid(int arg) public void Update(PortableGeneratorComponentBuiState state) { - MaximumPower = state.MaximumPower; - - if (!_entityManager.TryGetComponent(_entity, out FuelGeneratorComponent? component)) + if (_component == null) return; + _lastState = state; if (!TargetPower.LineEditControl.HasKeyboardFocus()) TargetPower.OverrideValue((int)(state.TargetPower / 1000.0f)); - var efficiency = SharedGeneratorSystem.CalcFuelEfficiency(state.TargetPower, state.OptimalPower, component); + var efficiency = SharedGeneratorSystem.CalcFuelEfficiency(state.TargetPower, state.OptimalPower, _component); Efficiency.Text = efficiency.ToString("P1"); - var burnRate = component.OptimalBurnRate / efficiency; + var burnRate = _component.OptimalBurnRate / efficiency; var left = state.RemainingFuel / burnRate; Eta.Text = Loc.GetString( @@ -107,15 +102,14 @@ public void Update(PortableGeneratorComponentBuiState state) } var canSwitch = _entityManager.TryGetComponent(_entity, out PowerSwitchableComponent? switchable); - var switcher = _entityManager.System(); OutputSwitchLabel.Visible = canSwitch; OutputSwitchButton.Visible = canSwitch; if (switchable != null) { - var voltage = switcher.VoltageString(switcher.GetVoltage(_entity, switchable)); + var voltage = _switchable.VoltageString(_switchable.GetVoltage(_entity, switchable)); OutputSwitchLabel.Text = Loc.GetString("portable-generator-ui-current-output", ("voltage", voltage)); - var nextVoltage = switcher.VoltageString(switcher.GetNextVoltage(_entity, switchable)); + var nextVoltage = _switchable.VoltageString(_switchable.GetNextVoltage(_entity, switchable)); OutputSwitchButton.Text = Loc.GetString("power-switchable-switch-voltage", ("voltage", nextVoltage)); OutputSwitchButton.Disabled = state.On; } diff --git a/Content.Client/Power/Generator/PortableGeneratorBoundUserInterface.cs b/Content.Client/Power/Generator/PortableGeneratorBoundUserInterface.cs index 550e1041b62..30679d71fd6 100644 --- a/Content.Client/Power/Generator/PortableGeneratorBoundUserInterface.cs +++ b/Content.Client/Power/Generator/PortableGeneratorBoundUserInterface.cs @@ -1,7 +1,6 @@ using Content.Shared.Power.Generator; using JetBrains.Annotations; using Robust.Client.GameObjects; -using Robust.Client.UserInterface; namespace Content.Client.Power.Generator; @@ -17,25 +16,10 @@ public PortableGeneratorBoundUserInterface(EntityUid owner, Enum uiKey) : base(o protected override void Open() { base.Open(); - _window = this.CreateWindow(); - _window.SetEntity(Owner); - _window.OnState += args => - { - if (args) - { - Start(); - } - else - { - Stop(); - } - }; - - _window.OnPower += SetTargetPower; - _window.OnEjectFuel += EjectFuel; - _window.OnSwitchOutput += SwitchOutput; + _window = new GeneratorWindow(this, Owner); _window.OpenCenteredLeft(); + _window.OnClose += Close; } protected override void UpdateState(BoundUserInterfaceState state) @@ -46,6 +30,11 @@ protected override void UpdateState(BoundUserInterfaceState state) _window?.Update(msg); } + protected override void Dispose(bool disposing) + { + _window?.Dispose(); + } + public void SetTargetPower(int target) { SendMessage(new PortableGeneratorSetTargetPowerMessage(target)); diff --git a/Content.Client/Power/PowerMonitoringConsoleBoundUserInterface.cs b/Content.Client/Power/PowerMonitoringConsoleBoundUserInterface.cs index cbc343c06c6..dc1dcd03ef1 100644 --- a/Content.Client/Power/PowerMonitoringConsoleBoundUserInterface.cs +++ b/Content.Client/Power/PowerMonitoringConsoleBoundUserInterface.cs @@ -1,5 +1,4 @@ using Content.Shared.Power; -using Robust.Client.UserInterface; namespace Content.Client.Power; @@ -12,9 +11,9 @@ public PowerMonitoringConsoleBoundUserInterface(EntityUid owner, Enum uiKey) : b protected override void Open() { - _menu = this.CreateWindow(); - _menu.SetEntity(Owner); - _menu.SendPowerMonitoringConsoleMessageAction += SendPowerMonitoringConsoleMessage; + _menu = new PowerMonitoringWindow(this, Owner); + _menu.OpenCentered(); + _menu.OnClose += Close; } protected override void UpdateState(BoundUserInterfaceState state) @@ -23,6 +22,9 @@ protected override void UpdateState(BoundUserInterfaceState state) var castState = (PowerMonitoringConsoleBoundInterfaceState) state; + if (castState == null) + return; + EntMan.TryGetComponent(Owner, out var xform); _menu?.ShowEntites (castState.TotalSources, @@ -38,4 +40,13 @@ public void SendPowerMonitoringConsoleMessage(NetEntity? netEntity, PowerMonitor { SendMessage(new PowerMonitoringConsoleMessage(netEntity, group)); } + + protected override void Dispose(bool disposing) + { + base.Dispose(disposing); + if (!disposing) + return; + + _menu?.Dispose(); + } } diff --git a/Content.Client/Power/PowerMonitoringWindow.xaml.Widgets.cs b/Content.Client/Power/PowerMonitoringWindow.xaml.Widgets.cs index d9952992070..74752ddc534 100644 --- a/Content.Client/Power/PowerMonitoringWindow.xaml.Widgets.cs +++ b/Content.Client/Power/PowerMonitoringWindow.xaml.Widgets.cs @@ -32,7 +32,7 @@ private void UpdateWindowConsoleEntry if (windowEntry == null) return; - // Update sources and loads + // Update sources and loads UpdateEntrySourcesOrLoads(masterContainer, windowEntry.SourcesContainer, focusSources, _sourceIcon); UpdateEntrySourcesOrLoads(masterContainer, windowEntry.LoadsContainer, focusLoads, _loadIconPath); @@ -134,7 +134,7 @@ private void UpdateEntrySourcesOrLoads(BoxContainer masterContainer, BoxContaine subEntry.Button.OnButtonUp += args => { ButtonAction(subEntry, masterContainer); }; } - if (!_entManager.TryGetComponent(Entity, out var console)) + if (!_entManager.TryGetComponent(_owner, out var console)) return; // Update all children @@ -379,7 +379,7 @@ public PowerMonitoringWindowEntry(PowerMonitoringConsoleEntry entry) : base(entr AddChild(MainContainer); - // Grid container to hold the list of sources when selected + // Grid container to hold the list of sources when selected SourcesContainer = new BoxContainer() { Orientation = LayoutOrientation.Vertical, diff --git a/Content.Client/Power/PowerMonitoringWindow.xaml.cs b/Content.Client/Power/PowerMonitoringWindow.xaml.cs index e3043252486..81fe1f4d047 100644 --- a/Content.Client/Power/PowerMonitoringWindow.xaml.cs +++ b/Content.Client/Power/PowerMonitoringWindow.xaml.cs @@ -15,12 +15,13 @@ namespace Content.Client.Power; [GenerateTypedNameReferences] public sealed partial class PowerMonitoringWindow : FancyWindow { - [Dependency] private IEntityManager _entManager = default!; + private readonly IEntityManager _entManager; private readonly SpriteSystem _spriteSystem; - [Dependency] private IGameTiming _gameTiming = default!; + private readonly IGameTiming _gameTiming; private const float BlinkFrequency = 1f; + private EntityUid? _owner; private NetEntity? _focusEntity; public event Action? SendPowerMonitoringConsoleMessageAction; @@ -33,56 +34,31 @@ public sealed partial class PowerMonitoringWindow : FancyWindow { PowerMonitoringConsoleGroup.APC, (new SpriteSpecifier.Texture(new ResPath("/Textures/Interface/NavMap/beveled_triangle.png")), Color.LimeGreen) }, }; - public EntityUid Entity; - - public PowerMonitoringWindow() + public PowerMonitoringWindow(PowerMonitoringConsoleBoundUserInterface userInterface, EntityUid? owner) { RobustXamlLoader.Load(this); - IoCManager.InjectDependencies(this); + _entManager = IoCManager.Resolve(); + _gameTiming = IoCManager.Resolve(); _spriteSystem = _entManager.System(); - - // Set trackable entity selected action - NavMap.TrackedEntitySelectedAction += SetTrackedEntityFromNavMap; - - // Update nav map - NavMap.ForceNavMapUpdate(); - - // Set UI tab titles - MasterTabContainer.SetTabTitle(0, Loc.GetString("power-monitoring-window-label-sources")); - MasterTabContainer.SetTabTitle(1, Loc.GetString("power-monitoring-window-label-smes")); - MasterTabContainer.SetTabTitle(2, Loc.GetString("power-monitoring-window-label-substation")); - MasterTabContainer.SetTabTitle(3, Loc.GetString("power-monitoring-window-label-apc")); - - // Track when the MasterTabContainer changes its tab - MasterTabContainer.OnTabChanged += OnTabChanged; - - // Set UI toggles - ShowHVCable.OnToggled += _ => OnShowCableToggled(PowerMonitoringConsoleLineGroup.HighVoltage); - ShowMVCable.OnToggled += _ => OnShowCableToggled(PowerMonitoringConsoleLineGroup.MediumVoltage); - ShowLVCable.OnToggled += _ => OnShowCableToggled(PowerMonitoringConsoleLineGroup.Apc); - } - - public void SetEntity(EntityUid uid) - { - Entity = uid; + _owner = owner; // Pass owner to nav map - NavMap.Owner = uid; + NavMap.Owner = _owner; // Set nav map grid uid var stationName = Loc.GetString("power-monitoring-window-unknown-location"); - if (_entManager.TryGetComponent(uid, out var xform)) + if (_entManager.TryGetComponent(owner, out var xform)) { NavMap.MapUid = xform.GridUid; - // Assign station name + // Assign station name if (_entManager.TryGetComponent(xform.GridUid, out var stationMetaData)) stationName = stationMetaData.EntityName; var msg = new FormattedMessage(); - msg.AddMarkupOrThrow(Loc.GetString("power-monitoring-window-station-name", ("stationName", stationName))); + msg.AddMarkup(Loc.GetString("power-monitoring-window-station-name", ("stationName", stationName))); StationName.SetMessage(msg); } @@ -92,6 +68,29 @@ public void SetEntity(EntityUid uid) StationName.SetMessage(stationName); NavMap.Visible = false; } + + // Set trackable entity selected action + NavMap.TrackedEntitySelectedAction += SetTrackedEntityFromNavMap; + + // Update nav map + NavMap.ForceNavMapUpdate(); + + // Set UI tab titles + MasterTabContainer.SetTabTitle(0, Loc.GetString("power-monitoring-window-label-sources")); + MasterTabContainer.SetTabTitle(1, Loc.GetString("power-monitoring-window-label-smes")); + MasterTabContainer.SetTabTitle(2, Loc.GetString("power-monitoring-window-label-substation")); + MasterTabContainer.SetTabTitle(3, Loc.GetString("power-monitoring-window-label-apc")); + + // Track when the MasterTabContainer changes its tab + MasterTabContainer.OnTabChanged += OnTabChanged; + + // Set UI toggles + ShowHVCable.OnToggled += _ => OnShowCableToggled(PowerMonitoringConsoleLineGroup.HighVoltage); + ShowMVCable.OnToggled += _ => OnShowCableToggled(PowerMonitoringConsoleLineGroup.MediumVoltage); + ShowLVCable.OnToggled += _ => OnShowCableToggled(PowerMonitoringConsoleLineGroup.Apc); + + // Set power monitoring message action + SendPowerMonitoringConsoleMessageAction += userInterface.SendPowerMonitoringConsoleMessage; } private void OnTabChanged(int tab) @@ -114,7 +113,10 @@ public void ShowEntites PowerMonitoringConsoleEntry[] focusLoads, EntityCoordinates? monitorCoords) { - if (!_entManager.TryGetComponent(Entity, out var console)) + if (_owner == null) + return; + + if (!_entManager.TryGetComponent(_owner.Value, out var console)) return; // Update power status text @@ -159,13 +161,13 @@ public void ShowEntites } // Show monitor location - var mon = _entManager.GetNetEntity(Entity); + var mon = _entManager.GetNetEntity(_owner); - if (monitorCoords != null && mon.IsValid()) + if (monitorCoords != null && mon != null) { var texture = _spriteSystem.Frame0(new SpriteSpecifier.Texture(new ResPath("/Textures/Interface/NavMap/beveled_circle.png"))); var blip = new NavMapBlip(monitorCoords.Value, texture, Color.Cyan, true, false); - NavMap.TrackedEntities[mon] = blip; + NavMap.TrackedEntities[mon.Value] = blip; } // If the entry group doesn't match the current tab, the data is out dated, do not use it @@ -237,7 +239,7 @@ private void SetTrackedEntityFromNavMap(NetEntity? netEntity) if (netEntity == null) return; - if (!_entManager.TryGetComponent(Entity, out var console)) + if (!_entManager.TryGetComponent(_owner, out var console)) return; if (!console.PowerMonitoringDeviceMetaData.TryGetValue(netEntity.Value, out var metaData)) @@ -264,7 +266,7 @@ protected override void FrameUpdate(FrameEventArgs args) { AutoScrollToFocus(); - // Warning sign pulse + // Warning sign pulse var lit = _gameTiming.RealTime.TotalSeconds % BlinkFrequency > BlinkFrequency / 2f; SystemWarningPanel.Modulate = lit ? Color.White : new Color(178, 178, 178); } diff --git a/Content.Client/RCD/RCDMenu.xaml.cs b/Content.Client/RCD/RCDMenu.xaml.cs index aefb3191812..3eb0397a690 100644 --- a/Content.Client/RCD/RCDMenu.xaml.cs +++ b/Content.Client/RCD/RCDMenu.xaml.cs @@ -20,36 +20,31 @@ public sealed partial class RCDMenu : RadialMenu [Dependency] private readonly IPrototypeManager _protoManager = default!; [Dependency] private readonly IPlayerManager _playerManager = default!; - private SharedPopupSystem _popup; - private SpriteSystem _sprites; + private readonly SpriteSystem _spriteSystem; + private readonly SharedPopupSystem _popup; public event Action>? SendRCDSystemMessageAction; private EntityUid _owner; - public RCDMenu() + public RCDMenu(EntityUid owner, RCDMenuBoundUserInterface bui) { IoCManager.InjectDependencies(this); RobustXamlLoader.Load(this); + _spriteSystem = _entManager.System(); _popup = _entManager.System(); - _sprites = _entManager.System(); - OnChildAdded += AddRCDMenuButtonOnClickActions; - } - - public void SetEntity(EntityUid uid) - { - _owner = uid; - } + _owner = owner; - public void Refresh() - { // Find the main radial container var main = FindControl("Main"); + if (main == null) + return; + // Populate secondary radial containers - if (!_entManager.TryGetComponent(_owner, out var rcd)) + if (!_entManager.TryGetComponent(owner, out var rcd)) return; foreach (var protoId in rcd.AvailablePrototypes) @@ -61,6 +56,10 @@ public void Refresh() continue; var parent = FindControl(proto.Category); + + if (parent == null) + continue; + var tooltip = Loc.GetString(proto.SetName); if ((proto.Mode == RcdMode.ConstructTile || proto.Mode == RcdMode.ConstructObject) && @@ -85,7 +84,7 @@ public void Refresh() { VerticalAlignment = VAlignment.Center, HorizontalAlignment = HAlignment.Center, - Texture = _sprites.Frame0(proto.Sprite), + Texture = _spriteSystem.Frame0(proto.Sprite), TextureScale = new Vector2(2f, 2f), }; @@ -113,9 +112,11 @@ public void Refresh() // Set up menu actions foreach (var child in Children) - { AddRCDMenuButtonOnClickActions(child); - } + + OnChildAdded += AddRCDMenuButtonOnClickActions; + + SendRCDSystemMessageAction += bui.SendRCDSystemMessage; } private static string OopsConcat(string a, string b) diff --git a/Content.Client/RCD/RCDMenuBoundUserInterface.cs b/Content.Client/RCD/RCDMenuBoundUserInterface.cs index 1dd03626ae6..a37dbcecf8c 100644 --- a/Content.Client/RCD/RCDMenuBoundUserInterface.cs +++ b/Content.Client/RCD/RCDMenuBoundUserInterface.cs @@ -3,7 +3,6 @@ using JetBrains.Annotations; using Robust.Client.Graphics; using Robust.Client.Input; -using Robust.Client.UserInterface; using Robust.Shared.Prototypes; namespace Content.Client.RCD; @@ -25,9 +24,8 @@ protected override void Open() { base.Open(); - _menu = this.CreateWindow(); - _menu.SetEntity(Owner); - _menu.SendRCDSystemMessageAction += SendRCDSystemMessage; + _menu = new(Owner, this); + _menu.OnClose += Close; // Open the menu, centered on the mouse var vpSize = _displayManager.ScreenSize; @@ -36,8 +34,16 @@ protected override void Open() public void SendRCDSystemMessage(ProtoId protoId) { - // A predicted message cannot be used here as the RCD UI is closed immediately + // A predicted message cannot be used here as the RCD UI is closed immediately // after this message is sent, which will stop the server from receiving it SendMessage(new RCDSystemMessage(protoId)); } + + protected override void Dispose(bool disposing) + { + base.Dispose(disposing); + if (!disposing) return; + + _menu?.Dispose(); + } } diff --git a/Content.Client/Radio/Ui/IntercomBoundUserInterface.cs b/Content.Client/Radio/Ui/IntercomBoundUserInterface.cs index 401e7edd44a..7b3e39aa084 100644 --- a/Content.Client/Radio/Ui/IntercomBoundUserInterface.cs +++ b/Content.Client/Radio/Ui/IntercomBoundUserInterface.cs @@ -1,8 +1,6 @@ using Content.Shared.Radio; using Content.Shared.Radio.Components; using JetBrains.Annotations; -using Robust.Client.GameObjects; -using Robust.Client.UserInterface; namespace Content.Client.Radio.Ui; @@ -21,12 +19,9 @@ protected override void Open() { base.Open(); - _menu = this.CreateWindow(); + var comp = EntMan.GetComponent(Owner); - if (EntMan.TryGetComponent(Owner, out IntercomComponent? intercom)) - { - _menu.Update((Owner, intercom)); - } + _menu = new((Owner, comp)); _menu.OnMicPressed += enabled => { @@ -40,6 +35,17 @@ protected override void Open() { SendMessage(new SelectIntercomChannelMessage(channel)); }; + + _menu.OnClose += Close; + _menu.OpenCentered(); + } + + protected override void Dispose(bool disposing) + { + base.Dispose(disposing); + if (!disposing) + return; + _menu?.Close(); } public void Update(Entity ent) diff --git a/Content.Client/Radio/Ui/IntercomMenu.xaml.cs b/Content.Client/Radio/Ui/IntercomMenu.xaml.cs index 20d2e4a3e54..2e08913051c 100644 --- a/Content.Client/Radio/Ui/IntercomMenu.xaml.cs +++ b/Content.Client/Radio/Ui/IntercomMenu.xaml.cs @@ -18,13 +18,15 @@ public sealed partial class IntercomMenu : FancyWindow private readonly List _channels = new(); - public IntercomMenu() + public IntercomMenu(Entity entity) { RobustXamlLoader.Load(this); IoCManager.InjectDependencies(this); MicButton.OnPressed += args => OnMicPressed?.Invoke(args.Button.Pressed); SpeakerButton.OnPressed += args => OnSpeakerPressed?.Invoke(args.Button.Pressed); + + Update(entity); } public void Update(Entity entity) diff --git a/Content.Client/Research/UI/DiskConsoleBoundUserInterface.cs b/Content.Client/Research/UI/DiskConsoleBoundUserInterface.cs index 9641adb5b2d..c14a8c5bd05 100644 --- a/Content.Client/Research/UI/DiskConsoleBoundUserInterface.cs +++ b/Content.Client/Research/UI/DiskConsoleBoundUserInterface.cs @@ -1,7 +1,5 @@ using Content.Shared.Research; using Content.Shared.Research.Components; -using Robust.Client.GameObjects; -using Robust.Client.UserInterface; namespace Content.Client.Research.UI { @@ -18,7 +16,10 @@ protected override void Open() { base.Open(); - _menu = this.CreateWindow(); + _menu = new(); + + _menu.OnClose += Close; + _menu.OpenCentered(); _menu.OnServerButtonPressed += () => { @@ -30,6 +31,14 @@ protected override void Open() }; } + protected override void Dispose(bool disposing) + { + base.Dispose(disposing); + if (!disposing) + return; + _menu?.Close(); + } + protected override void UpdateState(BoundUserInterfaceState state) { base.UpdateState(state); diff --git a/Content.Client/Research/UI/ResearchClientBoundUserInterface.cs b/Content.Client/Research/UI/ResearchClientBoundUserInterface.cs index 288445e4dea..a0a2b58e889 100644 --- a/Content.Client/Research/UI/ResearchClientBoundUserInterface.cs +++ b/Content.Client/Research/UI/ResearchClientBoundUserInterface.cs @@ -1,6 +1,4 @@ using Content.Shared.Research.Components; -using Robust.Client.GameObjects; -using Robust.Client.UserInterface; namespace Content.Client.Research.UI { @@ -17,9 +15,10 @@ public ResearchClientBoundUserInterface(EntityUid owner, Enum uiKey) : base(owne protected override void Open() { base.Open(); - _menu = this.CreateWindow(); - _menu.OnServerSelected += SelectServer; - _menu.OnServerDeselected += DeselectServer; + + _menu = new ResearchClientServerSelectionMenu(this); + _menu.OnClose += Close; + _menu.OpenCentered(); } public void SelectServer(int serverId) @@ -38,5 +37,12 @@ protected override void UpdateState(BoundUserInterfaceState state) if (state is not ResearchClientBoundInterfaceState rState) return; _menu?.Populate(rState.ServerCount, rState.ServerNames, rState.ServerIds, rState.SelectedServerId); } + + protected override void Dispose(bool disposing) + { + base.Dispose(disposing); + if (!disposing) return; + _menu?.Dispose(); + } } } diff --git a/Content.Client/Research/UI/ResearchClientServerSelectionMenu.xaml.cs b/Content.Client/Research/UI/ResearchClientServerSelectionMenu.xaml.cs index d10f8b39f48..ceaa965e59f 100644 --- a/Content.Client/Research/UI/ResearchClientServerSelectionMenu.xaml.cs +++ b/Content.Client/Research/UI/ResearchClientServerSelectionMenu.xaml.cs @@ -13,26 +13,27 @@ public sealed partial class ResearchClientServerSelectionMenu : DefaultWindow private int[] _serverIds = Array.Empty(); private int _selectedServerId = -1; - public event Action? OnServerSelected; - public event Action? OnServerDeselected; + private ResearchClientBoundUserInterface Owner { get; } - public ResearchClientServerSelectionMenu() + public ResearchClientServerSelectionMenu(ResearchClientBoundUserInterface owner) { RobustXamlLoader.Load(this); IoCManager.InjectDependencies(this); + Owner = owner; + Servers.OnItemSelected += OnItemSelected; Servers.OnItemDeselected += OnItemDeselected; } public void OnItemSelected(ItemList.ItemListSelectedEventArgs itemListSelectedEventArgs) { - OnServerSelected?.Invoke(_serverIds[itemListSelectedEventArgs.ItemIndex]); + Owner.SelectServer(_serverIds[itemListSelectedEventArgs.ItemIndex]); } public void OnItemDeselected(ItemList.ItemListDeselectedEventArgs itemListDeselectedEventArgs) { - OnServerDeselected?.Invoke(); + Owner.DeselectServer(); } public void Populate(int serverCount, string[] serverNames, int[] serverIds, int selectedServerId) diff --git a/Content.Client/Research/UI/ResearchConsoleBoundUserInterface.cs b/Content.Client/Research/UI/ResearchConsoleBoundUserInterface.cs index 2895ada61fb..2a9782045b8 100644 --- a/Content.Client/Research/UI/ResearchConsoleBoundUserInterface.cs +++ b/Content.Client/Research/UI/ResearchConsoleBoundUserInterface.cs @@ -1,8 +1,5 @@ using Content.Shared.Research.Components; -using Content.Shared.Research.Prototypes; using JetBrains.Annotations; -using Robust.Client.UserInterface; -using Robust.Shared.Prototypes; namespace Content.Client.Research.UI; @@ -22,8 +19,7 @@ protected override void Open() var owner = Owner; - _consoleMenu = this.CreateWindow(); - _consoleMenu.SetEntity(owner); + _consoleMenu = new ResearchConsoleMenu(owner); _consoleMenu.OnTechnologyCardPressed += id => { @@ -34,20 +30,10 @@ protected override void Open() { SendMessage(new ConsoleServerSelectionMessage()); }; - } - - public override void OnProtoReload(PrototypesReloadedEventArgs args) - { - base.OnProtoReload(args); - - if (!args.WasModified()) - return; - if (State is not ResearchConsoleBoundInterfaceState rState) - return; + _consoleMenu.OnClose += Close; - _consoleMenu?.UpdatePanels(rState); - _consoleMenu?.UpdateInformationPanel(rState); + _consoleMenu.OpenCentered(); } protected override void UpdateState(BoundUserInterfaceState state) @@ -59,4 +45,12 @@ protected override void UpdateState(BoundUserInterfaceState state) _consoleMenu?.UpdatePanels(castState); _consoleMenu?.UpdateInformationPanel(castState); } + + protected override void Dispose(bool disposing) + { + base.Dispose(disposing); + if (!disposing) + return; + _consoleMenu?.Dispose(); + } } diff --git a/Content.Client/Research/UI/ResearchConsoleMenu.xaml.cs b/Content.Client/Research/UI/ResearchConsoleMenu.xaml.cs index eafbe75fbb9..77ebe6740c5 100644 --- a/Content.Client/Research/UI/ResearchConsoleMenu.xaml.cs +++ b/Content.Client/Research/UI/ResearchConsoleMenu.xaml.cs @@ -25,13 +25,14 @@ public sealed partial class ResearchConsoleMenu : FancyWindow [Dependency] private readonly IEntityManager _entity = default!; [Dependency] private readonly IPrototypeManager _prototype = default!; [Dependency] private readonly IPlayerManager _player = default!; + private readonly TechnologyDatabaseComponent? _technologyDatabase; private readonly ResearchSystem _research; private readonly SpriteSystem _sprite; private readonly AccessReaderSystem _accessReader; - public EntityUid Entity; + public readonly EntityUid Entity; - public ResearchConsoleMenu() + public ResearchConsoleMenu(EntityUid entity) { RobustXamlLoader.Load(this); IoCManager.InjectDependencies(this); @@ -39,23 +40,21 @@ public ResearchConsoleMenu() _research = _entity.System(); _sprite = _entity.System(); _accessReader = _entity.System(); + Entity = entity; ServerButton.OnPressed += _ => OnServerButtonPressed?.Invoke(); - } - public void SetEntity(EntityUid entity) - { - Entity = entity; + _entity.TryGetComponent(entity, out _technologyDatabase); } - public void UpdatePanels(ResearchConsoleBoundInterfaceState state) + public void UpdatePanels(ResearchConsoleBoundInterfaceState state) { TechnologyCardsContainer.Children.Clear(); var availableTech = _research.GetAvailableTechnologies(Entity); SyncTechnologyList(AvailableCardsContainer, availableTech); - if (!_entity.TryGetComponent(Entity, out TechnologyDatabaseComponent? database)) + if (_technologyDatabase == null) return; // i can't figure out the spacing so here you go @@ -67,7 +66,7 @@ public void UpdatePanels(ResearchConsoleBoundInterfaceState state) var hasAccess = _player.LocalEntity is not { } local || !_entity.TryGetComponent(Entity, out var access) || _accessReader.IsAllowed(local, Entity, access); - foreach (var techId in database.CurrentTechnologyCards) + foreach (var techId in _technologyDatabase.CurrentTechnologyCards) { var tech = _prototype.Index(techId); var cardControl = new TechnologyCardControl(tech, _prototype, _sprite, _research.GetTechnologyDescription(tech, includeTier: false), state.Points, hasAccess); @@ -75,7 +74,7 @@ public void UpdatePanels(ResearchConsoleBoundInterfaceState state) TechnologyCardsContainer.AddChild(cardControl); } - var unlockedTech = database.UnlockedTechnologies.Select(x => _prototype.Index(x)); + var unlockedTech = _technologyDatabase.UnlockedTechnologies.Select(x => _prototype.Index(x)); SyncTechnologyList(UnlockedCardsContainer, unlockedTech); } @@ -86,14 +85,14 @@ public void UpdateInformationPanel(ResearchConsoleBoundInterfaceState state) ("points", state.Points))); ResearchAmountLabel.SetMessage(amountMsg); - if (!_entity.TryGetComponent(Entity, out TechnologyDatabaseComponent? database)) + if (_technologyDatabase == null) return; var disciplineText = Loc.GetString("research-discipline-none"); var disciplineColor = Color.Gray; - if (database.MainDiscipline != null) + if (_technologyDatabase.MainDiscipline != null) { - var discipline = _prototype.Index(database.MainDiscipline); + var discipline = _prototype.Index(_technologyDatabase.MainDiscipline); disciplineText = Loc.GetString(discipline.Name); disciplineColor = discipline.Color; } @@ -104,10 +103,10 @@ public void UpdateInformationPanel(ResearchConsoleBoundInterfaceState state) MainDisciplineLabel.SetMessage(msg); TierDisplayContainer.Children.Clear(); - foreach (var disciplineId in database.SupportedDisciplines) + foreach (var disciplineId in _technologyDatabase.SupportedDisciplines) { var discipline = _prototype.Index(disciplineId); - var tier = _research.GetHighestDisciplineTier(database, discipline); + var tier = _research.GetHighestDisciplineTier(_technologyDatabase, discipline); // don't show tiers with no available tech if (tier == 0) diff --git a/Content.Client/Robotics/UI/RoboticsConsoleBoundUserInterface.cs b/Content.Client/Robotics/UI/RoboticsConsoleBoundUserInterface.cs index 9a5159880f9..6185979eee6 100644 --- a/Content.Client/Robotics/UI/RoboticsConsoleBoundUserInterface.cs +++ b/Content.Client/Robotics/UI/RoboticsConsoleBoundUserInterface.cs @@ -1,6 +1,5 @@ using Content.Shared.Robotics; using Robust.Client.GameObjects; -using Robust.Client.UserInterface; namespace Content.Client.Robotics.UI; @@ -17,9 +16,7 @@ protected override void Open() { base.Open(); - _window = this.CreateWindow(); - _window.SetEntity(Owner); - + _window = new RoboticsConsoleWindow(Owner); _window.OnDisablePressed += address => { SendMessage(new RoboticsConsoleDisableMessage(address)); @@ -28,6 +25,9 @@ protected override void Open() { SendMessage(new RoboticsConsoleDestroyMessage(address)); }; + _window.OnClose += Close; + + _window.OpenCentered(); } protected override void UpdateState(BoundUserInterfaceState state) @@ -37,6 +37,14 @@ protected override void UpdateState(BoundUserInterfaceState state) if (state is not RoboticsConsoleState cast) return; - _window.UpdateState(cast); + _window?.UpdateState(cast); + } + + protected override void Dispose(bool disposing) + { + base.Dispose(disposing); + + if (disposing) + _window?.Dispose(); } } diff --git a/Content.Client/Robotics/UI/RoboticsConsoleWindow.xaml.cs b/Content.Client/Robotics/UI/RoboticsConsoleWindow.xaml.cs index 87d7e62c392..fc7b234bccc 100644 --- a/Content.Client/Robotics/UI/RoboticsConsoleWindow.xaml.cs +++ b/Content.Client/Robotics/UI/RoboticsConsoleWindow.xaml.cs @@ -23,12 +23,11 @@ public sealed partial class RoboticsConsoleWindow : FancyWindow public Action? OnDisablePressed; public Action? OnDestroyPressed; + private Entity _console; private string? _selected; private Dictionary _cyborgs = new(); - public EntityUid Entity; - - public RoboticsConsoleWindow() + public RoboticsConsoleWindow(EntityUid console) { RobustXamlLoader.Load(this); IoCManager.InjectDependencies(this); @@ -36,6 +35,9 @@ public RoboticsConsoleWindow() _lock = _entMan.System(); _sprite = _entMan.System(); + _console = (console, _entMan.GetComponent(console), null); + _entMan.TryGetComponent(_console, out _console.Comp2); + Cyborgs.OnItemSelected += args => { if (Cyborgs[args.ItemIndex].Metadata is not string address) @@ -64,11 +66,6 @@ public RoboticsConsoleWindow() DestroyButton.StyleClasses.Add(StyleBase.ButtonCaution); } - public void SetEntity(EntityUid uid) - { - Entity = uid; - } - public void UpdateState(RoboticsConsoleState state) { _cyborgs = state.Cyborgs; @@ -84,7 +81,7 @@ public void UpdateState(RoboticsConsoleState state) PopulateData(); - var locked = _lock.IsLocked(Entity); + var locked = _lock.IsLocked((_console, _console.Comp2)); DangerZone.Visible = !locked; LockedMessage.Visible = locked; } @@ -138,19 +135,13 @@ private void PopulateData() // how the turntables DisableButton.Disabled = !(data.HasBrain && data.CanDisable); + DestroyButton.Disabled = _timing.CurTime < _console.Comp1.NextDestroy; } protected override void FrameUpdate(FrameEventArgs args) { base.FrameUpdate(args); - if (_entMan.TryGetComponent(Entity, out RoboticsConsoleComponent? console)) - { - DestroyButton.Disabled = _timing.CurTime < console.NextDestroy; - } - else - { - DestroyButton.Disabled = true; - } + DestroyButton.Disabled = _timing.CurTime < _console.Comp1.NextDestroy; } } diff --git a/Content.Client/Salvage/UI/SalvageExpeditionConsoleBoundUserInterface.cs b/Content.Client/Salvage/UI/SalvageExpeditionConsoleBoundUserInterface.cs index 663bde15b0d..8f1723d1f22 100644 --- a/Content.Client/Salvage/UI/SalvageExpeditionConsoleBoundUserInterface.cs +++ b/Content.Client/Salvage/UI/SalvageExpeditionConsoleBoundUserInterface.cs @@ -30,9 +30,17 @@ public SalvageExpeditionConsoleBoundUserInterface(EntityUid owner, Enum uiKey) : protected override void Open() { base.Open(); - _window = this.CreateWindow(); + _window = new OfferingWindow(); _window.Title = Loc.GetString("salvage-expedition-window-title"); - _window.OpenCenteredLeft(); + _window.OnClose += Close; + _window?.OpenCenteredLeft(); + } + + protected override void Dispose(bool disposing) + { + base.Dispose(disposing); + _window?.Dispose(); + _window = null; } protected override void UpdateState(BoundUserInterfaceState state) diff --git a/Content.Client/Salvage/UI/SalvageMagnetBoundUserInterface.cs b/Content.Client/Salvage/UI/SalvageMagnetBoundUserInterface.cs index bee8092ea8e..be3ba0e046e 100644 --- a/Content.Client/Salvage/UI/SalvageMagnetBoundUserInterface.cs +++ b/Content.Client/Salvage/UI/SalvageMagnetBoundUserInterface.cs @@ -21,9 +21,13 @@ protected override void Open() { base.Open(); - _window = this.CreateWindow(); - _window.Title = Loc.GetString("salvage-magnet-window-title"); - _window.OpenCenteredLeft(); + if (_window is null) + { + _window = new OfferingWindow(); + _window.Title = Loc.GetString("salvage-magnet-window-title"); + _window.OnClose += Close; + _window.OpenCenteredLeft(); + } } protected override void UpdateState(BoundUserInterfaceState state) @@ -108,4 +112,15 @@ protected override void UpdateState(BoundUserInterfaceState state) _window.AddOption(option); } } + + protected override void Dispose(bool disposing) + { + base.Dispose(disposing); + + if (disposing) + { + _window?.Close(); + _window?.Dispose(); + } + } } diff --git a/Content.Client/Shuttles/BUI/IFFConsoleBoundUserInterface.cs b/Content.Client/Shuttles/BUI/IFFConsoleBoundUserInterface.cs index b8b4fb8a746..086369aa264 100644 --- a/Content.Client/Shuttles/BUI/IFFConsoleBoundUserInterface.cs +++ b/Content.Client/Shuttles/BUI/IFFConsoleBoundUserInterface.cs @@ -3,7 +3,6 @@ using Content.Shared.Shuttles.Events; using JetBrains.Annotations; using Robust.Client.GameObjects; -using Robust.Client.UserInterface; namespace Content.Client.Shuttles.BUI; @@ -21,7 +20,8 @@ protected override void Open() { base.Open(); - _window = this.CreateWindow(); + _window = new IFFConsoleWindow(); + _window.OnClose += Close; _window.ShowIFF += SendIFFMessage; _window.ShowVessel += SendVesselMessage; _window.OpenCenteredLeft(); diff --git a/Content.Client/Shuttles/BUI/RadarConsoleBoundUserInterface.cs b/Content.Client/Shuttles/BUI/RadarConsoleBoundUserInterface.cs index f75759b042f..4bd44a47a8e 100644 --- a/Content.Client/Shuttles/BUI/RadarConsoleBoundUserInterface.cs +++ b/Content.Client/Shuttles/BUI/RadarConsoleBoundUserInterface.cs @@ -2,7 +2,6 @@ using Content.Shared.Shuttles.BUIStates; using JetBrains.Annotations; using Robust.Client.GameObjects; -using Robust.Client.UserInterface; using RadarConsoleWindow = Content.Client.Shuttles.UI.RadarConsoleWindow; namespace Content.Client.Shuttles.BUI; @@ -21,7 +20,18 @@ protected override void Open() { base.Open(); - _window = this.CreateWindow(); + _window = new RadarConsoleWindow(); + _window.OnClose += Close; + _window.OpenCentered(); + } + + protected override void Dispose(bool disposing) + { + base.Dispose(disposing); + if (disposing) + { + _window?.Dispose(); + } } protected override void UpdateState(BoundUserInterfaceState state) diff --git a/Content.Client/Shuttles/BUI/ShuttleConsoleBoundUserInterface.cs b/Content.Client/Shuttles/BUI/ShuttleConsoleBoundUserInterface.cs index e677181419e..af7b6055c80 100644 --- a/Content.Client/Shuttles/BUI/ShuttleConsoleBoundUserInterface.cs +++ b/Content.Client/Shuttles/BUI/ShuttleConsoleBoundUserInterface.cs @@ -2,7 +2,6 @@ using Content.Shared.Shuttles.BUIStates; using Content.Shared.Shuttles.Events; using JetBrains.Annotations; -using Robust.Client.UserInterface; using Robust.Shared.Map; namespace Content.Client.Shuttles.BUI; @@ -20,7 +19,9 @@ public ShuttleConsoleBoundUserInterface(EntityUid owner, Enum uiKey) : base(owne protected override void Open() { base.Open(); - _window = this.CreateWindow(); + _window = new ShuttleConsoleWindow(); + _window.OpenCentered(); + _window.OnClose += Close; _window.RequestFTL += OnFTLRequest; _window.RequestBeaconFTL += OnFTLBeaconRequest; diff --git a/Content.Client/Silicons/Borgs/BorgBoundUserInterface.cs b/Content.Client/Silicons/Borgs/BorgBoundUserInterface.cs index ed9bf40a481..3cc2a35d795 100644 --- a/Content.Client/Silicons/Borgs/BorgBoundUserInterface.cs +++ b/Content.Client/Silicons/Borgs/BorgBoundUserInterface.cs @@ -1,7 +1,6 @@ using Content.Shared.Silicons.Borgs; using JetBrains.Annotations; using Robust.Client.GameObjects; -using Robust.Client.UserInterface; namespace Content.Client.Silicons.Borgs; @@ -19,8 +18,9 @@ protected override void Open() { base.Open(); - _menu = this.CreateWindow(); - _menu.SetEntity(Owner); + var owner = Owner; + + _menu = new BorgMenu(owner); _menu.BrainButtonPressed += () => { @@ -41,6 +41,10 @@ protected override void Open() { SendMessage(new BorgRemoveModuleBuiMessage(EntMan.GetNetEntity(module))); }; + + _menu.OnClose += Close; + + _menu.OpenCentered(); } protected override void UpdateState(BoundUserInterfaceState state) @@ -51,4 +55,12 @@ protected override void UpdateState(BoundUserInterfaceState state) return; _menu?.UpdateState(msg); } + + protected override void Dispose(bool disposing) + { + base.Dispose(disposing); + if (!disposing) + return; + _menu?.Dispose(); + } } diff --git a/Content.Client/Silicons/Borgs/BorgMenu.xaml b/Content.Client/Silicons/Borgs/BorgMenu.xaml index 4cc2e41a8fb..7d8fd9fe57d 100644 --- a/Content.Client/Silicons/Borgs/BorgMenu.xaml +++ b/Content.Client/Silicons/Borgs/BorgMenu.xaml @@ -10,7 +10,7 @@ VerticalExpand="True"> - + diff --git a/Content.Client/Silicons/Borgs/BorgMenu.xaml.cs b/Content.Client/Silicons/Borgs/BorgMenu.xaml.cs index f6a861aa057..474a83b4530 100644 --- a/Content.Client/Silicons/Borgs/BorgMenu.xaml.cs +++ b/Content.Client/Silicons/Borgs/BorgMenu.xaml.cs @@ -21,33 +21,25 @@ public sealed partial class BorgMenu : FancyWindow public Action? NameChanged; public Action? RemoveModuleButtonPressed; + private readonly BorgChassisComponent? _chassis; + public readonly EntityUid Entity; public float AccumulatedTime; private string _lastValidName; private List _modules = new(); - public EntityUid Entity; - - public BorgMenu() + public BorgMenu(EntityUid entity) { RobustXamlLoader.Load(this); IoCManager.InjectDependencies(this); - _lastValidName = NameLineEdit.Text; - - EjectBatteryButton.OnPressed += _ => EjectBatteryButtonPressed?.Invoke(); - BrainButton.OnPressed += _ => BrainButtonPressed?.Invoke(); - - NameLineEdit.OnTextChanged += OnNameChanged; - NameLineEdit.OnTextEntered += OnNameEntered; - NameLineEdit.OnFocusExit += OnNameFocusExit; + Entity = entity; - UpdateBrainButton(); - } + if (_entity.TryGetComponent(Entity, out var chassis)) + _chassis = chassis; - public void SetEntity(EntityUid entity) - { - Entity = entity; BorgSprite.SetEntity(entity); + ChargeBar.MaxValue = 1f; + ChargeBar.Value = 1f; if (_entity.TryGetComponent(Entity, out var nameIdentifierComponent)) { @@ -63,6 +55,17 @@ public void SetEntity(EntityUid entity) NameIdentifierLabel.Visible = false; NameLineEdit.Text = _entity.GetComponent(Entity).EntityName; } + + _lastValidName = NameLineEdit.Text; + + EjectBatteryButton.OnPressed += _ => EjectBatteryButtonPressed?.Invoke(); + BrainButton.OnPressed += _ => BrainButtonPressed?.Invoke(); + + NameLineEdit.OnTextChanged += OnNameChanged; + NameLineEdit.OnTextEntered += OnNameEntered; + NameLineEdit.OnFocusExit += OnNameFocusExit; + + UpdateBrainButton(); } protected override void FrameUpdate(FrameEventArgs args) @@ -86,7 +89,7 @@ public void UpdateState(BorgBuiState state) private void UpdateBrainButton() { - if (_entity.TryGetComponent(Entity, out BorgChassisComponent? chassis) && chassis.BrainEntity is { } brain) + if (_chassis?.BrainEntity is { } brain) { BrainButton.Text = _entity.GetComponent(brain).EntityName; BrainView.Visible = true; @@ -105,17 +108,17 @@ private void UpdateBrainButton() private void UpdateModulePanel() { - if (!_entity.TryGetComponent(Entity, out BorgChassisComponent? chassis)) + if (_chassis == null) return; ModuleCounter.Text = Loc.GetString("borg-ui-module-counter", - ("actual", chassis.ModuleCount), - ("max", chassis.MaxModules)); + ("actual", _chassis.ModuleCount), + ("max", _chassis.MaxModules)); - if (chassis.ModuleContainer.Count == _modules.Count) + if (_chassis.ModuleContainer.Count == _modules.Count) { var isSame = true; - foreach (var module in chassis.ModuleContainer.ContainedEntities) + foreach (var module in _chassis.ModuleContainer.ContainedEntities) { if (_modules.Contains(module)) continue; @@ -129,7 +132,7 @@ private void UpdateModulePanel() ModuleContainer.Children.Clear(); _modules.Clear(); - foreach (var module in chassis.ModuleContainer.ContainedEntities) + foreach (var module in _chassis.ModuleContainer.ContainedEntities) { var control = new BorgModuleControl(module, _entity); control.RemoveButtonPressed += () => diff --git a/Content.Client/Silicons/Laws/Ui/SiliconLawBoundUserInterface.cs b/Content.Client/Silicons/Laws/Ui/SiliconLawBoundUserInterface.cs index 56216b91847..d150735fa11 100644 --- a/Content.Client/Silicons/Laws/Ui/SiliconLawBoundUserInterface.cs +++ b/Content.Client/Silicons/Laws/Ui/SiliconLawBoundUserInterface.cs @@ -2,7 +2,6 @@ using Content.Shared.Silicons.Laws; using Content.Shared.Silicons.Laws.Components; using JetBrains.Annotations; -using Robust.Client.UserInterface; namespace Content.Client.Silicons.Laws.Ui; @@ -23,7 +22,18 @@ protected override void Open() { base.Open(); - _menu = this.CreateWindow(); + _menu = new(); + + _menu.OnClose += Close; + _menu.OpenCentered(); + } + + protected override void Dispose(bool disposing) + { + base.Dispose(disposing); + if (!disposing) + return; + _menu?.Close(); } protected override void UpdateState(BoundUserInterfaceState state) diff --git a/Content.Client/SprayPainter/UI/SprayPainterBoundUserInterface.cs b/Content.Client/SprayPainter/UI/SprayPainterBoundUserInterface.cs index 7d6a6cf2a5a..e8442d23908 100644 --- a/Content.Client/SprayPainter/UI/SprayPainterBoundUserInterface.cs +++ b/Content.Client/SprayPainter/UI/SprayPainterBoundUserInterface.cs @@ -1,6 +1,6 @@ using Content.Shared.SprayPainter; using Content.Shared.SprayPainter.Components; -using Robust.Client.UserInterface; +using Robust.Client.GameObjects; using Robust.Client.UserInterface.Controls; namespace Content.Client.SprayPainter.UI; @@ -10,6 +10,9 @@ public sealed class SprayPainterBoundUserInterface : BoundUserInterface [ViewVariables] private SprayPainterWindow? _window; + [ViewVariables] + private SprayPainterSystem? _painter; + public SprayPainterBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey) { } @@ -18,15 +21,27 @@ protected override void Open() { base.Open(); - _window = this.CreateWindow(); + if (!EntMan.TryGetComponent(Owner, out var comp)) + return; + + _window = new SprayPainterWindow(); + _painter = EntMan.System(); + + _window.OnClose += Close; _window.OnSpritePicked = OnSpritePicked; _window.OnColorPicked = OnColorPicked; - if (EntMan.TryGetComponent(Owner, out SprayPainterComponent? comp)) - { - _window.Populate(EntMan.System().Entries, comp.Index, comp.PickedColor, comp.ColorPalette); - } + _window.Populate(_painter.Entries, comp.Index, comp.PickedColor, comp.ColorPalette); + + _window.OpenCentered(); + } + + protected override void Dispose(bool disposing) + { + base.Dispose(disposing); + + _window?.Dispose(); } private void OnSpritePicked(ItemList.ItemListSelectedEventArgs args) diff --git a/Content.Client/StationRecords/GeneralStationRecordConsoleBoundUserInterface.cs b/Content.Client/StationRecords/GeneralStationRecordConsoleBoundUserInterface.cs index e7bab71e38e..720a2efb9dd 100644 --- a/Content.Client/StationRecords/GeneralStationRecordConsoleBoundUserInterface.cs +++ b/Content.Client/StationRecords/GeneralStationRecordConsoleBoundUserInterface.cs @@ -1,5 +1,4 @@ using Content.Shared.StationRecords; -using Robust.Client.UserInterface; namespace Content.Client.StationRecords; @@ -16,12 +15,15 @@ protected override void Open() { base.Open(); - _window = this.CreateWindow(); + _window = new(); _window.OnKeySelected += key => SendMessage(new SelectStationRecord(key)); _window.OnFiltersChanged += (type, filterValue) => SendMessage(new SetStationRecordFilter(type, filterValue)); _window.OnDeleted += id => SendMessage(new DeleteStationRecord(id)); + _window.OnClose += Close; + + _window.OpenCentered(); } protected override void UpdateState(BoundUserInterfaceState state) @@ -33,4 +35,11 @@ protected override void UpdateState(BoundUserInterfaceState state) _window?.UpdateState(cast); } + + protected override void Dispose(bool disposing) + { + base.Dispose(disposing); + + _window?.Close(); + } } diff --git a/Content.Client/Store/Ui/StoreBoundUserInterface.cs b/Content.Client/Store/Ui/StoreBoundUserInterface.cs index 7ed67f7b5dd..0010aedd964 100644 --- a/Content.Client/Store/Ui/StoreBoundUserInterface.cs +++ b/Content.Client/Store/Ui/StoreBoundUserInterface.cs @@ -2,7 +2,6 @@ using JetBrains.Annotations; using System.Linq; using Content.Shared.Store.Components; -using Robust.Client.UserInterface; using Robust.Shared.Prototypes; namespace Content.Client.Store.Ui; @@ -27,10 +26,13 @@ public StoreBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey) protected override void Open() { - _menu = this.CreateWindow(); + _menu = new StoreMenu(); if (EntMan.TryGetComponent(Owner, out var store)) _menu.Title = Loc.GetString(store.Name); + _menu.OpenCentered(); + _menu.OnClose += Close; + _menu.OnListingButtonPressed += (_, listing) => { SendMessage(new StoreBuyListingMessage(listing)); @@ -75,6 +77,15 @@ protected override void UpdateState(BoundUserInterfaceState state) } } + protected override void Dispose(bool disposing) + { + base.Dispose(disposing); + if (!disposing) + return; + _menu?.Close(); + _menu?.Dispose(); + } + private void UpdateListingsWithSearchFilter() { if (_menu == null) diff --git a/Content.Client/Strip/StrippingMenu.cs b/Content.Client/Strip/StrippingMenu.cs index 1c46b4be35c..eea867b7948 100644 --- a/Content.Client/Strip/StrippingMenu.cs +++ b/Content.Client/Strip/StrippingMenu.cs @@ -1,3 +1,4 @@ +using Content.Client.Inventory; using Robust.Client.UserInterface.Controls; using Robust.Client.UserInterface.CustomControls; using Robust.Shared.Timing; @@ -10,12 +11,14 @@ public sealed class StrippingMenu : DefaultWindow public LayoutContainer InventoryContainer = new(); public BoxContainer HandsContainer = new() { Orientation = LayoutOrientation.Horizontal }; public BoxContainer SnareContainer = new(); + private StrippableBoundUserInterface _bui; public bool Dirty = true; - public event Action? OnDirty; - - public StrippingMenu() + public StrippingMenu(string title, StrippableBoundUserInterface bui) { + Title = title; + _bui = bui; + var box = new BoxContainer() { Orientation = LayoutOrientation.Vertical, Margin = new Thickness(0, 8) }; Contents.AddChild(box); box.AddChild(SnareContainer); @@ -36,7 +39,7 @@ protected override void FrameUpdate(FrameEventArgs args) return; Dirty = false; - OnDirty?.Invoke(); + _bui.UpdateMenu(); } } } diff --git a/Content.Client/SurveillanceCamera/UI/SurveillanceCameraMonitorBoundUi.cs b/Content.Client/SurveillanceCamera/UI/SurveillanceCameraMonitorBoundUi.cs index e3646c00cc3..9132dd6ed5f 100644 --- a/Content.Client/SurveillanceCamera/UI/SurveillanceCameraMonitorBoundUi.cs +++ b/Content.Client/SurveillanceCamera/UI/SurveillanceCameraMonitorBoundUi.cs @@ -1,7 +1,6 @@ using Content.Client.Eye; using Content.Shared.SurveillanceCamera; using Robust.Client.GameObjects; -using Robust.Client.UserInterface; namespace Content.Client.SurveillanceCamera.UI; @@ -26,12 +25,20 @@ protected override void Open() { base.Open(); - _window = this.CreateWindow(); + _window = new SurveillanceCameraMonitorWindow(); + + if (State != null) + { + UpdateState(State); + } + + _window.OpenCentered(); _window.CameraSelected += OnCameraSelected; _window.SubnetOpened += OnSubnetRequest; _window.CameraRefresh += OnCameraRefresh; _window.SubnetRefresh += OnSubnetRefresh; + _window.OnClose += Close; _window.CameraSwitchTimer += OnCameraSwitchTimer; _window.CameraDisconnect += OnCameraDisconnect; } diff --git a/Content.Client/Thief/ThiefBackpackBoundUserInterface.cs b/Content.Client/Thief/ThiefBackpackBoundUserInterface.cs index 0631d98993a..37384daafef 100644 --- a/Content.Client/Thief/ThiefBackpackBoundUserInterface.cs +++ b/Content.Client/Thief/ThiefBackpackBoundUserInterface.cs @@ -1,7 +1,6 @@ using Content.Shared.Thief; using JetBrains.Annotations; using Robust.Client.GameObjects; -using Robust.Client.UserInterface; namespace Content.Client.Thief; @@ -16,9 +15,21 @@ protected override void Open() { base.Open(); - _window = this.CreateWindow(); - _window.OnApprove += SendApprove; - _window.OnSetChange += SendChangeSelected; + _window = new ThiefBackpackMenu(this); + _window.OnClose += Close; + _window.OpenCentered(); + } + + protected override void Dispose(bool disposing) + { + base.Dispose(disposing); + if (!disposing) + return; + + if (_window != null) + _window.OnClose -= Close; + + _window?.Dispose(); } protected override void UpdateState(BoundUserInterfaceState state) diff --git a/Content.Client/Thief/ThiefBackpackMenu.xaml.cs b/Content.Client/Thief/ThiefBackpackMenu.xaml.cs index aaee3576174..543772c704c 100644 --- a/Content.Client/Thief/ThiefBackpackMenu.xaml.cs +++ b/Content.Client/Thief/ThiefBackpackMenu.xaml.cs @@ -12,42 +12,46 @@ public sealed partial class ThiefBackpackMenu : FancyWindow [Dependency] private readonly IEntitySystemManager _sysMan = default!; private readonly SpriteSystem _spriteSystem; - public event Action? OnApprove; - public event Action? OnSetChange; + private readonly ThiefBackpackBoundUserInterface _owner; - public ThiefBackpackMenu() + public ThiefBackpackMenu(ThiefBackpackBoundUserInterface owner) { RobustXamlLoader.Load(this); IoCManager.InjectDependencies(this); _spriteSystem = _sysMan.GetEntitySystem(); - ApproveButton.OnPressed += args => + _owner = owner; + + ApproveButton.OnButtonDown += (args) => { - OnApprove?.Invoke(); + _owner.SendApprove(); }; } public void UpdateState(ThiefBackpackBoundUserInterfaceState state) { - SetsGrid.DisposeAllChildren(); - var selectedNumber = 0; - foreach (var (set, info) in state.Sets) + SetsGrid.RemoveAllChildren(); + int count = 0; + int selectedNumber = 0; + foreach (var set in state.Sets) { - var child = new ThiefBackpackSet(info, _spriteSystem); + var child = new ThiefBackpackSet(set.Value, _spriteSystem); child.SetButton.OnButtonDown += (args) => { - OnSetChange?.Invoke(set); + _owner.SendChangeSelected(set.Key); }; SetsGrid.AddChild(child); - if (info.Selected) + count++; + + if (set.Value.Selected) selectedNumber++; } Description.Text = Loc.GetString("thief-backpack-window-description", ("maxCount", state.MaxSelectedSets)); SelectedSets.Text = Loc.GetString("thief-backpack-window-selected", ("selectedCount", selectedNumber), ("maxCount", state.MaxSelectedSets)); - ApproveButton.Disabled = selectedNumber != state.MaxSelectedSets; + ApproveButton.Disabled = selectedNumber == state.MaxSelectedSets ? false : true; } } diff --git a/Content.Client/UserInterface/Systems/Atmos/GasTank/GasTankBoundUserInterface.cs b/Content.Client/UserInterface/Systems/Atmos/GasTank/GasTankBoundUserInterface.cs index 4ae74a5d65e..4702f8f3659 100644 --- a/Content.Client/UserInterface/Systems/Atmos/GasTank/GasTankBoundUserInterface.cs +++ b/Content.Client/UserInterface/Systems/Atmos/GasTank/GasTankBoundUserInterface.cs @@ -1,7 +1,5 @@ using Content.Shared.Atmos.Components; using JetBrains.Annotations; -using Robust.Client.GameObjects; -using Robust.Client.UserInterface; namespace Content.Client.UserInterface.Systems.Atmos.GasTank { @@ -15,7 +13,7 @@ public GasTankBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKe { } - public void SetOutputPressure(float value) + public void SetOutputPressure(in float value) { SendMessage(new GasTankSetPressureMessage { @@ -31,10 +29,9 @@ public void ToggleInternals() protected override void Open() { base.Open(); - _window = this.CreateWindow(); - _window.SetTitle(EntMan.GetComponent(Owner).EntityName); - _window.OnOutputPressure += SetOutputPressure; - _window.OnToggleInternals += ToggleInternals; + _window = new GasTankWindow(this, EntMan.GetComponent(Owner).EntityName); + _window.OnClose += Close; + _window.OpenCentered(); } protected override void UpdateState(BoundUserInterfaceState state) diff --git a/Content.Client/UserInterface/Systems/Atmos/GasTank/GasTankWindow.cs b/Content.Client/UserInterface/Systems/Atmos/GasTank/GasTankWindow.cs index 12eeaa55de9..c23850a6503 100644 --- a/Content.Client/UserInterface/Systems/Atmos/GasTank/GasTankWindow.cs +++ b/Content.Client/UserInterface/Systems/Atmos/GasTank/GasTankWindow.cs @@ -15,28 +15,23 @@ namespace Content.Client.UserInterface.Systems.Atmos.GasTank; public sealed class GasTankWindow : BaseWindow { - [Dependency] private readonly IResourceCache _cache = default!; - private readonly RichTextLabel _lblPressure; private readonly FloatSpinBox _spbPressure; private readonly RichTextLabel _lblInternals; private readonly Button _btnInternals; - private readonly Label _topLabel; - - public event Action? OnOutputPressure; - public event Action? OnToggleInternals; - public GasTankWindow() + public GasTankWindow(GasTankBoundUserInterface owner, string uidName) { Control contentContainer; BoxContainer topContainer; TextureButton btnClose; + var resourceCache = IoCManager.Resolve(); var rootContainer = new LayoutContainer { Name = "GasTankRoot" }; AddChild(rootContainer); MouseFilter = MouseFilterMode.Stop; - var panelTex = _cache.GetTexture("/Textures/Interface/Nano/button.svg.96dpi.png"); + var panelTex = resourceCache.GetTexture("/Textures/Interface/Nano/button.svg.96dpi.png"); var back = new StyleBoxTexture { Texture = panelTex, @@ -83,17 +78,7 @@ public GasTankWindow() LayoutContainer.SetAnchorPreset(topContainerWrap, LayoutContainer.LayoutPreset.Wide); - var font = _cache.GetFont("/Fonts/Boxfont-round/Boxfont Round.ttf", 13); - - _topLabel = new Label - { - FontOverride = font, - FontColorOverride = StyleNano.NanoGold, - VerticalAlignment = VAlignment.Center, - HorizontalExpand = true, - HorizontalAlignment = HAlignment.Left, - Margin = new Thickness(0, 0, 20, 0), - }; + var font = resourceCache.GetFont("/Fonts/Boxfont-round/Boxfont Round.ttf", 13); var topRow = new BoxContainer { @@ -101,7 +86,16 @@ public GasTankWindow() Margin = new Thickness(4, 2, 12, 2), Children = { - _topLabel, + (new Label + { + Text = uidName, + FontOverride = font, + FontColorOverride = StyleNano.NanoGold, + VerticalAlignment = VAlignment.Center, + HorizontalExpand = true, + HorizontalAlignment = HAlignment.Left, + Margin = new Thickness(0, 0, 20, 0), + }), (btnClose = new TextureButton { StyleClasses = {DefaultWindow.StyleClassWindowCloseButton}, @@ -174,22 +168,17 @@ public GasTankWindow() // Handlers _spbPressure.OnValueChanged += args => { - OnOutputPressure?.Invoke(args.Value); + owner.SetOutputPressure(args.Value); }; _btnInternals.OnPressed += args => { - OnToggleInternals?.Invoke(); + owner.ToggleInternals(); }; btnClose.OnPressed += _ => Close(); } - public void SetTitle(string name) - { - _topLabel.Text = name; - } - public void UpdateState(GasTankBoundUserInterfaceState state) { _lblPressure.SetMarkup(Loc.GetString("gas-tank-window-tank-pressure-text", ("tankPressure", $"{state.TankPressure:0.##}"))); diff --git a/Content.Client/VendingMachines/VendingMachineBoundUserInterface.cs b/Content.Client/VendingMachines/VendingMachineBoundUserInterface.cs index eafab84ed63..17ddba77ffc 100644 --- a/Content.Client/VendingMachines/VendingMachineBoundUserInterface.cs +++ b/Content.Client/VendingMachines/VendingMachineBoundUserInterface.cs @@ -2,7 +2,6 @@ using Content.Shared.VendingMachines; using Robust.Client.UserInterface.Controls; using System.Linq; -using Robust.Client.UserInterface; namespace Content.Client.VendingMachines { @@ -29,14 +28,15 @@ protected override void Open() _cachedInventory = vendingMachineSys.GetAllInventory(Owner); - _menu = this.CreateWindow(); - _menu.OpenCenteredLeft(); - _menu.Title = EntMan.GetComponent(Owner).EntityName; + _menu = new VendingMachineMenu { Title = EntMan.GetComponent(Owner).EntityName }; + _menu.OnClose += Close; _menu.OnItemSelected += OnItemSelected; _menu.OnSearchChanged += OnSearchChanged; _menu.Populate(_cachedInventory, out _cachedFilteredIndex); + + _menu.OpenCenteredLeft(); } protected override void UpdateState(BoundUserInterfaceState state) diff --git a/Content.Client/VoiceMask/VoiceMaskBoundUserInterface.cs b/Content.Client/VoiceMask/VoiceMaskBoundUserInterface.cs index 891804674d3..f700c6663b9 100644 --- a/Content.Client/VoiceMask/VoiceMaskBoundUserInterface.cs +++ b/Content.Client/VoiceMask/VoiceMaskBoundUserInterface.cs @@ -1,13 +1,12 @@ using Content.Shared.VoiceMask; using Robust.Client.GameObjects; -using Robust.Client.UserInterface; using Robust.Shared.Prototypes; namespace Content.Client.VoiceMask; public sealed class VoiceMaskBoundUserInterface : BoundUserInterface { - [Dependency] private readonly IPrototypeManager _protomanager = default!; + [Dependency] private readonly IPrototypeManager _proto = default!; [ViewVariables] private VoiceMaskNameChangeWindow? _window; @@ -20,11 +19,12 @@ protected override void Open() { base.Open(); - _window = this.CreateWindow(); - _window.ReloadVerbs(_protomanager); + _window = new(_proto); + _window.OpenCentered(); _window.OnNameChange += OnNameSelected; _window.OnVerbChange += verb => SendMessage(new VoiceMaskChangeVerbMessage(verb)); + _window.OnClose += Close; } private void OnNameSelected(string name) diff --git a/Content.Client/VoiceMask/VoiceMaskNameChangeWindow.xaml.cs b/Content.Client/VoiceMask/VoiceMaskNameChangeWindow.xaml.cs index 0dc41f807ab..16a28f9d9b3 100644 --- a/Content.Client/VoiceMask/VoiceMaskNameChangeWindow.xaml.cs +++ b/Content.Client/VoiceMask/VoiceMaskNameChangeWindow.xaml.cs @@ -17,7 +17,7 @@ public sealed partial class VoiceMaskNameChangeWindow : FancyWindow private string? _verb; - public VoiceMaskNameChangeWindow() + public VoiceMaskNameChangeWindow(IPrototypeManager proto) { RobustXamlLoader.Load(this); @@ -32,10 +32,12 @@ public VoiceMaskNameChangeWindow() SpeechVerbSelector.SelectId(args.Id); }; + ReloadVerbs(proto); + AddVerbs(); } - public void ReloadVerbs(IPrototypeManager proto) + private void ReloadVerbs(IPrototypeManager proto) { foreach (var verb in proto.EnumeratePrototypes()) { diff --git a/Content.Client/Weapons/Melee/UI/MeleeSpeechBoundUserInterface.cs b/Content.Client/Weapons/Melee/UI/MeleeSpeechBoundUserInterface.cs index 3f01808c422..f3e0c0a539a 100644 --- a/Content.Client/Weapons/Melee/UI/MeleeSpeechBoundUserInterface.cs +++ b/Content.Client/Weapons/Melee/UI/MeleeSpeechBoundUserInterface.cs @@ -1,6 +1,5 @@ using Robust.Client.GameObjects; using Content.Shared.Speech.Components; -using Robust.Client.UserInterface; namespace Content.Client.Weapons.Melee.UI; @@ -20,10 +19,17 @@ protected override void Open() { base.Open(); - _window = this.CreateWindow(); + _window = new MeleeSpeechWindow(); + if (State != null) + UpdateState(State); + + _window.OpenCentered(); + + _window.OnClose += Close; _window.OnBattlecryEntered += OnBattlecryChanged; } + private void OnBattlecryChanged(string newBattlecry) { SendMessage(new MeleeSpeechBattlecryChangedMessage(newBattlecry)); diff --git a/Content.Client/Wires/UI/WiresBoundUserInterface.cs b/Content.Client/Wires/UI/WiresBoundUserInterface.cs index edf1a2d3770..5a8869a204e 100644 --- a/Content.Client/Wires/UI/WiresBoundUserInterface.cs +++ b/Content.Client/Wires/UI/WiresBoundUserInterface.cs @@ -1,6 +1,5 @@ using Content.Shared.Wires; using Robust.Client.GameObjects; -using Robust.Client.UserInterface; namespace Content.Client.Wires.UI { @@ -16,8 +15,10 @@ public WiresBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey) protected override void Open() { base.Open(); - _menu = this.CreateWindow(); - _menu.OnAction += PerformAction; + + _menu = new WiresMenu(this); + _menu.OnClose += Close; + _menu.OpenCenteredLeft(); } protected override void UpdateState(BoundUserInterfaceState state) diff --git a/Content.Client/Wires/UI/WiresMenu.cs b/Content.Client/Wires/UI/WiresMenu.cs index eccc548297c..7bccc208616 100644 --- a/Content.Client/Wires/UI/WiresMenu.cs +++ b/Content.Client/Wires/UI/WiresMenu.cs @@ -1,3 +1,4 @@ +using System; using System.Numerics; using Content.Client.Examine; using Content.Client.Resources; @@ -11,6 +12,10 @@ using Robust.Client.UserInterface.CustomControls; using Robust.Shared.Animations; using Robust.Shared.Input; +using Robust.Shared.IoC; +using Robust.Shared.Localization; +using Robust.Shared.Maths; +using Robust.Shared.Random; using static Robust.Client.UserInterface.Controls.BoxContainer; namespace Content.Client.Wires.UI @@ -19,6 +24,8 @@ public sealed class WiresMenu : BaseWindow { [Dependency] private readonly IResourceCache _resourceCache = default!; + public WiresBoundUserInterface Owner { get; } + private readonly Control _wiresHBox; private readonly Control _topContainer; private readonly Control _statusContainer; @@ -28,12 +35,11 @@ public sealed class WiresMenu : BaseWindow public TextureButton CloseButton { get; set; } - public event Action? OnAction; - - public WiresMenu() + public WiresMenu(WiresBoundUserInterface owner) { IoCManager.InjectDependencies(this); + Owner = owner; var rootContainer = new LayoutContainer {Name = "WireRoot"}; AddChild(rootContainer); @@ -251,12 +257,12 @@ public void Populate(WiresBoundUserInterfaceState state) control.WireClicked += () => { - OnAction?.Invoke(wire.Id, wire.IsCut ? WiresAction.Mend : WiresAction.Cut); + Owner.PerformAction(wire.Id, wire.IsCut ? WiresAction.Mend : WiresAction.Cut); }; control.ContactsClicked += () => { - OnAction?.Invoke(wire.Id, WiresAction.Pulse); + Owner.PerformAction(wire.Id, WiresAction.Pulse); }; } diff --git a/Content.Client/Xenoarchaeology/Ui/AnalysisConsoleBoundUserInterface.cs b/Content.Client/Xenoarchaeology/Ui/AnalysisConsoleBoundUserInterface.cs index c7a74815b6b..2538caf6eb8 100644 --- a/Content.Client/Xenoarchaeology/Ui/AnalysisConsoleBoundUserInterface.cs +++ b/Content.Client/Xenoarchaeology/Ui/AnalysisConsoleBoundUserInterface.cs @@ -1,7 +1,6 @@ using Content.Shared.Xenoarchaeology.Equipment; using JetBrains.Annotations; using Robust.Client.GameObjects; -using Robust.Client.UserInterface; namespace Content.Client.Xenoarchaeology.Ui; @@ -19,7 +18,10 @@ protected override void Open() { base.Open(); - _consoleMenu = this.CreateWindow(); + _consoleMenu = new AnalysisConsoleMenu(); + + _consoleMenu.OnClose += Close; + _consoleMenu.OpenCentered(); _consoleMenu.OnServerSelectionButtonPressed += () => { From fe43bda936ffbcb21fb7b68d12427838eb67b619 Mon Sep 17 00:00:00 2001 From: buntobaggins <113877683+buntobaggins@users.noreply.github.com> Date: Sat, 20 Jul 2024 20:29:21 -0700 Subject: [PATCH 304/765] Spationaut Hardsuit Light buff (#30049) Buffed the light on the Spationaut Hardsuit Co-authored-by: buntobaggins --- .../Prototypes/Entities/Clothing/Head/hardsuit-helmets.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Resources/Prototypes/Entities/Clothing/Head/hardsuit-helmets.yml b/Resources/Prototypes/Entities/Clothing/Head/hardsuit-helmets.yml index 29db61071bc..c80e52b3b28 100644 --- a/Resources/Prototypes/Entities/Clothing/Head/hardsuit-helmets.yml +++ b/Resources/Prototypes/Entities/Clothing/Head/hardsuit-helmets.yml @@ -111,6 +111,8 @@ - state: equipped-head - state: equipped-head-unshaded shader: unshaded + - type: PointLight + radius: 6 - type: PressureProtection highPressureMultiplier: 0.72 lowPressureMultiplier: 1000 From 94beaf383b73424dc14429608d6ed134f0810812 Mon Sep 17 00:00:00 2001 From: PJBot Date: Sun, 21 Jul 2024 03:30:29 +0000 Subject: [PATCH 305/765] Automatic changelog update --- Resources/Changelog/Changelog.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index ed8f51b7865..1ed3320d344 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,11 +1,4 @@ Entries: -- author: metalgearsloth - changes: - - message: Add predicted UI opening for storage and PDAs. - type: Add - id: 6443 - time: '2024-04-26T08:16:24.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/27214 - author: DrSmugleaf changes: - message: Fixed mobs that are able to pry doors not being able to do so by just @@ -3798,3 +3791,10 @@ id: 6942 time: '2024-07-20T05:53:58.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/28748 +- author: buntobaggins + changes: + - message: Increased light radius on the Spationaut Hardsuit + type: Tweak + id: 6943 + time: '2024-07-21T03:29:21.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/30049 From 87a4203267fe26aede47caba78e84910bd8e15d3 Mon Sep 17 00:00:00 2001 From: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com> Date: Sun, 21 Jul 2024 14:48:13 +1000 Subject: [PATCH 306/765] Reapply "Remove some BUI boilerplate" (#30214) (#30219) * Reapply "Remove some BUI boilerplate" (#30214) This reverts commit cb0ba66be38677d248ce11f809221230ebe89642. * Fix gas tank * Fix PA * Fix microwave * Comms console underwrap * Fix rcd * log wehs --- .../UI/AccessOverriderBoundUserInterface.cs | 45 +++-- .../Access/UI/AccessOverriderWindow.xaml.cs | 41 ++--- .../UI/AgentIDCardBoundUserInterface.cs | 19 +- .../Access/UI/AgentIDCardWindow.xaml.cs | 10 +- .../Ame/UI/AmeControllerBoundUserInterface.cs | 16 +- Content.Client/Ame/UI/AmeWindow.xaml.cs | 19 +- .../Ui/AnomalyGeneratorBoundUserInterface.cs | 20 +- .../Anomaly/Ui/AnomalyGeneratorWindow.xaml.cs | 8 +- Content.Client/Arcade/BlockGameMenu.cs | 45 +++-- .../Arcade/SpaceVillainArcadeMenu.cs | 45 ++--- .../Arcade/UI/BlockGameBoundUserInterface.cs | 5 +- .../SpaceVillainArcadeBoundUserInterface.cs | 16 +- .../Monitor/UI/AirAlarmBoundUserInterface.cs | 12 +- .../Atmos/Monitor/UI/AirAlarmWindow.xaml.cs | 7 +- .../Atmos/UI/GasCanisterBoundUserInterface.cs | 9 +- .../Atmos/UI/GasFilterBoundUserInterface.cs | 11 +- .../Atmos/UI/GasFilterWindow.xaml.cs | 7 +- .../Atmos/UI/GasMixerBoundUserInteface.cs | 18 +- .../UI/GasPressurePumpBoundUserInterface.cs | 17 +- .../UI/GasThermomachineBoundUserInterface.cs | 17 +- .../UI/GasVolumePumpBoundUserInterface.cs | 19 +- .../Atmos/UI/SpaceHeaterBoundUserInterface.cs | 10 +- .../Jukebox/JukeboxBoundUserInterface.cs | 21 +-- .../CryostorageBoundUserInterface.cs | 15 +- .../CargoBountyConsoleBoundUserInterface.cs | 17 +- .../CargoPalletConsoleBoundUserInterface.cs | 15 +- .../CargoShuttleConsoleBoundUserInterface.cs | 24 +-- .../Cargo/UI/CargoShuttleMenu.xaml.cs | 13 +- .../UI/ChemMasterBoundUserInterface.cs | 20 +- .../UI/ReagentDispenserBoundUserInterface.cs | 27 +-- .../UI/TransferAmountBoundUserInterface.cs | 12 +- .../UI/CloningConsoleBoundUserInterface.cs | 25 +-- .../UI/ChameleonBoundUserInterface.cs | 16 +- ...CommunicationsConsoleBoundUserInterface.cs | 72 +++----- .../UI/CommunicationsConsoleMenu.xaml.cs | 81 +++++---- .../Computer/ComputerBoundUserInterface.cs | 15 +- .../UI/ConfigurationBoundUserInterface.cs | 28 +-- .../Configurable/UI/ConfigurationMenu.cs | 18 +- .../UI/FlatpackCreatorBoundUserInterface.cs | 14 +- .../UI/FlatpackCreatorMenu.xaml.cs | 13 +- .../Crayon/UI/CrayonBoundUserInterface.cs | 40 ++-- Content.Client/Crayon/UI/CrayonWindow.xaml.cs | 18 +- .../UI/DisposalRouterBoundUserInterface.cs | 22 +-- .../UI/DisposalTaggerBoundUserInterface.cs | 23 +-- .../DoorElectronicsBoundUserInterface.cs | 31 ++-- .../DoorElectronicsConfigurationMenu.xaml.cs | 21 ++- Content.Client/Fax/UI/FaxBoundUi.cs | 12 +- .../ForensicScannerBoundUserInterface.cs | 15 +- .../Gateway/UI/GatewayBoundUserInterface.cs | 16 +- .../Gateway/UI/GatewayWindow.xaml.cs | 10 +- .../UI/GravityGeneratorBoundUserInterface.cs | 23 +-- .../Gravity/UI/GravityGeneratorWindow.xaml.cs | 15 +- .../UI/HealthAnalyzerBoundUserInterface.cs | 23 +-- ...manoidMarkingModifierBoundUserInterface.cs | 4 +- .../Instruments/UI/BandMenu.xaml.cs | 6 +- .../Instruments/UI/ChannelsMenu.xaml.cs | 5 +- .../UI/InstrumentBoundUserInterface.cs | 36 +++- .../Instruments/UI/InstrumentMenu.xaml.cs | 171 ++++++++++-------- .../Inventory/StrippableBoundUserInterface.cs | 25 ++- Content.Client/Kitchen/UI/GrinderMenu.xaml.cs | 42 ++--- .../Kitchen/UI/MicrowaveBoundUserInterface.cs | 43 +---- .../Kitchen/UI/MicrowaveMenu.xaml.cs | 25 ++- .../UI/ReagentGrinderBoundUserInterface.cs | 34 ++-- .../UI/HandLabelerBoundUserInterface.cs | 16 +- .../Lathe/UI/LatheBoundUserInterface.cs | 17 +- Content.Client/Lathe/UI/LatheMenu.xaml.cs | 29 +-- .../UI/SignalTimerBoundUserInterface.cs | 24 +-- .../UI/SignalTimerWindow.xaml.cs | 24 +-- .../MagicMirrorBoundUserInterface.cs | 15 +- .../Ui/NewsWriterBoundUserInterface.cs | 18 +- .../MassMedia/Ui/NewsWriterMenu.xaml.cs | 6 +- .../Mech/Ui/MechBoundUserInterface.cs | 16 +- Content.Client/Mech/Ui/MechMenu.xaml.cs | 9 +- .../CrewMonitoringBoundUserInterface.cs | 18 +- .../CrewMonitoringWindow.xaml.cs | 17 +- .../NetworkConfiguratorBoundUserInterface.cs | 39 ++-- ...tworkConfiguratorConfigurationMenu.xaml.cs | 8 +- .../NetworkConfiguratorDeviceList.xaml.cs | 12 +- .../NetworkConfiguratorLinkMenu.xaml.cs | 16 +- .../NetworkConfiguratorListMenu.xaml.cs | 13 +- Content.Client/Nuke/NukeBoundUserInterface.cs | 17 +- .../WarDeclaratorBoundUserInterface.cs | 18 +- .../NukeOps/WarDeclaratorWindow.xaml.cs | 9 +- Content.Client/PDA/PdaBoundUserInterface.cs | 17 +- .../PDA/Ringer/RingerBoundUserInterface.cs | 4 +- .../Paper/UI/PaperBoundUserInterface.cs | 17 +- Content.Client/Paper/UI/PaperWindow.xaml.cs | 6 +- .../ParticleAcceleratorBoundUserInterface.cs | 16 +- .../UI/ParticleAcceleratorControlMenu.cs | 31 ++-- .../UI/NavMapBeaconBoundUserInterface.cs | 16 +- .../Pinpointer/UI/NavMapBeaconWindow.xaml.cs | 25 ++- .../UI/StationMapBoundUserInterface.cs | 15 +- .../Pinpointer/UI/StationMapWindow.xaml.cs | 11 +- .../UI/UntrackedMapBoundUserInterface.cs | 15 +- .../Power/APC/ApcBoundUserInterface.cs | 16 +- Content.Client/Power/APC/UI/ApcMenu.xaml.cs | 12 +- .../Power/Generator/GeneratorWindow.xaml.cs | 52 +++--- .../PortableGeneratorBoundUserInterface.cs | 25 ++- ...owerMonitoringConsoleBoundUserInterface.cs | 19 +- .../PowerMonitoringWindow.xaml.Widgets.cs | 6 +- .../Power/PowerMonitoringWindow.xaml.cs | 84 +++++---- Content.Client/RCD/RCDMenu.xaml.cs | 40 ++-- .../RCD/RCDMenuBoundUserInterface.cs | 16 +- .../Radio/Ui/IntercomBoundUserInterface.cs | 20 +- Content.Client/Radio/Ui/IntercomMenu.xaml.cs | 4 +- .../UI/DiskConsoleBoundUserInterface.cs | 15 +- .../UI/ResearchClientBoundUserInterface.cs | 16 +- .../ResearchClientServerSelectionMenu.xaml.cs | 11 +- .../UI/ResearchConsoleBoundUserInterface.cs | 28 +-- .../Research/UI/ResearchConsoleMenu.xaml.cs | 29 +-- .../UI/RoboticsConsoleBoundUserInterface.cs | 18 +- .../Robotics/UI/RoboticsConsoleWindow.xaml.cs | 25 ++- ...vageExpeditionConsoleBoundUserInterface.cs | 12 +- .../UI/SalvageMagnetBoundUserInterface.cs | 21 +-- .../BUI/IFFConsoleBoundUserInterface.cs | 4 +- .../BUI/RadarConsoleBoundUserInterface.cs | 14 +- .../BUI/ShuttleConsoleBoundUserInterface.cs | 5 +- .../Silicons/Borgs/BorgBoundUserInterface.cs | 18 +- Content.Client/Silicons/Borgs/BorgMenu.xaml | 2 +- .../Silicons/Borgs/BorgMenu.xaml.cs | 49 +++-- .../Laws/Ui/SiliconLawBoundUserInterface.cs | 14 +- .../UI/SprayPainterBoundUserInterface.cs | 27 +-- ...lStationRecordConsoleBoundUserInterface.cs | 13 +- .../Store/Ui/StoreBoundUserInterface.cs | 15 +- Content.Client/Strip/StrippingMenu.cs | 11 +- .../UI/SurveillanceCameraMonitorBoundUi.cs | 11 +- .../Thief/ThiefBackpackBoundUserInterface.cs | 19 +- .../Thief/ThiefBackpackMenu.xaml.cs | 28 ++- .../GasTank/GasTankBoundUserInterface.cs | 11 +- .../Systems/Atmos/GasTank/GasTankWindow.cs | 44 +++-- .../VendingMachineBoundUserInterface.cs | 8 +- .../VoiceMask/VoiceMaskBoundUserInterface.cs | 8 +- .../VoiceMaskNameChangeWindow.xaml.cs | 6 +- .../Melee/UI/MeleeSpeechBoundUserInterface.cs | 10 +- .../Wires/UI/WiresBoundUserInterface.cs | 7 +- Content.Client/Wires/UI/WiresMenu.cs | 16 +- .../Ui/AnalysisConsoleBoundUserInterface.cs | 6 +- 137 files changed, 1098 insertions(+), 1753 deletions(-) diff --git a/Content.Client/Access/UI/AccessOverriderBoundUserInterface.cs b/Content.Client/Access/UI/AccessOverriderBoundUserInterface.cs index c1b63dc4d05..d80c600c03e 100644 --- a/Content.Client/Access/UI/AccessOverriderBoundUserInterface.cs +++ b/Content.Client/Access/UI/AccessOverriderBoundUserInterface.cs @@ -2,6 +2,7 @@ using Content.Shared.Access.Components; using Content.Shared.Access.Systems; using Content.Shared.Containers.ItemSlots; +using Robust.Client.UserInterface; using Robust.Shared.Prototypes; using static Content.Shared.Access.Components.AccessOverriderComponent; @@ -23,6 +24,28 @@ protected override void Open() { base.Open(); + _window = this.CreateWindow(); + RefreshAccess(); + _window.Title = EntMan.GetComponent(Owner).EntityName; + _window.OnSubmit += SubmitData; + + _window.PrivilegedIdButton.OnPressed += _ => SendMessage(new ItemSlotButtonPressedEvent(PrivilegedIdCardSlotId)); + } + + public override void OnProtoReload(PrototypesReloadedEventArgs args) + { + base.OnProtoReload(args); + if (!args.WasModified()) + return; + + RefreshAccess(); + + if (State != null) + _window?.UpdateState(_prototypeManager, (AccessOverriderBoundUserInterfaceState) State); + } + + private void RefreshAccess() + { List> accessLevels; if (EntMan.TryGetComponent(Owner, out var accessOverrider)) @@ -30,38 +53,20 @@ protected override void Open() accessLevels = accessOverrider.AccessLevels; accessLevels.Sort(); } - else { accessLevels = new List>(); _accessOverriderSystem.Log.Error($"No AccessOverrider component found for {EntMan.ToPrettyString(Owner)}!"); } - _window = new AccessOverriderWindow(this, _prototypeManager, accessLevels) - { - Title = EntMan.GetComponent(Owner).EntityName - }; - - _window.PrivilegedIdButton.OnPressed += _ => SendMessage(new ItemSlotButtonPressedEvent(PrivilegedIdCardSlotId)); - - _window.OnClose += Close; - _window.OpenCentered(); - } - - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - if (!disposing) - return; - - _window?.Dispose(); + _window?.SetAccessLevels(_prototypeManager, accessLevels); } protected override void UpdateState(BoundUserInterfaceState state) { base.UpdateState(state); var castState = (AccessOverriderBoundUserInterfaceState) state; - _window?.UpdateState(castState); + _window?.UpdateState(_prototypeManager, castState); } public void SubmitData(List> newAccessList) diff --git a/Content.Client/Access/UI/AccessOverriderWindow.xaml.cs b/Content.Client/Access/UI/AccessOverriderWindow.xaml.cs index 6025c3b551f..ba087718583 100644 --- a/Content.Client/Access/UI/AccessOverriderWindow.xaml.cs +++ b/Content.Client/Access/UI/AccessOverriderWindow.xaml.cs @@ -13,26 +13,24 @@ namespace Content.Client.Access.UI [GenerateTypedNameReferences] public sealed partial class AccessOverriderWindow : DefaultWindow { - [Dependency] private readonly ILogManager _logManager = default!; - [Dependency] private readonly IPrototypeManager _prototypeManager = default!; - - private readonly AccessOverriderBoundUserInterface _owner; private readonly Dictionary _accessButtons = new(); - public AccessOverriderWindow(AccessOverriderBoundUserInterface owner, IPrototypeManager prototypeManager, - List> accessLevels) + public event Action>>? OnSubmit; + + public AccessOverriderWindow() { RobustXamlLoader.Load(this); - IoCManager.InjectDependencies(this); - var logMill = _logManager.GetSawmill(SharedAccessOverriderSystem.Sawmill); + } - _owner = owner; + public void SetAccessLevels(IPrototypeManager protoManager, List> accessLevels) + { + _accessButtons.Clear(); + AccessLevelGrid.DisposeAllChildren(); foreach (var access in accessLevels) { - if (!prototypeManager.TryIndex(access, out var accessLevel)) + if (!protoManager.TryIndex(access, out var accessLevel)) { - logMill.Error($"Unable to find accesslevel for {access}"); continue; } @@ -44,11 +42,16 @@ public AccessOverriderWindow(AccessOverriderBoundUserInterface owner, IPrototype AccessLevelGrid.AddChild(newButton); _accessButtons.Add(accessLevel.ID, newButton); - newButton.OnPressed += _ => SubmitData(); + newButton.OnPressed += _ => + { + OnSubmit?.Invoke( + // Iterate over the buttons dictionary, filter by `Pressed`, only get key from the key/value pair + _accessButtons.Where(x => x.Value.Pressed).Select(x => new ProtoId(x.Key)).ToList()); + }; } } - public void UpdateState(AccessOverriderBoundUserInterfaceState state) + public void UpdateState(IPrototypeManager protoManager, AccessOverriderBoundUserInterfaceState state) { PrivilegedIdLabel.Text = state.PrivilegedIdName; PrivilegedIdButton.Text = state.IsPrivilegedIdPresent @@ -66,11 +69,11 @@ public void UpdateState(AccessOverriderBoundUserInterfaceState state) if (state.MissingPrivilegesList != null && state.MissingPrivilegesList.Any()) { - List missingPrivileges = new List(); + var missingPrivileges = new List(); foreach (string tag in state.MissingPrivilegesList) { - string privilege = Loc.GetString(_prototypeManager.Index(tag)?.Name ?? "generic-unknown"); + var privilege = Loc.GetString(protoManager.Index(tag)?.Name ?? "generic-unknown"); missingPrivileges.Add(privilege); } @@ -90,13 +93,5 @@ public void UpdateState(AccessOverriderBoundUserInterfaceState state) } } } - - private void SubmitData() - { - _owner.SubmitData( - - // Iterate over the buttons dictionary, filter by `Pressed`, only get key from the key/value pair - _accessButtons.Where(x => x.Value.Pressed).Select(x => new ProtoId(x.Key)).ToList()); - } } } diff --git a/Content.Client/Access/UI/AgentIDCardBoundUserInterface.cs b/Content.Client/Access/UI/AgentIDCardBoundUserInterface.cs index 761f52988a9..50add43dc91 100644 --- a/Content.Client/Access/UI/AgentIDCardBoundUserInterface.cs +++ b/Content.Client/Access/UI/AgentIDCardBoundUserInterface.cs @@ -1,6 +1,7 @@ using Content.Shared.Access.Systems; using Content.Shared.StatusIcon; using Robust.Client.GameObjects; +using Robust.Client.UserInterface; using Robust.Shared.Prototypes; namespace Content.Client.Access.UI @@ -20,16 +21,11 @@ protected override void Open() { base.Open(); - _window?.Dispose(); - _window = new AgentIDCardWindow(this); - if (State != null) - UpdateState(State); + _window = this.CreateWindow(); - _window.OpenCentered(); - - _window.OnClose += Close; _window.OnNameChanged += OnNameChanged; _window.OnJobChanged += OnJobChanged; + _window.OnJobIconChanged += OnJobIconChanged; } private void OnNameChanged(string newName) @@ -61,14 +57,5 @@ protected override void UpdateState(BoundUserInterfaceState state) _window.SetCurrentJob(cast.CurrentJob); _window.SetAllowedIcons(cast.Icons, cast.CurrentJobIconId); } - - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - if (!disposing) - return; - - _window?.Dispose(); - } } } diff --git a/Content.Client/Access/UI/AgentIDCardWindow.xaml.cs b/Content.Client/Access/UI/AgentIDCardWindow.xaml.cs index 6d0b2a184f4..071ce41a069 100644 --- a/Content.Client/Access/UI/AgentIDCardWindow.xaml.cs +++ b/Content.Client/Access/UI/AgentIDCardWindow.xaml.cs @@ -17,19 +17,19 @@ public sealed partial class AgentIDCardWindow : DefaultWindow [Dependency] private readonly IPrototypeManager _prototypeManager = default!; [Dependency] private readonly IEntitySystemManager _entitySystem = default!; private readonly SpriteSystem _spriteSystem; - private readonly AgentIDCardBoundUserInterface _bui; private const int JobIconColumnCount = 10; public event Action? OnNameChanged; public event Action? OnJobChanged; - public AgentIDCardWindow(AgentIDCardBoundUserInterface bui) + public event Action>? OnJobIconChanged; + + public AgentIDCardWindow() { RobustXamlLoader.Load(this); IoCManager.InjectDependencies(this); _spriteSystem = _entitySystem.GetEntitySystem(); - _bui = bui; NameLineEdit.OnTextEntered += e => OnNameChanged?.Invoke(e.Text); NameLineEdit.OnFocusExit += e => OnNameChanged?.Invoke(e.Text); @@ -67,7 +67,7 @@ public void SetAllowedIcons(HashSet> icons, string }; // Generate buttons textures - TextureRect jobIconTexture = new TextureRect + var jobIconTexture = new TextureRect { Texture = _spriteSystem.Frame0(jobIcon.Icon), TextureScale = new Vector2(2.5f, 2.5f), @@ -75,7 +75,7 @@ public void SetAllowedIcons(HashSet> icons, string }; jobIconButton.AddChild(jobIconTexture); - jobIconButton.OnPressed += _ => _bui.OnJobIconChanged(jobIconId); + jobIconButton.OnPressed += _ => OnJobIconChanged?.Invoke(jobIcon.ID); IconGrid.AddChild(jobIconButton); if (jobIconId.Equals(currentJobIconId)) diff --git a/Content.Client/Ame/UI/AmeControllerBoundUserInterface.cs b/Content.Client/Ame/UI/AmeControllerBoundUserInterface.cs index e84cf5d34de..3d65f751899 100644 --- a/Content.Client/Ame/UI/AmeControllerBoundUserInterface.cs +++ b/Content.Client/Ame/UI/AmeControllerBoundUserInterface.cs @@ -1,5 +1,6 @@ using Content.Shared.Ame.Components; using JetBrains.Annotations; +using Robust.Client.UserInterface; namespace Content.Client.Ame.UI { @@ -16,9 +17,8 @@ protected override void Open() { base.Open(); - _window = new AmeWindow(this); - _window.OnClose += Close; - _window.OpenCentered(); + _window = this.CreateWindow(); + _window.OnAmeButton += ButtonPressed; } /// @@ -40,15 +40,5 @@ public void ButtonPressed(UiButton button) { SendMessage(new UiButtonPressedMessage(button)); } - - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - - if (disposing) - { - _window?.Dispose(); - } - } } } diff --git a/Content.Client/Ame/UI/AmeWindow.xaml.cs b/Content.Client/Ame/UI/AmeWindow.xaml.cs index 8b91ec59660..d6d580bcdaf 100644 --- a/Content.Client/Ame/UI/AmeWindow.xaml.cs +++ b/Content.Client/Ame/UI/AmeWindow.xaml.cs @@ -1,3 +1,4 @@ +using System.Linq; using Content.Client.UserInterface; using Content.Shared.Ame.Components; using Robust.Client.AutoGenerated; @@ -9,15 +10,17 @@ namespace Content.Client.Ame.UI [GenerateTypedNameReferences] public sealed partial class AmeWindow : DefaultWindow { - public AmeWindow(AmeControllerBoundUserInterface ui) + public event Action? OnAmeButton; + + public AmeWindow() { RobustXamlLoader.Load(this); IoCManager.InjectDependencies(this); - EjectButton.OnPressed += _ => ui.ButtonPressed(UiButton.Eject); - ToggleInjection.OnPressed += _ => ui.ButtonPressed(UiButton.ToggleInjection); - IncreaseFuelButton.OnPressed += _ => ui.ButtonPressed(UiButton.IncreaseFuel); - DecreaseFuelButton.OnPressed += _ => ui.ButtonPressed(UiButton.DecreaseFuel); + EjectButton.OnPressed += _ => OnAmeButton?.Invoke(UiButton.Eject); + ToggleInjection.OnPressed += _ => OnAmeButton?.Invoke(UiButton.ToggleInjection); + IncreaseFuelButton.OnPressed += _ => OnAmeButton?.Invoke(UiButton.IncreaseFuel); + DecreaseFuelButton.OnPressed += _ => OnAmeButton?.Invoke(UiButton.DecreaseFuel); } /// @@ -29,7 +32,7 @@ public void UpdateState(BoundUserInterfaceState state) var castState = (AmeControllerBoundUserInterfaceState) state; // Disable all buttons if not powered - if (Contents.Children != null) + if (Contents.Children.Any()) { ButtonHelpers.SetButtonDisabledRecursive(Contents, !castState.HasPower); EjectButton.Disabled = false; @@ -65,8 +68,8 @@ public void UpdateState(BoundUserInterfaceState state) CoreCount.Text = $"{castState.CoreCount}"; InjectionAmount.Text = $"{castState.InjectionAmount}"; // format power statistics to pretty numbers - CurrentPowerSupply.Text = $"{castState.CurrentPowerSupply.ToString("N1")}"; - TargetedPowerSupply.Text = $"{castState.TargetedPowerSupply.ToString("N1")}"; + CurrentPowerSupply.Text = $"{castState.CurrentPowerSupply:N1}"; + TargetedPowerSupply.Text = $"{castState.TargetedPowerSupply:N1}"; } } } diff --git a/Content.Client/Anomaly/Ui/AnomalyGeneratorBoundUserInterface.cs b/Content.Client/Anomaly/Ui/AnomalyGeneratorBoundUserInterface.cs index 5764d0a097d..5d1985485c4 100644 --- a/Content.Client/Anomaly/Ui/AnomalyGeneratorBoundUserInterface.cs +++ b/Content.Client/Anomaly/Ui/AnomalyGeneratorBoundUserInterface.cs @@ -2,6 +2,7 @@ using Content.Shared.Gravity; using JetBrains.Annotations; using Robust.Client.GameObjects; +using Robust.Client.UserInterface; namespace Content.Client.Anomaly.Ui; @@ -18,10 +19,8 @@ protected override void Open() { base.Open(); - _window = new(Owner); - - _window.OpenCentered(); - _window.OnClose += Close; + _window = this.CreateWindow(); + _window.SetEntity(Owner); _window.OnGenerateButtonPressed += () => { @@ -37,18 +36,5 @@ protected override void UpdateState(BoundUserInterfaceState state) return; _window?.UpdateState(msg); } - - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - if (!disposing) return; - - _window?.Dispose(); - } - - public void SetPowerSwitch(bool on) - { - SendMessage(new SharedGravityGeneratorComponent.SwitchGeneratorMessage(on)); - } } diff --git a/Content.Client/Anomaly/Ui/AnomalyGeneratorWindow.xaml.cs b/Content.Client/Anomaly/Ui/AnomalyGeneratorWindow.xaml.cs index 08438e2a1b2..82d41192dd0 100644 --- a/Content.Client/Anomaly/Ui/AnomalyGeneratorWindow.xaml.cs +++ b/Content.Client/Anomaly/Ui/AnomalyGeneratorWindow.xaml.cs @@ -18,17 +18,21 @@ public sealed partial class AnomalyGeneratorWindow : FancyWindow public Action? OnGenerateButtonPressed; - public AnomalyGeneratorWindow(EntityUid gen) + public AnomalyGeneratorWindow() { RobustXamlLoader.Load(this); IoCManager.InjectDependencies(this); - EntityView.SetEntity(gen); EntityView.SpriteOffset = false; GenerateButton.OnPressed += _ => OnGenerateButtonPressed?.Invoke(); } + public void SetEntity(EntityUid uid) + { + EntityView.SetEntity(uid); + } + public void UpdateState(AnomalyGeneratorUserInterfaceState state) { _cooldownEnd = state.CooldownEndTime; diff --git a/Content.Client/Arcade/BlockGameMenu.cs b/Content.Client/Arcade/BlockGameMenu.cs index eeda2a31020..4a579fc4bf4 100644 --- a/Content.Client/Arcade/BlockGameMenu.cs +++ b/Content.Client/Arcade/BlockGameMenu.cs @@ -28,8 +28,6 @@ public sealed class BlockGameMenu : DefaultWindow private static readonly Vector2 BlockSize = new(15, 15); - private readonly BlockGameBoundUserInterface _owner; - private readonly PanelContainer _mainPanel; private readonly BoxContainer _gameRootContainer; @@ -58,10 +56,11 @@ public sealed class BlockGameMenu : DefaultWindow private bool _isPlayer = false; private bool _gameOver = false; - public BlockGameMenu(BlockGameBoundUserInterface owner) + public event Action? OnAction; + + public BlockGameMenu() { Title = Loc.GetString("blockgame-menu-title"); - _owner = owner; MinSize = SetSize = new Vector2(410, 490); @@ -176,7 +175,7 @@ public BlockGameMenu(BlockGameBoundUserInterface owner) }; _newGameButton.OnPressed += (e) => { - _owner.SendAction(BlockGamePlayerAction.NewGame); + OnAction?.Invoke(BlockGamePlayerAction.NewGame); }; pauseMenuContainer.AddChild(_newGameButton); pauseMenuContainer.AddChild(new Control { MinSize = new Vector2(1, 10) }); @@ -186,7 +185,10 @@ public BlockGameMenu(BlockGameBoundUserInterface owner) Text = Loc.GetString("blockgame-menu-button-scoreboard"), TextAlign = Label.AlignMode.Center }; - _scoreBoardButton.OnPressed += (e) => _owner.SendAction(BlockGamePlayerAction.ShowHighscores); + _scoreBoardButton.OnPressed += (e) => + { + OnAction?.Invoke(BlockGamePlayerAction.ShowHighscores); + }; pauseMenuContainer.AddChild(_scoreBoardButton); _unpauseButtonMargin = new Control { MinSize = new Vector2(1, 10), Visible = false }; pauseMenuContainer.AddChild(_unpauseButtonMargin); @@ -199,7 +201,7 @@ public BlockGameMenu(BlockGameBoundUserInterface owner) }; _unpauseButton.OnPressed += (e) => { - _owner.SendAction(BlockGamePlayerAction.Unpause); + OnAction?.Invoke(BlockGamePlayerAction.Unpause); }; pauseMenuContainer.AddChild(_unpauseButton); @@ -257,7 +259,7 @@ public BlockGameMenu(BlockGameBoundUserInterface owner) }; _finalNewGameButton.OnPressed += (e) => { - _owner.SendAction(BlockGamePlayerAction.NewGame); + OnAction?.Invoke(BlockGamePlayerAction.NewGame); }; gameOverMenuContainer.AddChild(_finalNewGameButton); @@ -327,7 +329,10 @@ public BlockGameMenu(BlockGameBoundUserInterface owner) Text = Loc.GetString("blockgame-menu-button-back"), TextAlign = Label.AlignMode.Center }; - _highscoreBackButton.OnPressed += (e) => _owner.SendAction(BlockGamePlayerAction.Pause); + _highscoreBackButton.OnPressed += (e) => + { + OnAction?.Invoke(BlockGamePlayerAction.Pause); + }; menuContainer.AddChild(_highscoreBackButton); menuInnerPanel.AddChild(menuContainer); @@ -473,7 +478,7 @@ protected override void KeyboardFocusExited() private void TryPause() { - _owner.SendAction(BlockGamePlayerAction.Pause); + OnAction?.Invoke(BlockGamePlayerAction.Pause); } public void SetStarted() @@ -576,19 +581,19 @@ protected override void KeyBindDown(GUIBoundKeyEventArgs args) return; else if (args.Function == ContentKeyFunctions.ArcadeLeft) - _owner.SendAction(BlockGamePlayerAction.StartLeft); + OnAction?.Invoke(BlockGamePlayerAction.StartLeft); else if (args.Function == ContentKeyFunctions.ArcadeRight) - _owner.SendAction(BlockGamePlayerAction.StartRight); + OnAction?.Invoke(BlockGamePlayerAction.StartRight); else if (args.Function == ContentKeyFunctions.ArcadeUp) - _owner.SendAction(BlockGamePlayerAction.Rotate); + OnAction?.Invoke(BlockGamePlayerAction.Rotate); else if (args.Function == ContentKeyFunctions.Arcade3) - _owner.SendAction(BlockGamePlayerAction.CounterRotate); + OnAction?.Invoke(BlockGamePlayerAction.CounterRotate); else if (args.Function == ContentKeyFunctions.ArcadeDown) - _owner.SendAction(BlockGamePlayerAction.SoftdropStart); + OnAction?.Invoke(BlockGamePlayerAction.SoftdropStart); else if (args.Function == ContentKeyFunctions.Arcade2) - _owner.SendAction(BlockGamePlayerAction.Hold); + OnAction?.Invoke(BlockGamePlayerAction.Hold); else if (args.Function == ContentKeyFunctions.Arcade1) - _owner.SendAction(BlockGamePlayerAction.Harddrop); + OnAction?.Invoke(BlockGamePlayerAction.Harddrop); } protected override void KeyBindUp(GUIBoundKeyEventArgs args) @@ -599,11 +604,11 @@ protected override void KeyBindUp(GUIBoundKeyEventArgs args) return; else if (args.Function == ContentKeyFunctions.ArcadeLeft) - _owner.SendAction(BlockGamePlayerAction.EndLeft); + OnAction?.Invoke(BlockGamePlayerAction.EndLeft); else if (args.Function == ContentKeyFunctions.ArcadeRight) - _owner.SendAction(BlockGamePlayerAction.EndRight); + OnAction?.Invoke(BlockGamePlayerAction.EndRight); else if (args.Function == ContentKeyFunctions.ArcadeDown) - _owner.SendAction(BlockGamePlayerAction.SoftdropEnd); + OnAction?.Invoke(BlockGamePlayerAction.SoftdropEnd); } public void UpdateNextBlock(BlockGameBlock[] blocks) diff --git a/Content.Client/Arcade/SpaceVillainArcadeMenu.cs b/Content.Client/Arcade/SpaceVillainArcadeMenu.cs index e5542a5848e..1ee4c268184 100644 --- a/Content.Client/Arcade/SpaceVillainArcadeMenu.cs +++ b/Content.Client/Arcade/SpaceVillainArcadeMenu.cs @@ -8,8 +8,6 @@ namespace Content.Client.Arcade { public sealed class SpaceVillainArcadeMenu : DefaultWindow { - public SpaceVillainArcadeBoundUserInterface Owner { get; set; } - private readonly Label _enemyNameLabel; private readonly Label _playerInfoLabel; private readonly Label _enemyInfoLabel; @@ -17,11 +15,13 @@ public sealed class SpaceVillainArcadeMenu : DefaultWindow private readonly Label _enemyActionLabel; private readonly Button[] _gameButtons = new Button[3]; //used to disable/enable all game buttons - public SpaceVillainArcadeMenu(SpaceVillainArcadeBoundUserInterface owner) + + public event Action? OnPlayerAction; + + public SpaceVillainArcadeMenu() { MinSize = SetSize = new Vector2(300, 225); Title = Loc.GetString("spacevillain-menu-title"); - Owner = owner; var grid = new GridContainer { Columns = 1 }; @@ -47,32 +47,43 @@ public SpaceVillainArcadeMenu(SpaceVillainArcadeBoundUserInterface owner) grid.AddChild(_enemyActionLabel); var buttonGrid = new GridContainer { Columns = 3 }; - _gameButtons[0] = new ActionButton(Owner, SharedSpaceVillainArcadeComponent.PlayerAction.Attack) + _gameButtons[0] = new Button() { Text = Loc.GetString("spacevillain-menu-button-attack") }; + + _gameButtons[0].OnPressed += + _ => OnPlayerAction?.Invoke(SharedSpaceVillainArcadeComponent.PlayerAction.Attack); buttonGrid.AddChild(_gameButtons[0]); - _gameButtons[1] = new ActionButton(Owner, SharedSpaceVillainArcadeComponent.PlayerAction.Heal) + _gameButtons[1] = new Button() { Text = Loc.GetString("spacevillain-menu-button-heal") }; + + _gameButtons[1].OnPressed += + _ => OnPlayerAction?.Invoke(SharedSpaceVillainArcadeComponent.PlayerAction.Heal); buttonGrid.AddChild(_gameButtons[1]); - _gameButtons[2] = new ActionButton(Owner, SharedSpaceVillainArcadeComponent.PlayerAction.Recharge) + _gameButtons[2] = new Button() { Text = Loc.GetString("spacevillain-menu-button-recharge") }; + + _gameButtons[2].OnPressed += + _ => OnPlayerAction?.Invoke(SharedSpaceVillainArcadeComponent.PlayerAction.Recharge); buttonGrid.AddChild(_gameButtons[2]); centerContainer = new CenterContainer(); centerContainer.AddChild(buttonGrid); grid.AddChild(centerContainer); - var newGame = new ActionButton(Owner, SharedSpaceVillainArcadeComponent.PlayerAction.NewGame) + var newGame = new Button() { Text = Loc.GetString("spacevillain-menu-button-new-game") }; + + newGame.OnPressed += _ => OnPlayerAction?.Invoke(SharedSpaceVillainArcadeComponent.PlayerAction.NewGame); grid.AddChild(newGame); Contents.AddChild(grid); @@ -99,23 +110,5 @@ public void UpdateInfo(SharedSpaceVillainArcadeComponent.SpaceVillainArcadeDataU _playerActionLabel.Text = message.PlayerActionMessage; _enemyActionLabel.Text = message.EnemyActionMessage; } - - private sealed class ActionButton : Button - { - private readonly SpaceVillainArcadeBoundUserInterface _owner; - private readonly SharedSpaceVillainArcadeComponent.PlayerAction _playerAction; - - public ActionButton(SpaceVillainArcadeBoundUserInterface owner, SharedSpaceVillainArcadeComponent.PlayerAction playerAction) - { - _owner = owner; - _playerAction = playerAction; - OnPressed += Clicked; - } - - private void Clicked(ButtonEventArgs e) - { - _owner.SendAction(_playerAction); - } - } } } diff --git a/Content.Client/Arcade/UI/BlockGameBoundUserInterface.cs b/Content.Client/Arcade/UI/BlockGameBoundUserInterface.cs index 1a3422dec0f..8fa8035afd6 100644 --- a/Content.Client/Arcade/UI/BlockGameBoundUserInterface.cs +++ b/Content.Client/Arcade/UI/BlockGameBoundUserInterface.cs @@ -1,5 +1,6 @@ using Content.Shared.Arcade; using Robust.Client.GameObjects; +using Robust.Client.UserInterface; namespace Content.Client.Arcade.UI; @@ -15,9 +16,7 @@ protected override void Open() { base.Open(); - _menu = new BlockGameMenu(this); - _menu.OnClose += Close; - _menu.OpenCentered(); + _menu = this.CreateWindow(); } protected override void ReceiveMessage(BoundUserInterfaceMessage message) diff --git a/Content.Client/Arcade/UI/SpaceVillainArcadeBoundUserInterface.cs b/Content.Client/Arcade/UI/SpaceVillainArcadeBoundUserInterface.cs index 40bbe8b2d8c..c0704530de2 100644 --- a/Content.Client/Arcade/UI/SpaceVillainArcadeBoundUserInterface.cs +++ b/Content.Client/Arcade/UI/SpaceVillainArcadeBoundUserInterface.cs @@ -1,4 +1,5 @@ using Robust.Client.GameObjects; +using Robust.Client.UserInterface; using Robust.Shared.GameObjects; using Robust.Shared.ViewVariables; using static Content.Shared.Arcade.SharedSpaceVillainArcadeComponent; @@ -9,8 +10,6 @@ public sealed class SpaceVillainArcadeBoundUserInterface : BoundUserInterface { [ViewVariables] private SpaceVillainArcadeMenu? _menu; - //public SharedSpaceVillainArcadeComponent SpaceVillainArcade; - public SpaceVillainArcadeBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey) { SendAction(PlayerAction.RequestData); @@ -25,10 +24,7 @@ protected override void Open() { base.Open(); - _menu = new SpaceVillainArcadeMenu(this); - - _menu.OnClose += Close; - _menu.OpenCentered(); + _menu = this.CreateWindow(); } protected override void ReceiveMessage(BoundUserInterfaceMessage message) @@ -36,12 +32,4 @@ protected override void ReceiveMessage(BoundUserInterfaceMessage message) if (message is SpaceVillainArcadeDataUpdateMessage msg) _menu?.UpdateInfo(msg); } - - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - - if (disposing) - _menu?.Dispose(); - } } diff --git a/Content.Client/Atmos/Monitor/UI/AirAlarmBoundUserInterface.cs b/Content.Client/Atmos/Monitor/UI/AirAlarmBoundUserInterface.cs index 8f3b507c806..2ae15188355 100644 --- a/Content.Client/Atmos/Monitor/UI/AirAlarmBoundUserInterface.cs +++ b/Content.Client/Atmos/Monitor/UI/AirAlarmBoundUserInterface.cs @@ -2,6 +2,7 @@ using Content.Shared.Atmos.Monitor; using Content.Shared.Atmos.Monitor.Components; using Robust.Client.GameObjects; +using Robust.Client.UserInterface; using Robust.Shared.GameObjects; using Robust.Shared.IoC; using Robust.Shared.Log; @@ -20,16 +21,9 @@ protected override void Open() { base.Open(); - _window = new AirAlarmWindow(this); + _window = this.CreateWindow(); + _window.SetEntity(Owner); - if (State != null) - { - UpdateState(State); - } - - _window.OpenCentered(); - - _window.OnClose += Close; _window.AtmosDeviceDataChanged += OnDeviceDataChanged; _window.AtmosDeviceDataCopied += OnDeviceDataCopied; _window.AtmosAlarmThresholdChanged += OnThresholdChanged; diff --git a/Content.Client/Atmos/Monitor/UI/AirAlarmWindow.xaml.cs b/Content.Client/Atmos/Monitor/UI/AirAlarmWindow.xaml.cs index 43be67c9d6b..eeec11c7660 100644 --- a/Content.Client/Atmos/Monitor/UI/AirAlarmWindow.xaml.cs +++ b/Content.Client/Atmos/Monitor/UI/AirAlarmWindow.xaml.cs @@ -47,7 +47,7 @@ public sealed partial class AirAlarmWindow : FancyWindow private CheckBox _autoMode => AutoModeCheckBox; - public AirAlarmWindow(BoundUserInterface owner) + public AirAlarmWindow() { RobustXamlLoader.Load(this); @@ -95,8 +95,11 @@ public AirAlarmWindow(BoundUserInterface owner) _sensors.Clear(); ResyncAllRequested!.Invoke(); }; + } - EntityView.SetEntity(owner.Owner); + public void SetEntity(EntityUid uid) + { + EntityView.SetEntity(uid); } public void UpdateState(AirAlarmUIState state) diff --git a/Content.Client/Atmos/UI/GasCanisterBoundUserInterface.cs b/Content.Client/Atmos/UI/GasCanisterBoundUserInterface.cs index a5e316a8def..7bf9b396d5e 100644 --- a/Content.Client/Atmos/UI/GasCanisterBoundUserInterface.cs +++ b/Content.Client/Atmos/UI/GasCanisterBoundUserInterface.cs @@ -1,6 +1,7 @@ using Content.Shared.Atmos.Piping.Binary.Components; using JetBrains.Annotations; using Robust.Client.GameObjects; +using Robust.Client.UserInterface; namespace Content.Client.Atmos.UI { @@ -21,14 +22,8 @@ protected override void Open() { base.Open(); - _window = new GasCanisterWindow(); + _window = this.CreateWindow(); - if (State != null) - UpdateState(State); - - _window.OpenCentered(); - - _window.OnClose += Close; _window.ReleaseValveCloseButtonPressed += OnReleaseValveClosePressed; _window.ReleaseValveOpenButtonPressed += OnReleaseValveOpenPressed; _window.ReleasePressureSet += OnReleasePressureSet; diff --git a/Content.Client/Atmos/UI/GasFilterBoundUserInterface.cs b/Content.Client/Atmos/UI/GasFilterBoundUserInterface.cs index 1904e2b3402..2b8020924cf 100644 --- a/Content.Client/Atmos/UI/GasFilterBoundUserInterface.cs +++ b/Content.Client/Atmos/UI/GasFilterBoundUserInterface.cs @@ -3,6 +3,7 @@ using Content.Shared.Atmos.Piping.Trinary.Components; using Content.Shared.Localizations; using JetBrains.Annotations; +using Robust.Client.UserInterface; namespace Content.Client.Atmos.UI { @@ -28,14 +29,8 @@ protected override void Open() var atmosSystem = EntMan.System(); - _window = new GasFilterWindow(atmosSystem.Gases); - - if (State != null) - UpdateState(State); - - _window.OpenCentered(); - - _window.OnClose += Close; + _window = this.CreateWindow(); + _window.PopulateGasList(atmosSystem.Gases); _window.ToggleStatusButtonPressed += OnToggleStatusButtonPressed; _window.FilterTransferRateChanged += OnFilterTransferRatePressed; diff --git a/Content.Client/Atmos/UI/GasFilterWindow.xaml.cs b/Content.Client/Atmos/UI/GasFilterWindow.xaml.cs index 28766c688a0..62748b52592 100644 --- a/Content.Client/Atmos/UI/GasFilterWindow.xaml.cs +++ b/Content.Client/Atmos/UI/GasFilterWindow.xaml.cs @@ -26,10 +26,9 @@ public sealed partial class GasFilterWindow : DefaultWindow public event Action? FilterTransferRateChanged; public event Action? SelectGasPressed; - public GasFilterWindow(IEnumerable gases) + public GasFilterWindow() { RobustXamlLoader.Load(this); - PopulateGasList(gases); ToggleStatusButton.OnPressed += _ => SetFilterStatus(!FilterStatus); ToggleStatusButton.OnPressed += _ => ToggleStatusButtonPressed?.Invoke(); @@ -73,7 +72,7 @@ public void SetGasFiltered(string? id, string name) SelectGasButton.Disabled = true; } - private void PopulateGasList(IEnumerable gases) + public void PopulateGasList(IEnumerable gases) { GasList.Add(new ItemList.Item(GasList) { @@ -81,7 +80,7 @@ private void PopulateGasList(IEnumerable gases) Text = Loc.GetString("comp-gas-filter-ui-filter-gas-none") }); - foreach (GasPrototype gas in gases) + foreach (var gas in gases) { var gasName = Loc.GetString(gas.Name); GasList.Add(GetGasItem(gas.ID, gasName, GasList)); diff --git a/Content.Client/Atmos/UI/GasMixerBoundUserInteface.cs b/Content.Client/Atmos/UI/GasMixerBoundUserInteface.cs index 709c06517cb..392fbf1cd9a 100644 --- a/Content.Client/Atmos/UI/GasMixerBoundUserInteface.cs +++ b/Content.Client/Atmos/UI/GasMixerBoundUserInteface.cs @@ -2,7 +2,7 @@ using Content.Shared.Atmos.Piping.Trinary.Components; using Content.Shared.Localizations; using JetBrains.Annotations; -using Robust.Client.GameObjects; +using Robust.Client.UserInterface; namespace Content.Client.Atmos.UI { @@ -26,14 +26,7 @@ protected override void Open() { base.Open(); - _window = new GasMixerWindow(); - - if (State != null) - UpdateState(State); - - _window.OpenCentered(); - - _window.OnClose += Close; + _window = this.CreateWindow(); _window.ToggleStatusButtonPressed += OnToggleStatusButtonPressed; _window.MixerOutputPressureChanged += OnMixerOutputPressurePressed; @@ -83,12 +76,5 @@ protected override void UpdateState(BoundUserInterfaceState state) _window.SetOutputPressure(cast.OutputPressure); _window.SetNodePercentages(cast.NodeOne); } - - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - if (!disposing) return; - _window?.Dispose(); - } } } diff --git a/Content.Client/Atmos/UI/GasPressurePumpBoundUserInterface.cs b/Content.Client/Atmos/UI/GasPressurePumpBoundUserInterface.cs index 6eba2e0d215..220fdbe875c 100644 --- a/Content.Client/Atmos/UI/GasPressurePumpBoundUserInterface.cs +++ b/Content.Client/Atmos/UI/GasPressurePumpBoundUserInterface.cs @@ -3,6 +3,7 @@ using Content.Shared.Localizations; using JetBrains.Annotations; using Robust.Client.GameObjects; +using Robust.Client.UserInterface; namespace Content.Client.Atmos.UI { @@ -26,14 +27,7 @@ protected override void Open() { base.Open(); - _window = new GasPressurePumpWindow(); - - if (State != null) - UpdateState(State); - - _window.OpenCentered(); - - _window.OnClose += Close; + _window = this.CreateWindow(); _window.ToggleStatusButtonPressed += OnToggleStatusButtonPressed; _window.PumpOutputPressureChanged += OnPumpOutputPressurePressed; @@ -67,12 +61,5 @@ protected override void UpdateState(BoundUserInterfaceState state) _window.SetPumpStatus(cast.Enabled); _window.SetOutputPressure(cast.OutputPressure); } - - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - if (!disposing) return; - _window?.Dispose(); - } } } diff --git a/Content.Client/Atmos/UI/GasThermomachineBoundUserInterface.cs b/Content.Client/Atmos/UI/GasThermomachineBoundUserInterface.cs index 1664c8b9d75..d62be8f4bb4 100644 --- a/Content.Client/Atmos/UI/GasThermomachineBoundUserInterface.cs +++ b/Content.Client/Atmos/UI/GasThermomachineBoundUserInterface.cs @@ -2,6 +2,7 @@ using Content.Shared.Atmos.Piping.Unary.Components; using JetBrains.Annotations; using Robust.Client.GameObjects; +using Robust.Client.UserInterface; namespace Content.Client.Atmos.UI { @@ -31,14 +32,7 @@ protected override void Open() { base.Open(); - _window = new GasThermomachineWindow(); - - if (State != null) - UpdateState(State); - - _window.OpenCentered(); - - _window.OnClose += Close; + _window = this.CreateWindow(); _window.ToggleStatusButton.OnPressed += _ => OnToggleStatusButtonPressed(); _window.TemperatureSpinbox.OnValueChanged += _ => OnTemperatureChanged(_window.TemperatureSpinbox.Value); @@ -91,12 +85,5 @@ protected override void UpdateState(BoundUserInterfaceState state) true => Loc.GetString("comp-gas-thermomachine-ui-title-heater") }; } - - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - if (!disposing) return; - _window?.Dispose(); - } } } diff --git a/Content.Client/Atmos/UI/GasVolumePumpBoundUserInterface.cs b/Content.Client/Atmos/UI/GasVolumePumpBoundUserInterface.cs index 1b39306181a..642f34c2f92 100644 --- a/Content.Client/Atmos/UI/GasVolumePumpBoundUserInterface.cs +++ b/Content.Client/Atmos/UI/GasVolumePumpBoundUserInterface.cs @@ -3,6 +3,7 @@ using Content.Shared.Localizations; using JetBrains.Annotations; using Robust.Client.GameObjects; +using Robust.Client.UserInterface; namespace Content.Client.Atmos.UI { @@ -26,14 +27,7 @@ protected override void Open() { base.Open(); - _window = new GasVolumePumpWindow(); - - if (State != null) - UpdateState(State); - - _window.OpenCentered(); - - _window.OnClose += Close; + _window = this.CreateWindow(); _window.ToggleStatusButtonPressed += OnToggleStatusButtonPressed; _window.PumpTransferRateChanged += OnPumpTransferRatePressed; @@ -64,16 +58,9 @@ protected override void UpdateState(BoundUserInterfaceState state) if (_window == null || state is not GasVolumePumpBoundUserInterfaceState cast) return; - _window.Title = (cast.PumpLabel); + _window.Title = cast.PumpLabel; _window.SetPumpStatus(cast.Enabled); _window.SetTransferRate(cast.TransferRate); } - - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - if (!disposing) return; - _window?.Dispose(); - } } } diff --git a/Content.Client/Atmos/UI/SpaceHeaterBoundUserInterface.cs b/Content.Client/Atmos/UI/SpaceHeaterBoundUserInterface.cs index 4d8d1191e91..e70426575d4 100644 --- a/Content.Client/Atmos/UI/SpaceHeaterBoundUserInterface.cs +++ b/Content.Client/Atmos/UI/SpaceHeaterBoundUserInterface.cs @@ -1,5 +1,6 @@ using Content.Shared.Atmos.Piping.Portable.Components; using JetBrains.Annotations; +using Robust.Client.UserInterface; using Robust.Client.UserInterface.Controls; namespace Content.Client.Atmos.UI; @@ -21,14 +22,7 @@ protected override void Open() { base.Open(); - _window = new SpaceHeaterWindow(); - - if (State != null) - UpdateState(State); - - _window.OpenCentered(); - - _window.OnClose += Close; + _window = this.CreateWindow(); _window.ToggleStatusButton.OnPressed += _ => OnToggleStatusButtonPressed(); _window.IncreaseTempRange.OnPressed += _ => OnTemperatureRangeChanged(_window.TemperatureChangeDelta); diff --git a/Content.Client/Audio/Jukebox/JukeboxBoundUserInterface.cs b/Content.Client/Audio/Jukebox/JukeboxBoundUserInterface.cs index 60fe339069a..865dfc478d0 100644 --- a/Content.Client/Audio/Jukebox/JukeboxBoundUserInterface.cs +++ b/Content.Client/Audio/Jukebox/JukeboxBoundUserInterface.cs @@ -1,8 +1,7 @@ using Content.Shared.Audio.Jukebox; using Robust.Client.Audio; -using Robust.Client.Player; +using Robust.Client.UserInterface; using Robust.Shared.Audio.Components; -using Robust.Shared.Player; using Robust.Shared.Prototypes; namespace Content.Client.Audio.Jukebox; @@ -23,9 +22,7 @@ protected override void Open() { base.Open(); - _menu = new JukeboxMenu(); - _menu.OnClose += Close; - _menu.OpenCentered(); + _menu = this.CreateWindow(); _menu.OnPlayPressed += args => { @@ -100,19 +97,5 @@ public void SetTime(float time) SendMessage(new JukeboxSetTimeMessage(sentTime)); } - - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - if (!disposing) - return; - - if (_menu == null) - return; - - _menu.OnClose -= Close; - _menu.Dispose(); - _menu = null; - } } diff --git a/Content.Client/Bed/Cryostorage/CryostorageBoundUserInterface.cs b/Content.Client/Bed/Cryostorage/CryostorageBoundUserInterface.cs index ffab1625483..09f3cec8fbf 100644 --- a/Content.Client/Bed/Cryostorage/CryostorageBoundUserInterface.cs +++ b/Content.Client/Bed/Cryostorage/CryostorageBoundUserInterface.cs @@ -1,5 +1,6 @@ using Content.Shared.Bed.Cryostorage; using JetBrains.Annotations; +using Robust.Client.UserInterface; namespace Content.Client.Bed.Cryostorage; @@ -17,9 +18,7 @@ protected override void Open() { base.Open(); - _menu = new(); - - _menu.OnClose += Close; + _menu = this.CreateWindow(); _menu.SlotRemoveButtonPressed += (ent, slot) => { @@ -30,8 +29,6 @@ protected override void Open() { SendMessage(new CryostorageRemoveItemBuiMessage(ent, hand, CryostorageRemoveItemBuiMessage.RemovalType.Hand)); }; - - _menu.OpenCentered(); } protected override void UpdateState(BoundUserInterfaceState state) @@ -45,12 +42,4 @@ protected override void UpdateState(BoundUserInterfaceState state) break; } } - - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - if (!disposing) - return; - _menu?.Dispose(); - } } diff --git a/Content.Client/Cargo/BUI/CargoBountyConsoleBoundUserInterface.cs b/Content.Client/Cargo/BUI/CargoBountyConsoleBoundUserInterface.cs index d3365702bcf..44c40143d83 100644 --- a/Content.Client/Cargo/BUI/CargoBountyConsoleBoundUserInterface.cs +++ b/Content.Client/Cargo/BUI/CargoBountyConsoleBoundUserInterface.cs @@ -1,6 +1,7 @@ using Content.Client.Cargo.UI; using Content.Shared.Cargo.Components; using JetBrains.Annotations; +using Robust.Client.UserInterface; namespace Content.Client.Cargo.BUI; @@ -18,9 +19,7 @@ protected override void Open() { base.Open(); - _menu = new(); - - _menu.OnClose += Close; + _menu = this.CreateWindow(); _menu.OnLabelButtonPressed += id => { @@ -31,8 +30,6 @@ protected override void Open() { SendMessage(new BountySkipMessage(id)); }; - - _menu.OpenCentered(); } protected override void UpdateState(BoundUserInterfaceState message) @@ -44,14 +41,4 @@ protected override void UpdateState(BoundUserInterfaceState message) _menu?.UpdateEntries(state.Bounties, state.UntilNextSkip); } - - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - - if (!disposing) - return; - - _menu?.Dispose(); - } } diff --git a/Content.Client/Cargo/BUI/CargoPalletConsoleBoundUserInterface.cs b/Content.Client/Cargo/BUI/CargoPalletConsoleBoundUserInterface.cs index 20c23a48a0d..2461dafb5f3 100644 --- a/Content.Client/Cargo/BUI/CargoPalletConsoleBoundUserInterface.cs +++ b/Content.Client/Cargo/BUI/CargoPalletConsoleBoundUserInterface.cs @@ -2,6 +2,7 @@ using Content.Shared.Cargo.BUI; using Content.Shared.Cargo.Events; using Robust.Client.GameObjects; +using Robust.Client.UserInterface; namespace Content.Client.Cargo.BUI; @@ -18,21 +19,9 @@ protected override void Open() { base.Open(); - _menu = new CargoPalletMenu(); + _menu = this.CreateWindow(); _menu.AppraiseRequested += OnAppraisal; _menu.SellRequested += OnSell; - _menu.OnClose += Close; - - _menu.OpenCentered(); - } - - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - if (disposing) - { - _menu?.Dispose(); - } } private void OnAppraisal() diff --git a/Content.Client/Cargo/BUI/CargoShuttleConsoleBoundUserInterface.cs b/Content.Client/Cargo/BUI/CargoShuttleConsoleBoundUserInterface.cs index 422d03707a0..02b721b9020 100644 --- a/Content.Client/Cargo/BUI/CargoShuttleConsoleBoundUserInterface.cs +++ b/Content.Client/Cargo/BUI/CargoShuttleConsoleBoundUserInterface.cs @@ -2,6 +2,7 @@ using Content.Shared.Cargo.BUI; using JetBrains.Annotations; using Robust.Client.GameObjects; +using Robust.Client.UserInterface; using Robust.Shared.Prototypes; namespace Content.Client.Cargo.BUI; @@ -9,6 +10,8 @@ namespace Content.Client.Cargo.BUI; [UsedImplicitly] public sealed class CargoShuttleConsoleBoundUserInterface : BoundUserInterface { + [Dependency] private readonly IPrototypeManager _protoManager = default!; + [ViewVariables] private CargoShuttleMenu? _menu; @@ -19,24 +22,7 @@ public CargoShuttleConsoleBoundUserInterface(EntityUid owner, Enum uiKey) : base protected override void Open() { base.Open(); - var collection = IoCManager.Instance; - - if (collection == null) - return; - - _menu = new CargoShuttleMenu(collection.Resolve(), collection.Resolve().GetEntitySystem()); - _menu.OnClose += Close; - - _menu.OpenCentered(); - } - - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - if (disposing) - { - _menu?.Dispose(); - } + _menu = this.CreateWindow(); } protected override void UpdateState(BoundUserInterfaceState state) @@ -45,6 +31,6 @@ protected override void UpdateState(BoundUserInterfaceState state) if (state is not CargoShuttleConsoleBoundUserInterfaceState cargoState) return; _menu?.SetAccountName(cargoState.AccountName); _menu?.SetShuttleName(cargoState.ShuttleName); - _menu?.SetOrders(cargoState.Orders); + _menu?.SetOrders(EntMan.System(), _protoManager, cargoState.Orders); } } diff --git a/Content.Client/Cargo/UI/CargoShuttleMenu.xaml.cs b/Content.Client/Cargo/UI/CargoShuttleMenu.xaml.cs index c591f917da3..43b00089e16 100644 --- a/Content.Client/Cargo/UI/CargoShuttleMenu.xaml.cs +++ b/Content.Client/Cargo/UI/CargoShuttleMenu.xaml.cs @@ -12,14 +12,9 @@ namespace Content.Client.Cargo.UI [GenerateTypedNameReferences] public sealed partial class CargoShuttleMenu : FancyWindow { - private readonly IPrototypeManager _protoManager; - private readonly SpriteSystem _spriteSystem; - - public CargoShuttleMenu(IPrototypeManager protoManager, SpriteSystem spriteSystem) + public CargoShuttleMenu() { RobustXamlLoader.Load(this); - _protoManager = protoManager; - _spriteSystem = spriteSystem; Title = Loc.GetString("cargo-shuttle-console-menu-title"); } @@ -33,19 +28,19 @@ public void SetShuttleName(string name) ShuttleNameLabel.Text = name; } - public void SetOrders(List orders) + public void SetOrders(SpriteSystem sprites, IPrototypeManager protoManager, List orders) { Orders.DisposeAllChildren(); foreach (var order in orders) { - var product = _protoManager.Index(order.ProductId); + var product = protoManager.Index(order.ProductId); var productName = product.Name; var row = new CargoOrderRow { Order = order, - Icon = { Texture = _spriteSystem.Frame0(product) }, + Icon = { Texture = sprites.Frame0(product) }, ProductName = { Text = Loc.GetString( diff --git a/Content.Client/Chemistry/UI/ChemMasterBoundUserInterface.cs b/Content.Client/Chemistry/UI/ChemMasterBoundUserInterface.cs index 988fea7978b..3ef7f0ae73e 100644 --- a/Content.Client/Chemistry/UI/ChemMasterBoundUserInterface.cs +++ b/Content.Client/Chemistry/UI/ChemMasterBoundUserInterface.cs @@ -2,6 +2,7 @@ using Content.Shared.Containers.ItemSlots; using JetBrains.Annotations; using Robust.Client.GameObjects; +using Robust.Client.UserInterface; namespace Content.Client.Chemistry.UI { @@ -27,13 +28,8 @@ protected override void Open() base.Open(); // Setup window layout/elements - _window = new ChemMasterWindow - { - Title = EntMan.GetComponent(Owner).EntityName, - }; - - _window.OpenCentered(); - _window.OnClose += Close; + _window = this.CreateWindow(); + _window.Title = EntMan.GetComponent(Owner).EntityName; // Setup static button actions. _window.InputEjectButton.OnPressed += _ => SendMessage( @@ -75,15 +71,5 @@ protected override void UpdateState(BoundUserInterfaceState state) _window?.UpdateState(castState); // Update window state } - - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - - if (disposing) - { - _window?.Dispose(); - } - } } } diff --git a/Content.Client/Chemistry/UI/ReagentDispenserBoundUserInterface.cs b/Content.Client/Chemistry/UI/ReagentDispenserBoundUserInterface.cs index 99e5a3d3953..2ad1b718887 100644 --- a/Content.Client/Chemistry/UI/ReagentDispenserBoundUserInterface.cs +++ b/Content.Client/Chemistry/UI/ReagentDispenserBoundUserInterface.cs @@ -3,6 +3,7 @@ using Content.Shared.Containers.ItemSlots; using JetBrains.Annotations; using Robust.Client.GameObjects; +using Robust.Client.UserInterface; namespace Content.Client.Chemistry.UI { @@ -15,9 +16,6 @@ public sealed class ReagentDispenserBoundUserInterface : BoundUserInterface [ViewVariables] private ReagentDispenserWindow? _window; - [ViewVariables] - private ReagentDispenserBoundUserInterfaceState? _lastState; - public ReagentDispenserBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey) { } @@ -32,14 +30,9 @@ protected override void Open() base.Open(); // Setup window layout/elements - _window = new() - { - Title = EntMan.GetComponent(Owner).EntityName, - HelpGuidebookIds = EntMan.GetComponent(Owner).Guides - }; - - _window.OpenCentered(); - _window.OnClose += Close; + _window = this.CreateWindow(); + _window.Title = EntMan.GetComponent(Owner).EntityName; + _window.HelpGuidebookIds = EntMan.GetComponent(Owner).Guides; // Setup static button actions. _window.EjectButton.OnPressed += _ => SendMessage(new ItemSlotButtonPressedEvent(SharedReagentDispenser.OutputSlotName)); @@ -63,19 +56,7 @@ protected override void UpdateState(BoundUserInterfaceState state) base.UpdateState(state); var castState = (ReagentDispenserBoundUserInterfaceState) state; - _lastState = castState; - _window?.UpdateState(castState); //Update window state } - - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - - if (disposing) - { - _window?.Dispose(); - } - } } } diff --git a/Content.Client/Chemistry/UI/TransferAmountBoundUserInterface.cs b/Content.Client/Chemistry/UI/TransferAmountBoundUserInterface.cs index 35df131312d..f1cb27a62a4 100644 --- a/Content.Client/Chemistry/UI/TransferAmountBoundUserInterface.cs +++ b/Content.Client/Chemistry/UI/TransferAmountBoundUserInterface.cs @@ -2,6 +2,7 @@ using Content.Shared.FixedPoint; using JetBrains.Annotations; using Robust.Client.GameObjects; +using Robust.Client.UserInterface; namespace Content.Client.Chemistry.UI { @@ -18,7 +19,7 @@ public TransferAmountBoundUserInterface(EntityUid owner, Enum uiKey) : base(owne protected override void Open() { base.Open(); - _window = new TransferAmountWindow(); + _window = this.CreateWindow(); _window.ApplyButton.OnPressed += _ => { @@ -28,15 +29,6 @@ protected override void Open() _window.Close(); } }; - _window.OnClose += Close; - _window.OpenCentered(); - } - - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - if (!disposing) return; - _window?.Dispose(); } } } diff --git a/Content.Client/CloningConsole/UI/CloningConsoleBoundUserInterface.cs b/Content.Client/CloningConsole/UI/CloningConsoleBoundUserInterface.cs index 26f0994701e..62a02f37186 100644 --- a/Content.Client/CloningConsole/UI/CloningConsoleBoundUserInterface.cs +++ b/Content.Client/CloningConsole/UI/CloningConsoleBoundUserInterface.cs @@ -1,6 +1,7 @@ using JetBrains.Annotations; using Robust.Client.GameObjects; using Content.Shared.Cloning.CloningConsole; +using Robust.Client.UserInterface; namespace Content.Client.CloningConsole.UI { @@ -17,13 +18,11 @@ public CloningConsoleBoundUserInterface(EntityUid owner, Enum uiKey) : base(owne protected override void Open() { base.Open(); - _window = new CloningConsoleWindow - { - Title = Loc.GetString("cloning-console-window-title") - }; - _window.OnClose += Close; + + _window = this.CreateWindow(); + _window.Title = Loc.GetString("cloning-console-window-title"); + _window.CloneButton.OnPressed += _ => SendMessage(new UiButtonPressedMessage(UiButton.Clone)); - _window.OpenCentered(); } protected override void UpdateState(BoundUserInterfaceState state) @@ -32,19 +31,5 @@ protected override void UpdateState(BoundUserInterfaceState state) _window?.Populate((CloningConsoleBoundUserInterfaceState) state); } - - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - if (!disposing) - return; - - if (_window != null) - { - _window.OnClose -= Close; - _window.CloneButton.OnPressed -= _ => SendMessage(new UiButtonPressedMessage(UiButton.Clone)); - } - _window?.Dispose(); - } } } diff --git a/Content.Client/Clothing/UI/ChameleonBoundUserInterface.cs b/Content.Client/Clothing/UI/ChameleonBoundUserInterface.cs index 5b0d5fcf21f..83f6ba15662 100644 --- a/Content.Client/Clothing/UI/ChameleonBoundUserInterface.cs +++ b/Content.Client/Clothing/UI/ChameleonBoundUserInterface.cs @@ -2,6 +2,7 @@ using Content.Shared.Clothing.Components; using JetBrains.Annotations; using Robust.Client.GameObjects; +using Robust.Client.UserInterface; namespace Content.Client.Clothing.UI; @@ -22,10 +23,8 @@ protected override void Open() { base.Open(); - _menu = new ChameleonMenu(); - _menu.OnClose += Close; + _menu = this.CreateWindow(); _menu.OnIdSelected += OnIdSelected; - _menu.OpenCentered(); } protected override void UpdateState(BoundUserInterfaceState state) @@ -42,15 +41,4 @@ private void OnIdSelected(string selectedId) { SendMessage(new ChameleonPrototypeSelectedMessage(selectedId)); } - - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - - if (disposing) - { - _menu?.Close(); - _menu = null; - } - } } diff --git a/Content.Client/Communications/UI/CommunicationsConsoleBoundUserInterface.cs b/Content.Client/Communications/UI/CommunicationsConsoleBoundUserInterface.cs index 1c94d32bf8d..0310e91eeb0 100644 --- a/Content.Client/Communications/UI/CommunicationsConsoleBoundUserInterface.cs +++ b/Content.Client/Communications/UI/CommunicationsConsoleBoundUserInterface.cs @@ -1,6 +1,7 @@ using Content.Shared.CCVar; using Content.Shared.Chat; using Content.Shared.Communications; +using Robust.Client.UserInterface; using Robust.Shared.Configuration; using Robust.Shared.Timing; @@ -8,34 +9,11 @@ namespace Content.Client.Communications.UI { public sealed class CommunicationsConsoleBoundUserInterface : BoundUserInterface { - [Dependency] private readonly IGameTiming _gameTiming = default!; [Dependency] private readonly IConfigurationManager _cfg = default!; [ViewVariables] private CommunicationsConsoleMenu? _menu; - [ViewVariables] - public bool CanAnnounce { get; private set; } - [ViewVariables] - public bool CanBroadcast { get; private set; } - - [ViewVariables] - public bool CanCall { get; private set; } - - [ViewVariables] - public bool CountdownStarted { get; private set; } - - [ViewVariables] - public bool AlertLevelSelectable { get; private set; } - - [ViewVariables] - public string CurrentLevel { get; private set; } = default!; - - [ViewVariables] - private TimeSpan? _expectedCountdownTime; - - public int Countdown => _expectedCountdownTime == null ? 0 : Math.Max((int) _expectedCountdownTime.Value.Subtract(_gameTiming.CurTime).TotalSeconds, 0); - public CommunicationsConsoleBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey) { } @@ -44,23 +22,25 @@ protected override void Open() { base.Open(); - _menu = new CommunicationsConsoleMenu(this); - _menu.OnClose += Close; - _menu.OpenCentered(); + _menu = this.CreateWindow(); + _menu.OnAnnounce += AnnounceButtonPressed; + _menu.OnBroadcast += BroadcastButtonPressed; + _menu.OnAlertLevel += AlertLevelSelected; + _menu.OnEmergencyLevel += EmergencyShuttleButtonPressed; } public void AlertLevelSelected(string level) { - if (AlertLevelSelectable) + if (_menu!.AlertLevelSelectable) { - CurrentLevel = level; + _menu.CurrentLevel = level; SendMessage(new CommunicationsConsoleSelectAlertLevelMessage(level)); } } public void EmergencyShuttleButtonPressed() { - if (CountdownStarted) + if (_menu!.CountdownStarted) RecallShuttle(); else CallShuttle(); @@ -95,31 +75,23 @@ protected override void UpdateState(BoundUserInterfaceState state) if (state is not CommunicationsConsoleInterfaceState commsState) return; - CanAnnounce = commsState.CanAnnounce; - CanBroadcast = commsState.CanBroadcast; - CanCall = commsState.CanCall; - _expectedCountdownTime = commsState.ExpectedCountdownEnd; - CountdownStarted = commsState.CountdownStarted; - AlertLevelSelectable = commsState.AlertLevels != null && !float.IsNaN(commsState.CurrentAlertDelay) && commsState.CurrentAlertDelay <= 0; - CurrentLevel = commsState.CurrentAlert; - if (_menu != null) { + _menu.CanAnnounce = commsState.CanAnnounce; + _menu.CanBroadcast = commsState.CanBroadcast; + _menu.CanCall = commsState.CanCall; + _menu.CountdownStarted = commsState.CountdownStarted; + _menu.AlertLevelSelectable = commsState.AlertLevels != null && !float.IsNaN(commsState.CurrentAlertDelay) && commsState.CurrentAlertDelay <= 0; + _menu.CurrentLevel = commsState.CurrentAlert; + _menu.CountdownEnd = commsState.ExpectedCountdownEnd; + _menu.UpdateCountdown(); - _menu.UpdateAlertLevels(commsState.AlertLevels, CurrentLevel); - _menu.AlertLevelButton.Disabled = !AlertLevelSelectable; - _menu.EmergencyShuttleButton.Disabled = !CanCall; - _menu.AnnounceButton.Disabled = !CanAnnounce; - _menu.BroadcastButton.Disabled = !CanBroadcast; + _menu.UpdateAlertLevels(commsState.AlertLevels, _menu.CurrentLevel); + _menu.AlertLevelButton.Disabled = !_menu.AlertLevelSelectable; + _menu.EmergencyShuttleButton.Disabled = !_menu.CanCall; + _menu.AnnounceButton.Disabled = !_menu.CanAnnounce; + _menu.BroadcastButton.Disabled = !_menu.CanBroadcast; } } - - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - if (!disposing) return; - - _menu?.Dispose(); - } } } diff --git a/Content.Client/Communications/UI/CommunicationsConsoleMenu.xaml.cs b/Content.Client/Communications/UI/CommunicationsConsoleMenu.xaml.cs index bbca06f5194..63868e7a93e 100644 --- a/Content.Client/Communications/UI/CommunicationsConsoleMenu.xaml.cs +++ b/Content.Client/Communications/UI/CommunicationsConsoleMenu.xaml.cs @@ -1,31 +1,40 @@ -using Content.Client.UserInterface.Controls; -using System.Threading; +using System.Globalization; +using Content.Client.UserInterface.Controls; using Content.Shared.CCVar; using Robust.Client.AutoGenerated; using Robust.Client.UserInterface.XAML; using Robust.Shared.Configuration; +using Robust.Shared.Timing; using Robust.Shared.Utility; -using Timer = Robust.Shared.Timing.Timer; namespace Content.Client.Communications.UI { [GenerateTypedNameReferences] public sealed partial class CommunicationsConsoleMenu : FancyWindow { - private CommunicationsConsoleBoundUserInterface Owner { get; set; } - private readonly CancellationTokenSource _timerCancelTokenSource = new(); - [Dependency] private readonly IConfigurationManager _cfg = default!; - - public CommunicationsConsoleMenu(CommunicationsConsoleBoundUserInterface owner) + [Dependency] private readonly IGameTiming _timing = default!; + [Dependency] private readonly ILocalizationManager _loc = default!; + + public bool CanAnnounce; + public bool CanBroadcast; + public bool CanCall; + public bool AlertLevelSelectable; + public bool CountdownStarted; + public string CurrentLevel = string.Empty; + public TimeSpan? CountdownEnd; + + public event Action? OnEmergencyLevel; + public event Action? OnAlertLevel; + public event Action? OnAnnounce; + public event Action? OnBroadcast; + + public CommunicationsConsoleMenu() { IoCManager.InjectDependencies(this); RobustXamlLoader.Load(this); - Owner = owner; - - var loc = IoCManager.Resolve(); - MessageInput.Placeholder = new Rope.Leaf(loc.GetString("comms-console-menu-announcement-placeholder")); + MessageInput.Placeholder = new Rope.Leaf(_loc.GetString("comms-console-menu-announcement-placeholder")); var maxAnnounceLength = _cfg.GetCVar(CCVars.ChatMaxAnnouncementLength); MessageInput.OnTextChanged += (args) => @@ -37,33 +46,38 @@ public CommunicationsConsoleMenu(CommunicationsConsoleBoundUserInterface owner) } else { - AnnounceButton.Disabled = !owner.CanAnnounce; + AnnounceButton.Disabled = !CanAnnounce; AnnounceButton.ToolTip = null; } }; - AnnounceButton.OnPressed += (_) => Owner.AnnounceButtonPressed(Rope.Collapse(MessageInput.TextRope)); - AnnounceButton.Disabled = !owner.CanAnnounce; + AnnounceButton.OnPressed += _ => OnAnnounce?.Invoke(Rope.Collapse(MessageInput.TextRope)); + AnnounceButton.Disabled = !CanAnnounce; - BroadcastButton.OnPressed += (_) => Owner.BroadcastButtonPressed(Rope.Collapse(MessageInput.TextRope)); - BroadcastButton.Disabled = !owner.CanBroadcast; + BroadcastButton.OnPressed += _ => OnBroadcast?.Invoke(Rope.Collapse(MessageInput.TextRope)); + BroadcastButton.Disabled = !CanBroadcast; AlertLevelButton.OnItemSelected += args => { var metadata = AlertLevelButton.GetItemMetadata(args.Id); if (metadata != null && metadata is string cast) { - Owner.AlertLevelSelected(cast); + OnAlertLevel?.Invoke(cast); } }; - AlertLevelButton.Disabled = !owner.AlertLevelSelectable; - EmergencyShuttleButton.OnPressed += (_) => Owner.EmergencyShuttleButtonPressed(); - EmergencyShuttleButton.Disabled = !owner.CanCall; + AlertLevelButton.Disabled = !AlertLevelSelectable; + + EmergencyShuttleButton.OnPressed += _ => OnEmergencyLevel?.Invoke(); + EmergencyShuttleButton.Disabled = !CanCall; + } + + protected override void FrameUpdate(FrameEventArgs args) + { + base.FrameUpdate(args); UpdateCountdown(); - Timer.SpawnRepeating(1000, UpdateCountdown, _timerCancelTokenSource.Token); } // The current alert could make levels unselectable, so we need to ensure that the UI reacts properly. @@ -105,32 +119,19 @@ public void UpdateAlertLevels(List? alerts, string currentAlert) public void UpdateCountdown() { - if (!Owner.CountdownStarted) + if (!CountdownStarted) { - CountdownLabel.SetMessage(""); + CountdownLabel.SetMessage(string.Empty); EmergencyShuttleButton.Text = Loc.GetString("comms-console-menu-call-shuttle"); return; } + var diff = MathHelper.Max((CountdownEnd - _timing.CurTime) ?? TimeSpan.Zero, TimeSpan.Zero); + EmergencyShuttleButton.Text = Loc.GetString("comms-console-menu-recall-shuttle"); var infoText = Loc.GetString($"comms-console-menu-time-remaining", - ("time", Owner.Countdown.ToString())); + ("time", diff.TotalSeconds.ToString(CultureInfo.CurrentCulture))); CountdownLabel.SetMessage(infoText); } - - public override void Close() - { - base.Close(); - - _timerCancelTokenSource.Cancel(); - } - - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - - if (disposing) - _timerCancelTokenSource.Cancel(); - } } } diff --git a/Content.Client/Computer/ComputerBoundUserInterface.cs b/Content.Client/Computer/ComputerBoundUserInterface.cs index bdbfe03fa10..11c26b252e9 100644 --- a/Content.Client/Computer/ComputerBoundUserInterface.cs +++ b/Content.Client/Computer/ComputerBoundUserInterface.cs @@ -1,4 +1,5 @@ using Robust.Client.GameObjects; +using Robust.Client.UserInterface; using Robust.Client.UserInterface.CustomControls; namespace Content.Client.Computer @@ -19,10 +20,8 @@ protected override void Open() { base.Open(); - _window = (TWindow) _dynamicTypeFactory.CreateInstance(typeof(TWindow)); + _window = this.CreateWindow(); _window.SetupComputerWindow(this); - _window.OnClose += Close; - _window.OpenCentered(); } // Alas, this constructor has to be copied to the subclass. :( @@ -42,16 +41,6 @@ protected override void UpdateState(BoundUserInterfaceState state) _window.UpdateState((TState) state); } - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - - if (disposing) - { - _window?.Dispose(); - } - } - protected override void ReceiveMessage(BoundUserInterfaceMessage message) { _window?.ReceiveMessage(message); diff --git a/Content.Client/Configurable/UI/ConfigurationBoundUserInterface.cs b/Content.Client/Configurable/UI/ConfigurationBoundUserInterface.cs index 4fea44f2253..e4966f1ec43 100644 --- a/Content.Client/Configurable/UI/ConfigurationBoundUserInterface.cs +++ b/Content.Client/Configurable/UI/ConfigurationBoundUserInterface.cs @@ -1,5 +1,6 @@ using System.Text.RegularExpressions; using Robust.Client.GameObjects; +using Robust.Client.UserInterface; using static Content.Shared.Configurable.ConfigurationComponent; namespace Content.Client.Configurable.UI @@ -9,9 +10,6 @@ public sealed class ConfigurationBoundUserInterface : BoundUserInterface [ViewVariables] private ConfigurationMenu? _menu; - [ViewVariables] - public Regex? Validation { get; internal set; } - public ConfigurationBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey) { } @@ -19,10 +17,8 @@ public ConfigurationBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner protected override void Open() { base.Open(); - _menu = new ConfigurationMenu(this); - - _menu.OnClose += Close; - _menu.OpenCentered(); + _menu = this.CreateWindow(); + _menu.OnConfiguration += SendConfiguration; } protected override void UpdateState(BoundUserInterfaceState state) @@ -30,9 +26,7 @@ protected override void UpdateState(BoundUserInterfaceState state) base.UpdateState(state); if (state is not ConfigurationBoundUserInterfaceState configurationState) - { return; - } _menu?.Populate(configurationState); } @@ -41,9 +35,12 @@ protected override void ReceiveMessage(BoundUserInterfaceMessage message) { base.ReceiveMessage(message); + if (_menu == null) + return; + if (message is ValidationUpdateMessage msg) { - Validation = new Regex(msg.ValidationString, RegexOptions.Compiled); + _menu.Validation = new Regex(msg.ValidationString, RegexOptions.Compiled); } } @@ -51,16 +48,5 @@ public void SendConfiguration(Dictionary config) { SendMessage(new ConfigurationUpdatedMessage(config)); } - - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - - if (disposing && _menu != null) - { - _menu.OnClose -= Close; - _menu.Close(); - } - } } } diff --git a/Content.Client/Configurable/UI/ConfigurationMenu.cs b/Content.Client/Configurable/UI/ConfigurationMenu.cs index cc24af28692..29217eef7be 100644 --- a/Content.Client/Configurable/UI/ConfigurationMenu.cs +++ b/Content.Client/Configurable/UI/ConfigurationMenu.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using System.Numerics; +using System.Text.RegularExpressions; using Robust.Client.UserInterface; using Robust.Client.UserInterface.Controls; using Robust.Client.UserInterface.CustomControls; @@ -13,23 +14,25 @@ namespace Content.Client.Configurable.UI { public sealed class ConfigurationMenu : DefaultWindow { - public ConfigurationBoundUserInterface Owner { get; } - private readonly BoxContainer _column; private readonly BoxContainer _row; private readonly List<(string name, LineEdit input)> _inputs; - public ConfigurationMenu(ConfigurationBoundUserInterface owner) + [ViewVariables] + public Regex? Validation { get; internal set; } + + public event Action>? OnConfiguration; + + public ConfigurationMenu() { MinSize = SetSize = new Vector2(300, 250); - Owner = owner; _inputs = new List<(string name, LineEdit input)>(); Title = Loc.GetString("configuration-menu-device-title"); - BoxContainer baseContainer = new BoxContainer + var baseContainer = new BoxContainer { Orientation = LayoutOrientation.Vertical, VerticalExpand = true, @@ -116,14 +119,13 @@ public void Populate(ConfigurationBoundUserInterfaceState state) private void OnConfirm(ButtonEventArgs args) { var config = GenerateDictionary(_inputs, "Text"); - - Owner.SendConfiguration(config); + OnConfiguration?.Invoke(config); Close(); } private bool Validate(string value) { - return Owner.Validation == null || Owner.Validation.IsMatch(value); + return Validation?.IsMatch(value) != false; } private Dictionary GenerateDictionary(IEnumerable<(string name, LineEdit input)> inputs, string propertyName) diff --git a/Content.Client/Construction/UI/FlatpackCreatorBoundUserInterface.cs b/Content.Client/Construction/UI/FlatpackCreatorBoundUserInterface.cs index 86f1b8b83c7..887492955e9 100644 --- a/Content.Client/Construction/UI/FlatpackCreatorBoundUserInterface.cs +++ b/Content.Client/Construction/UI/FlatpackCreatorBoundUserInterface.cs @@ -1,5 +1,6 @@ using Content.Shared.Construction.Components; using JetBrains.Annotations; +using Robust.Client.UserInterface; namespace Content.Client.Construction.UI { @@ -17,8 +18,8 @@ protected override void Open() { base.Open(); - _menu = new FlatpackCreatorMenu(Owner); - _menu.OnClose += Close; + _menu = this.CreateWindow(); + _menu.SetEntity(Owner); _menu.PackButtonPressed += () => { @@ -27,14 +28,5 @@ protected override void Open() _menu.OpenCentered(); } - - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - if (!disposing) - return; - - _menu?.Dispose(); - } } } diff --git a/Content.Client/Construction/UI/FlatpackCreatorMenu.xaml.cs b/Content.Client/Construction/UI/FlatpackCreatorMenu.xaml.cs index 00261632378..2a386a03de6 100644 --- a/Content.Client/Construction/UI/FlatpackCreatorMenu.xaml.cs +++ b/Content.Client/Construction/UI/FlatpackCreatorMenu.xaml.cs @@ -25,7 +25,7 @@ public sealed partial class FlatpackCreatorMenu : FancyWindow private readonly MaterialStorageSystem _materialStorage; private readonly SpriteSystem _spriteSystem; - private readonly EntityUid _owner; + private EntityUid _owner; [ValidatePrototypeId] public const string NoBoardEffectId = "FlatpackerNoBoardEffect"; @@ -35,7 +35,7 @@ public sealed partial class FlatpackCreatorMenu : FancyWindow public event Action? PackButtonPressed; - public FlatpackCreatorMenu(EntityUid uid) + public FlatpackCreatorMenu() { RobustXamlLoader.Load(this); IoCManager.InjectDependencies(this); @@ -45,14 +45,17 @@ public FlatpackCreatorMenu(EntityUid uid) _materialStorage = _entityManager.System(); _spriteSystem = _entityManager.System(); - _owner = uid; - PackButton.OnPressed += _ => PackButtonPressed?.Invoke(); - MaterialStorageControl.SetOwner(uid); InsertLabel.SetMarkup(Loc.GetString("flatpacker-ui-insert-board")); } + public void SetEntity(EntityUid uid) + { + _owner = uid; + MaterialStorageControl.SetOwner(uid); + } + protected override void FrameUpdate(FrameEventArgs args) { base.FrameUpdate(args); diff --git a/Content.Client/Crayon/UI/CrayonBoundUserInterface.cs b/Content.Client/Crayon/UI/CrayonBoundUserInterface.cs index e2c4d51ecd1..e5be0b1811f 100644 --- a/Content.Client/Crayon/UI/CrayonBoundUserInterface.cs +++ b/Content.Client/Crayon/UI/CrayonBoundUserInterface.cs @@ -2,12 +2,15 @@ using Content.Shared.Crayon; using Content.Shared.Decals; using Robust.Client.GameObjects; +using Robust.Client.UserInterface; using Robust.Shared.Prototypes; namespace Content.Client.Crayon.UI { public sealed class CrayonBoundUserInterface : BoundUserInterface { + [Dependency] private readonly IPrototypeManager _protoManager = default!; + [ViewVariables] private CrayonWindow? _menu; @@ -18,15 +21,29 @@ public CrayonBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey protected override void Open() { base.Open(); - _menu = new CrayonWindow(this); - - _menu.OnClose += Close; - var prototypeManager = IoCManager.Resolve(); - var crayonDecals = prototypeManager.EnumeratePrototypes().Where(x => x.Tags.Contains("crayon")); - _menu.Populate(crayonDecals); + _menu = this.CreateWindow(); + _menu.OnColorSelected += SelectColor; + _menu.OnSelected += Select; + PopulateCrayons(); _menu.OpenCenteredLeft(); } + private void PopulateCrayons() + { + var crayonDecals = _protoManager.EnumeratePrototypes().Where(x => x.Tags.Contains("crayon")); + _menu?.Populate(crayonDecals); + } + + public override void OnProtoReload(PrototypesReloadedEventArgs args) + { + base.OnProtoReload(args); + + if (!args.WasModified()) + return; + + PopulateCrayons(); + } + protected override void UpdateState(BoundUserInterfaceState state) { base.UpdateState(state); @@ -43,16 +60,5 @@ public void SelectColor(Color color) { SendMessage(new CrayonColorMessage(color)); } - - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - - if (disposing) - { - _menu?.Close(); - _menu = null; - } - } } } diff --git a/Content.Client/Crayon/UI/CrayonWindow.xaml.cs b/Content.Client/Crayon/UI/CrayonWindow.xaml.cs index 2a5801ccf2d..b97786cd41a 100644 --- a/Content.Client/Crayon/UI/CrayonWindow.xaml.cs +++ b/Content.Client/Crayon/UI/CrayonWindow.xaml.cs @@ -18,18 +18,17 @@ namespace Content.Client.Crayon.UI [GenerateTypedNameReferences] public sealed partial class CrayonWindow : DefaultWindow { - public CrayonBoundUserInterface Owner { get; } - private Dictionary? _decals; private string? _selected; private Color _color; - public CrayonWindow(CrayonBoundUserInterface owner) + public event Action? OnColorSelected; + public event Action? OnSelected; + + public CrayonWindow() { RobustXamlLoader.Load(this); - Owner = owner; - Search.OnTextChanged += _ => RefreshList(); ColorSelector.OnColorChanged += SelectColor; } @@ -38,16 +37,16 @@ private void SelectColor(Color color) { _color = color; - Owner.SelectColor(color); - + OnColorSelected?.Invoke(color); RefreshList(); } private void RefreshList() { // Clear - Grid.RemoveAllChildren(); - if (_decals == null) return; + Grid.DisposeAllChildren(); + if (_decals == null) + return; var filter = Search.Text; foreach (var (decal, tex) in _decals) @@ -89,7 +88,6 @@ private void ButtonOnPressed(ButtonEventArgs obj) { if (obj.Button.Name == null) return; - Owner.Select(obj.Button.Name); _selected = obj.Button.Name; RefreshList(); } diff --git a/Content.Client/Disposal/UI/DisposalRouterBoundUserInterface.cs b/Content.Client/Disposal/UI/DisposalRouterBoundUserInterface.cs index e8e77217ea5..296e71d3a95 100644 --- a/Content.Client/Disposal/UI/DisposalRouterBoundUserInterface.cs +++ b/Content.Client/Disposal/UI/DisposalRouterBoundUserInterface.cs @@ -1,5 +1,6 @@ using JetBrains.Annotations; using Robust.Client.GameObjects; +using Robust.Client.UserInterface; using static Content.Shared.Disposal.Components.SharedDisposalRouterComponent; namespace Content.Client.Disposal.UI @@ -21,20 +22,16 @@ protected override void Open() { base.Open(); - _window = new DisposalRouterWindow(); - - _window.OpenCentered(); - _window.OnClose += Close; + _window = this.CreateWindow(); _window.Confirm.OnPressed += _ => ButtonPressed(UiAction.Ok, _window.TagInput.Text); _window.TagInput.OnTextEntered += args => ButtonPressed(UiAction.Ok, args.Text); - } private void ButtonPressed(UiAction action, string tag) { SendMessage(new UiActionMessage(action, tag)); - _window?.Close(); + Close(); } protected override void UpdateState(BoundUserInterfaceState state) @@ -48,18 +45,5 @@ protected override void UpdateState(BoundUserInterfaceState state) _window?.UpdateState(cast); } - - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - - if (disposing) - { - _window?.Dispose(); - } - } - - } - } diff --git a/Content.Client/Disposal/UI/DisposalTaggerBoundUserInterface.cs b/Content.Client/Disposal/UI/DisposalTaggerBoundUserInterface.cs index 3aeed8dc802..7fc0eb85401 100644 --- a/Content.Client/Disposal/UI/DisposalTaggerBoundUserInterface.cs +++ b/Content.Client/Disposal/UI/DisposalTaggerBoundUserInterface.cs @@ -1,5 +1,6 @@ using JetBrains.Annotations; using Robust.Client.GameObjects; +using Robust.Client.UserInterface; using static Content.Shared.Disposal.Components.SharedDisposalTaggerComponent; namespace Content.Client.Disposal.UI @@ -21,20 +22,17 @@ protected override void Open() { base.Open(); - _window = new DisposalTaggerWindow(); - - _window.OpenCentered(); - _window.OnClose += Close; + _window = this.CreateWindow(); _window.Confirm.OnPressed += _ => ButtonPressed(UiAction.Ok, _window.TagInput.Text); _window.TagInput.OnTextEntered += args => ButtonPressed(UiAction.Ok, args.Text); - } private void ButtonPressed(UiAction action, string tag) { + // TODO: This looks copy-pasted with the other mailing stuff... SendMessage(new UiActionMessage(action, tag)); - _window?.Close(); + Close(); } protected override void UpdateState(BoundUserInterfaceState state) @@ -48,18 +46,5 @@ protected override void UpdateState(BoundUserInterfaceState state) _window?.UpdateState(cast); } - - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - - if (disposing) - { - _window?.Dispose(); - } - } - - } - } diff --git a/Content.Client/Doors/Electronics/DoorElectronicsBoundUserInterface.cs b/Content.Client/Doors/Electronics/DoorElectronicsBoundUserInterface.cs index cd7ea717ce3..9b7e23c03aa 100644 --- a/Content.Client/Doors/Electronics/DoorElectronicsBoundUserInterface.cs +++ b/Content.Client/Doors/Electronics/DoorElectronicsBoundUserInterface.cs @@ -1,6 +1,7 @@ using Content.Shared.Access; using Content.Shared.Doors.Electronics; using Robust.Client.GameObjects; +using Robust.Client.UserInterface; using Robust.Shared.Prototypes; namespace Content.Client.Doors.Electronics; @@ -18,6 +19,23 @@ public DoorElectronicsBoundUserInterface(EntityUid owner, Enum uiKey) : base(own protected override void Open() { base.Open(); + _window = this.CreateWindow(); + _window.OnAccessChanged += UpdateConfiguration; + Reset(); + } + + public override void OnProtoReload(PrototypesReloadedEventArgs args) + { + base.OnProtoReload(args); + + if (!args.WasModified()) + return; + + Reset(); + } + + private void Reset() + { List> accessLevels = new(); foreach (var accessLevel in _prototypeManager.EnumeratePrototypes()) @@ -29,10 +47,7 @@ protected override void Open() } accessLevels.Sort(); - - _window = new DoorElectronicsConfigurationMenu(this, accessLevels, _prototypeManager); - _window.OnClose += Close; - _window.OpenCentered(); + _window?.Reset(_prototypeManager, accessLevels); } protected override void UpdateState(BoundUserInterfaceState state) @@ -44,14 +59,6 @@ protected override void UpdateState(BoundUserInterfaceState state) _window?.UpdateState(castState); } - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - if (!disposing) return; - - _window?.Dispose(); - } - public void UpdateConfiguration(List> newAccessList) { SendMessage(new DoorElectronicsUpdateConfigurationMessage(newAccessList)); diff --git a/Content.Client/Doors/Electronics/DoorElectronicsConfigurationMenu.xaml.cs b/Content.Client/Doors/Electronics/DoorElectronicsConfigurationMenu.xaml.cs index c01f13a462e..2112a562971 100644 --- a/Content.Client/Doors/Electronics/DoorElectronicsConfigurationMenu.xaml.cs +++ b/Content.Client/Doors/Electronics/DoorElectronicsConfigurationMenu.xaml.cs @@ -15,22 +15,23 @@ namespace Content.Client.Doors.Electronics; [GenerateTypedNameReferences] public sealed partial class DoorElectronicsConfigurationMenu : FancyWindow { - private readonly DoorElectronicsBoundUserInterface _owner; - private AccessLevelControl _buttonsList = new(); + private readonly AccessLevelControl _buttonsList = new(); - public DoorElectronicsConfigurationMenu(DoorElectronicsBoundUserInterface ui, List> accessLevels, IPrototypeManager prototypeManager) + public event Action>>? OnAccessChanged; + + public DoorElectronicsConfigurationMenu() { RobustXamlLoader.Load(this); - - _owner = ui; - - _buttonsList.Populate(accessLevels, prototypeManager); AccessLevelControlContainer.AddChild(_buttonsList); + } + + public void Reset(IPrototypeManager protoManager, List> accessLevels) + { + _buttonsList.Populate(accessLevels, protoManager); - foreach (var (id, button) in _buttonsList.ButtonsList) + foreach (var button in _buttonsList.ButtonsList.Values) { - button.OnPressed += _ => _owner.UpdateConfiguration( - _buttonsList.ButtonsList.Where(x => x.Value.Pressed).Select(x => x.Key).ToList()); + button.OnPressed += _ => OnAccessChanged?.Invoke(_buttonsList.ButtonsList.Where(x => x.Value.Pressed).Select(x => x.Key).ToList()); } } diff --git a/Content.Client/Fax/UI/FaxBoundUi.cs b/Content.Client/Fax/UI/FaxBoundUi.cs index a95066a3b58..ca2e834b4fe 100644 --- a/Content.Client/Fax/UI/FaxBoundUi.cs +++ b/Content.Client/Fax/UI/FaxBoundUi.cs @@ -25,10 +25,7 @@ protected override void Open() { base.Open(); - _window = new FaxWindow(); - _window.OpenCentered(); - - _window.OnClose += Close; + _window = this.CreateWindow(); _window.FileButtonPressed += OnFileButtonPressed; _window.CopyButtonPressed += OnCopyButtonPressed; _window.SendButtonPressed += OnSendButtonPressed; @@ -104,11 +101,4 @@ protected override void UpdateState(BoundUserInterfaceState state) _window.UpdateState(cast); } - - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - if (disposing) - _window?.Dispose(); - } } diff --git a/Content.Client/Forensics/ForensicScannerBoundUserInterface.cs b/Content.Client/Forensics/ForensicScannerBoundUserInterface.cs index ba49f11ea0f..08596b04e6e 100644 --- a/Content.Client/Forensics/ForensicScannerBoundUserInterface.cs +++ b/Content.Client/Forensics/ForensicScannerBoundUserInterface.cs @@ -1,6 +1,7 @@ using Robust.Client.GameObjects; using Robust.Shared.Timing; using Content.Shared.Forensics; +using Robust.Client.UserInterface; namespace Content.Client.Forensics { @@ -21,11 +22,9 @@ public ForensicScannerBoundUserInterface(EntityUid owner, Enum uiKey) : base(own protected override void Open() { base.Open(); - _window = new ForensicScannerMenu(); - _window.OnClose += Close; + _window = this.CreateWindow(); _window.Print.OnPressed += _ => Print(); _window.Clear.OnPressed += _ => Clear(); - _window.OpenCentered(); } private void Print() @@ -62,6 +61,7 @@ protected override void UpdateState(BoundUserInterfaceState state) _printCooldown = cast.PrintCooldown; + // TODO: Fix this if (cast.PrintReadyAt > _gameTiming.CurTime) Timer.Spawn(cast.PrintReadyAt - _gameTiming.CurTime, () => { @@ -71,14 +71,5 @@ protected override void UpdateState(BoundUserInterfaceState state) _window.UpdateState(cast); } - - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - if (!disposing) - return; - - _window?.Dispose(); - } } } diff --git a/Content.Client/Gateway/UI/GatewayBoundUserInterface.cs b/Content.Client/Gateway/UI/GatewayBoundUserInterface.cs index fdb3cdbc010..457b70ca7ca 100644 --- a/Content.Client/Gateway/UI/GatewayBoundUserInterface.cs +++ b/Content.Client/Gateway/UI/GatewayBoundUserInterface.cs @@ -1,6 +1,7 @@ using Content.Shared.Gateway; using JetBrains.Annotations; using Robust.Client.GameObjects; +using Robust.Client.UserInterface; namespace Content.Client.Gateway.UI; @@ -17,24 +18,13 @@ protected override void Open() { base.Open(); - _window = new GatewayWindow(EntMan.GetNetEntity(Owner)); + _window = this.CreateWindow(); + _window.SetEntity(EntMan.GetNetEntity(Owner)); _window.OpenPortal += destination => { SendMessage(new GatewayOpenPortalMessage(destination)); }; - _window.OnClose += Close; - _window?.OpenCentered(); - } - - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - if (disposing) - { - _window?.Dispose(); - _window = null; - } } protected override void UpdateState(BoundUserInterfaceState state) diff --git a/Content.Client/Gateway/UI/GatewayWindow.xaml.cs b/Content.Client/Gateway/UI/GatewayWindow.xaml.cs index 889dd6e1759..1c779b2b350 100644 --- a/Content.Client/Gateway/UI/GatewayWindow.xaml.cs +++ b/Content.Client/Gateway/UI/GatewayWindow.xaml.cs @@ -22,7 +22,7 @@ public sealed partial class GatewayWindow : FancyWindow, public event Action? OpenPortal; private List _destinations = new(); - public readonly NetEntity Owner; + public NetEntity Owner; private NetEntity? _current; private TimeSpan _nextReady; @@ -46,16 +46,20 @@ public sealed partial class GatewayWindow : FancyWindow, /// private bool _isCooldownPending = true; - public GatewayWindow(NetEntity netEntity) + public GatewayWindow() { RobustXamlLoader.Load(this); var dependencies = IoCManager.Instance!; _timing = dependencies.Resolve(); - Owner = netEntity; NextUnlockBar.ForegroundStyleBoxOverride = new StyleBoxFlat(Color.FromHex("#C74EBD")); } + public void SetEntity(NetEntity entity) + { + + } + public void UpdateState(GatewayBoundUserInterfaceState state) { _destinations = state.Destinations; diff --git a/Content.Client/Gravity/UI/GravityGeneratorBoundUserInterface.cs b/Content.Client/Gravity/UI/GravityGeneratorBoundUserInterface.cs index d72da3e8120..32b40747d55 100644 --- a/Content.Client/Gravity/UI/GravityGeneratorBoundUserInterface.cs +++ b/Content.Client/Gravity/UI/GravityGeneratorBoundUserInterface.cs @@ -1,6 +1,6 @@ using Content.Shared.Gravity; using JetBrains.Annotations; -using Robust.Client.GameObjects; +using Robust.Client.UserInterface; namespace Content.Client.Gravity.UI { @@ -18,17 +18,8 @@ protected override void Open() { base.Open(); - _window = new GravityGeneratorWindow(this); - - /* - _window.Switch.OnPressed += _ => - { - SendMessage(new SharedGravityGeneratorComponent.SwitchGeneratorMessage(!IsOn)); - }; - */ - - _window.OpenCentered(); - _window.OnClose += Close; + _window = this.CreateWindow(); + _window.SetEntity(Owner); } protected override void UpdateState(BoundUserInterfaceState state) @@ -39,14 +30,6 @@ protected override void UpdateState(BoundUserInterfaceState state) _window?.UpdateState(castState); } - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - if (!disposing) return; - - _window?.Dispose(); - } - public void SetPowerSwitch(bool on) { SendMessage(new SharedGravityGeneratorComponent.SwitchGeneratorMessage(on)); diff --git a/Content.Client/Gravity/UI/GravityGeneratorWindow.xaml.cs b/Content.Client/Gravity/UI/GravityGeneratorWindow.xaml.cs index 75f8eb479b5..6f04133b594 100644 --- a/Content.Client/Gravity/UI/GravityGeneratorWindow.xaml.cs +++ b/Content.Client/Gravity/UI/GravityGeneratorWindow.xaml.cs @@ -12,22 +12,23 @@ public sealed partial class GravityGeneratorWindow : FancyWindow { private readonly ButtonGroup _buttonGroup = new(); - private readonly GravityGeneratorBoundUserInterface _owner; + public event Action? OnPowerSwitch; - public GravityGeneratorWindow(GravityGeneratorBoundUserInterface owner) + public GravityGeneratorWindow() { RobustXamlLoader.Load(this); IoCManager.InjectDependencies(this); - _owner = owner; - OnButton.Group = _buttonGroup; OffButton.Group = _buttonGroup; - OnButton.OnPressed += _ => _owner.SetPowerSwitch(true); - OffButton.OnPressed += _ => _owner.SetPowerSwitch(false); + OnButton.OnPressed += _ => OnPowerSwitch?.Invoke(true); + OffButton.OnPressed += _ => OnPowerSwitch?.Invoke(false); + } - EntityView.SetEntity(owner.Owner); + public void SetEntity(EntityUid uid) + { + EntityView.SetEntity(uid); } public void UpdateState(SharedGravityGeneratorComponent.GeneratorState state) diff --git a/Content.Client/HealthAnalyzer/UI/HealthAnalyzerBoundUserInterface.cs b/Content.Client/HealthAnalyzer/UI/HealthAnalyzerBoundUserInterface.cs index dc0a3e9fccd..38760f4aa3c 100644 --- a/Content.Client/HealthAnalyzer/UI/HealthAnalyzerBoundUserInterface.cs +++ b/Content.Client/HealthAnalyzer/UI/HealthAnalyzerBoundUserInterface.cs @@ -1,6 +1,6 @@ using Content.Shared.MedicalScanner; using JetBrains.Annotations; -using Robust.Client.GameObjects; +using Robust.Client.UserInterface; namespace Content.Client.HealthAnalyzer.UI { @@ -17,12 +17,9 @@ public HealthAnalyzerBoundUserInterface(EntityUid owner, Enum uiKey) : base(owne protected override void Open() { base.Open(); - _window = new HealthAnalyzerWindow - { - Title = EntMan.GetComponent(Owner).EntityName, - }; - _window.OnClose += Close; - _window.OpenCentered(); + _window = this.CreateWindow(); + + _window.Title = EntMan.GetComponent(Owner).EntityName; } protected override void ReceiveMessage(BoundUserInterfaceMessage message) @@ -35,17 +32,5 @@ protected override void ReceiveMessage(BoundUserInterfaceMessage message) _window.Populate(cast); } - - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - if (!disposing) - return; - - if (_window != null) - _window.OnClose -= Close; - - _window?.Dispose(); - } } } diff --git a/Content.Client/Humanoid/HumanoidMarkingModifierBoundUserInterface.cs b/Content.Client/Humanoid/HumanoidMarkingModifierBoundUserInterface.cs index a8872604a4c..53977eb636b 100644 --- a/Content.Client/Humanoid/HumanoidMarkingModifierBoundUserInterface.cs +++ b/Content.Client/Humanoid/HumanoidMarkingModifierBoundUserInterface.cs @@ -1,5 +1,6 @@ using Content.Shared.Humanoid; using Content.Shared.Humanoid.Markings; +using Robust.Client.UserInterface; namespace Content.Client.Humanoid; @@ -20,8 +21,7 @@ protected override void Open() { base.Open(); - _window = new(); - _window.OnClose += Close; + _window = this.CreateWindow(); _window.OnMarkingAdded += SendMarkingSet; _window.OnMarkingRemoved += SendMarkingSet; _window.OnMarkingColorChange += SendMarkingSetNoResend; diff --git a/Content.Client/Instruments/UI/BandMenu.xaml.cs b/Content.Client/Instruments/UI/BandMenu.xaml.cs index 5fb293a194d..26cd1369e55 100644 --- a/Content.Client/Instruments/UI/BandMenu.xaml.cs +++ b/Content.Client/Instruments/UI/BandMenu.xaml.cs @@ -11,7 +11,9 @@ public sealed partial class BandMenu : DefaultWindow { private readonly InstrumentBoundUserInterface _owner; - public BandMenu(InstrumentBoundUserInterface owner) : base() + public EntityUid? Master; + + public BandMenu(InstrumentBoundUserInterface owner) { RobustXamlLoader.Load(this); @@ -40,7 +42,7 @@ public void Populate((NetEntity, string)[] nearby, IEntityManager entManager) { var uid = entManager.GetEntity(nent); var item = BandList.AddItem(name, null, true, uid); - item.Selected = _owner.Instrument?.Master == uid; + item.Selected = Master == uid; } } } diff --git a/Content.Client/Instruments/UI/ChannelsMenu.xaml.cs b/Content.Client/Instruments/UI/ChannelsMenu.xaml.cs index 2814d415365..c175e67842f 100644 --- a/Content.Client/Instruments/UI/ChannelsMenu.xaml.cs +++ b/Content.Client/Instruments/UI/ChannelsMenu.xaml.cs @@ -51,7 +51,7 @@ private void OnClearPressed(BaseButton.ButtonEventArgs obj) } } - public void Populate() + public void Populate(InstrumentComponent? instrument) { ChannelList.Clear(); @@ -60,7 +60,8 @@ public void Populate() var item = ChannelList.AddItem(_owner.Loc.GetString("instrument-component-channel-name", ("number", i)), null, true, i); - item.Selected = !_owner.Instrument?.FilteredChannels[i] ?? false; + + item.Selected = !instrument?.FilteredChannels[i] ?? false; } } } diff --git a/Content.Client/Instruments/UI/InstrumentBoundUserInterface.cs b/Content.Client/Instruments/UI/InstrumentBoundUserInterface.cs index 0f5729f55b1..4816ce8c365 100644 --- a/Content.Client/Instruments/UI/InstrumentBoundUserInterface.cs +++ b/Content.Client/Instruments/UI/InstrumentBoundUserInterface.cs @@ -24,8 +24,6 @@ public sealed class InstrumentBoundUserInterface : BoundUserInterface [ViewVariables] private BandMenu? _bandMenu; [ViewVariables] private ChannelsMenu? _channelsMenu; - [ViewVariables] public InstrumentComponent? Instrument { get; private set; } - public InstrumentBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey) { IoCManager.InjectDependencies(this); @@ -43,14 +41,20 @@ protected override void ReceiveMessage(BoundUserInterfaceMessage message) protected override void Open() { - if (!EntMan.TryGetComponent(Owner, out InstrumentComponent? instrument)) - return; + _instrumentMenu = this.CreateWindow(); + _instrumentMenu.Title = EntMan.GetComponent(Owner).EntityName; - Instrument = instrument; - _instrumentMenu = new InstrumentMenu(this); - _instrumentMenu.OnClose += Close; + _instrumentMenu.OnOpenBand += OpenBandMenu; + _instrumentMenu.OnOpenChannels += OpenChannelsMenu; + _instrumentMenu.OnCloseChannels += CloseChannelsMenu; + _instrumentMenu.OnCloseBands += CloseBandMenu; - _instrumentMenu.OpenCentered(); + _instrumentMenu.SetMIDI(MidiManager.IsAvailable); + + if (EntMan.TryGetComponent(Owner, out InstrumentComponent? instrument)) + { + _instrumentMenu.SetInstrument((Owner, instrument)); + } } protected override void Dispose(bool disposing) @@ -58,7 +62,12 @@ protected override void Dispose(bool disposing) base.Dispose(disposing); if (!disposing) return; - _instrumentMenu?.Dispose(); + + if (EntMan.TryGetComponent(Owner, out InstrumentComponent? instrument)) + { + _instrumentMenu?.RemoveInstrument(instrument); + } + _bandMenu?.Dispose(); _channelsMenu?.Dispose(); } @@ -72,6 +81,11 @@ public void OpenBandMenu() { _bandMenu ??= new BandMenu(this); + if (EntMan.TryGetComponent(Owner, out InstrumentComponent? instrument)) + { + _bandMenu.Master = instrument.Master; + } + // Refresh cache... RefreshBands(); @@ -87,7 +101,9 @@ public void CloseBandMenu() public void OpenChannelsMenu() { _channelsMenu ??= new ChannelsMenu(this); - _channelsMenu.Populate(); + EntMan.TryGetComponent(Owner, out InstrumentComponent? instrument); + + _channelsMenu.Populate(instrument); _channelsMenu.OpenCenteredRight(); } diff --git a/Content.Client/Instruments/UI/InstrumentMenu.xaml.cs b/Content.Client/Instruments/UI/InstrumentMenu.xaml.cs index da443e3fb5b..fc863648d79 100644 --- a/Content.Client/Instruments/UI/InstrumentMenu.xaml.cs +++ b/Content.Client/Instruments/UI/InstrumentMenu.xaml.cs @@ -1,7 +1,10 @@ using System.IO; using System.Numerics; using System.Threading.Tasks; +using Content.Client.Interactable; +using Content.Shared.ActionBlocker; using Robust.Client.AutoGenerated; +using Robust.Client.Player; using Robust.Client.UserInterface; using Robust.Client.UserInterface.CustomControls; using Robust.Client.UserInterface.XAML; @@ -16,33 +19,23 @@ namespace Content.Client.Instruments.UI [GenerateTypedNameReferences] public sealed partial class InstrumentMenu : DefaultWindow { - private readonly InstrumentBoundUserInterface _owner; + [Dependency] private readonly IEntityManager _entManager = default!; + [Dependency] private readonly IFileDialogManager _dialogs = default!; + [Dependency] private readonly IPlayerManager _player = default!; private bool _isMidiFileDialogueWindowOpen; - public InstrumentMenu(InstrumentBoundUserInterface owner) - { - RobustXamlLoader.Load(this); - - _owner = owner; + public event Action? OnOpenBand; + public event Action? OnOpenChannels; + public event Action? OnCloseBands; + public event Action? OnCloseChannels; - if (_owner.Instrument != null) - { - _owner.Instrument.OnMidiPlaybackEnded += InstrumentOnMidiPlaybackEnded; - Title = _owner.Entities.GetComponent(_owner.Owner).EntityName; - LoopButton.Disabled = !_owner.Instrument.IsMidiOpen; - LoopButton.Pressed = _owner.Instrument.LoopMidi; - ChannelsButton.Disabled = !_owner.Instrument.IsRendererAlive; - StopButton.Disabled = !_owner.Instrument.IsMidiOpen; - PlaybackSlider.MouseFilter = _owner.Instrument.IsMidiOpen ? MouseFilterMode.Pass : MouseFilterMode.Ignore; - } + public EntityUid Entity; - if (!_owner.MidiManager.IsAvailable) - { - UnavailableOverlay.Visible = true; - // We return early as to not give the buttons behavior. - return; - } + public InstrumentMenu() + { + RobustXamlLoader.Load(this); + IoCManager.InjectDependencies(this); InputButton.OnToggled += MidiInputButtonOnOnToggled; BandButton.OnPressed += BandButtonOnPressed; @@ -57,12 +50,34 @@ public InstrumentMenu(InstrumentBoundUserInterface owner) MinSize = SetSize = new Vector2(400, 150); } + public void SetInstrument(Entity entity) + { + Entity = entity; + var component = entity.Comp; + component.OnMidiPlaybackEnded += InstrumentOnMidiPlaybackEnded; + LoopButton.Disabled = !component.IsMidiOpen; + LoopButton.Pressed = component.LoopMidi; + ChannelsButton.Disabled = !component.IsRendererAlive; + StopButton.Disabled = !component.IsMidiOpen; + PlaybackSlider.MouseFilter = component.IsMidiOpen ? MouseFilterMode.Pass : MouseFilterMode.Ignore; + } + + public void RemoveInstrument(InstrumentComponent component) + { + component.OnMidiPlaybackEnded -= InstrumentOnMidiPlaybackEnded; + } + + public void SetMIDI(bool available) + { + UnavailableOverlay.Visible = !available; + } + private void BandButtonOnPressed(ButtonEventArgs obj) { if (!PlayCheck()) return; - _owner.OpenBandMenu(); + OnOpenBand?.Invoke(); } private void BandButtonOnToggled(ButtonToggledEventArgs obj) @@ -70,12 +85,15 @@ private void BandButtonOnToggled(ButtonToggledEventArgs obj) if (obj.Pressed) return; - _owner.Instruments.SetMaster(_owner.Owner, null); + if (_entManager.TryGetComponent(Entity, out InstrumentComponent? instrument)) + { + _entManager.System().SetMaster(Entity, instrument.Master); + } } private void ChannelsButtonOnPressed(ButtonEventArgs obj) { - _owner.OpenChannelsMenu(); + OnOpenChannels?.Invoke(); } private void InstrumentOnMidiPlaybackEnded() @@ -85,8 +103,10 @@ private void InstrumentOnMidiPlaybackEnded() public void MidiPlaybackSetButtonsDisabled(bool disabled) { - if(disabled) - _owner.CloseChannelsMenu(); + if (disabled) + { + OnCloseChannels?.Invoke(); + } LoopButton.Disabled = disabled; StopButton.Disabled = disabled; @@ -100,7 +120,7 @@ private async void MidiFileButtonOnOnPressed(ButtonEventArgs obj) if (_isMidiFileDialogueWindowOpen) return; - _owner.CloseBandMenu(); + OnCloseBands?.Invoke(); var filters = new FileDialogFilters(new FileDialogFilters.Group("mid", "midi")); @@ -108,7 +128,7 @@ private async void MidiFileButtonOnOnPressed(ButtonEventArgs obj) // or focus the previously-opened window. _isMidiFileDialogueWindowOpen = true; - await using var file = await _owner.FileDialogManager.OpenFile(filters); + await using var file = await _dialogs.OpenFile(filters); _isMidiFileDialogueWindowOpen = false; @@ -129,9 +149,18 @@ private async void MidiFileButtonOnOnPressed(ButtonEventArgs obj) await file.CopyToAsync(memStream); - if (_owner.Instrument is not {} instrument - || !_owner.Instruments.OpenMidi(_owner.Owner, memStream.GetBuffer().AsSpan(0, (int) memStream.Length), instrument)) + if (!_entManager.TryGetComponent(Entity, out var instrument)) + { return; + } + + if (!_entManager.System() + .OpenMidi(Entity, + memStream.GetBuffer().AsSpan(0, (int) memStream.Length), + instrument)) + { + return; + } MidiPlaybackSetButtonsDisabled(false); if (InputButton.Pressed) @@ -140,7 +169,7 @@ private async void MidiFileButtonOnOnPressed(ButtonEventArgs obj) private void MidiInputButtonOnOnToggled(ButtonToggledEventArgs obj) { - _owner.CloseBandMenu(); + OnCloseBands?.Invoke(); if (obj.Pressed) { @@ -148,109 +177,99 @@ private void MidiInputButtonOnOnToggled(ButtonToggledEventArgs obj) return; MidiStopButtonOnPressed(null); - if(_owner.Instrument is {} instrument) - _owner.Instruments.OpenInput(_owner.Owner, instrument); + + if (_entManager.TryGetComponent(Entity, out InstrumentComponent? instrument)) + _entManager.System().OpenInput(Entity, instrument); } - else if (_owner.Instrument is { } instrument) + else { - _owner.Instruments.CloseInput(_owner.Owner, false, instrument); - _owner.CloseChannelsMenu(); + _entManager.System().CloseInput(Entity, false); + OnCloseChannels?.Invoke(); } } private bool PlayCheck() { // TODO all of these checks should also be done server-side. - - var instrumentEnt = _owner.Owner; - var instrument = _owner.Instrument; - - if (instrument == null) + if (!_entManager.TryGetComponent(Entity, out InstrumentComponent? instrument)) return false; - var localEntity = _owner.PlayerManager.LocalEntity; + var localEntity = _player.LocalEntity; // If we don't have a player or controlled entity, we return. if (localEntity == null) return false; // By default, allow an instrument to play itself and skip all other checks - if (localEntity == instrumentEnt) + if (localEntity == Entity) return true; - var container = _owner.Entities.System(); + var container = _entManager.System(); // If we're a handheld instrument, we might be in a container. Get it just in case. - container.TryGetContainingContainer(instrumentEnt, out var conMan); + container.TryGetContainingContainer(Entity, out var conMan); // If the instrument is handheld and we're not holding it, we return. - if ((instrument.Handheld && (conMan == null || conMan.Owner != localEntity))) + if (instrument.Handheld && (conMan == null || conMan.Owner != localEntity)) return false; - if (!_owner.ActionBlocker.CanInteract(localEntity.Value, instrumentEnt)) + if (!_entManager.System().CanInteract(localEntity.Value, Entity)) return false; // We check that we're in range unobstructed just in case. - return _owner.Interactions.InRangeUnobstructed(localEntity.Value, instrumentEnt); + return _entManager.System().InRangeUnobstructed(localEntity.Value, Entity); } private void MidiStopButtonOnPressed(ButtonEventArgs? obj) { MidiPlaybackSetButtonsDisabled(true); - if (_owner.Instrument is not {} instrument) - return; - - _owner.Instruments.CloseMidi(_owner.Owner, false, instrument); - _owner.CloseChannelsMenu(); + _entManager.System().CloseMidi(Entity, false); + OnCloseChannels?.Invoke(); } private void MidiLoopButtonOnOnToggled(ButtonToggledEventArgs obj) { - if (_owner.Instrument == null) - return; + var instrument = _entManager.System(); + + if (_entManager.TryGetComponent(Entity, out InstrumentComponent? instrumentComp)) + { + instrumentComp.LoopMidi = obj.Pressed; + } - _owner.Instrument.LoopMidi = obj.Pressed; - _owner.Instruments.UpdateRenderer(_owner.Owner, _owner.Instrument); + instrument.UpdateRenderer(Entity); } private void PlaybackSliderSeek(Range _) { // Do not seek while still grabbing. - if (PlaybackSlider.Grabbed || _owner.Instrument is not {} instrument) + if (PlaybackSlider.Grabbed) return; - _owner.Instruments.SetPlayerTick(_owner.Owner, (int)Math.Ceiling(PlaybackSlider.Value), instrument); + _entManager.System().SetPlayerTick(Entity, (int)Math.Ceiling(PlaybackSlider.Value)); } private void PlaybackSliderKeyUp(GUIBoundKeyEventArgs args) { - if (args.Function != EngineKeyFunctions.UIClick || _owner.Instrument is not {} instrument) + if (args.Function != EngineKeyFunctions.UIClick) return; - _owner.Instruments.SetPlayerTick(_owner.Owner, (int)Math.Ceiling(PlaybackSlider.Value), instrument); - } - - public override void Close() - { - base.Close(); - _owner.CloseBandMenu(); - _owner.CloseChannelsMenu(); + _entManager.System().SetPlayerTick(Entity, (int)Math.Ceiling(PlaybackSlider.Value)); } protected override void FrameUpdate(FrameEventArgs args) { base.FrameUpdate(args); - if (_owner.Instrument == null) + if (!_entManager.TryGetComponent(Entity, out InstrumentComponent? instrument)) return; - var hasMaster = _owner.Instrument.Master != null; + var hasMaster = instrument.Master != null; BandButton.ToggleMode = hasMaster; BandButton.Pressed = hasMaster; - BandButton.Disabled = _owner.Instrument.IsMidiOpen || _owner.Instrument.IsInputOpen; - ChannelsButton.Disabled = !_owner.Instrument.IsRendererAlive; + BandButton.Disabled = instrument.IsMidiOpen || instrument.IsInputOpen; + ChannelsButton.Disabled = !instrument.IsRendererAlive; - if (!_owner.Instrument.IsMidiOpen) + if (!instrument.IsMidiOpen) { PlaybackSlider.MaxValue = 1; PlaybackSlider.SetValueWithoutEvent(0); @@ -260,8 +279,8 @@ protected override void FrameUpdate(FrameEventArgs args) if (PlaybackSlider.Grabbed) return; - PlaybackSlider.MaxValue = _owner.Instrument.PlayerTotalTick; - PlaybackSlider.SetValueWithoutEvent(_owner.Instrument.PlayerTick); + PlaybackSlider.MaxValue = instrument.PlayerTotalTick; + PlaybackSlider.SetValueWithoutEvent(instrument.PlayerTick); } } } diff --git a/Content.Client/Inventory/StrippableBoundUserInterface.cs b/Content.Client/Inventory/StrippableBoundUserInterface.cs index 7e50eb1c68a..132c5ed654c 100644 --- a/Content.Client/Inventory/StrippableBoundUserInterface.cs +++ b/Content.Client/Inventory/StrippableBoundUserInterface.cs @@ -41,7 +41,7 @@ public sealed class StrippableBoundUserInterface : BoundUserInterface public const string HiddenPocketEntityId = "StrippingHiddenEntity"; [ViewVariables] - private readonly StrippingMenu? _strippingMenu; + private StrippingMenu? _strippingMenu; [ViewVariables] private readonly EntityUid _virtualHiddenEntity; @@ -51,33 +51,30 @@ public StrippableBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, u _examine = EntMan.System(); _inv = EntMan.System(); _cuffable = EntMan.System(); - - // TODO update name when identity changes - var title = Loc.GetString("strippable-bound-user-interface-stripping-menu-title", ("ownerName", Identity.Name(Owner, EntMan))); - _strippingMenu = new StrippingMenu(title, this); - _strippingMenu.OnClose += Close; - - // TODO use global entity - // BUIs are opened and closed while applying comp sates, so spawning entities here is probably not the best idea. _virtualHiddenEntity = EntMan.SpawnEntity(HiddenPocketEntityId, MapCoordinates.Nullspace); } protected override void Open() { base.Open(); + + _strippingMenu = this.CreateWindow(); + _strippingMenu.OnDirty += UpdateMenu; + _strippingMenu.Title = Loc.GetString("strippable-bound-user-interface-stripping-menu-title", ("ownerName", Identity.Name(Owner, EntMan))); + _strippingMenu?.OpenCenteredLeft(); } protected override void Dispose(bool disposing) { - base.Dispose(disposing); - - EntMan.DeleteEntity(_virtualHiddenEntity); - if (!disposing) return; - _strippingMenu?.Dispose(); + if (_strippingMenu != null) + _strippingMenu.OnDirty -= UpdateMenu; + + EntMan.DeleteEntity(_virtualHiddenEntity); + base.Dispose(disposing); } public void DirtyMenu() diff --git a/Content.Client/Kitchen/UI/GrinderMenu.xaml.cs b/Content.Client/Kitchen/UI/GrinderMenu.xaml.cs index f97d8a73302..7884268c428 100644 --- a/Content.Client/Kitchen/UI/GrinderMenu.xaml.cs +++ b/Content.Client/Kitchen/UI/GrinderMenu.xaml.cs @@ -12,42 +12,34 @@ namespace Content.Client.Kitchen.UI [GenerateTypedNameReferences] public sealed partial class GrinderMenu : FancyWindow { - private readonly IEntityManager _entityManager; - private readonly IPrototypeManager _prototypeManager; - private readonly ReagentGrinderBoundUserInterface _owner; + [Dependency] private readonly IEntityManager _entityManager = default!; + [Dependency] private readonly IPrototypeManager _prototypeManager = default!; private readonly Dictionary _chamberVisualContents = new(); - public GrinderMenu(ReagentGrinderBoundUserInterface owner, IEntityManager entityManager, IPrototypeManager prototypeManager) + public event Action? OnToggleAuto; + public event Action? OnGrind; + public event Action? OnJuice; + public event Action? OnEjectAll; + public event Action? OnEjectBeaker; + public event Action? OnEjectChamber; + + public GrinderMenu() { RobustXamlLoader.Load(this); - _entityManager = entityManager; - _prototypeManager = prototypeManager; - _owner = owner; - AutoModeButton.OnPressed += owner.ToggleAutoMode; - GrindButton.OnPressed += owner.StartGrinding; - JuiceButton.OnPressed += owner.StartJuicing; - ChamberContentBox.EjectButton.OnPressed += owner.EjectAll; - BeakerContentBox.EjectButton.OnPressed += owner.EjectBeaker; + IoCManager.InjectDependencies(this); + AutoModeButton.OnPressed += _ => OnToggleAuto?.Invoke(); + GrindButton.OnPressed += _ => OnGrind?.Invoke(); + JuiceButton.OnPressed += _ => OnJuice?.Invoke(); + ChamberContentBox.EjectButton.OnPressed += _ => OnEjectAll?.Invoke(); + BeakerContentBox.EjectButton.OnPressed += _ => OnEjectBeaker?.Invoke(); ChamberContentBox.BoxContents.OnItemSelected += OnChamberBoxContentsItemSelected; BeakerContentBox.BoxContents.SelectMode = ItemList.ItemListSelectMode.None; } private void OnChamberBoxContentsItemSelected(ItemList.ItemListSelectedEventArgs args) { - _owner.EjectChamberContent(_chamberVisualContents[args.ItemIndex]); - } - - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - - _chamberVisualContents.Clear(); - GrindButton.OnPressed -= _owner.StartGrinding; - JuiceButton.OnPressed -= _owner.StartJuicing; - ChamberContentBox.EjectButton.OnPressed -= _owner.EjectAll; - BeakerContentBox.EjectButton.OnPressed -= _owner.EjectBeaker; - ChamberContentBox.BoxContents.OnItemSelected -= OnChamberBoxContentsItemSelected; + OnEjectChamber?.Invoke(_chamberVisualContents[args.ItemIndex]); } public void UpdateState(ReagentGrinderInterfaceState state) diff --git a/Content.Client/Kitchen/UI/MicrowaveBoundUserInterface.cs b/Content.Client/Kitchen/UI/MicrowaveBoundUserInterface.cs index 7e7dd2d6935..643ac47054b 100644 --- a/Content.Client/Kitchen/UI/MicrowaveBoundUserInterface.cs +++ b/Content.Client/Kitchen/UI/MicrowaveBoundUserInterface.cs @@ -3,6 +3,7 @@ using JetBrains.Annotations; using Robust.Client.GameObjects; using Robust.Client.Graphics; +using Robust.Client.UserInterface; using Robust.Client.UserInterface.Controls; using Robust.Shared.Timing; @@ -19,28 +20,15 @@ public sealed class MicrowaveBoundUserInterface : BoundUserInterface [ViewVariables] private readonly Dictionary _reagents = new(); - [Dependency] private readonly IGameTiming _gameTiming = default!; - - public MicrowaveUpdateUserInterfaceState currentState = default!; - - private IEntityManager _entManager; public MicrowaveBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey) { - _entManager = IoCManager.Resolve(); - } - - public TimeSpan GetCurrentTime() - { - return _gameTiming.CurTime; } protected override void Open() { base.Open(); - _menu = new MicrowaveMenu(this); - _menu.OpenCentered(); - _menu.OnClose += Close; + _menu = this.CreateWindow(); _menu.StartButton.OnPressed += _ => SendPredictedMessage(new MicrowaveStartCookMessage()); _menu.EjectButton.OnPressed += _ => SendPredictedMessage(new MicrowaveEjectMessage()); _menu.IngredientsList.OnItemSelected += args => @@ -74,38 +62,23 @@ protected override void Open() }; } - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - - if (!disposing) - { - return; - } - - _solids.Clear(); - _menu?.Dispose(); - } - protected override void UpdateState(BoundUserInterfaceState state) { base.UpdateState(state); - if (state is not MicrowaveUpdateUserInterfaceState cState) + if (state is not MicrowaveUpdateUserInterfaceState cState || _menu == null) { return; } + _menu.IsBusy = cState.IsMicrowaveBusy; + _menu.CurrentCooktimeEnd = cState.CurrentCookTimeEnd; - _menu?.ToggleBusyDisableOverlayPanel(cState.IsMicrowaveBusy || cState.ContainedSolids.Length == 0); - currentState = cState; - + _menu.ToggleBusyDisableOverlayPanel(cState.IsMicrowaveBusy || cState.ContainedSolids.Length == 0); // TODO move this to a component state and ensure the net ids. - RefreshContentsDisplay(_entManager.GetEntityArray(cState.ContainedSolids)); - - if (_menu == null) return; + RefreshContentsDisplay(EntMan.GetEntityArray(cState.ContainedSolids)); //Set the cook time info label - var cookTime = cState.ActiveButtonIndex == 0 + var cookTime = cState.ActiveButtonIndex == 0 ? Loc.GetString("microwave-menu-instant-button") : cState.CurrentCookTime.ToString(); diff --git a/Content.Client/Kitchen/UI/MicrowaveMenu.xaml.cs b/Content.Client/Kitchen/UI/MicrowaveMenu.xaml.cs index b292e9f1465..13029e38469 100644 --- a/Content.Client/Kitchen/UI/MicrowaveMenu.xaml.cs +++ b/Content.Client/Kitchen/UI/MicrowaveMenu.xaml.cs @@ -9,22 +9,21 @@ namespace Content.Client.Kitchen.UI [GenerateTypedNameReferences] public sealed partial class MicrowaveMenu : FancyWindow { - public sealed class MicrowaveCookTimeButton : Button - { - public uint CookTime; - } + [Dependency] private readonly IGameTiming _timing = default!; public event Action? OnCookTimeSelected; public ButtonGroup CookTimeButtonGroup { get; } - private readonly MicrowaveBoundUserInterface _owner; - public MicrowaveMenu(MicrowaveBoundUserInterface owner) + public bool IsBusy; + public TimeSpan CurrentCooktimeEnd; + + public MicrowaveMenu() { RobustXamlLoader.Load(this); + IoCManager.InjectDependencies(this); CookTimeButtonGroup = new ButtonGroup(); InstantCookButton.Group = CookTimeButtonGroup; - _owner = owner; InstantCookButton.OnPressed += args => { OnCookTimeSelected?.Invoke(args, 0); @@ -65,14 +64,20 @@ public void ToggleBusyDisableOverlayPanel(bool shouldDisable) protected override void FrameUpdate(FrameEventArgs args) { base.FrameUpdate(args); - if(!_owner.currentState.IsMicrowaveBusy) + + if (!IsBusy) return; - if(_owner.currentState.CurrentCookTimeEnd > _owner.GetCurrentTime()) + if (CurrentCooktimeEnd > _timing.CurTime) { CookTimeInfoLabel.Text = Loc.GetString("microwave-bound-user-interface-cook-time-label", - ("time",_owner.currentState.CurrentCookTimeEnd.Subtract(_owner.GetCurrentTime()).Seconds)); + ("time", CurrentCooktimeEnd.Subtract(_timing.CurTime).Seconds)); } } + + public sealed class MicrowaveCookTimeButton : Button + { + public uint CookTime; + } } } diff --git a/Content.Client/Kitchen/UI/ReagentGrinderBoundUserInterface.cs b/Content.Client/Kitchen/UI/ReagentGrinderBoundUserInterface.cs index e6f108b3050..bc4cc75b4d1 100644 --- a/Content.Client/Kitchen/UI/ReagentGrinderBoundUserInterface.cs +++ b/Content.Client/Kitchen/UI/ReagentGrinderBoundUserInterface.cs @@ -1,6 +1,7 @@ using Content.Shared.Containers.ItemSlots; using Content.Shared.Kitchen; using Robust.Client.GameObjects; +using Robust.Client.UserInterface; using Robust.Client.UserInterface.Controls; using Robust.Shared.Prototypes; @@ -8,8 +9,6 @@ namespace Content.Client.Kitchen.UI { public sealed class ReagentGrinderBoundUserInterface : BoundUserInterface { - [Dependency] private readonly IPrototypeManager _prototypeManager = default!; - [ViewVariables] private GrinderMenu? _menu; @@ -21,20 +20,13 @@ protected override void Open() { base.Open(); - _menu = new GrinderMenu(this, EntMan, _prototypeManager); - _menu.OpenCentered(); - _menu.OnClose += Close; - } - - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - if (!disposing) - { - return; - } - - _menu?.Dispose(); + _menu = this.CreateWindow(); + _menu.OnToggleAuto += ToggleAutoMode; + _menu.OnGrind += StartGrinding; + _menu.OnJuice += StartJuicing; + _menu.OnEjectAll += EjectAll; + _menu.OnEjectBeaker += EjectBeaker; + _menu.OnEjectChamber += EjectChamberContent; } protected override void UpdateState(BoundUserInterfaceState state) @@ -52,27 +44,27 @@ protected override void ReceiveMessage(BoundUserInterfaceMessage message) _menu?.HandleMessage(message); } - public void ToggleAutoMode(BaseButton.ButtonEventArgs args) + public void ToggleAutoMode() { SendMessage(new ReagentGrinderToggleAutoModeMessage()); } - public void StartGrinding(BaseButton.ButtonEventArgs? _ = null) + public void StartGrinding() { SendMessage(new ReagentGrinderStartMessage(GrinderProgram.Grind)); } - public void StartJuicing(BaseButton.ButtonEventArgs? _ = null) + public void StartJuicing() { SendMessage(new ReagentGrinderStartMessage(GrinderProgram.Juice)); } - public void EjectAll(BaseButton.ButtonEventArgs? _ = null) + public void EjectAll() { SendMessage(new ReagentGrinderEjectChamberAllMessage()); } - public void EjectBeaker(BaseButton.ButtonEventArgs? _ = null) + public void EjectBeaker() { SendMessage(new ItemSlotButtonPressedEvent(SharedReagentGrinder.BeakerSlotId)); } diff --git a/Content.Client/Labels/UI/HandLabelerBoundUserInterface.cs b/Content.Client/Labels/UI/HandLabelerBoundUserInterface.cs index 555f1ff09e6..6b656123412 100644 --- a/Content.Client/Labels/UI/HandLabelerBoundUserInterface.cs +++ b/Content.Client/Labels/UI/HandLabelerBoundUserInterface.cs @@ -1,6 +1,7 @@ using Content.Shared.Labels; using Content.Shared.Labels.Components; using Robust.Client.GameObjects; +using Robust.Client.UserInterface; namespace Content.Client.Labels.UI { @@ -23,13 +24,8 @@ protected override void Open() { base.Open(); - _window = new HandLabelerWindow(); - if (State != null) - UpdateState(State); + _window = this.CreateWindow(); - _window.OpenCentered(); - - _window.OnClose += Close; _window.OnLabelChanged += OnLabelChanged; Reload(); } @@ -51,13 +47,5 @@ public void Reload() _window.SetCurrentLabel(component.AssignedLabel); } - - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - if (!disposing) return; - _window?.Dispose(); - } } - } diff --git a/Content.Client/Lathe/UI/LatheBoundUserInterface.cs b/Content.Client/Lathe/UI/LatheBoundUserInterface.cs index 6e6d1b91761..a599f79152e 100644 --- a/Content.Client/Lathe/UI/LatheBoundUserInterface.cs +++ b/Content.Client/Lathe/UI/LatheBoundUserInterface.cs @@ -1,6 +1,7 @@ using Content.Shared.Lathe; using Content.Shared.Research.Components; using JetBrains.Annotations; +using Robust.Client.UserInterface; namespace Content.Client.Lathe.UI { @@ -17,9 +18,9 @@ protected override void Open() { base.Open(); - _menu = new LatheMenu(this); - _menu.OnClose += Close; - + _menu = this.CreateWindow(); + _menu.SetEntity(Owner); + _menu.OpenCenteredRight(); _menu.OnServerListButtonPressed += _ => { @@ -30,8 +31,6 @@ protected override void Open() { SendMessage(new LatheQueueRecipeMessage(recipe, amount)); }; - - _menu.OpenCenteredRight(); } protected override void UpdateState(BoundUserInterfaceState state) @@ -50,13 +49,5 @@ protected override void UpdateState(BoundUserInterfaceState state) break; } } - - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - if (!disposing) - return; - _menu?.Dispose(); - } } } diff --git a/Content.Client/Lathe/UI/LatheMenu.xaml.cs b/Content.Client/Lathe/UI/LatheMenu.xaml.cs index d597a7d432c..bfbcd94ed6c 100644 --- a/Content.Client/Lathe/UI/LatheMenu.xaml.cs +++ b/Content.Client/Lathe/UI/LatheMenu.xaml.cs @@ -1,3 +1,4 @@ +using System.Buffers; using System.Linq; using System.Text; using Content.Client.Materials; @@ -20,7 +21,6 @@ public sealed partial class LatheMenu : DefaultWindow [Dependency] private readonly IEntityManager _entityManager = default!; [Dependency] private readonly IPrototypeManager _prototypeManager = default!; - private EntityUid _owner; private readonly SpriteSystem _spriteSystem; private readonly LatheSystem _lathe; private readonly MaterialStorageSystem _materialStorage; @@ -34,9 +34,10 @@ public sealed partial class LatheMenu : DefaultWindow public ProtoId? CurrentCategory; - public LatheMenu(LatheBoundUserInterface owner) + public EntityUid Entity; + + public LatheMenu() { - _owner = owner.Owner; RobustXamlLoader.Load(this); IoCManager.InjectDependencies(this); @@ -44,8 +45,6 @@ public LatheMenu(LatheBoundUserInterface owner) _lathe = _entityManager.System(); _materialStorage = _entityManager.System(); - Title = _entityManager.GetComponent(owner.Owner).EntityName; - SearchBar.OnTextChanged += _ => { PopulateRecipes(); @@ -58,8 +57,13 @@ public LatheMenu(LatheBoundUserInterface owner) FilterOption.OnItemSelected += OnItemSelected; ServerListButton.OnPressed += a => OnServerListButtonPressed?.Invoke(a); + } - if (_entityManager.TryGetComponent(owner.Owner, out var latheComponent)) + public void SetEntity(EntityUid uid) + { + Entity = uid; + + if (_entityManager.TryGetComponent(Entity, out var latheComponent)) { if (!latheComponent.DynamicRecipes.Any()) { @@ -67,7 +71,7 @@ public LatheMenu(LatheBoundUserInterface owner) } } - MaterialsList.SetOwner(owner.Owner); + MaterialsList.SetOwner(Entity); } /// @@ -100,13 +104,15 @@ public void PopulateRecipes() var sortedRecipesToShow = recipesToShow.OrderBy(p => p.Name); RecipeList.Children.Clear(); + _entityManager.TryGetComponent(Entity, out LatheComponent? lathe); + foreach (var prototype in sortedRecipesToShow) { EntityPrototype? recipeProto = null; - if (_prototypeManager.TryIndex(prototype.Result, out EntityPrototype? entityProto) && entityProto != null) + if (_prototypeManager.TryIndex(prototype.Result, out EntityPrototype? entityProto)) recipeProto = entityProto; - var canProduce = _lathe.CanProduce(_owner, prototype, quantity); + var canProduce = _lathe.CanProduce(Entity, prototype, quantity, component: lathe); var control = new RecipeControl(prototype, () => GenerateTooltipText(prototype), canProduce, icon); control.OnButtonPressed += s => @@ -122,19 +128,20 @@ public void PopulateRecipes() private string GenerateTooltipText(LatheRecipePrototype prototype) { StringBuilder sb = new(); + var multiplier = _entityManager.GetComponent(Entity).MaterialUseMultiplier; foreach (var (id, amount) in prototype.RequiredMaterials) { if (!_prototypeManager.TryIndex(id, out var proto)) continue; - var adjustedAmount = SharedLatheSystem.AdjustMaterial(amount, prototype.ApplyMaterialDiscount, _entityManager.GetComponent(_owner).MaterialUseMultiplier); + var adjustedAmount = SharedLatheSystem.AdjustMaterial(amount, prototype.ApplyMaterialDiscount, multiplier); var sheetVolume = _materialStorage.GetSheetVolume(proto); var unit = Loc.GetString(proto.Unit); var sheets = adjustedAmount / (float) sheetVolume; - var availableAmount = _materialStorage.GetMaterialAmount(_owner, id); + var availableAmount = _materialStorage.GetMaterialAmount(Entity, id); var missingAmount = Math.Max(0, adjustedAmount - availableAmount); var missingSheets = missingAmount / (float) sheetVolume; diff --git a/Content.Client/MachineLinking/UI/SignalTimerBoundUserInterface.cs b/Content.Client/MachineLinking/UI/SignalTimerBoundUserInterface.cs index 09bdedfd94c..11abe8c2451 100644 --- a/Content.Client/MachineLinking/UI/SignalTimerBoundUserInterface.cs +++ b/Content.Client/MachineLinking/UI/SignalTimerBoundUserInterface.cs @@ -1,5 +1,6 @@ using Content.Shared.MachineLinking; using Robust.Client.GameObjects; +using Robust.Client.UserInterface; using Robust.Shared.Timing; namespace Content.Client.MachineLinking.UI; @@ -19,19 +20,14 @@ protected override void Open() { base.Open(); - _window = new SignalTimerWindow(this); - - if (State != null) - UpdateState(State); - - _window.OpenCentered(); - _window.OnClose += Close; + _window = this.CreateWindow(); + _window.OnStartTimer += StartTimer; _window.OnCurrentTextChanged += OnTextChanged; _window.OnCurrentDelayMinutesChanged += OnDelayChanged; _window.OnCurrentDelaySecondsChanged += OnDelayChanged; } - public void OnStartTimer() + public void StartTimer() { SendMessage(new SignalTimerStartMessage()); } @@ -48,11 +44,6 @@ private void OnDelayChanged(string newDelay) SendMessage(new SignalTimerDelayChangedMessage(_window.GetDelay())); } - public TimeSpan GetCurrentTime() - { - return _gameTiming.CurTime; - } - /// /// Update the UI state based on server-sent info /// @@ -72,11 +63,4 @@ protected override void UpdateState(BoundUserInterfaceState state) _window.SetTimerStarted(cast.TimerStarted); _window.SetHasAccess(cast.HasAccess); } - - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - if (!disposing) return; - _window?.Dispose(); - } } diff --git a/Content.Client/MachineLinking/UI/SignalTimerWindow.xaml.cs b/Content.Client/MachineLinking/UI/SignalTimerWindow.xaml.cs index b62595595e5..6133abfcb70 100644 --- a/Content.Client/MachineLinking/UI/SignalTimerWindow.xaml.cs +++ b/Content.Client/MachineLinking/UI/SignalTimerWindow.xaml.cs @@ -9,42 +9,44 @@ namespace Content.Client.MachineLinking.UI; [GenerateTypedNameReferences] public sealed partial class SignalTimerWindow : DefaultWindow { + [Dependency] private readonly IGameTiming _timing = default!; + private const int MaxTextLength = 5; public event Action? OnCurrentTextChanged; public event Action? OnCurrentDelayMinutesChanged; public event Action? OnCurrentDelaySecondsChanged; - private readonly SignalTimerBoundUserInterface _owner; - private TimeSpan? _triggerTime; private bool _timerStarted; - public SignalTimerWindow(SignalTimerBoundUserInterface owner) + public event Action? OnStartTimer; + + public SignalTimerWindow() { RobustXamlLoader.Load(this); - - _owner = owner; + IoCManager.InjectDependencies(this); CurrentTextEdit.OnTextChanged += e => OnCurrentTextChange(e.Text); CurrentDelayEditMinutes.OnTextChanged += e => OnCurrentDelayMinutesChange(e.Text); CurrentDelayEditSeconds.OnTextChanged += e => OnCurrentDelaySecondsChange(e.Text); - StartTimer.OnPressed += _ => OnStartTimer(); + StartTimer.OnPressed += _ => StartTimerWeh(); } - public void OnStartTimer() + private void StartTimerWeh() { if (!_timerStarted) { _timerStarted = true; - _triggerTime = _owner.GetCurrentTime() + GetDelay(); + _triggerTime = _timing.CurTime + GetDelay(); } else { SetTimerStarted(false); } - _owner.OnStartTimer(); + + OnStartTimer?.Invoke(); } protected override void FrameUpdate(FrameEventArgs args) @@ -54,9 +56,9 @@ protected override void FrameUpdate(FrameEventArgs args) if (!_timerStarted || _triggerTime == null) return; - if (_owner.GetCurrentTime() < _triggerTime.Value) + if (_timing.CurTime < _triggerTime.Value) { - StartTimer.Text = TextScreenSystem.TimeToString(_triggerTime.Value - _owner.GetCurrentTime()); + StartTimer.Text = TextScreenSystem.TimeToString(_triggerTime.Value - _timing.CurTime); } else { diff --git a/Content.Client/MagicMirror/MagicMirrorBoundUserInterface.cs b/Content.Client/MagicMirror/MagicMirrorBoundUserInterface.cs index f6979bf8d7b..0a87948ff62 100644 --- a/Content.Client/MagicMirror/MagicMirrorBoundUserInterface.cs +++ b/Content.Client/MagicMirror/MagicMirrorBoundUserInterface.cs @@ -1,6 +1,7 @@ using Content.Shared.Humanoid.Markings; using Content.Shared.MagicMirror; using Robust.Client.GameObjects; +using Robust.Client.UserInterface; namespace Content.Client.MagicMirror; @@ -17,7 +18,7 @@ protected override void Open() { base.Open(); - _window = new(); + _window = this.CreateWindow(); _window.OnHairSelected += tuple => SelectHair(MagicMirrorCategory.Hair, tuple.id, tuple.slot); _window.OnHairColorChanged += args => ChangeColor(MagicMirrorCategory.Hair, args.marking, args.slot); @@ -29,9 +30,6 @@ protected override void Open() args => ChangeColor(MagicMirrorCategory.FacialHair, args.marking, args.slot); _window.OnFacialHairSlotAdded += delegate () { AddSlot(MagicMirrorCategory.FacialHair); }; _window.OnFacialHairSlotRemoved += args => RemoveSlot(MagicMirrorCategory.FacialHair, args); - - _window.OnClose += Close; - _window.OpenCentered(); } private void SelectHair(MagicMirrorCategory category, string marking, int slot) @@ -65,14 +63,5 @@ protected override void UpdateState(BoundUserInterfaceState state) _window.UpdateState(data); } - - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - if (!disposing) - return; - - _window?.Dispose(); - } } diff --git a/Content.Client/MassMedia/Ui/NewsWriterBoundUserInterface.cs b/Content.Client/MassMedia/Ui/NewsWriterBoundUserInterface.cs index 80eca82e324..22e5bc452a0 100644 --- a/Content.Client/MassMedia/Ui/NewsWriterBoundUserInterface.cs +++ b/Content.Client/MassMedia/Ui/NewsWriterBoundUserInterface.cs @@ -1,6 +1,7 @@ using JetBrains.Annotations; using Content.Shared.MassMedia.Systems; using Content.Shared.MassMedia.Components; +using Robust.Client.UserInterface; using Robust.Shared.Timing; using Robust.Shared.Utility; @@ -9,8 +10,6 @@ namespace Content.Client.MassMedia.Ui; [UsedImplicitly] public sealed class NewsWriterBoundUserInterface : BoundUserInterface { - [Dependency] private readonly IGameTiming _gameTiming = default!; - [ViewVariables] private NewsWriterMenu? _menu; @@ -21,10 +20,7 @@ public NewsWriterBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, u protected override void Open() { - _menu = new NewsWriterMenu(_gameTiming); - - _menu.OpenCentered(); - _menu.OnClose += Close; + _menu = this.CreateWindow(); _menu.ArticleEditorPanel.PublishButtonPressed += OnPublishButtonPressed; _menu.DeleteButtonPressed += OnDeleteButtonPressed; @@ -32,16 +28,6 @@ protected override void Open() SendMessage(new NewsWriterArticlesRequestMessage()); } - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - if (!disposing) - return; - - _menu?.Close(); - _menu?.Dispose(); - } - protected override void UpdateState(BoundUserInterfaceState state) { base.UpdateState(state); diff --git a/Content.Client/MassMedia/Ui/NewsWriterMenu.xaml.cs b/Content.Client/MassMedia/Ui/NewsWriterMenu.xaml.cs index e2d57935e3a..c059ce785af 100644 --- a/Content.Client/MassMedia/Ui/NewsWriterMenu.xaml.cs +++ b/Content.Client/MassMedia/Ui/NewsWriterMenu.xaml.cs @@ -10,17 +10,17 @@ namespace Content.Client.MassMedia.Ui; [GenerateTypedNameReferences] public sealed partial class NewsWriterMenu : FancyWindow { - private readonly IGameTiming _gameTiming; + [Dependency] private readonly IGameTiming _gameTiming = default!; private TimeSpan? _nextPublish; public event Action? DeleteButtonPressed; - public NewsWriterMenu(IGameTiming gameTiming) + public NewsWriterMenu() { RobustXamlLoader.Load(this); + IoCManager.InjectDependencies(this); - _gameTiming = gameTiming; ContentsContainer.RectClipContent = false; // Customize scrollbar width and margin. This is not possible in xaml diff --git a/Content.Client/Mech/Ui/MechBoundUserInterface.cs b/Content.Client/Mech/Ui/MechBoundUserInterface.cs index 4172bdc90f1..2130a8c6099 100644 --- a/Content.Client/Mech/Ui/MechBoundUserInterface.cs +++ b/Content.Client/Mech/Ui/MechBoundUserInterface.cs @@ -3,6 +3,7 @@ using Content.Shared.Mech.Components; using JetBrains.Annotations; using Robust.Client.GameObjects; +using Robust.Client.UserInterface; namespace Content.Client.Mech.Ui; @@ -20,9 +21,8 @@ protected override void Open() { base.Open(); - _menu = new(Owner); - - _menu.OnClose += Close; + _menu = this.CreateWindow(); + _menu.SetEntity(Owner); _menu.OpenCenteredLeft(); _menu.OnRemoveButtonPressed += uid => @@ -60,16 +60,6 @@ public void UpdateEquipmentControls(MechBoundUiState state) } } - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - - if (!disposing) - return; - - _menu?.Close(); - } - public UIFragment? GetEquipmentUi(EntityUid? uid) { var component = EntMan.GetComponentOrNull(uid); diff --git a/Content.Client/Mech/Ui/MechMenu.xaml.cs b/Content.Client/Mech/Ui/MechMenu.xaml.cs index fad76488086..6f39bc386ee 100644 --- a/Content.Client/Mech/Ui/MechMenu.xaml.cs +++ b/Content.Client/Mech/Ui/MechMenu.xaml.cs @@ -16,14 +16,15 @@ public sealed partial class MechMenu : FancyWindow public event Action? OnRemoveButtonPressed; - public MechMenu(EntityUid mech) + public MechMenu() { RobustXamlLoader.Load(this); IoCManager.InjectDependencies(this); + } - _mech = mech; - - MechView.SetEntity(mech); + public void SetEntity(EntityUid uid) + { + MechView.SetEntity(uid); } public void UpdateMechStats() diff --git a/Content.Client/Medical/CrewMonitoring/CrewMonitoringBoundUserInterface.cs b/Content.Client/Medical/CrewMonitoring/CrewMonitoringBoundUserInterface.cs index 39788809871..b1f239cd78e 100644 --- a/Content.Client/Medical/CrewMonitoring/CrewMonitoringBoundUserInterface.cs +++ b/Content.Client/Medical/CrewMonitoring/CrewMonitoringBoundUserInterface.cs @@ -1,4 +1,5 @@ using Content.Shared.Medical.CrewMonitoring; +using Robust.Client.UserInterface; namespace Content.Client.Medical.CrewMonitoring; @@ -14,7 +15,7 @@ public CrewMonitoringBoundUserInterface(EntityUid owner, Enum uiKey) : base(owne protected override void Open() { EntityUid? gridUid = null; - string stationName = string.Empty; + var stationName = string.Empty; if (EntMan.TryGetComponent(Owner, out var xform)) { @@ -26,10 +27,8 @@ protected override void Open() } } - _menu = new CrewMonitoringWindow(stationName, gridUid); - - _menu.OpenCentered(); - _menu.OnClose += Close; + _menu = this.CreateWindow(); + _menu.Set(stationName, gridUid); } protected override void UpdateState(BoundUserInterfaceState state) @@ -44,13 +43,4 @@ protected override void UpdateState(BoundUserInterfaceState state) break; } } - - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - if (!disposing) - return; - - _menu?.Dispose(); - } } diff --git a/Content.Client/Medical/CrewMonitoring/CrewMonitoringWindow.xaml.cs b/Content.Client/Medical/CrewMonitoring/CrewMonitoringWindow.xaml.cs index 863412e5532..e861864c144 100644 --- a/Content.Client/Medical/CrewMonitoring/CrewMonitoringWindow.xaml.cs +++ b/Content.Client/Medical/CrewMonitoring/CrewMonitoringWindow.xaml.cs @@ -23,22 +23,27 @@ namespace Content.Client.Medical.CrewMonitoring; [GenerateTypedNameReferences] public sealed partial class CrewMonitoringWindow : FancyWindow { - private readonly IEntityManager _entManager; - private readonly IPrototypeManager _prototypeManager; + [Dependency] private readonly IEntityManager _entManager = default!; + [Dependency] private readonly IPrototypeManager _prototypeManager = default!; private readonly SpriteSystem _spriteSystem; private NetEntity? _trackedEntity; private bool _tryToScrollToListFocus; private Texture? _blipTexture; - public CrewMonitoringWindow(string stationName, EntityUid? mapUid) + public CrewMonitoringWindow() { RobustXamlLoader.Load(this); + IoCManager.InjectDependencies(this); - _entManager = IoCManager.Resolve(); - _prototypeManager = IoCManager.Resolve(); _spriteSystem = _entManager.System(); + NavMap.TrackedEntitySelectedAction += SetTrackedEntityFromNavMap; + + } + + public void Set(string stationName, EntityUid? mapUid) + { _blipTexture = _spriteSystem.Frame0(new SpriteSpecifier.Texture(new ResPath("/Textures/Interface/NavMap/beveled_circle.png"))); if (_entManager.TryGetComponent(mapUid, out var xform)) @@ -49,8 +54,6 @@ public CrewMonitoringWindow(string stationName, EntityUid? mapUid) StationName.AddStyleClass("LabelBig"); StationName.Text = stationName; - - NavMap.TrackedEntitySelectedAction += SetTrackedEntityFromNavMap; NavMap.ForceNavMapUpdate(); } diff --git a/Content.Client/NetworkConfigurator/NetworkConfiguratorBoundUserInterface.cs b/Content.Client/NetworkConfigurator/NetworkConfiguratorBoundUserInterface.cs index 80c98f143b9..f85220a9266 100644 --- a/Content.Client/NetworkConfigurator/NetworkConfiguratorBoundUserInterface.cs +++ b/Content.Client/NetworkConfigurator/NetworkConfiguratorBoundUserInterface.cs @@ -1,6 +1,7 @@ using Content.Client.NetworkConfigurator.Systems; using Content.Shared.DeviceNetwork; using Robust.Client.GameObjects; +using Robust.Client.UserInterface; using Robust.Client.UserInterface.Controls; namespace Content.Client.NetworkConfigurator; @@ -35,14 +36,12 @@ protected override void Open() switch (UiKey) { case NetworkConfiguratorUiKey.List: - _listMenu = new NetworkConfiguratorListMenu(this); - _listMenu.OnClose += Close; + _listMenu = this.CreateWindow(); _listMenu.ClearButton.OnPressed += _ => OnClearButtonPressed(); - _listMenu.OpenCenteredRight(); + _listMenu.OnRemoveAddress += OnRemoveButtonPressed; break; case NetworkConfiguratorUiKey.Configure: - _configurationMenu = new NetworkConfiguratorConfigurationMenu(); - _configurationMenu.OnClose += Close; + _configurationMenu = this.CreateWindow(); _configurationMenu.Set.OnPressed += _ => OnConfigButtonPressed(NetworkConfiguratorButtonKey.Set); _configurationMenu.Add.OnPressed += _ => OnConfigButtonPressed(NetworkConfiguratorButtonKey.Add); //_configurationMenu.Edit.OnPressed += _ => OnConfigButtonPressed(NetworkConfiguratorButtonKey.Edit); @@ -50,12 +49,24 @@ protected override void Open() _configurationMenu.Copy.OnPressed += _ => OnConfigButtonPressed(NetworkConfiguratorButtonKey.Copy); _configurationMenu.Show.OnPressed += OnShowPressed; _configurationMenu.Show.Pressed = _netConfig.ConfiguredListIsTracked(Owner); - _configurationMenu.OpenCentered(); + _configurationMenu.OnRemoveAddress += OnRemoveButtonPressed; break; case NetworkConfiguratorUiKey.Link: - _linkMenu = new NetworkConfiguratorLinkMenu(this); - _linkMenu.OnClose += Close; - _linkMenu.OpenCentered(); + _linkMenu = this.CreateWindow(); + _linkMenu.OnLinkDefaults += args => + { + SendMessage(new NetworkConfiguratorLinksSaveMessage(args)); + }; + + _linkMenu.OnToggleLink += (left, right) => + { + SendMessage(new NetworkConfiguratorToggleLinkMessage(left, right)); + }; + + _linkMenu.OnClearLinks += () => + { + SendMessage(new NetworkConfiguratorClearLinksMessage()); + }; break; } } @@ -83,16 +94,6 @@ protected override void UpdateState(BoundUserInterfaceState state) } } - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - if (!disposing) return; - - _linkMenu?.Dispose(); - _listMenu?.Dispose(); - _configurationMenu?.Dispose(); - } - private void OnClearButtonPressed() { SendMessage(new NetworkConfiguratorClearDevicesMessage()); diff --git a/Content.Client/NetworkConfigurator/NetworkConfiguratorConfigurationMenu.xaml.cs b/Content.Client/NetworkConfigurator/NetworkConfiguratorConfigurationMenu.xaml.cs index 19d04cd3464..fcd2f759187 100644 --- a/Content.Client/NetworkConfigurator/NetworkConfiguratorConfigurationMenu.xaml.cs +++ b/Content.Client/NetworkConfigurator/NetworkConfiguratorConfigurationMenu.xaml.cs @@ -9,17 +9,23 @@ namespace Content.Client.NetworkConfigurator; [GenerateTypedNameReferences] public sealed partial class NetworkConfiguratorConfigurationMenu : FancyWindow { + public event Action? OnRemoveAddress; + public NetworkConfiguratorConfigurationMenu() { RobustXamlLoader.Load(this); Clear.StyleClasses.Add(StyleBase.ButtonOpenLeft); Clear.StyleClasses.Add(StyleNano.StyleClassButtonColorRed); + DeviceList.OnRemoveAddress += args => + { + OnRemoveAddress?.Invoke(args); + }; } public void UpdateState(DeviceListUserInterfaceState state) { - DeviceList.UpdateState(null, state.DeviceList); + DeviceList.UpdateState(state.DeviceList, false); Count.Text = Loc.GetString("network-configurator-ui-count-label", ("count", state.DeviceList.Count)); } diff --git a/Content.Client/NetworkConfigurator/NetworkConfiguratorDeviceList.xaml.cs b/Content.Client/NetworkConfigurator/NetworkConfiguratorDeviceList.xaml.cs index 8cfa97dc6c2..e75c60058cb 100644 --- a/Content.Client/NetworkConfigurator/NetworkConfiguratorDeviceList.xaml.cs +++ b/Content.Client/NetworkConfigurator/NetworkConfiguratorDeviceList.xaml.cs @@ -7,17 +7,19 @@ namespace Content.Client.NetworkConfigurator; [GenerateTypedNameReferences] public sealed partial class NetworkConfiguratorDeviceList : ScrollContainer { - public void UpdateState(NetworkConfiguratorBoundUserInterface? ui, HashSet<(string address, string name)> devices) + public event Action? OnRemoveAddress; + + public void UpdateState(HashSet<(string address, string name)> devices, bool ui) { DeviceList.RemoveAllChildren(); foreach (var device in devices) { - DeviceList.AddChild(BuildDeviceListRow(ui, device)); + DeviceList.AddChild(BuildDeviceListRow(device, ui)); } } - private static BoxContainer BuildDeviceListRow(NetworkConfiguratorBoundUserInterface? ui, (string address, string name) savedDevice) + private BoxContainer BuildDeviceListRow((string address, string name) savedDevice, bool ui) { var row = new BoxContainer() { @@ -48,10 +50,10 @@ private static BoxContainer BuildDeviceListRow(NetworkConfiguratorBoundUserInter row.AddChild(name); row.AddChild(address); - if (ui != null) + if (ui) { row.AddChild(removeButton); - removeButton.OnPressed += _ => ui.OnRemoveButtonPressed(savedDevice.address); + removeButton.OnPressed += _ => OnRemoveAddress?.Invoke(savedDevice.address); } return row; diff --git a/Content.Client/NetworkConfigurator/NetworkConfiguratorLinkMenu.xaml.cs b/Content.Client/NetworkConfigurator/NetworkConfiguratorLinkMenu.xaml.cs index c04b42f249b..8cdffd16af6 100644 --- a/Content.Client/NetworkConfigurator/NetworkConfiguratorLinkMenu.xaml.cs +++ b/Content.Client/NetworkConfigurator/NetworkConfiguratorLinkMenu.xaml.cs @@ -18,20 +18,20 @@ public sealed partial class NetworkConfiguratorLinkMenu : FancyWindow private readonly LinksRender _links; - private readonly List _sources = new(); private readonly List _sinks = new(); - private readonly NetworkConfiguratorBoundUserInterface _userInterface; - private (ButtonPosition position, string id, int index)? _selectedButton; private List<(string left, string right)>? _defaults; - public NetworkConfiguratorLinkMenu(NetworkConfiguratorBoundUserInterface userInterface) + public event Action? OnClearLinks; + public event Action? OnToggleLink; + public event Action>? OnLinkDefaults; + + public NetworkConfiguratorLinkMenu() { - _userInterface = userInterface; RobustXamlLoader.Load(this); var footerStyleBox = new StyleBoxFlat() @@ -52,7 +52,7 @@ public NetworkConfiguratorLinkMenu(NetworkConfiguratorBoundUserInterface userInt ButtonOk.OnPressed += _ => Close(); ButtonLinkDefault.OnPressed += _ => LinkDefaults(); - ButtonClear.OnPressed += _ => _userInterface.SendMessage(new NetworkConfiguratorClearLinksMessage()); + ButtonClear.OnPressed += _ => OnClearLinks?.Invoke(); } public void UpdateState(DeviceLinkUserInterfaceState linkState) @@ -98,7 +98,7 @@ private void LinkDefaults() if (_defaults == default) return; - _userInterface.SendMessage(new NetworkConfiguratorLinksSaveMessage(_defaults)); + OnLinkDefaults?.Invoke(_defaults); } private Button CreateButton(ButtonPosition position, string name, string description, string id, int index) @@ -138,7 +138,7 @@ private void OnButtonPressed(BaseButton.ButtonEventArgs args, ButtonPosition pos var left = _selectedButton.Value.position == ButtonPosition.Left ? _selectedButton.Value.id : id; var right = _selectedButton.Value.position == ButtonPosition.Left ? id : _selectedButton.Value.id; - _userInterface.SendMessage(new NetworkConfiguratorToggleLinkMessage(left, right)); + OnToggleLink?.Invoke(left, right); args.Button.Pressed = false; diff --git a/Content.Client/NetworkConfigurator/NetworkConfiguratorListMenu.xaml.cs b/Content.Client/NetworkConfigurator/NetworkConfiguratorListMenu.xaml.cs index fb4aec1974b..6294facaeed 100644 --- a/Content.Client/NetworkConfigurator/NetworkConfiguratorListMenu.xaml.cs +++ b/Content.Client/NetworkConfigurator/NetworkConfiguratorListMenu.xaml.cs @@ -9,17 +9,20 @@ namespace Content.Client.NetworkConfigurator; [GenerateTypedNameReferences] public sealed partial class NetworkConfiguratorListMenu : FancyWindow { - private readonly NetworkConfiguratorBoundUserInterface _ui; - public NetworkConfiguratorListMenu(NetworkConfiguratorBoundUserInterface ui) + public event Action? OnRemoveAddress; + + public NetworkConfiguratorListMenu() { RobustXamlLoader.Load(this); - - _ui = ui; + DeviceList.OnRemoveAddress += args => + { + OnRemoveAddress?.Invoke(args); + }; } public void UpdateState(NetworkConfiguratorUserInterfaceState state) { DeviceCountLabel.Text = Loc.GetString("network-configurator-ui-count-label", ("count", state.DeviceList.Count)); - DeviceList.UpdateState(_ui, state.DeviceList); + DeviceList.UpdateState(state.DeviceList, true); } } diff --git a/Content.Client/Nuke/NukeBoundUserInterface.cs b/Content.Client/Nuke/NukeBoundUserInterface.cs index 59fbc5b319b..2e150423734 100644 --- a/Content.Client/Nuke/NukeBoundUserInterface.cs +++ b/Content.Client/Nuke/NukeBoundUserInterface.cs @@ -2,6 +2,7 @@ using Content.Shared.Nuke; using JetBrains.Annotations; using Robust.Client.GameObjects; +using Robust.Client.UserInterface; namespace Content.Client.Nuke { @@ -11,15 +12,13 @@ public sealed class NukeBoundUserInterface : BoundUserInterface [ViewVariables] private NukeMenu? _menu; - public NukeBoundUserInterface([NotNull] EntityUid owner, [NotNull] Enum uiKey) : base(owner, uiKey) + public NukeBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey) { } protected override void Open() { - _menu = new NukeMenu(); - _menu.OpenCentered(); - _menu.OnClose += Close; + _menu = this.CreateWindow(); _menu.OnKeypadButtonPressed += i => { @@ -62,15 +61,5 @@ protected override void UpdateState(BoundUserInterfaceState state) break; } } - - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - if (!disposing) - return; - - _menu?.Close(); - _menu?.Dispose(); - } } } diff --git a/Content.Client/NukeOps/WarDeclaratorBoundUserInterface.cs b/Content.Client/NukeOps/WarDeclaratorBoundUserInterface.cs index ec055b3240c..ad4f1a75d47 100644 --- a/Content.Client/NukeOps/WarDeclaratorBoundUserInterface.cs +++ b/Content.Client/NukeOps/WarDeclaratorBoundUserInterface.cs @@ -2,6 +2,7 @@ using Content.Shared.Chat; using Content.Shared.NukeOps; using JetBrains.Annotations; +using Robust.Client.UserInterface; using Robust.Shared.Configuration; using Robust.Shared.Timing; @@ -11,8 +12,6 @@ namespace Content.Client.NukeOps; public sealed class WarDeclaratorBoundUserInterface : BoundUserInterface { [Dependency] private readonly IConfigurationManager _cfg = default!; - [Dependency] private readonly IGameTiming _gameTiming = default!; - [Dependency] private readonly ILocalizationManager _localizationManager = default!; [ViewVariables] private WarDeclaratorWindow? _window; @@ -23,13 +22,7 @@ protected override void Open() { base.Open(); - _window = new WarDeclaratorWindow(_gameTiming, _localizationManager); - if (State != null) - UpdateState(State); - - _window.OpenCentered(); - - _window.OnClose += Close; + _window = this.CreateWindow(); _window.OnActivated += OnWarDeclaratorActivated; } @@ -42,13 +35,6 @@ protected override void UpdateState(BoundUserInterfaceState state) _window?.UpdateState(cast); } - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - if (disposing) - _window?.Dispose(); - } - private void OnWarDeclaratorActivated(string message) { var maxLength = _cfg.GetCVar(CCVars.ChatMaxAnnouncementLength); diff --git a/Content.Client/NukeOps/WarDeclaratorWindow.xaml.cs b/Content.Client/NukeOps/WarDeclaratorWindow.xaml.cs index b4a3f1c7fa5..aeceae13275 100644 --- a/Content.Client/NukeOps/WarDeclaratorWindow.xaml.cs +++ b/Content.Client/NukeOps/WarDeclaratorWindow.xaml.cs @@ -11,7 +11,8 @@ namespace Content.Client.NukeOps; [GenerateTypedNameReferences] public sealed partial class WarDeclaratorWindow : FancyWindow { - private readonly IGameTiming _gameTiming; + [Dependency] private readonly IGameTiming _gameTiming = default!; + [Dependency] private readonly ILocalizationManager _localizationManager = default!; public event Action? OnActivated; @@ -19,15 +20,13 @@ public sealed partial class WarDeclaratorWindow : FancyWindow private TimeSpan _shuttleDisabledTime; private WarConditionStatus _status; - public WarDeclaratorWindow(IGameTiming gameTiming, ILocalizationManager localizationManager) + public WarDeclaratorWindow() { RobustXamlLoader.Load(this); - _gameTiming = gameTiming; - WarButton.OnPressed += (_) => OnActivated?.Invoke(Rope.Collapse(MessageEdit.TextRope)); - MessageEdit.Placeholder = new Rope.Leaf(localizationManager.GetString("war-declarator-message-placeholder")); + MessageEdit.Placeholder = new Rope.Leaf(_localizationManager.GetString("war-declarator-message-placeholder")); } protected override void FrameUpdate(FrameEventArgs args) diff --git a/Content.Client/PDA/PdaBoundUserInterface.cs b/Content.Client/PDA/PdaBoundUserInterface.cs index f8f4c67076c..37ce9c4280f 100644 --- a/Content.Client/PDA/PdaBoundUserInterface.cs +++ b/Content.Client/PDA/PdaBoundUserInterface.cs @@ -24,14 +24,13 @@ protected override void Open() if (_menu == null) CreateMenu(); - - _menu?.OpenCenteredLeft(); } private void CreateMenu() { - _menu = new PdaMenu(); - _menu.OnClose += Close; + _menu = this.CreateWindow(); + _menu.OpenCenteredLeft(); + _menu.FlashLightToggleButton.OnToggled += _ => { SendMessage(new PdaToggleFlashlightMessage()); @@ -96,7 +95,6 @@ protected override void UpdateState(BoundUserInterfaceState state) _menu?.UpdateState(updateState); } - protected override void AttachCartridgeUI(Control cartridgeUIFragment, string? title) { _menu?.ProgramView.AddChild(cartridgeUIFragment); @@ -118,15 +116,6 @@ protected override void UpdateAvailablePrograms(List<(EntityUid, CartridgeCompon _menu?.UpdateAvailablePrograms(programs); } - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - if (!disposing) - return; - - _menu?.Dispose(); - } - private PdaBorderColorComponent? GetBorderColorComponent() { return EntMan.GetComponentOrNull(Owner); diff --git a/Content.Client/PDA/Ringer/RingerBoundUserInterface.cs b/Content.Client/PDA/Ringer/RingerBoundUserInterface.cs index a0688523f1e..170a296ac2e 100644 --- a/Content.Client/PDA/Ringer/RingerBoundUserInterface.cs +++ b/Content.Client/PDA/Ringer/RingerBoundUserInterface.cs @@ -1,6 +1,7 @@ using Content.Shared.PDA; using Content.Shared.PDA.Ringer; using JetBrains.Annotations; +using Robust.Client.UserInterface; using Robust.Shared.Timing; namespace Content.Client.PDA.Ringer @@ -18,9 +19,8 @@ public RingerBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey protected override void Open() { base.Open(); - _menu = new RingtoneMenu(); + _menu = this.CreateWindow(); _menu.OpenToLeft(); - _menu.OnClose += Close; _menu.TestRingerButton.OnPressed += _ => { diff --git a/Content.Client/Paper/UI/PaperBoundUserInterface.cs b/Content.Client/Paper/UI/PaperBoundUserInterface.cs index 4b0ac868f01..f3ad1e347e7 100644 --- a/Content.Client/Paper/UI/PaperBoundUserInterface.cs +++ b/Content.Client/Paper/UI/PaperBoundUserInterface.cs @@ -1,4 +1,5 @@ using JetBrains.Annotations; +using Robust.Client.UserInterface; using Robust.Client.UserInterface.Controls; using Robust.Shared.Utility; using static Content.Shared.Paper.SharedPaperComponent; @@ -19,16 +20,13 @@ protected override void Open() { base.Open(); - _window = new PaperWindow(); - _window.OnClose += Close; - _window.OnSaved += Input_OnTextEntered; + _window = this.CreateWindow(); + _window.OnSaved += InputOnTextEntered; if (EntMan.TryGetComponent(Owner, out var visuals)) { _window.InitVisuals(Owner, visuals); } - - _window.OpenCentered(); } protected override void UpdateState(BoundUserInterfaceState state) @@ -37,7 +35,7 @@ protected override void UpdateState(BoundUserInterfaceState state) _window?.Populate((PaperBoundUserInterfaceState) state); } - private void Input_OnTextEntered(string text) + private void InputOnTextEntered(string text) { SendMessage(new PaperInputTextMessage(text)); @@ -47,11 +45,4 @@ private void Input_OnTextEntered(string text) _window.Input.CursorPosition = new TextEdit.CursorPos(0, TextEdit.LineBreakBias.Top); } } - - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - if (!disposing) return; - _window?.Dispose(); - } } diff --git a/Content.Client/Paper/UI/PaperWindow.xaml.cs b/Content.Client/Paper/UI/PaperWindow.xaml.cs index 7a5fd652643..f7cace642ce 100644 --- a/Content.Client/Paper/UI/PaperWindow.xaml.cs +++ b/Content.Client/Paper/UI/PaperWindow.xaml.cs @@ -17,6 +17,7 @@ namespace Content.Client.Paper.UI public sealed partial class PaperWindow : BaseWindow { [Dependency] private readonly IInputManager _inputManager = default!; + [Dependency] private readonly IResourceCache _resCache = default!; private static Color DefaultTextColor = new(25, 25, 25); @@ -85,11 +86,10 @@ public void InitVisuals(EntityUid entity, PaperVisualsComponent visuals) // Randomize the placement of any stamps based on the entity UID // so that there's some variety in different papers. StampDisplay.PlacementSeed = (int)entity; - var resCache = IoCManager.Resolve(); // Initialize the background: PaperBackground.ModulateSelfOverride = visuals.BackgroundModulate; - var backgroundImage = visuals.BackgroundImagePath != null? resCache.GetResource(visuals.BackgroundImagePath) : null; + var backgroundImage = visuals.BackgroundImagePath != null? _resCache.GetResource(visuals.BackgroundImagePath) : null; if (backgroundImage != null) { var backgroundImageMode = visuals.BackgroundImageTile ? StyleBoxTexture.StretchMode.Tile : StyleBoxTexture.StretchMode.Stretch; @@ -127,7 +127,7 @@ public void InitVisuals(EntityUid entity, PaperVisualsComponent visuals) PaperContent.ModulateSelfOverride = visuals.ContentImageModulate; WrittenTextLabel.ModulateSelfOverride = visuals.FontAccentColor; - var contentImage = visuals.ContentImagePath != null ? resCache.GetResource(visuals.ContentImagePath) : null; + var contentImage = visuals.ContentImagePath != null ? _resCache.GetResource(visuals.ContentImagePath) : null; if (contentImage != null) { // Setup the paper content texture, but keep a reference to it, as we can't set diff --git a/Content.Client/ParticleAccelerator/UI/ParticleAcceleratorBoundUserInterface.cs b/Content.Client/ParticleAccelerator/UI/ParticleAcceleratorBoundUserInterface.cs index cde5ba9ef79..ff1eae36f55 100644 --- a/Content.Client/ParticleAccelerator/UI/ParticleAcceleratorBoundUserInterface.cs +++ b/Content.Client/ParticleAccelerator/UI/ParticleAcceleratorBoundUserInterface.cs @@ -1,5 +1,6 @@ using Content.Shared.Singularity.Components; using Robust.Client.GameObjects; +using Robust.Client.UserInterface; namespace Content.Client.ParticleAccelerator.UI { @@ -16,9 +17,10 @@ protected override void Open() { base.Open(); - _menu = new ParticleAcceleratorControlMenu(this); - _menu.OnClose += Close; - _menu.OpenCentered(); + _menu = this.CreateWindow(); + _menu.OnOverallState += SendEnableMessage; + _menu.OnPowerState += SendPowerStateMessage; + _menu.OnScanPartsRequested += SendScanPartsMessage; } public void SendEnableMessage(bool enable) @@ -40,13 +42,5 @@ protected override void UpdateState(BoundUserInterfaceState state) { _menu?.DataUpdate((ParticleAcceleratorUIState) state); } - - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - - _menu?.Dispose(); - _menu = null; - } } } diff --git a/Content.Client/ParticleAccelerator/UI/ParticleAcceleratorControlMenu.cs b/Content.Client/ParticleAccelerator/UI/ParticleAcceleratorControlMenu.cs index c69e0271372..05a296edf39 100644 --- a/Content.Client/ParticleAccelerator/UI/ParticleAcceleratorControlMenu.cs +++ b/Content.Client/ParticleAccelerator/UI/ParticleAcceleratorControlMenu.cs @@ -18,9 +18,10 @@ namespace Content.Client.ParticleAccelerator.UI { public sealed class ParticleAcceleratorControlMenu : BaseWindow { - private readonly ShaderInstance _greyScaleShader; + [Dependency] private readonly IPrototypeManager _protoManager = default!; + [Dependency] private readonly IResourceCache _cache = default!; - private readonly ParticleAcceleratorBoundUserInterface _owner; + private readonly ShaderInstance _greyScaleShader; private readonly Label _drawLabel; private readonly FastNoiseLite _drawNoiseGenerator; @@ -50,19 +51,22 @@ public sealed class ParticleAcceleratorControlMenu : BaseWindow private bool _shouldContinueAnimating; private int _maxStrength = 3; - public ParticleAcceleratorControlMenu(ParticleAcceleratorBoundUserInterface owner) + public event Action? OnOverallState; + public event Action? OnPowerState; + public event Action? OnScanPartsRequested; + + public ParticleAcceleratorControlMenu() { + IoCManager.InjectDependencies(this); SetSize = new Vector2(400, 320); - _greyScaleShader = IoCManager.Resolve().Index("Greyscale").Instance(); + _greyScaleShader = _protoManager.Index("Greyscale").Instance(); - _owner = owner; _drawNoiseGenerator = new(); _drawNoiseGenerator.SetFractalType(FastNoiseLite.FractalType.FBm); _drawNoiseGenerator.SetFrequency(0.5f); - var resourceCache = IoCManager.Resolve(); - var font = resourceCache.GetFont("/Fonts/Boxfont-round/Boxfont Round.ttf", 13); - var panelTex = resourceCache.GetTexture("/Textures/Interface/Nano/button.svg.96dpi.png"); + var font = _cache.GetFont("/Fonts/Boxfont-round/Boxfont Round.ttf", 13); + var panelTex = _cache.GetTexture("/Textures/Interface/Nano/button.svg.96dpi.png"); MouseFilter = MouseFilterMode.Stop; @@ -112,7 +116,8 @@ public ParticleAcceleratorControlMenu(ParticleAcceleratorBoundUserInterface owne Text = Loc.GetString("particle-accelerator-control-menu-off-button"), StyleClasses = { StyleBase.ButtonOpenRight }, }; - _offButton.OnPressed += args => owner.SendEnableMessage(false); + + _offButton.OnPressed += args => OnOverallState?.Invoke(false); _onButton = new Button { @@ -120,7 +125,7 @@ public ParticleAcceleratorControlMenu(ParticleAcceleratorBoundUserInterface owne Text = Loc.GetString("particle-accelerator-control-menu-on-button"), StyleClasses = { StyleBase.ButtonOpenLeft }, }; - _onButton.OnPressed += args => owner.SendEnableMessage(true); + _onButton.OnPressed += args => OnOverallState?.Invoke(true); var closeButton = new TextureButton { @@ -316,7 +321,7 @@ public ParticleAcceleratorControlMenu(ParticleAcceleratorBoundUserInterface owne } }); - _scanButton.OnPressed += args => _owner.SendScanPartsMessage(); + _scanButton.OnPressed += args => OnScanPartsRequested?.Invoke(); _alarmControl.AnimationCompleted += s => { @@ -332,7 +337,7 @@ public ParticleAcceleratorControlMenu(ParticleAcceleratorBoundUserInterface owne PASegmentControl Segment(string name) { - return new(this, resourceCache, name); + return new(this, _cache, name); } UpdateUI(false, false, false, false); @@ -368,7 +373,7 @@ private void PowerStateChanged(ValueChangedEventArgs e) } _stateSpinBox.SetButtonDisabled(true); - _owner.SendPowerStateMessage(newState); + OnPowerState?.Invoke(newState); } protected override DragMode GetDragModeFor(Vector2 relativeMousePos) diff --git a/Content.Client/Pinpointer/UI/NavMapBeaconBoundUserInterface.cs b/Content.Client/Pinpointer/UI/NavMapBeaconBoundUserInterface.cs index 3ebcf7cbced..0df6787170a 100644 --- a/Content.Client/Pinpointer/UI/NavMapBeaconBoundUserInterface.cs +++ b/Content.Client/Pinpointer/UI/NavMapBeaconBoundUserInterface.cs @@ -1,5 +1,6 @@ using Content.Shared.Pinpointer; using JetBrains.Annotations; +using Robust.Client.UserInterface; namespace Content.Client.Pinpointer.UI; @@ -16,19 +17,16 @@ public NavMapBeaconBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, protected override void Open() { base.Open(); - _window = new NavMapBeaconWindow(Owner); - _window.OpenCentered(); - _window.OnClose += Close; + _window = this.CreateWindow(); + + if (EntMan.TryGetComponent(Owner, out NavMapBeaconComponent? beacon)) + { + _window.SetEntity(Owner, beacon); + } _window.OnApplyButtonPressed += (label, enabled, color) => { SendMessage(new NavMapBeaconConfigureBuiMessage(label, enabled, color)); }; } - - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - _window?.Dispose(); - } } diff --git a/Content.Client/Pinpointer/UI/NavMapBeaconWindow.xaml.cs b/Content.Client/Pinpointer/UI/NavMapBeaconWindow.xaml.cs index 968fe188f75..b77f1af0472 100644 --- a/Content.Client/Pinpointer/UI/NavMapBeaconWindow.xaml.cs +++ b/Content.Client/Pinpointer/UI/NavMapBeaconWindow.xaml.cs @@ -10,38 +10,37 @@ namespace Content.Client.Pinpointer.UI; [GenerateTypedNameReferences] public sealed partial class NavMapBeaconWindow : FancyWindow { - [Dependency] private readonly IEntityManager _entityManager = default!; - private string? _defaultLabel; private bool _defaultEnabled; private Color _defaultColor; public event Action? OnApplyButtonPressed; - public NavMapBeaconWindow(EntityUid beaconEntity) + public NavMapBeaconWindow() { RobustXamlLoader.Load(this); IoCManager.InjectDependencies(this); - if (!_entityManager.TryGetComponent(beaconEntity, out var navMap)) - return; - _defaultLabel = navMap.Text; - _defaultEnabled = navMap.Enabled; - _defaultColor = navMap.Color; - UpdateVisibleButton(navMap.Enabled); VisibleButton.OnPressed += args => UpdateVisibleButton(args.Button.Pressed); - - LabelLineEdit.Text = navMap.Text ?? string.Empty; LabelLineEdit.OnTextChanged += OnTextChanged; - - ColorSelector.Color = navMap.Color; ColorSelector.OnColorChanged += _ => TryEnableApplyButton(); TryEnableApplyButton(); ApplyButton.OnPressed += OnApplyPressed; } + public void SetEntity(EntityUid uid, NavMapBeaconComponent navMap) + { + _defaultLabel = navMap.Text; + _defaultEnabled = navMap.Enabled; + _defaultColor = navMap.Color; + + UpdateVisibleButton(navMap.Enabled); + LabelLineEdit.Text = navMap.Text ?? string.Empty; + ColorSelector.Color = navMap.Color; + } + private void UpdateVisibleButton(bool value) { VisibleButton.Pressed = value; diff --git a/Content.Client/Pinpointer/UI/StationMapBoundUserInterface.cs b/Content.Client/Pinpointer/UI/StationMapBoundUserInterface.cs index 1483e75e732..7417fafede5 100644 --- a/Content.Client/Pinpointer/UI/StationMapBoundUserInterface.cs +++ b/Content.Client/Pinpointer/UI/StationMapBoundUserInterface.cs @@ -1,4 +1,4 @@ -using Robust.Client.GameObjects; +using Robust.Client.UserInterface; namespace Content.Client.Pinpointer.UI; @@ -14,7 +14,6 @@ public StationMapBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, u protected override void Open() { base.Open(); - _window?.Close(); EntityUid? gridUid = null; if (EntMan.TryGetComponent(Owner, out var xform)) @@ -22,14 +21,8 @@ protected override void Open() gridUid = xform.GridUid; } - _window = new StationMapWindow(gridUid, Owner); - _window.OpenCentered(); - _window.OnClose += Close; - } - - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - _window?.Dispose(); + _window = this.CreateWindow(); + _window.Title = EntMan.GetComponent(Owner).EntityName; + _window.Set(gridUid, Owner); } } diff --git a/Content.Client/Pinpointer/UI/StationMapWindow.xaml.cs b/Content.Client/Pinpointer/UI/StationMapWindow.xaml.cs index 1b01fe4e304..7cbb8b7d0db 100644 --- a/Content.Client/Pinpointer/UI/StationMapWindow.xaml.cs +++ b/Content.Client/Pinpointer/UI/StationMapWindow.xaml.cs @@ -9,19 +9,18 @@ namespace Content.Client.Pinpointer.UI; [GenerateTypedNameReferences] public sealed partial class StationMapWindow : FancyWindow { - public StationMapWindow(EntityUid? mapUid, EntityUid? trackedEntity) + public StationMapWindow() { RobustXamlLoader.Load(this); + } + + public void Set(EntityUid? mapUid, EntityUid? trackedEntity) + { NavMapScreen.MapUid = mapUid; if (trackedEntity != null) NavMapScreen.TrackedCoordinates.Add(new EntityCoordinates(trackedEntity.Value, Vector2.Zero), (true, Color.Cyan)); - if (IoCManager.Resolve().TryGetComponent(mapUid, out var metadata)) - { - Title = metadata.EntityName; - } - NavMapScreen.ForceNavMapUpdate(); } } diff --git a/Content.Client/Pinpointer/UI/UntrackedMapBoundUserInterface.cs b/Content.Client/Pinpointer/UI/UntrackedMapBoundUserInterface.cs index 57965b030a2..a3ca6f65da2 100644 --- a/Content.Client/Pinpointer/UI/UntrackedMapBoundUserInterface.cs +++ b/Content.Client/Pinpointer/UI/UntrackedMapBoundUserInterface.cs @@ -1,4 +1,4 @@ -using Robust.Client.GameObjects; +using Robust.Client.UserInterface; namespace Content.Client.Pinpointer.UI; @@ -14,22 +14,15 @@ public UntrackedStationMapBoundUserInterface(EntityUid owner, Enum uiKey) : base protected override void Open() { base.Open(); - _window?.Close(); EntityUid? gridUid = null; + // TODO: What this just looks like it's been copy-pasted wholesale from StationMapBoundUserInterface? if (EntMan.TryGetComponent(Owner, out var xform)) { gridUid = xform.GridUid; } - _window = new StationMapWindow(gridUid, null); - _window.OpenCentered(); - _window.OnClose += Close; - } - - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - _window?.Dispose(); + _window = this.CreateWindow(); + _window.Set(gridUid, Owner); } } diff --git a/Content.Client/Power/APC/ApcBoundUserInterface.cs b/Content.Client/Power/APC/ApcBoundUserInterface.cs index fbcbf011569..759a5949ba6 100644 --- a/Content.Client/Power/APC/ApcBoundUserInterface.cs +++ b/Content.Client/Power/APC/ApcBoundUserInterface.cs @@ -2,6 +2,7 @@ using Content.Shared.APC; using JetBrains.Annotations; using Robust.Client.GameObjects; +using Robust.Client.UserInterface; namespace Content.Client.Power.APC { @@ -19,9 +20,8 @@ protected override void Open() { base.Open(); - _menu = new ApcMenu(this); - _menu.OnClose += Close; - _menu.OpenCentered(); + _menu = this.CreateWindow(); + _menu.OnBreaker += BreakerPressed; } protected override void UpdateState(BoundUserInterfaceState state) @@ -36,15 +36,5 @@ public void BreakerPressed() { SendMessage(new ApcToggleMainBreakerMessage()); } - - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - - if (disposing) - { - _menu?.Dispose(); - } - } } } diff --git a/Content.Client/Power/APC/UI/ApcMenu.xaml.cs b/Content.Client/Power/APC/UI/ApcMenu.xaml.cs index dbf68ea07b0..2f61ea63a86 100644 --- a/Content.Client/Power/APC/UI/ApcMenu.xaml.cs +++ b/Content.Client/Power/APC/UI/ApcMenu.xaml.cs @@ -17,13 +17,19 @@ namespace Content.Client.Power.APC.UI [GenerateTypedNameReferences] public sealed partial class ApcMenu : FancyWindow { - public ApcMenu(ApcBoundUserInterface owner) + public event Action? OnBreaker; + + public ApcMenu() { IoCManager.InjectDependencies(this); RobustXamlLoader.Load(this); - EntityView.SetEntity(owner.Owner); - BreakerButton.OnPressed += _ => owner.BreakerPressed(); + BreakerButton.OnPressed += _ => OnBreaker?.Invoke(); + } + + public void SetEntity(EntityUid entity) + { + EntityView.SetEntity(entity); } public void UpdateState(BoundUserInterfaceState state) diff --git a/Content.Client/Power/Generator/GeneratorWindow.xaml.cs b/Content.Client/Power/Generator/GeneratorWindow.xaml.cs index bd5b75de1da..e975e5d466e 100644 --- a/Content.Client/Power/Generator/GeneratorWindow.xaml.cs +++ b/Content.Client/Power/Generator/GeneratorWindow.xaml.cs @@ -9,35 +9,39 @@ namespace Content.Client.Power.Generator; [GenerateTypedNameReferences] public sealed partial class GeneratorWindow : FancyWindow { - private readonly EntityUid _entity; - [Dependency] private readonly IEntityManager _entityManager = default!; [Dependency] private readonly ILocalizationManager _loc = default!; - private readonly SharedPowerSwitchableSystem _switchable; - private readonly FuelGeneratorComponent? _component; - private PortableGeneratorComponentBuiState? _lastState; + private EntityUid _entity; + + public float? MaximumPower; + + public event Action? OnPower; + public event Action? OnState; + public event Action? OnSwitchOutput; + public event Action? OnEjectFuel; - public GeneratorWindow(PortableGeneratorBoundUserInterface bui, EntityUid entity) + public GeneratorWindow() { - _entity = entity; RobustXamlLoader.Load(this); IoCManager.InjectDependencies(this); - _entityManager.TryGetComponent(entity, out _component); - _switchable = _entityManager.System(); - - EntityView.SetEntity(entity); TargetPower.IsValid += IsValid; TargetPower.ValueChanged += (args) => { - bui.SetTargetPower(args.Value); + OnPower?.Invoke(args.Value); }; - StartButton.OnPressed += _ => bui.Start(); - StopButton.OnPressed += _ => bui.Stop(); - OutputSwitchButton.OnPressed += _ => bui.SwitchOutput(); - FuelEject.OnPressed += _ => bui.EjectFuel(); + StartButton.OnPressed += _ => OnState?.Invoke(true); + StopButton.OnPressed += _ => OnState?.Invoke(false); + OutputSwitchButton.OnPressed += _ => OnSwitchOutput?.Invoke(); + FuelEject.OnPressed += _ => OnEjectFuel?.Invoke(); + } + + public void SetEntity(EntityUid entity) + { + _entity = entity; + EntityView.SetEntity(entity); } private bool IsValid(int arg) @@ -45,7 +49,7 @@ private bool IsValid(int arg) if (arg < 0) return false; - if (arg > (_lastState?.MaximumPower / 1000.0f ?? 0)) + if (arg > (MaximumPower / 1000.0f ?? 0)) return false; return true; @@ -53,16 +57,17 @@ private bool IsValid(int arg) public void Update(PortableGeneratorComponentBuiState state) { - if (_component == null) + MaximumPower = state.MaximumPower; + + if (!_entityManager.TryGetComponent(_entity, out FuelGeneratorComponent? component)) return; - _lastState = state; if (!TargetPower.LineEditControl.HasKeyboardFocus()) TargetPower.OverrideValue((int)(state.TargetPower / 1000.0f)); - var efficiency = SharedGeneratorSystem.CalcFuelEfficiency(state.TargetPower, state.OptimalPower, _component); + var efficiency = SharedGeneratorSystem.CalcFuelEfficiency(state.TargetPower, state.OptimalPower, component); Efficiency.Text = efficiency.ToString("P1"); - var burnRate = _component.OptimalBurnRate / efficiency; + var burnRate = component.OptimalBurnRate / efficiency; var left = state.RemainingFuel / burnRate; Eta.Text = Loc.GetString( @@ -102,14 +107,15 @@ public void Update(PortableGeneratorComponentBuiState state) } var canSwitch = _entityManager.TryGetComponent(_entity, out PowerSwitchableComponent? switchable); + var switcher = _entityManager.System(); OutputSwitchLabel.Visible = canSwitch; OutputSwitchButton.Visible = canSwitch; if (switchable != null) { - var voltage = _switchable.VoltageString(_switchable.GetVoltage(_entity, switchable)); + var voltage = switcher.VoltageString(switcher.GetVoltage(_entity, switchable)); OutputSwitchLabel.Text = Loc.GetString("portable-generator-ui-current-output", ("voltage", voltage)); - var nextVoltage = _switchable.VoltageString(_switchable.GetNextVoltage(_entity, switchable)); + var nextVoltage = switcher.VoltageString(switcher.GetNextVoltage(_entity, switchable)); OutputSwitchButton.Text = Loc.GetString("power-switchable-switch-voltage", ("voltage", nextVoltage)); OutputSwitchButton.Disabled = state.On; } diff --git a/Content.Client/Power/Generator/PortableGeneratorBoundUserInterface.cs b/Content.Client/Power/Generator/PortableGeneratorBoundUserInterface.cs index 30679d71fd6..550e1041b62 100644 --- a/Content.Client/Power/Generator/PortableGeneratorBoundUserInterface.cs +++ b/Content.Client/Power/Generator/PortableGeneratorBoundUserInterface.cs @@ -1,6 +1,7 @@ using Content.Shared.Power.Generator; using JetBrains.Annotations; using Robust.Client.GameObjects; +using Robust.Client.UserInterface; namespace Content.Client.Power.Generator; @@ -16,10 +17,25 @@ public PortableGeneratorBoundUserInterface(EntityUid owner, Enum uiKey) : base(o protected override void Open() { base.Open(); - _window = new GeneratorWindow(this, Owner); + _window = this.CreateWindow(); + _window.SetEntity(Owner); + _window.OnState += args => + { + if (args) + { + Start(); + } + else + { + Stop(); + } + }; + + _window.OnPower += SetTargetPower; + _window.OnEjectFuel += EjectFuel; + _window.OnSwitchOutput += SwitchOutput; _window.OpenCenteredLeft(); - _window.OnClose += Close; } protected override void UpdateState(BoundUserInterfaceState state) @@ -30,11 +46,6 @@ protected override void UpdateState(BoundUserInterfaceState state) _window?.Update(msg); } - protected override void Dispose(bool disposing) - { - _window?.Dispose(); - } - public void SetTargetPower(int target) { SendMessage(new PortableGeneratorSetTargetPowerMessage(target)); diff --git a/Content.Client/Power/PowerMonitoringConsoleBoundUserInterface.cs b/Content.Client/Power/PowerMonitoringConsoleBoundUserInterface.cs index dc1dcd03ef1..cbc343c06c6 100644 --- a/Content.Client/Power/PowerMonitoringConsoleBoundUserInterface.cs +++ b/Content.Client/Power/PowerMonitoringConsoleBoundUserInterface.cs @@ -1,4 +1,5 @@ using Content.Shared.Power; +using Robust.Client.UserInterface; namespace Content.Client.Power; @@ -11,9 +12,9 @@ public PowerMonitoringConsoleBoundUserInterface(EntityUid owner, Enum uiKey) : b protected override void Open() { - _menu = new PowerMonitoringWindow(this, Owner); - _menu.OpenCentered(); - _menu.OnClose += Close; + _menu = this.CreateWindow(); + _menu.SetEntity(Owner); + _menu.SendPowerMonitoringConsoleMessageAction += SendPowerMonitoringConsoleMessage; } protected override void UpdateState(BoundUserInterfaceState state) @@ -22,9 +23,6 @@ protected override void UpdateState(BoundUserInterfaceState state) var castState = (PowerMonitoringConsoleBoundInterfaceState) state; - if (castState == null) - return; - EntMan.TryGetComponent(Owner, out var xform); _menu?.ShowEntites (castState.TotalSources, @@ -40,13 +38,4 @@ public void SendPowerMonitoringConsoleMessage(NetEntity? netEntity, PowerMonitor { SendMessage(new PowerMonitoringConsoleMessage(netEntity, group)); } - - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - if (!disposing) - return; - - _menu?.Dispose(); - } } diff --git a/Content.Client/Power/PowerMonitoringWindow.xaml.Widgets.cs b/Content.Client/Power/PowerMonitoringWindow.xaml.Widgets.cs index 74752ddc534..d9952992070 100644 --- a/Content.Client/Power/PowerMonitoringWindow.xaml.Widgets.cs +++ b/Content.Client/Power/PowerMonitoringWindow.xaml.Widgets.cs @@ -32,7 +32,7 @@ private void UpdateWindowConsoleEntry if (windowEntry == null) return; - // Update sources and loads + // Update sources and loads UpdateEntrySourcesOrLoads(masterContainer, windowEntry.SourcesContainer, focusSources, _sourceIcon); UpdateEntrySourcesOrLoads(masterContainer, windowEntry.LoadsContainer, focusLoads, _loadIconPath); @@ -134,7 +134,7 @@ private void UpdateEntrySourcesOrLoads(BoxContainer masterContainer, BoxContaine subEntry.Button.OnButtonUp += args => { ButtonAction(subEntry, masterContainer); }; } - if (!_entManager.TryGetComponent(_owner, out var console)) + if (!_entManager.TryGetComponent(Entity, out var console)) return; // Update all children @@ -379,7 +379,7 @@ public PowerMonitoringWindowEntry(PowerMonitoringConsoleEntry entry) : base(entr AddChild(MainContainer); - // Grid container to hold the list of sources when selected + // Grid container to hold the list of sources when selected SourcesContainer = new BoxContainer() { Orientation = LayoutOrientation.Vertical, diff --git a/Content.Client/Power/PowerMonitoringWindow.xaml.cs b/Content.Client/Power/PowerMonitoringWindow.xaml.cs index 81fe1f4d047..e3043252486 100644 --- a/Content.Client/Power/PowerMonitoringWindow.xaml.cs +++ b/Content.Client/Power/PowerMonitoringWindow.xaml.cs @@ -15,13 +15,12 @@ namespace Content.Client.Power; [GenerateTypedNameReferences] public sealed partial class PowerMonitoringWindow : FancyWindow { - private readonly IEntityManager _entManager; + [Dependency] private IEntityManager _entManager = default!; private readonly SpriteSystem _spriteSystem; - private readonly IGameTiming _gameTiming; + [Dependency] private IGameTiming _gameTiming = default!; private const float BlinkFrequency = 1f; - private EntityUid? _owner; private NetEntity? _focusEntity; public event Action? SendPowerMonitoringConsoleMessageAction; @@ -34,31 +33,56 @@ public sealed partial class PowerMonitoringWindow : FancyWindow { PowerMonitoringConsoleGroup.APC, (new SpriteSpecifier.Texture(new ResPath("/Textures/Interface/NavMap/beveled_triangle.png")), Color.LimeGreen) }, }; - public PowerMonitoringWindow(PowerMonitoringConsoleBoundUserInterface userInterface, EntityUid? owner) + public EntityUid Entity; + + public PowerMonitoringWindow() { RobustXamlLoader.Load(this); - _entManager = IoCManager.Resolve(); - _gameTiming = IoCManager.Resolve(); + IoCManager.InjectDependencies(this); _spriteSystem = _entManager.System(); - _owner = owner; + + // Set trackable entity selected action + NavMap.TrackedEntitySelectedAction += SetTrackedEntityFromNavMap; + + // Update nav map + NavMap.ForceNavMapUpdate(); + + // Set UI tab titles + MasterTabContainer.SetTabTitle(0, Loc.GetString("power-monitoring-window-label-sources")); + MasterTabContainer.SetTabTitle(1, Loc.GetString("power-monitoring-window-label-smes")); + MasterTabContainer.SetTabTitle(2, Loc.GetString("power-monitoring-window-label-substation")); + MasterTabContainer.SetTabTitle(3, Loc.GetString("power-monitoring-window-label-apc")); + + // Track when the MasterTabContainer changes its tab + MasterTabContainer.OnTabChanged += OnTabChanged; + + // Set UI toggles + ShowHVCable.OnToggled += _ => OnShowCableToggled(PowerMonitoringConsoleLineGroup.HighVoltage); + ShowMVCable.OnToggled += _ => OnShowCableToggled(PowerMonitoringConsoleLineGroup.MediumVoltage); + ShowLVCable.OnToggled += _ => OnShowCableToggled(PowerMonitoringConsoleLineGroup.Apc); + } + + public void SetEntity(EntityUid uid) + { + Entity = uid; // Pass owner to nav map - NavMap.Owner = _owner; + NavMap.Owner = uid; // Set nav map grid uid var stationName = Loc.GetString("power-monitoring-window-unknown-location"); - if (_entManager.TryGetComponent(owner, out var xform)) + if (_entManager.TryGetComponent(uid, out var xform)) { NavMap.MapUid = xform.GridUid; - // Assign station name + // Assign station name if (_entManager.TryGetComponent(xform.GridUid, out var stationMetaData)) stationName = stationMetaData.EntityName; var msg = new FormattedMessage(); - msg.AddMarkup(Loc.GetString("power-monitoring-window-station-name", ("stationName", stationName))); + msg.AddMarkupOrThrow(Loc.GetString("power-monitoring-window-station-name", ("stationName", stationName))); StationName.SetMessage(msg); } @@ -68,29 +92,6 @@ public PowerMonitoringWindow(PowerMonitoringConsoleBoundUserInterface userInterf StationName.SetMessage(stationName); NavMap.Visible = false; } - - // Set trackable entity selected action - NavMap.TrackedEntitySelectedAction += SetTrackedEntityFromNavMap; - - // Update nav map - NavMap.ForceNavMapUpdate(); - - // Set UI tab titles - MasterTabContainer.SetTabTitle(0, Loc.GetString("power-monitoring-window-label-sources")); - MasterTabContainer.SetTabTitle(1, Loc.GetString("power-monitoring-window-label-smes")); - MasterTabContainer.SetTabTitle(2, Loc.GetString("power-monitoring-window-label-substation")); - MasterTabContainer.SetTabTitle(3, Loc.GetString("power-monitoring-window-label-apc")); - - // Track when the MasterTabContainer changes its tab - MasterTabContainer.OnTabChanged += OnTabChanged; - - // Set UI toggles - ShowHVCable.OnToggled += _ => OnShowCableToggled(PowerMonitoringConsoleLineGroup.HighVoltage); - ShowMVCable.OnToggled += _ => OnShowCableToggled(PowerMonitoringConsoleLineGroup.MediumVoltage); - ShowLVCable.OnToggled += _ => OnShowCableToggled(PowerMonitoringConsoleLineGroup.Apc); - - // Set power monitoring message action - SendPowerMonitoringConsoleMessageAction += userInterface.SendPowerMonitoringConsoleMessage; } private void OnTabChanged(int tab) @@ -113,10 +114,7 @@ public void ShowEntites PowerMonitoringConsoleEntry[] focusLoads, EntityCoordinates? monitorCoords) { - if (_owner == null) - return; - - if (!_entManager.TryGetComponent(_owner.Value, out var console)) + if (!_entManager.TryGetComponent(Entity, out var console)) return; // Update power status text @@ -161,13 +159,13 @@ public void ShowEntites } // Show monitor location - var mon = _entManager.GetNetEntity(_owner); + var mon = _entManager.GetNetEntity(Entity); - if (monitorCoords != null && mon != null) + if (monitorCoords != null && mon.IsValid()) { var texture = _spriteSystem.Frame0(new SpriteSpecifier.Texture(new ResPath("/Textures/Interface/NavMap/beveled_circle.png"))); var blip = new NavMapBlip(monitorCoords.Value, texture, Color.Cyan, true, false); - NavMap.TrackedEntities[mon.Value] = blip; + NavMap.TrackedEntities[mon] = blip; } // If the entry group doesn't match the current tab, the data is out dated, do not use it @@ -239,7 +237,7 @@ private void SetTrackedEntityFromNavMap(NetEntity? netEntity) if (netEntity == null) return; - if (!_entManager.TryGetComponent(_owner, out var console)) + if (!_entManager.TryGetComponent(Entity, out var console)) return; if (!console.PowerMonitoringDeviceMetaData.TryGetValue(netEntity.Value, out var metaData)) @@ -266,7 +264,7 @@ protected override void FrameUpdate(FrameEventArgs args) { AutoScrollToFocus(); - // Warning sign pulse + // Warning sign pulse var lit = _gameTiming.RealTime.TotalSeconds % BlinkFrequency > BlinkFrequency / 2f; SystemWarningPanel.Modulate = lit ? Color.White : new Color(178, 178, 178); } diff --git a/Content.Client/RCD/RCDMenu.xaml.cs b/Content.Client/RCD/RCDMenu.xaml.cs index 3eb0397a690..f0d27d6b1fb 100644 --- a/Content.Client/RCD/RCDMenu.xaml.cs +++ b/Content.Client/RCD/RCDMenu.xaml.cs @@ -20,31 +20,37 @@ public sealed partial class RCDMenu : RadialMenu [Dependency] private readonly IPrototypeManager _protoManager = default!; [Dependency] private readonly IPlayerManager _playerManager = default!; - private readonly SpriteSystem _spriteSystem; - private readonly SharedPopupSystem _popup; + private SharedPopupSystem _popup; + private SpriteSystem _sprites; public event Action>? SendRCDSystemMessageAction; private EntityUid _owner; - public RCDMenu(EntityUid owner, RCDMenuBoundUserInterface bui) + public RCDMenu() { IoCManager.InjectDependencies(this); RobustXamlLoader.Load(this); - _spriteSystem = _entManager.System(); _popup = _entManager.System(); + _sprites = _entManager.System(); - _owner = owner; + OnChildAdded += AddRCDMenuButtonOnClickActions; + } + + public void SetEntity(EntityUid uid) + { + _owner = uid; + Refresh(); + } + public void Refresh() + { // Find the main radial container var main = FindControl("Main"); - if (main == null) - return; - // Populate secondary radial containers - if (!_entManager.TryGetComponent(owner, out var rcd)) + if (!_entManager.TryGetComponent(_owner, out var rcd)) return; foreach (var protoId in rcd.AvailablePrototypes) @@ -56,14 +62,10 @@ public RCDMenu(EntityUid owner, RCDMenuBoundUserInterface bui) continue; var parent = FindControl(proto.Category); - - if (parent == null) - continue; - var tooltip = Loc.GetString(proto.SetName); if ((proto.Mode == RcdMode.ConstructTile || proto.Mode == RcdMode.ConstructObject) && - proto.Prototype != null && _protoManager.TryIndex(proto.Prototype, out var entProto)) + proto.Prototype != null && _protoManager.TryIndex(proto.Prototype, out var entProto, logError: false)) { tooltip = Loc.GetString(entProto.Name); } @@ -84,7 +86,7 @@ public RCDMenu(EntityUid owner, RCDMenuBoundUserInterface bui) { VerticalAlignment = VAlignment.Center, HorizontalAlignment = HAlignment.Center, - Texture = _spriteSystem.Frame0(proto.Sprite), + Texture = _sprites.Frame0(proto.Sprite), TextureScale = new Vector2(2f, 2f), }; @@ -112,11 +114,9 @@ public RCDMenu(EntityUid owner, RCDMenuBoundUserInterface bui) // Set up menu actions foreach (var child in Children) + { AddRCDMenuButtonOnClickActions(child); - - OnChildAdded += AddRCDMenuButtonOnClickActions; - - SendRCDSystemMessageAction += bui.SendRCDSystemMessage; + } } private static string OopsConcat(string a, string b) @@ -153,7 +153,7 @@ private void AddRCDMenuButtonOnClickActions(Control control) var name = Loc.GetString(proto.SetName); if (proto.Prototype != null && - _protoManager.TryIndex(proto.Prototype, out var entProto)) + _protoManager.TryIndex(proto.Prototype, out var entProto, logError: false)) name = entProto.Name; msg = Loc.GetString("rcd-component-change-build-mode", ("name", name)); diff --git a/Content.Client/RCD/RCDMenuBoundUserInterface.cs b/Content.Client/RCD/RCDMenuBoundUserInterface.cs index a37dbcecf8c..1dd03626ae6 100644 --- a/Content.Client/RCD/RCDMenuBoundUserInterface.cs +++ b/Content.Client/RCD/RCDMenuBoundUserInterface.cs @@ -3,6 +3,7 @@ using JetBrains.Annotations; using Robust.Client.Graphics; using Robust.Client.Input; +using Robust.Client.UserInterface; using Robust.Shared.Prototypes; namespace Content.Client.RCD; @@ -24,8 +25,9 @@ protected override void Open() { base.Open(); - _menu = new(Owner, this); - _menu.OnClose += Close; + _menu = this.CreateWindow(); + _menu.SetEntity(Owner); + _menu.SendRCDSystemMessageAction += SendRCDSystemMessage; // Open the menu, centered on the mouse var vpSize = _displayManager.ScreenSize; @@ -34,16 +36,8 @@ protected override void Open() public void SendRCDSystemMessage(ProtoId protoId) { - // A predicted message cannot be used here as the RCD UI is closed immediately + // A predicted message cannot be used here as the RCD UI is closed immediately // after this message is sent, which will stop the server from receiving it SendMessage(new RCDSystemMessage(protoId)); } - - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - if (!disposing) return; - - _menu?.Dispose(); - } } diff --git a/Content.Client/Radio/Ui/IntercomBoundUserInterface.cs b/Content.Client/Radio/Ui/IntercomBoundUserInterface.cs index 7b3e39aa084..401e7edd44a 100644 --- a/Content.Client/Radio/Ui/IntercomBoundUserInterface.cs +++ b/Content.Client/Radio/Ui/IntercomBoundUserInterface.cs @@ -1,6 +1,8 @@ using Content.Shared.Radio; using Content.Shared.Radio.Components; using JetBrains.Annotations; +using Robust.Client.GameObjects; +using Robust.Client.UserInterface; namespace Content.Client.Radio.Ui; @@ -19,9 +21,12 @@ protected override void Open() { base.Open(); - var comp = EntMan.GetComponent(Owner); + _menu = this.CreateWindow(); - _menu = new((Owner, comp)); + if (EntMan.TryGetComponent(Owner, out IntercomComponent? intercom)) + { + _menu.Update((Owner, intercom)); + } _menu.OnMicPressed += enabled => { @@ -35,17 +40,6 @@ protected override void Open() { SendMessage(new SelectIntercomChannelMessage(channel)); }; - - _menu.OnClose += Close; - _menu.OpenCentered(); - } - - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - if (!disposing) - return; - _menu?.Close(); } public void Update(Entity ent) diff --git a/Content.Client/Radio/Ui/IntercomMenu.xaml.cs b/Content.Client/Radio/Ui/IntercomMenu.xaml.cs index 2e08913051c..20d2e4a3e54 100644 --- a/Content.Client/Radio/Ui/IntercomMenu.xaml.cs +++ b/Content.Client/Radio/Ui/IntercomMenu.xaml.cs @@ -18,15 +18,13 @@ public sealed partial class IntercomMenu : FancyWindow private readonly List _channels = new(); - public IntercomMenu(Entity entity) + public IntercomMenu() { RobustXamlLoader.Load(this); IoCManager.InjectDependencies(this); MicButton.OnPressed += args => OnMicPressed?.Invoke(args.Button.Pressed); SpeakerButton.OnPressed += args => OnSpeakerPressed?.Invoke(args.Button.Pressed); - - Update(entity); } public void Update(Entity entity) diff --git a/Content.Client/Research/UI/DiskConsoleBoundUserInterface.cs b/Content.Client/Research/UI/DiskConsoleBoundUserInterface.cs index c14a8c5bd05..9641adb5b2d 100644 --- a/Content.Client/Research/UI/DiskConsoleBoundUserInterface.cs +++ b/Content.Client/Research/UI/DiskConsoleBoundUserInterface.cs @@ -1,5 +1,7 @@ using Content.Shared.Research; using Content.Shared.Research.Components; +using Robust.Client.GameObjects; +using Robust.Client.UserInterface; namespace Content.Client.Research.UI { @@ -16,10 +18,7 @@ protected override void Open() { base.Open(); - _menu = new(); - - _menu.OnClose += Close; - _menu.OpenCentered(); + _menu = this.CreateWindow(); _menu.OnServerButtonPressed += () => { @@ -31,14 +30,6 @@ protected override void Open() }; } - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - if (!disposing) - return; - _menu?.Close(); - } - protected override void UpdateState(BoundUserInterfaceState state) { base.UpdateState(state); diff --git a/Content.Client/Research/UI/ResearchClientBoundUserInterface.cs b/Content.Client/Research/UI/ResearchClientBoundUserInterface.cs index a0a2b58e889..288445e4dea 100644 --- a/Content.Client/Research/UI/ResearchClientBoundUserInterface.cs +++ b/Content.Client/Research/UI/ResearchClientBoundUserInterface.cs @@ -1,4 +1,6 @@ using Content.Shared.Research.Components; +using Robust.Client.GameObjects; +using Robust.Client.UserInterface; namespace Content.Client.Research.UI { @@ -15,10 +17,9 @@ public ResearchClientBoundUserInterface(EntityUid owner, Enum uiKey) : base(owne protected override void Open() { base.Open(); - - _menu = new ResearchClientServerSelectionMenu(this); - _menu.OnClose += Close; - _menu.OpenCentered(); + _menu = this.CreateWindow(); + _menu.OnServerSelected += SelectServer; + _menu.OnServerDeselected += DeselectServer; } public void SelectServer(int serverId) @@ -37,12 +38,5 @@ protected override void UpdateState(BoundUserInterfaceState state) if (state is not ResearchClientBoundInterfaceState rState) return; _menu?.Populate(rState.ServerCount, rState.ServerNames, rState.ServerIds, rState.SelectedServerId); } - - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - if (!disposing) return; - _menu?.Dispose(); - } } } diff --git a/Content.Client/Research/UI/ResearchClientServerSelectionMenu.xaml.cs b/Content.Client/Research/UI/ResearchClientServerSelectionMenu.xaml.cs index ceaa965e59f..d10f8b39f48 100644 --- a/Content.Client/Research/UI/ResearchClientServerSelectionMenu.xaml.cs +++ b/Content.Client/Research/UI/ResearchClientServerSelectionMenu.xaml.cs @@ -13,27 +13,26 @@ public sealed partial class ResearchClientServerSelectionMenu : DefaultWindow private int[] _serverIds = Array.Empty(); private int _selectedServerId = -1; - private ResearchClientBoundUserInterface Owner { get; } + public event Action? OnServerSelected; + public event Action? OnServerDeselected; - public ResearchClientServerSelectionMenu(ResearchClientBoundUserInterface owner) + public ResearchClientServerSelectionMenu() { RobustXamlLoader.Load(this); IoCManager.InjectDependencies(this); - Owner = owner; - Servers.OnItemSelected += OnItemSelected; Servers.OnItemDeselected += OnItemDeselected; } public void OnItemSelected(ItemList.ItemListSelectedEventArgs itemListSelectedEventArgs) { - Owner.SelectServer(_serverIds[itemListSelectedEventArgs.ItemIndex]); + OnServerSelected?.Invoke(_serverIds[itemListSelectedEventArgs.ItemIndex]); } public void OnItemDeselected(ItemList.ItemListDeselectedEventArgs itemListDeselectedEventArgs) { - Owner.DeselectServer(); + OnServerDeselected?.Invoke(); } public void Populate(int serverCount, string[] serverNames, int[] serverIds, int selectedServerId) diff --git a/Content.Client/Research/UI/ResearchConsoleBoundUserInterface.cs b/Content.Client/Research/UI/ResearchConsoleBoundUserInterface.cs index 2a9782045b8..2895ada61fb 100644 --- a/Content.Client/Research/UI/ResearchConsoleBoundUserInterface.cs +++ b/Content.Client/Research/UI/ResearchConsoleBoundUserInterface.cs @@ -1,5 +1,8 @@ using Content.Shared.Research.Components; +using Content.Shared.Research.Prototypes; using JetBrains.Annotations; +using Robust.Client.UserInterface; +using Robust.Shared.Prototypes; namespace Content.Client.Research.UI; @@ -19,7 +22,8 @@ protected override void Open() var owner = Owner; - _consoleMenu = new ResearchConsoleMenu(owner); + _consoleMenu = this.CreateWindow(); + _consoleMenu.SetEntity(owner); _consoleMenu.OnTechnologyCardPressed += id => { @@ -30,10 +34,20 @@ protected override void Open() { SendMessage(new ConsoleServerSelectionMessage()); }; + } + + public override void OnProtoReload(PrototypesReloadedEventArgs args) + { + base.OnProtoReload(args); + + if (!args.WasModified()) + return; - _consoleMenu.OnClose += Close; + if (State is not ResearchConsoleBoundInterfaceState rState) + return; - _consoleMenu.OpenCentered(); + _consoleMenu?.UpdatePanels(rState); + _consoleMenu?.UpdateInformationPanel(rState); } protected override void UpdateState(BoundUserInterfaceState state) @@ -45,12 +59,4 @@ protected override void UpdateState(BoundUserInterfaceState state) _consoleMenu?.UpdatePanels(castState); _consoleMenu?.UpdateInformationPanel(castState); } - - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - if (!disposing) - return; - _consoleMenu?.Dispose(); - } } diff --git a/Content.Client/Research/UI/ResearchConsoleMenu.xaml.cs b/Content.Client/Research/UI/ResearchConsoleMenu.xaml.cs index 77ebe6740c5..eafbe75fbb9 100644 --- a/Content.Client/Research/UI/ResearchConsoleMenu.xaml.cs +++ b/Content.Client/Research/UI/ResearchConsoleMenu.xaml.cs @@ -25,14 +25,13 @@ public sealed partial class ResearchConsoleMenu : FancyWindow [Dependency] private readonly IEntityManager _entity = default!; [Dependency] private readonly IPrototypeManager _prototype = default!; [Dependency] private readonly IPlayerManager _player = default!; - private readonly TechnologyDatabaseComponent? _technologyDatabase; private readonly ResearchSystem _research; private readonly SpriteSystem _sprite; private readonly AccessReaderSystem _accessReader; - public readonly EntityUid Entity; + public EntityUid Entity; - public ResearchConsoleMenu(EntityUid entity) + public ResearchConsoleMenu() { RobustXamlLoader.Load(this); IoCManager.InjectDependencies(this); @@ -40,21 +39,23 @@ public ResearchConsoleMenu(EntityUid entity) _research = _entity.System(); _sprite = _entity.System(); _accessReader = _entity.System(); - Entity = entity; ServerButton.OnPressed += _ => OnServerButtonPressed?.Invoke(); + } - _entity.TryGetComponent(entity, out _technologyDatabase); + public void SetEntity(EntityUid entity) + { + Entity = entity; } - public void UpdatePanels(ResearchConsoleBoundInterfaceState state) + public void UpdatePanels(ResearchConsoleBoundInterfaceState state) { TechnologyCardsContainer.Children.Clear(); var availableTech = _research.GetAvailableTechnologies(Entity); SyncTechnologyList(AvailableCardsContainer, availableTech); - if (_technologyDatabase == null) + if (!_entity.TryGetComponent(Entity, out TechnologyDatabaseComponent? database)) return; // i can't figure out the spacing so here you go @@ -66,7 +67,7 @@ public void UpdatePanels(ResearchConsoleBoundInterfaceState state) var hasAccess = _player.LocalEntity is not { } local || !_entity.TryGetComponent(Entity, out var access) || _accessReader.IsAllowed(local, Entity, access); - foreach (var techId in _technologyDatabase.CurrentTechnologyCards) + foreach (var techId in database.CurrentTechnologyCards) { var tech = _prototype.Index(techId); var cardControl = new TechnologyCardControl(tech, _prototype, _sprite, _research.GetTechnologyDescription(tech, includeTier: false), state.Points, hasAccess); @@ -74,7 +75,7 @@ public void UpdatePanels(ResearchConsoleBoundInterfaceState state) TechnologyCardsContainer.AddChild(cardControl); } - var unlockedTech = _technologyDatabase.UnlockedTechnologies.Select(x => _prototype.Index(x)); + var unlockedTech = database.UnlockedTechnologies.Select(x => _prototype.Index(x)); SyncTechnologyList(UnlockedCardsContainer, unlockedTech); } @@ -85,14 +86,14 @@ public void UpdateInformationPanel(ResearchConsoleBoundInterfaceState state) ("points", state.Points))); ResearchAmountLabel.SetMessage(amountMsg); - if (_technologyDatabase == null) + if (!_entity.TryGetComponent(Entity, out TechnologyDatabaseComponent? database)) return; var disciplineText = Loc.GetString("research-discipline-none"); var disciplineColor = Color.Gray; - if (_technologyDatabase.MainDiscipline != null) + if (database.MainDiscipline != null) { - var discipline = _prototype.Index(_technologyDatabase.MainDiscipline); + var discipline = _prototype.Index(database.MainDiscipline); disciplineText = Loc.GetString(discipline.Name); disciplineColor = discipline.Color; } @@ -103,10 +104,10 @@ public void UpdateInformationPanel(ResearchConsoleBoundInterfaceState state) MainDisciplineLabel.SetMessage(msg); TierDisplayContainer.Children.Clear(); - foreach (var disciplineId in _technologyDatabase.SupportedDisciplines) + foreach (var disciplineId in database.SupportedDisciplines) { var discipline = _prototype.Index(disciplineId); - var tier = _research.GetHighestDisciplineTier(_technologyDatabase, discipline); + var tier = _research.GetHighestDisciplineTier(database, discipline); // don't show tiers with no available tech if (tier == 0) diff --git a/Content.Client/Robotics/UI/RoboticsConsoleBoundUserInterface.cs b/Content.Client/Robotics/UI/RoboticsConsoleBoundUserInterface.cs index 6185979eee6..9a5159880f9 100644 --- a/Content.Client/Robotics/UI/RoboticsConsoleBoundUserInterface.cs +++ b/Content.Client/Robotics/UI/RoboticsConsoleBoundUserInterface.cs @@ -1,5 +1,6 @@ using Content.Shared.Robotics; using Robust.Client.GameObjects; +using Robust.Client.UserInterface; namespace Content.Client.Robotics.UI; @@ -16,7 +17,9 @@ protected override void Open() { base.Open(); - _window = new RoboticsConsoleWindow(Owner); + _window = this.CreateWindow(); + _window.SetEntity(Owner); + _window.OnDisablePressed += address => { SendMessage(new RoboticsConsoleDisableMessage(address)); @@ -25,9 +28,6 @@ protected override void Open() { SendMessage(new RoboticsConsoleDestroyMessage(address)); }; - _window.OnClose += Close; - - _window.OpenCentered(); } protected override void UpdateState(BoundUserInterfaceState state) @@ -37,14 +37,6 @@ protected override void UpdateState(BoundUserInterfaceState state) if (state is not RoboticsConsoleState cast) return; - _window?.UpdateState(cast); - } - - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - - if (disposing) - _window?.Dispose(); + _window.UpdateState(cast); } } diff --git a/Content.Client/Robotics/UI/RoboticsConsoleWindow.xaml.cs b/Content.Client/Robotics/UI/RoboticsConsoleWindow.xaml.cs index fc7b234bccc..87d7e62c392 100644 --- a/Content.Client/Robotics/UI/RoboticsConsoleWindow.xaml.cs +++ b/Content.Client/Robotics/UI/RoboticsConsoleWindow.xaml.cs @@ -23,11 +23,12 @@ public sealed partial class RoboticsConsoleWindow : FancyWindow public Action? OnDisablePressed; public Action? OnDestroyPressed; - private Entity _console; private string? _selected; private Dictionary _cyborgs = new(); - public RoboticsConsoleWindow(EntityUid console) + public EntityUid Entity; + + public RoboticsConsoleWindow() { RobustXamlLoader.Load(this); IoCManager.InjectDependencies(this); @@ -35,9 +36,6 @@ public RoboticsConsoleWindow(EntityUid console) _lock = _entMan.System(); _sprite = _entMan.System(); - _console = (console, _entMan.GetComponent(console), null); - _entMan.TryGetComponent(_console, out _console.Comp2); - Cyborgs.OnItemSelected += args => { if (Cyborgs[args.ItemIndex].Metadata is not string address) @@ -66,6 +64,11 @@ public RoboticsConsoleWindow(EntityUid console) DestroyButton.StyleClasses.Add(StyleBase.ButtonCaution); } + public void SetEntity(EntityUid uid) + { + Entity = uid; + } + public void UpdateState(RoboticsConsoleState state) { _cyborgs = state.Cyborgs; @@ -81,7 +84,7 @@ public void UpdateState(RoboticsConsoleState state) PopulateData(); - var locked = _lock.IsLocked((_console, _console.Comp2)); + var locked = _lock.IsLocked(Entity); DangerZone.Visible = !locked; LockedMessage.Visible = locked; } @@ -135,13 +138,19 @@ private void PopulateData() // how the turntables DisableButton.Disabled = !(data.HasBrain && data.CanDisable); - DestroyButton.Disabled = _timing.CurTime < _console.Comp1.NextDestroy; } protected override void FrameUpdate(FrameEventArgs args) { base.FrameUpdate(args); - DestroyButton.Disabled = _timing.CurTime < _console.Comp1.NextDestroy; + if (_entMan.TryGetComponent(Entity, out RoboticsConsoleComponent? console)) + { + DestroyButton.Disabled = _timing.CurTime < console.NextDestroy; + } + else + { + DestroyButton.Disabled = true; + } } } diff --git a/Content.Client/Salvage/UI/SalvageExpeditionConsoleBoundUserInterface.cs b/Content.Client/Salvage/UI/SalvageExpeditionConsoleBoundUserInterface.cs index 8f1723d1f22..663bde15b0d 100644 --- a/Content.Client/Salvage/UI/SalvageExpeditionConsoleBoundUserInterface.cs +++ b/Content.Client/Salvage/UI/SalvageExpeditionConsoleBoundUserInterface.cs @@ -30,17 +30,9 @@ public SalvageExpeditionConsoleBoundUserInterface(EntityUid owner, Enum uiKey) : protected override void Open() { base.Open(); - _window = new OfferingWindow(); + _window = this.CreateWindow(); _window.Title = Loc.GetString("salvage-expedition-window-title"); - _window.OnClose += Close; - _window?.OpenCenteredLeft(); - } - - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - _window?.Dispose(); - _window = null; + _window.OpenCenteredLeft(); } protected override void UpdateState(BoundUserInterfaceState state) diff --git a/Content.Client/Salvage/UI/SalvageMagnetBoundUserInterface.cs b/Content.Client/Salvage/UI/SalvageMagnetBoundUserInterface.cs index be3ba0e046e..bee8092ea8e 100644 --- a/Content.Client/Salvage/UI/SalvageMagnetBoundUserInterface.cs +++ b/Content.Client/Salvage/UI/SalvageMagnetBoundUserInterface.cs @@ -21,13 +21,9 @@ protected override void Open() { base.Open(); - if (_window is null) - { - _window = new OfferingWindow(); - _window.Title = Loc.GetString("salvage-magnet-window-title"); - _window.OnClose += Close; - _window.OpenCenteredLeft(); - } + _window = this.CreateWindow(); + _window.Title = Loc.GetString("salvage-magnet-window-title"); + _window.OpenCenteredLeft(); } protected override void UpdateState(BoundUserInterfaceState state) @@ -112,15 +108,4 @@ protected override void UpdateState(BoundUserInterfaceState state) _window.AddOption(option); } } - - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - - if (disposing) - { - _window?.Close(); - _window?.Dispose(); - } - } } diff --git a/Content.Client/Shuttles/BUI/IFFConsoleBoundUserInterface.cs b/Content.Client/Shuttles/BUI/IFFConsoleBoundUserInterface.cs index 086369aa264..b8b4fb8a746 100644 --- a/Content.Client/Shuttles/BUI/IFFConsoleBoundUserInterface.cs +++ b/Content.Client/Shuttles/BUI/IFFConsoleBoundUserInterface.cs @@ -3,6 +3,7 @@ using Content.Shared.Shuttles.Events; using JetBrains.Annotations; using Robust.Client.GameObjects; +using Robust.Client.UserInterface; namespace Content.Client.Shuttles.BUI; @@ -20,8 +21,7 @@ protected override void Open() { base.Open(); - _window = new IFFConsoleWindow(); - _window.OnClose += Close; + _window = this.CreateWindow(); _window.ShowIFF += SendIFFMessage; _window.ShowVessel += SendVesselMessage; _window.OpenCenteredLeft(); diff --git a/Content.Client/Shuttles/BUI/RadarConsoleBoundUserInterface.cs b/Content.Client/Shuttles/BUI/RadarConsoleBoundUserInterface.cs index 4bd44a47a8e..f75759b042f 100644 --- a/Content.Client/Shuttles/BUI/RadarConsoleBoundUserInterface.cs +++ b/Content.Client/Shuttles/BUI/RadarConsoleBoundUserInterface.cs @@ -2,6 +2,7 @@ using Content.Shared.Shuttles.BUIStates; using JetBrains.Annotations; using Robust.Client.GameObjects; +using Robust.Client.UserInterface; using RadarConsoleWindow = Content.Client.Shuttles.UI.RadarConsoleWindow; namespace Content.Client.Shuttles.BUI; @@ -20,18 +21,7 @@ protected override void Open() { base.Open(); - _window = new RadarConsoleWindow(); - _window.OnClose += Close; - _window.OpenCentered(); - } - - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - if (disposing) - { - _window?.Dispose(); - } + _window = this.CreateWindow(); } protected override void UpdateState(BoundUserInterfaceState state) diff --git a/Content.Client/Shuttles/BUI/ShuttleConsoleBoundUserInterface.cs b/Content.Client/Shuttles/BUI/ShuttleConsoleBoundUserInterface.cs index af7b6055c80..e677181419e 100644 --- a/Content.Client/Shuttles/BUI/ShuttleConsoleBoundUserInterface.cs +++ b/Content.Client/Shuttles/BUI/ShuttleConsoleBoundUserInterface.cs @@ -2,6 +2,7 @@ using Content.Shared.Shuttles.BUIStates; using Content.Shared.Shuttles.Events; using JetBrains.Annotations; +using Robust.Client.UserInterface; using Robust.Shared.Map; namespace Content.Client.Shuttles.BUI; @@ -19,9 +20,7 @@ public ShuttleConsoleBoundUserInterface(EntityUid owner, Enum uiKey) : base(owne protected override void Open() { base.Open(); - _window = new ShuttleConsoleWindow(); - _window.OpenCentered(); - _window.OnClose += Close; + _window = this.CreateWindow(); _window.RequestFTL += OnFTLRequest; _window.RequestBeaconFTL += OnFTLBeaconRequest; diff --git a/Content.Client/Silicons/Borgs/BorgBoundUserInterface.cs b/Content.Client/Silicons/Borgs/BorgBoundUserInterface.cs index 3cc2a35d795..ed9bf40a481 100644 --- a/Content.Client/Silicons/Borgs/BorgBoundUserInterface.cs +++ b/Content.Client/Silicons/Borgs/BorgBoundUserInterface.cs @@ -1,6 +1,7 @@ using Content.Shared.Silicons.Borgs; using JetBrains.Annotations; using Robust.Client.GameObjects; +using Robust.Client.UserInterface; namespace Content.Client.Silicons.Borgs; @@ -18,9 +19,8 @@ protected override void Open() { base.Open(); - var owner = Owner; - - _menu = new BorgMenu(owner); + _menu = this.CreateWindow(); + _menu.SetEntity(Owner); _menu.BrainButtonPressed += () => { @@ -41,10 +41,6 @@ protected override void Open() { SendMessage(new BorgRemoveModuleBuiMessage(EntMan.GetNetEntity(module))); }; - - _menu.OnClose += Close; - - _menu.OpenCentered(); } protected override void UpdateState(BoundUserInterfaceState state) @@ -55,12 +51,4 @@ protected override void UpdateState(BoundUserInterfaceState state) return; _menu?.UpdateState(msg); } - - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - if (!disposing) - return; - _menu?.Dispose(); - } } diff --git a/Content.Client/Silicons/Borgs/BorgMenu.xaml b/Content.Client/Silicons/Borgs/BorgMenu.xaml index 7d8fd9fe57d..4cc2e41a8fb 100644 --- a/Content.Client/Silicons/Borgs/BorgMenu.xaml +++ b/Content.Client/Silicons/Borgs/BorgMenu.xaml @@ -10,7 +10,7 @@ VerticalExpand="True"> - + diff --git a/Content.Client/Silicons/Borgs/BorgMenu.xaml.cs b/Content.Client/Silicons/Borgs/BorgMenu.xaml.cs index 474a83b4530..f6a861aa057 100644 --- a/Content.Client/Silicons/Borgs/BorgMenu.xaml.cs +++ b/Content.Client/Silicons/Borgs/BorgMenu.xaml.cs @@ -21,25 +21,33 @@ public sealed partial class BorgMenu : FancyWindow public Action? NameChanged; public Action? RemoveModuleButtonPressed; - private readonly BorgChassisComponent? _chassis; - public readonly EntityUid Entity; public float AccumulatedTime; private string _lastValidName; private List _modules = new(); - public BorgMenu(EntityUid entity) + public EntityUid Entity; + + public BorgMenu() { RobustXamlLoader.Load(this); IoCManager.InjectDependencies(this); - Entity = entity; + _lastValidName = NameLineEdit.Text; - if (_entity.TryGetComponent(Entity, out var chassis)) - _chassis = chassis; + EjectBatteryButton.OnPressed += _ => EjectBatteryButtonPressed?.Invoke(); + BrainButton.OnPressed += _ => BrainButtonPressed?.Invoke(); + NameLineEdit.OnTextChanged += OnNameChanged; + NameLineEdit.OnTextEntered += OnNameEntered; + NameLineEdit.OnFocusExit += OnNameFocusExit; + + UpdateBrainButton(); + } + + public void SetEntity(EntityUid entity) + { + Entity = entity; BorgSprite.SetEntity(entity); - ChargeBar.MaxValue = 1f; - ChargeBar.Value = 1f; if (_entity.TryGetComponent(Entity, out var nameIdentifierComponent)) { @@ -55,17 +63,6 @@ public BorgMenu(EntityUid entity) NameIdentifierLabel.Visible = false; NameLineEdit.Text = _entity.GetComponent(Entity).EntityName; } - - _lastValidName = NameLineEdit.Text; - - EjectBatteryButton.OnPressed += _ => EjectBatteryButtonPressed?.Invoke(); - BrainButton.OnPressed += _ => BrainButtonPressed?.Invoke(); - - NameLineEdit.OnTextChanged += OnNameChanged; - NameLineEdit.OnTextEntered += OnNameEntered; - NameLineEdit.OnFocusExit += OnNameFocusExit; - - UpdateBrainButton(); } protected override void FrameUpdate(FrameEventArgs args) @@ -89,7 +86,7 @@ public void UpdateState(BorgBuiState state) private void UpdateBrainButton() { - if (_chassis?.BrainEntity is { } brain) + if (_entity.TryGetComponent(Entity, out BorgChassisComponent? chassis) && chassis.BrainEntity is { } brain) { BrainButton.Text = _entity.GetComponent(brain).EntityName; BrainView.Visible = true; @@ -108,17 +105,17 @@ private void UpdateBrainButton() private void UpdateModulePanel() { - if (_chassis == null) + if (!_entity.TryGetComponent(Entity, out BorgChassisComponent? chassis)) return; ModuleCounter.Text = Loc.GetString("borg-ui-module-counter", - ("actual", _chassis.ModuleCount), - ("max", _chassis.MaxModules)); + ("actual", chassis.ModuleCount), + ("max", chassis.MaxModules)); - if (_chassis.ModuleContainer.Count == _modules.Count) + if (chassis.ModuleContainer.Count == _modules.Count) { var isSame = true; - foreach (var module in _chassis.ModuleContainer.ContainedEntities) + foreach (var module in chassis.ModuleContainer.ContainedEntities) { if (_modules.Contains(module)) continue; @@ -132,7 +129,7 @@ private void UpdateModulePanel() ModuleContainer.Children.Clear(); _modules.Clear(); - foreach (var module in _chassis.ModuleContainer.ContainedEntities) + foreach (var module in chassis.ModuleContainer.ContainedEntities) { var control = new BorgModuleControl(module, _entity); control.RemoveButtonPressed += () => diff --git a/Content.Client/Silicons/Laws/Ui/SiliconLawBoundUserInterface.cs b/Content.Client/Silicons/Laws/Ui/SiliconLawBoundUserInterface.cs index d150735fa11..56216b91847 100644 --- a/Content.Client/Silicons/Laws/Ui/SiliconLawBoundUserInterface.cs +++ b/Content.Client/Silicons/Laws/Ui/SiliconLawBoundUserInterface.cs @@ -2,6 +2,7 @@ using Content.Shared.Silicons.Laws; using Content.Shared.Silicons.Laws.Components; using JetBrains.Annotations; +using Robust.Client.UserInterface; namespace Content.Client.Silicons.Laws.Ui; @@ -22,18 +23,7 @@ protected override void Open() { base.Open(); - _menu = new(); - - _menu.OnClose += Close; - _menu.OpenCentered(); - } - - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - if (!disposing) - return; - _menu?.Close(); + _menu = this.CreateWindow(); } protected override void UpdateState(BoundUserInterfaceState state) diff --git a/Content.Client/SprayPainter/UI/SprayPainterBoundUserInterface.cs b/Content.Client/SprayPainter/UI/SprayPainterBoundUserInterface.cs index e8442d23908..7d6a6cf2a5a 100644 --- a/Content.Client/SprayPainter/UI/SprayPainterBoundUserInterface.cs +++ b/Content.Client/SprayPainter/UI/SprayPainterBoundUserInterface.cs @@ -1,6 +1,6 @@ using Content.Shared.SprayPainter; using Content.Shared.SprayPainter.Components; -using Robust.Client.GameObjects; +using Robust.Client.UserInterface; using Robust.Client.UserInterface.Controls; namespace Content.Client.SprayPainter.UI; @@ -10,9 +10,6 @@ public sealed class SprayPainterBoundUserInterface : BoundUserInterface [ViewVariables] private SprayPainterWindow? _window; - [ViewVariables] - private SprayPainterSystem? _painter; - public SprayPainterBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey) { } @@ -21,27 +18,15 @@ protected override void Open() { base.Open(); - if (!EntMan.TryGetComponent(Owner, out var comp)) - return; - - _window = new SprayPainterWindow(); + _window = this.CreateWindow(); - _painter = EntMan.System(); - - _window.OnClose += Close; _window.OnSpritePicked = OnSpritePicked; _window.OnColorPicked = OnColorPicked; - _window.Populate(_painter.Entries, comp.Index, comp.PickedColor, comp.ColorPalette); - - _window.OpenCentered(); - } - - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - - _window?.Dispose(); + if (EntMan.TryGetComponent(Owner, out SprayPainterComponent? comp)) + { + _window.Populate(EntMan.System().Entries, comp.Index, comp.PickedColor, comp.ColorPalette); + } } private void OnSpritePicked(ItemList.ItemListSelectedEventArgs args) diff --git a/Content.Client/StationRecords/GeneralStationRecordConsoleBoundUserInterface.cs b/Content.Client/StationRecords/GeneralStationRecordConsoleBoundUserInterface.cs index 720a2efb9dd..e7bab71e38e 100644 --- a/Content.Client/StationRecords/GeneralStationRecordConsoleBoundUserInterface.cs +++ b/Content.Client/StationRecords/GeneralStationRecordConsoleBoundUserInterface.cs @@ -1,4 +1,5 @@ using Content.Shared.StationRecords; +using Robust.Client.UserInterface; namespace Content.Client.StationRecords; @@ -15,15 +16,12 @@ protected override void Open() { base.Open(); - _window = new(); + _window = this.CreateWindow(); _window.OnKeySelected += key => SendMessage(new SelectStationRecord(key)); _window.OnFiltersChanged += (type, filterValue) => SendMessage(new SetStationRecordFilter(type, filterValue)); _window.OnDeleted += id => SendMessage(new DeleteStationRecord(id)); - _window.OnClose += Close; - - _window.OpenCentered(); } protected override void UpdateState(BoundUserInterfaceState state) @@ -35,11 +33,4 @@ protected override void UpdateState(BoundUserInterfaceState state) _window?.UpdateState(cast); } - - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - - _window?.Close(); - } } diff --git a/Content.Client/Store/Ui/StoreBoundUserInterface.cs b/Content.Client/Store/Ui/StoreBoundUserInterface.cs index 0010aedd964..7ed67f7b5dd 100644 --- a/Content.Client/Store/Ui/StoreBoundUserInterface.cs +++ b/Content.Client/Store/Ui/StoreBoundUserInterface.cs @@ -2,6 +2,7 @@ using JetBrains.Annotations; using System.Linq; using Content.Shared.Store.Components; +using Robust.Client.UserInterface; using Robust.Shared.Prototypes; namespace Content.Client.Store.Ui; @@ -26,13 +27,10 @@ public StoreBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey) protected override void Open() { - _menu = new StoreMenu(); + _menu = this.CreateWindow(); if (EntMan.TryGetComponent(Owner, out var store)) _menu.Title = Loc.GetString(store.Name); - _menu.OpenCentered(); - _menu.OnClose += Close; - _menu.OnListingButtonPressed += (_, listing) => { SendMessage(new StoreBuyListingMessage(listing)); @@ -77,15 +75,6 @@ protected override void UpdateState(BoundUserInterfaceState state) } } - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - if (!disposing) - return; - _menu?.Close(); - _menu?.Dispose(); - } - private void UpdateListingsWithSearchFilter() { if (_menu == null) diff --git a/Content.Client/Strip/StrippingMenu.cs b/Content.Client/Strip/StrippingMenu.cs index eea867b7948..1c46b4be35c 100644 --- a/Content.Client/Strip/StrippingMenu.cs +++ b/Content.Client/Strip/StrippingMenu.cs @@ -1,4 +1,3 @@ -using Content.Client.Inventory; using Robust.Client.UserInterface.Controls; using Robust.Client.UserInterface.CustomControls; using Robust.Shared.Timing; @@ -11,14 +10,12 @@ public sealed class StrippingMenu : DefaultWindow public LayoutContainer InventoryContainer = new(); public BoxContainer HandsContainer = new() { Orientation = LayoutOrientation.Horizontal }; public BoxContainer SnareContainer = new(); - private StrippableBoundUserInterface _bui; public bool Dirty = true; - public StrippingMenu(string title, StrippableBoundUserInterface bui) - { - Title = title; - _bui = bui; + public event Action? OnDirty; + public StrippingMenu() + { var box = new BoxContainer() { Orientation = LayoutOrientation.Vertical, Margin = new Thickness(0, 8) }; Contents.AddChild(box); box.AddChild(SnareContainer); @@ -39,7 +36,7 @@ protected override void FrameUpdate(FrameEventArgs args) return; Dirty = false; - _bui.UpdateMenu(); + OnDirty?.Invoke(); } } } diff --git a/Content.Client/SurveillanceCamera/UI/SurveillanceCameraMonitorBoundUi.cs b/Content.Client/SurveillanceCamera/UI/SurveillanceCameraMonitorBoundUi.cs index 9132dd6ed5f..e3646c00cc3 100644 --- a/Content.Client/SurveillanceCamera/UI/SurveillanceCameraMonitorBoundUi.cs +++ b/Content.Client/SurveillanceCamera/UI/SurveillanceCameraMonitorBoundUi.cs @@ -1,6 +1,7 @@ using Content.Client.Eye; using Content.Shared.SurveillanceCamera; using Robust.Client.GameObjects; +using Robust.Client.UserInterface; namespace Content.Client.SurveillanceCamera.UI; @@ -25,20 +26,12 @@ protected override void Open() { base.Open(); - _window = new SurveillanceCameraMonitorWindow(); - - if (State != null) - { - UpdateState(State); - } - - _window.OpenCentered(); + _window = this.CreateWindow(); _window.CameraSelected += OnCameraSelected; _window.SubnetOpened += OnSubnetRequest; _window.CameraRefresh += OnCameraRefresh; _window.SubnetRefresh += OnSubnetRefresh; - _window.OnClose += Close; _window.CameraSwitchTimer += OnCameraSwitchTimer; _window.CameraDisconnect += OnCameraDisconnect; } diff --git a/Content.Client/Thief/ThiefBackpackBoundUserInterface.cs b/Content.Client/Thief/ThiefBackpackBoundUserInterface.cs index 37384daafef..0631d98993a 100644 --- a/Content.Client/Thief/ThiefBackpackBoundUserInterface.cs +++ b/Content.Client/Thief/ThiefBackpackBoundUserInterface.cs @@ -1,6 +1,7 @@ using Content.Shared.Thief; using JetBrains.Annotations; using Robust.Client.GameObjects; +using Robust.Client.UserInterface; namespace Content.Client.Thief; @@ -15,21 +16,9 @@ protected override void Open() { base.Open(); - _window = new ThiefBackpackMenu(this); - _window.OnClose += Close; - _window.OpenCentered(); - } - - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - if (!disposing) - return; - - if (_window != null) - _window.OnClose -= Close; - - _window?.Dispose(); + _window = this.CreateWindow(); + _window.OnApprove += SendApprove; + _window.OnSetChange += SendChangeSelected; } protected override void UpdateState(BoundUserInterfaceState state) diff --git a/Content.Client/Thief/ThiefBackpackMenu.xaml.cs b/Content.Client/Thief/ThiefBackpackMenu.xaml.cs index 543772c704c..aaee3576174 100644 --- a/Content.Client/Thief/ThiefBackpackMenu.xaml.cs +++ b/Content.Client/Thief/ThiefBackpackMenu.xaml.cs @@ -12,46 +12,42 @@ public sealed partial class ThiefBackpackMenu : FancyWindow [Dependency] private readonly IEntitySystemManager _sysMan = default!; private readonly SpriteSystem _spriteSystem; - private readonly ThiefBackpackBoundUserInterface _owner; + public event Action? OnApprove; + public event Action? OnSetChange; - public ThiefBackpackMenu(ThiefBackpackBoundUserInterface owner) + public ThiefBackpackMenu() { RobustXamlLoader.Load(this); IoCManager.InjectDependencies(this); _spriteSystem = _sysMan.GetEntitySystem(); - _owner = owner; - - ApproveButton.OnButtonDown += (args) => + ApproveButton.OnPressed += args => { - _owner.SendApprove(); + OnApprove?.Invoke(); }; } public void UpdateState(ThiefBackpackBoundUserInterfaceState state) { - SetsGrid.RemoveAllChildren(); - int count = 0; - int selectedNumber = 0; - foreach (var set in state.Sets) + SetsGrid.DisposeAllChildren(); + var selectedNumber = 0; + foreach (var (set, info) in state.Sets) { - var child = new ThiefBackpackSet(set.Value, _spriteSystem); + var child = new ThiefBackpackSet(info, _spriteSystem); child.SetButton.OnButtonDown += (args) => { - _owner.SendChangeSelected(set.Key); + OnSetChange?.Invoke(set); }; SetsGrid.AddChild(child); - count++; - - if (set.Value.Selected) + if (info.Selected) selectedNumber++; } Description.Text = Loc.GetString("thief-backpack-window-description", ("maxCount", state.MaxSelectedSets)); SelectedSets.Text = Loc.GetString("thief-backpack-window-selected", ("selectedCount", selectedNumber), ("maxCount", state.MaxSelectedSets)); - ApproveButton.Disabled = selectedNumber == state.MaxSelectedSets ? false : true; + ApproveButton.Disabled = selectedNumber != state.MaxSelectedSets; } } diff --git a/Content.Client/UserInterface/Systems/Atmos/GasTank/GasTankBoundUserInterface.cs b/Content.Client/UserInterface/Systems/Atmos/GasTank/GasTankBoundUserInterface.cs index 4702f8f3659..4ae74a5d65e 100644 --- a/Content.Client/UserInterface/Systems/Atmos/GasTank/GasTankBoundUserInterface.cs +++ b/Content.Client/UserInterface/Systems/Atmos/GasTank/GasTankBoundUserInterface.cs @@ -1,5 +1,7 @@ using Content.Shared.Atmos.Components; using JetBrains.Annotations; +using Robust.Client.GameObjects; +using Robust.Client.UserInterface; namespace Content.Client.UserInterface.Systems.Atmos.GasTank { @@ -13,7 +15,7 @@ public GasTankBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKe { } - public void SetOutputPressure(in float value) + public void SetOutputPressure(float value) { SendMessage(new GasTankSetPressureMessage { @@ -29,9 +31,10 @@ public void ToggleInternals() protected override void Open() { base.Open(); - _window = new GasTankWindow(this, EntMan.GetComponent(Owner).EntityName); - _window.OnClose += Close; - _window.OpenCentered(); + _window = this.CreateWindow(); + _window.SetTitle(EntMan.GetComponent(Owner).EntityName); + _window.OnOutputPressure += SetOutputPressure; + _window.OnToggleInternals += ToggleInternals; } protected override void UpdateState(BoundUserInterfaceState state) diff --git a/Content.Client/UserInterface/Systems/Atmos/GasTank/GasTankWindow.cs b/Content.Client/UserInterface/Systems/Atmos/GasTank/GasTankWindow.cs index c23850a6503..fd5624ad8a7 100644 --- a/Content.Client/UserInterface/Systems/Atmos/GasTank/GasTankWindow.cs +++ b/Content.Client/UserInterface/Systems/Atmos/GasTank/GasTankWindow.cs @@ -15,23 +15,29 @@ namespace Content.Client.UserInterface.Systems.Atmos.GasTank; public sealed class GasTankWindow : BaseWindow { + [Dependency] private readonly IResourceCache _cache = default!; + private readonly RichTextLabel _lblPressure; private readonly FloatSpinBox _spbPressure; private readonly RichTextLabel _lblInternals; private readonly Button _btnInternals; + private readonly Label _topLabel; + + public event Action? OnOutputPressure; + public event Action? OnToggleInternals; - public GasTankWindow(GasTankBoundUserInterface owner, string uidName) + public GasTankWindow() { + IoCManager.InjectDependencies(this); Control contentContainer; BoxContainer topContainer; TextureButton btnClose; - var resourceCache = IoCManager.Resolve(); var rootContainer = new LayoutContainer { Name = "GasTankRoot" }; AddChild(rootContainer); MouseFilter = MouseFilterMode.Stop; - var panelTex = resourceCache.GetTexture("/Textures/Interface/Nano/button.svg.96dpi.png"); + var panelTex = _cache.GetTexture("/Textures/Interface/Nano/button.svg.96dpi.png"); var back = new StyleBoxTexture { Texture = panelTex, @@ -78,7 +84,17 @@ public GasTankWindow(GasTankBoundUserInterface owner, string uidName) LayoutContainer.SetAnchorPreset(topContainerWrap, LayoutContainer.LayoutPreset.Wide); - var font = resourceCache.GetFont("/Fonts/Boxfont-round/Boxfont Round.ttf", 13); + var font = _cache.GetFont("/Fonts/Boxfont-round/Boxfont Round.ttf", 13); + + _topLabel = new Label + { + FontOverride = font, + FontColorOverride = StyleNano.NanoGold, + VerticalAlignment = VAlignment.Center, + HorizontalExpand = true, + HorizontalAlignment = HAlignment.Left, + Margin = new Thickness(0, 0, 20, 0), + }; var topRow = new BoxContainer { @@ -86,16 +102,7 @@ public GasTankWindow(GasTankBoundUserInterface owner, string uidName) Margin = new Thickness(4, 2, 12, 2), Children = { - (new Label - { - Text = uidName, - FontOverride = font, - FontColorOverride = StyleNano.NanoGold, - VerticalAlignment = VAlignment.Center, - HorizontalExpand = true, - HorizontalAlignment = HAlignment.Left, - Margin = new Thickness(0, 0, 20, 0), - }), + _topLabel, (btnClose = new TextureButton { StyleClasses = {DefaultWindow.StyleClassWindowCloseButton}, @@ -168,17 +175,22 @@ public GasTankWindow(GasTankBoundUserInterface owner, string uidName) // Handlers _spbPressure.OnValueChanged += args => { - owner.SetOutputPressure(args.Value); + OnOutputPressure?.Invoke(args.Value); }; _btnInternals.OnPressed += args => { - owner.ToggleInternals(); + OnToggleInternals?.Invoke(); }; btnClose.OnPressed += _ => Close(); } + public void SetTitle(string name) + { + _topLabel.Text = name; + } + public void UpdateState(GasTankBoundUserInterfaceState state) { _lblPressure.SetMarkup(Loc.GetString("gas-tank-window-tank-pressure-text", ("tankPressure", $"{state.TankPressure:0.##}"))); diff --git a/Content.Client/VendingMachines/VendingMachineBoundUserInterface.cs b/Content.Client/VendingMachines/VendingMachineBoundUserInterface.cs index 17ddba77ffc..eafab84ed63 100644 --- a/Content.Client/VendingMachines/VendingMachineBoundUserInterface.cs +++ b/Content.Client/VendingMachines/VendingMachineBoundUserInterface.cs @@ -2,6 +2,7 @@ using Content.Shared.VendingMachines; using Robust.Client.UserInterface.Controls; using System.Linq; +using Robust.Client.UserInterface; namespace Content.Client.VendingMachines { @@ -28,15 +29,14 @@ protected override void Open() _cachedInventory = vendingMachineSys.GetAllInventory(Owner); - _menu = new VendingMachineMenu { Title = EntMan.GetComponent(Owner).EntityName }; + _menu = this.CreateWindow(); + _menu.OpenCenteredLeft(); + _menu.Title = EntMan.GetComponent(Owner).EntityName; - _menu.OnClose += Close; _menu.OnItemSelected += OnItemSelected; _menu.OnSearchChanged += OnSearchChanged; _menu.Populate(_cachedInventory, out _cachedFilteredIndex); - - _menu.OpenCenteredLeft(); } protected override void UpdateState(BoundUserInterfaceState state) diff --git a/Content.Client/VoiceMask/VoiceMaskBoundUserInterface.cs b/Content.Client/VoiceMask/VoiceMaskBoundUserInterface.cs index f700c6663b9..891804674d3 100644 --- a/Content.Client/VoiceMask/VoiceMaskBoundUserInterface.cs +++ b/Content.Client/VoiceMask/VoiceMaskBoundUserInterface.cs @@ -1,12 +1,13 @@ using Content.Shared.VoiceMask; using Robust.Client.GameObjects; +using Robust.Client.UserInterface; using Robust.Shared.Prototypes; namespace Content.Client.VoiceMask; public sealed class VoiceMaskBoundUserInterface : BoundUserInterface { - [Dependency] private readonly IPrototypeManager _proto = default!; + [Dependency] private readonly IPrototypeManager _protomanager = default!; [ViewVariables] private VoiceMaskNameChangeWindow? _window; @@ -19,12 +20,11 @@ protected override void Open() { base.Open(); - _window = new(_proto); + _window = this.CreateWindow(); + _window.ReloadVerbs(_protomanager); - _window.OpenCentered(); _window.OnNameChange += OnNameSelected; _window.OnVerbChange += verb => SendMessage(new VoiceMaskChangeVerbMessage(verb)); - _window.OnClose += Close; } private void OnNameSelected(string name) diff --git a/Content.Client/VoiceMask/VoiceMaskNameChangeWindow.xaml.cs b/Content.Client/VoiceMask/VoiceMaskNameChangeWindow.xaml.cs index 16a28f9d9b3..0dc41f807ab 100644 --- a/Content.Client/VoiceMask/VoiceMaskNameChangeWindow.xaml.cs +++ b/Content.Client/VoiceMask/VoiceMaskNameChangeWindow.xaml.cs @@ -17,7 +17,7 @@ public sealed partial class VoiceMaskNameChangeWindow : FancyWindow private string? _verb; - public VoiceMaskNameChangeWindow(IPrototypeManager proto) + public VoiceMaskNameChangeWindow() { RobustXamlLoader.Load(this); @@ -32,12 +32,10 @@ public VoiceMaskNameChangeWindow(IPrototypeManager proto) SpeechVerbSelector.SelectId(args.Id); }; - ReloadVerbs(proto); - AddVerbs(); } - private void ReloadVerbs(IPrototypeManager proto) + public void ReloadVerbs(IPrototypeManager proto) { foreach (var verb in proto.EnumeratePrototypes()) { diff --git a/Content.Client/Weapons/Melee/UI/MeleeSpeechBoundUserInterface.cs b/Content.Client/Weapons/Melee/UI/MeleeSpeechBoundUserInterface.cs index f3e0c0a539a..3f01808c422 100644 --- a/Content.Client/Weapons/Melee/UI/MeleeSpeechBoundUserInterface.cs +++ b/Content.Client/Weapons/Melee/UI/MeleeSpeechBoundUserInterface.cs @@ -1,5 +1,6 @@ using Robust.Client.GameObjects; using Content.Shared.Speech.Components; +using Robust.Client.UserInterface; namespace Content.Client.Weapons.Melee.UI; @@ -19,17 +20,10 @@ protected override void Open() { base.Open(); - _window = new MeleeSpeechWindow(); - if (State != null) - UpdateState(State); - - _window.OpenCentered(); - - _window.OnClose += Close; + _window = this.CreateWindow(); _window.OnBattlecryEntered += OnBattlecryChanged; } - private void OnBattlecryChanged(string newBattlecry) { SendMessage(new MeleeSpeechBattlecryChangedMessage(newBattlecry)); diff --git a/Content.Client/Wires/UI/WiresBoundUserInterface.cs b/Content.Client/Wires/UI/WiresBoundUserInterface.cs index 5a8869a204e..edf1a2d3770 100644 --- a/Content.Client/Wires/UI/WiresBoundUserInterface.cs +++ b/Content.Client/Wires/UI/WiresBoundUserInterface.cs @@ -1,5 +1,6 @@ using Content.Shared.Wires; using Robust.Client.GameObjects; +using Robust.Client.UserInterface; namespace Content.Client.Wires.UI { @@ -15,10 +16,8 @@ public WiresBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey) protected override void Open() { base.Open(); - - _menu = new WiresMenu(this); - _menu.OnClose += Close; - _menu.OpenCenteredLeft(); + _menu = this.CreateWindow(); + _menu.OnAction += PerformAction; } protected override void UpdateState(BoundUserInterfaceState state) diff --git a/Content.Client/Wires/UI/WiresMenu.cs b/Content.Client/Wires/UI/WiresMenu.cs index 7bccc208616..eccc548297c 100644 --- a/Content.Client/Wires/UI/WiresMenu.cs +++ b/Content.Client/Wires/UI/WiresMenu.cs @@ -1,4 +1,3 @@ -using System; using System.Numerics; using Content.Client.Examine; using Content.Client.Resources; @@ -12,10 +11,6 @@ using Robust.Client.UserInterface.CustomControls; using Robust.Shared.Animations; using Robust.Shared.Input; -using Robust.Shared.IoC; -using Robust.Shared.Localization; -using Robust.Shared.Maths; -using Robust.Shared.Random; using static Robust.Client.UserInterface.Controls.BoxContainer; namespace Content.Client.Wires.UI @@ -24,8 +19,6 @@ public sealed class WiresMenu : BaseWindow { [Dependency] private readonly IResourceCache _resourceCache = default!; - public WiresBoundUserInterface Owner { get; } - private readonly Control _wiresHBox; private readonly Control _topContainer; private readonly Control _statusContainer; @@ -35,11 +28,12 @@ public sealed class WiresMenu : BaseWindow public TextureButton CloseButton { get; set; } - public WiresMenu(WiresBoundUserInterface owner) + public event Action? OnAction; + + public WiresMenu() { IoCManager.InjectDependencies(this); - Owner = owner; var rootContainer = new LayoutContainer {Name = "WireRoot"}; AddChild(rootContainer); @@ -257,12 +251,12 @@ public void Populate(WiresBoundUserInterfaceState state) control.WireClicked += () => { - Owner.PerformAction(wire.Id, wire.IsCut ? WiresAction.Mend : WiresAction.Cut); + OnAction?.Invoke(wire.Id, wire.IsCut ? WiresAction.Mend : WiresAction.Cut); }; control.ContactsClicked += () => { - Owner.PerformAction(wire.Id, WiresAction.Pulse); + OnAction?.Invoke(wire.Id, WiresAction.Pulse); }; } diff --git a/Content.Client/Xenoarchaeology/Ui/AnalysisConsoleBoundUserInterface.cs b/Content.Client/Xenoarchaeology/Ui/AnalysisConsoleBoundUserInterface.cs index 2538caf6eb8..c7a74815b6b 100644 --- a/Content.Client/Xenoarchaeology/Ui/AnalysisConsoleBoundUserInterface.cs +++ b/Content.Client/Xenoarchaeology/Ui/AnalysisConsoleBoundUserInterface.cs @@ -1,6 +1,7 @@ using Content.Shared.Xenoarchaeology.Equipment; using JetBrains.Annotations; using Robust.Client.GameObjects; +using Robust.Client.UserInterface; namespace Content.Client.Xenoarchaeology.Ui; @@ -18,10 +19,7 @@ protected override void Open() { base.Open(); - _consoleMenu = new AnalysisConsoleMenu(); - - _consoleMenu.OnClose += Close; - _consoleMenu.OpenCentered(); + _consoleMenu = this.CreateWindow(); _consoleMenu.OnServerSelectionButtonPressed += () => { From 055169e12e1709f376e5409ecde62fe77cdcb822 Mon Sep 17 00:00:00 2001 From: Nemanja <98561806+EmoGarbage404@users.noreply.github.com> Date: Sun, 21 Jul 2024 01:27:18 -0400 Subject: [PATCH 307/765] PA ui cleanup + bugfixes (#28750) * ui and visual aspect + radio * finish jank ui shit and finish radio * remove radio * send it --------- Co-authored-by: metalgearsloth --- .../ParticleAcceleratorBoundUserInterface.cs | 5 +- .../UI/ParticleAcceleratorControlMenu.cs | 526 ------------------ .../UI/ParticleAcceleratorControlMenu.xaml | 74 +++ .../UI/ParticleAcceleratorControlMenu.xaml.cs | 311 +++++++++++ .../ParticleAcceleratorEmitterComponent.cs | 7 +- .../ParticleAcceleratorSystem.ControlBox.cs | 27 +- .../ParticleAcceleratorSystem.Parts.cs | 38 +- .../ParticleAcceleratorInterfaceWireAction.cs | 5 + .../ParticleAcceleratorLimiterWireAction.cs | 7 +- .../ParticleAcceleratorStrengthWireAction.cs | 4 + .../ui/particle-accelerator-control-menu.ftl | 24 +- .../Generation/PA/control_box.rsi/unlitp0.png | Bin 526 -> 529 bytes .../Generation/PA/control_box.rsi/unlitp1.png | Bin 533 -> 533 bytes .../Generation/PA/control_box.rsi/unlitp2.png | Bin 537 -> 539 bytes .../Generation/PA/control_box.rsi/unlitp3.png | Bin 870 -> 859 bytes 15 files changed, 462 insertions(+), 566 deletions(-) delete mode 100644 Content.Client/ParticleAccelerator/UI/ParticleAcceleratorControlMenu.cs create mode 100644 Content.Client/ParticleAccelerator/UI/ParticleAcceleratorControlMenu.xaml create mode 100644 Content.Client/ParticleAccelerator/UI/ParticleAcceleratorControlMenu.xaml.cs diff --git a/Content.Client/ParticleAccelerator/UI/ParticleAcceleratorBoundUserInterface.cs b/Content.Client/ParticleAccelerator/UI/ParticleAcceleratorBoundUserInterface.cs index ff1eae36f55..93306f2fd1f 100644 --- a/Content.Client/ParticleAccelerator/UI/ParticleAcceleratorBoundUserInterface.cs +++ b/Content.Client/ParticleAccelerator/UI/ParticleAcceleratorBoundUserInterface.cs @@ -1,5 +1,4 @@ using Content.Shared.Singularity.Components; -using Robust.Client.GameObjects; using Robust.Client.UserInterface; namespace Content.Client.ParticleAccelerator.UI @@ -18,9 +17,11 @@ protected override void Open() base.Open(); _menu = this.CreateWindow(); + _menu.SetEntity(Owner); + _menu.OnOverallState += SendEnableMessage; _menu.OnPowerState += SendPowerStateMessage; - _menu.OnScanPartsRequested += SendScanPartsMessage; + _menu.OnScan += SendScanPartsMessage; } public void SendEnableMessage(bool enable) diff --git a/Content.Client/ParticleAccelerator/UI/ParticleAcceleratorControlMenu.cs b/Content.Client/ParticleAccelerator/UI/ParticleAcceleratorControlMenu.cs deleted file mode 100644 index 05a296edf39..00000000000 --- a/Content.Client/ParticleAccelerator/UI/ParticleAcceleratorControlMenu.cs +++ /dev/null @@ -1,526 +0,0 @@ -using System.Numerics; -using Content.Client.Resources; -using Content.Client.Stylesheets; -using Content.Client.UserInterface.Controls; -using Content.Shared.Singularity.Components; -using Robust.Client.Animations; -using Robust.Client.Graphics; -using Robust.Client.ResourceManagement; -using Robust.Client.UserInterface; -using Robust.Client.UserInterface.Controls; -using Robust.Client.UserInterface.CustomControls; -using Robust.Shared.Noise; -using Robust.Shared.Prototypes; -using Robust.Shared.Timing; -using static Robust.Client.UserInterface.Controls.BoxContainer; - -namespace Content.Client.ParticleAccelerator.UI -{ - public sealed class ParticleAcceleratorControlMenu : BaseWindow - { - [Dependency] private readonly IPrototypeManager _protoManager = default!; - [Dependency] private readonly IResourceCache _cache = default!; - - private readonly ShaderInstance _greyScaleShader; - - private readonly Label _drawLabel; - private readonly FastNoiseLite _drawNoiseGenerator; - private readonly Button _onButton; - private readonly Button _offButton; - private readonly Button _scanButton; - private readonly Label _statusLabel; - private readonly SpinBox _stateSpinBox; - - private readonly BoxContainer _alarmControl; - private readonly Animation _alarmControlAnimation; - - private readonly PASegmentControl _endCapTexture; - private readonly PASegmentControl _fuelChamberTexture; - private readonly PASegmentControl _controlBoxTexture; - private readonly PASegmentControl _powerBoxTexture; - private readonly PASegmentControl _emitterForeTexture; - private readonly PASegmentControl _emitterPortTexture; - private readonly PASegmentControl _emitterStarboardTexture; - - private float _time; - private int _lastDraw; - private int _lastReceive; - - private bool _blockSpinBox; - private bool _assembled; - private bool _shouldContinueAnimating; - private int _maxStrength = 3; - - public event Action? OnOverallState; - public event Action? OnPowerState; - public event Action? OnScanPartsRequested; - - public ParticleAcceleratorControlMenu() - { - IoCManager.InjectDependencies(this); - SetSize = new Vector2(400, 320); - _greyScaleShader = _protoManager.Index("Greyscale").Instance(); - - _drawNoiseGenerator = new(); - _drawNoiseGenerator.SetFractalType(FastNoiseLite.FractalType.FBm); - _drawNoiseGenerator.SetFrequency(0.5f); - - var font = _cache.GetFont("/Fonts/Boxfont-round/Boxfont Round.ttf", 13); - var panelTex = _cache.GetTexture("/Textures/Interface/Nano/button.svg.96dpi.png"); - - MouseFilter = MouseFilterMode.Stop; - - _alarmControlAnimation = new Animation - { - Length = TimeSpan.FromSeconds(1), - AnimationTracks = - { - new AnimationTrackControlProperty - { - Property = nameof(Control.Visible), - KeyFrames = - { - new AnimationTrackProperty.KeyFrame(true, 0), - new AnimationTrackProperty.KeyFrame(false, 0.75f), - } - } - } - }; - - var back = new StyleBoxTexture - { - Texture = panelTex, - Modulate = Color.FromHex("#25252A"), - }; - back.SetPatchMargin(StyleBox.Margin.All, 10); - - var back2 = new StyleBoxTexture(back) - { - Modulate = Color.FromHex("#202023") - }; - - AddChild(new PanelContainer - { - PanelOverride = back, - MouseFilter = MouseFilterMode.Pass - }); - - _stateSpinBox = new SpinBox { Value = 0, IsValid = StrengthSpinBoxValid }; - _stateSpinBox.InitDefaultButtons(); - _stateSpinBox.ValueChanged += PowerStateChanged; - _stateSpinBox.LineEditDisabled = true; - - _offButton = new Button - { - ToggleMode = false, - Text = Loc.GetString("particle-accelerator-control-menu-off-button"), - StyleClasses = { StyleBase.ButtonOpenRight }, - }; - - _offButton.OnPressed += args => OnOverallState?.Invoke(false); - - _onButton = new Button - { - ToggleMode = false, - Text = Loc.GetString("particle-accelerator-control-menu-on-button"), - StyleClasses = { StyleBase.ButtonOpenLeft }, - }; - _onButton.OnPressed += args => OnOverallState?.Invoke(true); - - var closeButton = new TextureButton - { - StyleClasses = { "windowCloseButton" }, - HorizontalAlignment = HAlignment.Right, - Margin = new Thickness(0, 0, 8, 0) - }; - closeButton.OnPressed += args => Close(); - - var serviceManual = new Label - { - HorizontalAlignment = HAlignment.Center, - StyleClasses = { StyleBase.StyleClassLabelSubText }, - Text = Loc.GetString("particle-accelerator-control-menu-service-manual-reference") - }; - _drawLabel = new Label(); - var imgSize = new Vector2(32, 32); - AddChild(new BoxContainer - { - Orientation = LayoutOrientation.Vertical, - Children = - { - new Control - { - Margin = new Thickness(2, 2, 0, 0), - Children = - { - new Label - { - Text = Loc.GetString("particle-accelerator-control-menu-device-version-label"), - FontOverride = font, - FontColorOverride = StyleNano.NanoGold, - }, - closeButton - } - }, - new PanelContainer - { - PanelOverride = new StyleBoxFlat {BackgroundColor = StyleNano.NanoGold}, - MinSize = new Vector2(0, 2), - }, - new Control - { - MinSize = new Vector2(0, 4) - }, - - new BoxContainer - { - Orientation = LayoutOrientation.Horizontal, - VerticalExpand = true, - Children = - { - new BoxContainer - { - Orientation = LayoutOrientation.Vertical, - Margin = new Thickness(4, 0, 0, 0), - HorizontalExpand = true, - Children = - { - new BoxContainer - { - Orientation = LayoutOrientation.Horizontal, - Children = - { - new Label - { - Text = Loc.GetString("particle-accelerator-control-menu-power-label") + " ", - HorizontalExpand = true, - HorizontalAlignment = HAlignment.Left, - }, - _offButton, - _onButton - } - }, - new BoxContainer - { - Orientation = LayoutOrientation.Horizontal, - Children = - { - new Label - { - Text = Loc.GetString("particle-accelerator-control-menu-strength-label") + " ", - HorizontalExpand = true, - HorizontalAlignment = HAlignment.Left, - }, - _stateSpinBox - } - }, - new Control - { - MinSize = new Vector2(0, 10), - }, - _drawLabel, - new Control - { - VerticalExpand = true, - }, - (_alarmControl = new BoxContainer - { - Orientation = LayoutOrientation.Vertical, - Children = - { - new Label - { - Text = Loc.GetString("particle-accelerator-control-menu-alarm-control"), - FontColorOverride = Color.Red, - Align = Label.AlignMode.Center - }, - serviceManual - }, - Visible = false, - }), - } - }, - new BoxContainer - { - Orientation = LayoutOrientation.Vertical, - MinSize = new Vector2(186, 0), - Children = - { - (_statusLabel = new Label - { - HorizontalAlignment = HAlignment.Center - }), - new Control - { - MinSize = new Vector2(0, 20) - }, - new PanelContainer - { - HorizontalAlignment = HAlignment.Center, - PanelOverride = back2, - Children = - { - new GridContainer - { - Columns = 3, - VSeparationOverride = 0, - HSeparationOverride = 0, - Children = - { - new Control {MinSize = imgSize}, - (_endCapTexture = Segment("end_cap")), - new Control {MinSize = imgSize}, - (_controlBoxTexture = Segment("control_box")), - (_fuelChamberTexture = Segment("fuel_chamber")), - new Control {MinSize = imgSize}, - new Control {MinSize = imgSize}, - (_powerBoxTexture = Segment("power_box")), - new Control {MinSize = imgSize}, - (_emitterStarboardTexture = Segment("emitter_starboard")), - (_emitterForeTexture = Segment("emitter_fore")), - (_emitterPortTexture = Segment("emitter_port")), - } - } - } - }, - (_scanButton = new Button - { - Text = Loc.GetString("particle-accelerator-control-menu-scan-parts-button"), - HorizontalAlignment = HAlignment.Center - }) - } - } - } - }, - new StripeBack - { - Children = - { - new Label - { - Margin = new Thickness(4, 4, 0, 4), - Text = Loc.GetString("particle-accelerator-control-menu-check-containment-field-warning"), - HorizontalAlignment = HAlignment.Center, - StyleClasses = {StyleBase.StyleClassLabelSubText}, - } - } - }, - new BoxContainer - { - Orientation = LayoutOrientation.Horizontal, - Margin = new Thickness(12, 0, 0, 0), - Children = - { - new Label - { - Text = Loc.GetString("particle-accelerator-control-menu-foo-bar-baz"), - StyleClasses = {StyleBase.StyleClassLabelSubText} - } - } - }, - } - }); - - _scanButton.OnPressed += args => OnScanPartsRequested?.Invoke(); - - _alarmControl.AnimationCompleted += s => - { - if (_shouldContinueAnimating) - { - _alarmControl.PlayAnimation(_alarmControlAnimation, "warningAnim"); - } - else - { - _alarmControl.Visible = false; - } - }; - - PASegmentControl Segment(string name) - { - return new(this, _cache, name); - } - - UpdateUI(false, false, false, false); - } - - private bool StrengthSpinBoxValid(int n) - { - return n >= 0 && n <= _maxStrength && !_blockSpinBox; - } - - private void PowerStateChanged(ValueChangedEventArgs e) - { - ParticleAcceleratorPowerState newState; - switch (e.Value) - { - case 0: - newState = ParticleAcceleratorPowerState.Standby; - break; - case 1: - newState = ParticleAcceleratorPowerState.Level0; - break; - case 2: - newState = ParticleAcceleratorPowerState.Level1; - break; - case 3: - newState = ParticleAcceleratorPowerState.Level2; - break; - case 4: - newState = ParticleAcceleratorPowerState.Level3; - break; - default: - return; - } - - _stateSpinBox.SetButtonDisabled(true); - OnPowerState?.Invoke(newState); - } - - protected override DragMode GetDragModeFor(Vector2 relativeMousePos) - { - return DragMode.Move; - } - - public void DataUpdate(ParticleAcceleratorUIState uiState) - { - _assembled = uiState.Assembled; - UpdateUI(uiState.Assembled, uiState.InterfaceBlock, uiState.Enabled, - uiState.WirePowerBlock); - _statusLabel.Text = Loc.GetString("particle-accelerator-control-menu-status-label", - ("status", Loc.GetString(uiState.Assembled ? "particle-accelerator-control-menu-status-operational" : - "particle-accelerator-control-menu-status-incomplete"))); - UpdatePowerState(uiState.State, uiState.Enabled, uiState.Assembled, - uiState.MaxLevel); - UpdatePreview(uiState); - _lastDraw = uiState.PowerDraw; - _lastReceive = uiState.PowerReceive; - } - - private void UpdatePowerState(ParticleAcceleratorPowerState state, bool enabled, bool assembled, - ParticleAcceleratorPowerState maxState) - { - _stateSpinBox.OverrideValue(state switch - { - ParticleAcceleratorPowerState.Standby => 0, - ParticleAcceleratorPowerState.Level0 => 1, - ParticleAcceleratorPowerState.Level1 => 2, - ParticleAcceleratorPowerState.Level2 => 3, - ParticleAcceleratorPowerState.Level3 => 4, - _ => 0 - }); - - - _maxStrength = maxState == ParticleAcceleratorPowerState.Level3 ? 4 : 3; - if (_maxStrength > 3 && enabled && assembled) - { - _shouldContinueAnimating = true; - if (!_alarmControl.HasRunningAnimation("warningAnim")) - _alarmControl.PlayAnimation(_alarmControlAnimation, "warningAnim"); - } - else - _shouldContinueAnimating = false; - } - - private void UpdateUI(bool assembled, bool blocked, bool enabled, bool powerBlock) - { - _onButton.Pressed = enabled; - _offButton.Pressed = !enabled; - - var cantUse = !assembled || blocked || powerBlock; - _onButton.Disabled = cantUse; - _offButton.Disabled = cantUse; - _scanButton.Disabled = blocked; - - var cantChangeLevel = !assembled || blocked; - _stateSpinBox.SetButtonDisabled(cantChangeLevel); - _blockSpinBox = cantChangeLevel; - } - - private void UpdatePreview(ParticleAcceleratorUIState updateMessage) - { - _endCapTexture.SetPowerState(updateMessage, updateMessage.EndCapExists); - _controlBoxTexture.SetPowerState(updateMessage, true); - _fuelChamberTexture.SetPowerState(updateMessage, updateMessage.FuelChamberExists); - _powerBoxTexture.SetPowerState(updateMessage, updateMessage.PowerBoxExists); - _emitterStarboardTexture.SetPowerState(updateMessage, updateMessage.EmitterStarboardExists); - _emitterForeTexture.SetPowerState(updateMessage, updateMessage.EmitterForeExists); - _emitterPortTexture.SetPowerState(updateMessage, updateMessage.EmitterPortExists); - } - - protected override void FrameUpdate(FrameEventArgs args) - { - base.FrameUpdate(args); - - if (!_assembled) - { - _drawLabel.Text = Loc.GetString("particle-accelerator-control-menu-draw-not-available"); - return; - } - - _time += args.DeltaSeconds; - - var watts = 0; - if (_lastDraw != 0) - { - var val = _drawNoiseGenerator.GetNoise(_time, 0f); - watts = (int) (_lastDraw + val * 5); - } - - _drawLabel.Text = Loc.GetString("particle-accelerator-control-menu-draw", - ("watts", $"{watts:##,##0}"), - ("lastReceive", $"{_lastReceive:##,##0}")); - } - - private sealed class PASegmentControl : Control - { - private readonly ParticleAcceleratorControlMenu _menu; - private readonly string _baseState; - private readonly TextureRect _base; - private readonly TextureRect _unlit; - private readonly RSI _rsi; - - public PASegmentControl(ParticleAcceleratorControlMenu menu, IResourceCache cache, string name) - { - _menu = menu; - _baseState = name; - _rsi = cache.GetResource($"/Textures/Structures/Power/Generation/PA/{name}.rsi").RSI; - - AddChild(_base = new TextureRect { Texture = _rsi[$"completed"].Frame0 }); - AddChild(_unlit = new TextureRect()); - MinSize = _rsi.Size; - } - - public void SetPowerState(ParticleAcceleratorUIState state, bool exists) - { - _base.ShaderOverride = exists ? null : _menu._greyScaleShader; - _base.ModulateSelfOverride = exists ? null : new Color(127, 127, 127); - - if (!state.Enabled || !exists) - { - _unlit.Visible = false; - return; - } - - _unlit.Visible = true; - - var suffix = state.State switch - { - ParticleAcceleratorPowerState.Standby => "_unlitp", - ParticleAcceleratorPowerState.Level0 => "_unlitp0", - ParticleAcceleratorPowerState.Level1 => "_unlitp1", - ParticleAcceleratorPowerState.Level2 => "_unlitp2", - ParticleAcceleratorPowerState.Level3 => "_unlitp3", - _ => "" - }; - - if (!_rsi.TryGetState(_baseState + suffix, out var rState)) - { - _unlit.Visible = false; - return; - } - - _unlit.Texture = rState.Frame0; - } - } - } -} diff --git a/Content.Client/ParticleAccelerator/UI/ParticleAcceleratorControlMenu.xaml b/Content.Client/ParticleAccelerator/UI/ParticleAcceleratorControlMenu.xaml new file mode 100644 index 00000000000..63f15837068 --- /dev/null +++ b/Content.Client/ParticleAccelerator/UI/ParticleAcceleratorControlMenu.xaml @@ -0,0 +1,74 @@ + + + + + + + + + + + + [DataField(required: true)] - public ComponentRegistry ChasingComponent = default!; + public ComponentRegistry ChasingComponent = []; /// /// The maximum radius in which the entity chooses the target component to follow diff --git a/Content.Server/Physics/Controllers/ChasingWalkSystem.cs b/Content.Server/Physics/Controllers/ChasingWalkSystem.cs index 618dd4156fc..fa55ce024e4 100644 --- a/Content.Server/Physics/Controllers/ChasingWalkSystem.cs +++ b/Content.Server/Physics/Controllers/ChasingWalkSystem.cs @@ -61,6 +61,9 @@ public override void UpdateBeforeSolve(bool prediction, float frameTime) private void ChangeTarget(EntityUid uid, ChasingWalkComponent component) { + if (component.ChasingComponent.Count <= 0) + return; + //We find our coordinates and calculate the radius of the target search. var xform = Transform(uid); var range = component.MaxChaseRadius; From dcc885d65c5ca41267441aad31a2621585c50a23 Mon Sep 17 00:00:00 2001 From: slarticodefast <161409025+slarticodefast@users.noreply.github.com> Date: Sun, 21 Jul 2024 18:20:09 +0200 Subject: [PATCH 334/765] fix microwave construction (#30232) * fix microwave construction * retry --- Content.Server/Kitchen/Components/MicrowaveComponent.cs | 3 +++ Content.Server/Kitchen/EntitySystems/MicrowaveSystem.cs | 5 ++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/Content.Server/Kitchen/Components/MicrowaveComponent.cs b/Content.Server/Kitchen/Components/MicrowaveComponent.cs index 1d26f68cae8..5337d80fd17 100644 --- a/Content.Server/Kitchen/Components/MicrowaveComponent.cs +++ b/Content.Server/Kitchen/Components/MicrowaveComponent.cs @@ -79,6 +79,9 @@ public sealed partial class MicrowaveComponent : Component public Container Storage = default!; + [DataField] + public string ContainerId = "microwave_entity_container"; + [DataField, ViewVariables(VVAccess.ReadWrite)] public int Capacity = 10; diff --git a/Content.Server/Kitchen/EntitySystems/MicrowaveSystem.cs b/Content.Server/Kitchen/EntitySystems/MicrowaveSystem.cs index 71986ae859e..98c875e7735 100644 --- a/Content.Server/Kitchen/EntitySystems/MicrowaveSystem.cs +++ b/Content.Server/Kitchen/EntitySystems/MicrowaveSystem.cs @@ -252,7 +252,7 @@ private void SubtractContents(MicrowaveComponent component, FoodRecipePrototype private void OnInit(Entity ent, ref ComponentInit args) { // this really does have to be in ComponentInit - ent.Comp.Storage = _container.EnsureContainer(ent, "microwave_entity_container"); + ent.Comp.Storage = _container.EnsureContainer(ent, ent.Comp.ContainerId); } private void OnMapInit(Entity ent, ref MapInitEvent args) @@ -312,6 +312,9 @@ private void OnContentUpdate(EntityUid uid, MicrowaveComponent component, Contai private void OnInsertAttempt(Entity ent, ref ContainerIsInsertingAttemptEvent args) { + if (args.Container.ID != ent.Comp.ContainerId) + return; + if (ent.Comp.Broken) { args.Cancel(); From 50ca49bb904f900754cc0b23d0095c01f56d56b4 Mon Sep 17 00:00:00 2001 From: PJBot Date: Sun, 21 Jul 2024 16:21:15 +0000 Subject: [PATCH 335/765] Automatic changelog update --- Resources/Changelog/Changelog.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 7b951424864..f625cdfdbc1 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,11 +1,4 @@ Entries: -- author: Errant - changes: - - message: Vox now take significant damage over time while inhaling oxygen. - type: Tweak - id: 6458 - time: '2024-04-27T10:33:35.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/26705 - author: TheShuEd changes: - message: Added tomato killers in floral anomaly berries @@ -3800,3 +3793,10 @@ id: 6957 time: '2024-07-21T10:46:33.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/29842 +- author: slarticodefast + changes: + - message: Fixed microwave construction. + type: Fix + id: 6958 + time: '2024-07-21T16:20:09.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/30232 From 11cbe7b53411acf1d5ff7ad4a2430cb5e3cffe6a Mon Sep 17 00:00:00 2001 From: Sphiral <145869023+SphiraI@users.noreply.github.com> Date: Sun, 21 Jul 2024 12:16:58 -0500 Subject: [PATCH 336/765] The Shelfs Update (#27858) * goofed up * wip, mostly test sprites * Nearly done, just need to fix storage locks * everything done to my knowledge * Alright, construction tested and working, and updated health spread * remove a single comment I forgot. Pending sprite changes. * Update sprites and add chemistry locked preset * Forgot to remove a comment --- .../Objects/Consumable/Drinks/drinks.yml | 3 + .../Objects/Consumable/Food/ingredients.yml | 9 + .../Entities/Structures/Wallmounts/shelfs.yml | 475 ++++++++++++++++++ .../Construction/Graphs/furniture/shelfs.yml | 268 ++++++++++ .../Recipes/Construction/storage.yml | 148 ++++++ Resources/Prototypes/tags.yml | 6 + .../Medical/chemistry.rsi/base.png | Bin 0 -> 692 bytes .../Medical/chemistry.rsi/chem-0.png | Bin 0 -> 108 bytes .../Medical/chemistry.rsi/chem-1.png | Bin 0 -> 233 bytes .../Medical/chemistry.rsi/chem-2.png | Bin 0 -> 311 bytes .../Medical/chemistry.rsi/chem-3.png | Bin 0 -> 393 bytes .../Medical/chemistry.rsi/chem-4.png | Bin 0 -> 520 bytes .../Medical/chemistry.rsi/chem-5.png | Bin 0 -> 605 bytes .../Medical/chemistry.rsi/chem-6.png | Bin 0 -> 710 bytes .../Medical/chemistry.rsi/closed.png | Bin 0 -> 267 bytes .../Medical/chemistry.rsi/locked.png | Bin 0 -> 109 bytes .../Medical/chemistry.rsi/meta.json | 47 ++ .../Medical/chemistry.rsi/open.png | Bin 0 -> 267 bytes .../Medical/chemistry.rsi/unlocked.png | Bin 0 -> 107 bytes .../Departments/Service/bar.rsi/bar-0.png | Bin 0 -> 170 bytes .../Departments/Service/bar.rsi/bar-1.png | Bin 0 -> 238 bytes .../Departments/Service/bar.rsi/bar-10.png | Bin 0 -> 652 bytes .../Departments/Service/bar.rsi/bar-11.png | Bin 0 -> 690 bytes .../Departments/Service/bar.rsi/bar-12.png | Bin 0 -> 729 bytes .../Departments/Service/bar.rsi/bar-2.png | Bin 0 -> 306 bytes .../Departments/Service/bar.rsi/bar-3.png | Bin 0 -> 305 bytes .../Departments/Service/bar.rsi/bar-4.png | Bin 0 -> 417 bytes .../Departments/Service/bar.rsi/bar-5.png | Bin 0 -> 445 bytes .../Departments/Service/bar.rsi/bar-6.png | Bin 0 -> 489 bytes .../Departments/Service/bar.rsi/bar-7.png | Bin 0 -> 546 bytes .../Departments/Service/bar.rsi/bar-8.png | Bin 0 -> 577 bytes .../Departments/Service/bar.rsi/bar-9.png | Bin 0 -> 613 bytes .../Departments/Service/bar.rsi/base.png | Bin 0 -> 672 bytes .../Departments/Service/bar.rsi/meta.json | 53 ++ .../Departments/Service/kitchen.rsi/base.png | Bin 0 -> 420 bytes .../Service/kitchen.rsi/kitchen-0.png | Bin 0 -> 108 bytes .../Service/kitchen.rsi/kitchen-1.png | Bin 0 -> 188 bytes .../Service/kitchen.rsi/kitchen-10.png | Bin 0 -> 741 bytes .../Service/kitchen.rsi/kitchen-11.png | Bin 0 -> 804 bytes .../Service/kitchen.rsi/kitchen-12.png | Bin 0 -> 818 bytes .../Service/kitchen.rsi/kitchen-2.png | Bin 0 -> 275 bytes .../Service/kitchen.rsi/kitchen-3.png | Bin 0 -> 342 bytes .../Service/kitchen.rsi/kitchen-4.png | Bin 0 -> 387 bytes .../Service/kitchen.rsi/kitchen-5.png | Bin 0 -> 465 bytes .../Service/kitchen.rsi/kitchen-6.png | Bin 0 -> 547 bytes .../Service/kitchen.rsi/kitchen-7.png | Bin 0 -> 564 bytes .../Service/kitchen.rsi/kitchen-8.png | Bin 0 -> 585 bytes .../Service/kitchen.rsi/kitchen-9.png | Bin 0 -> 650 bytes .../Departments/Service/kitchen.rsi/meta.json | 53 ++ .../Storage/Shelfs/glass.rsi/base.png | Bin 0 -> 223 bytes .../Storage/Shelfs/glass.rsi/closed.png | Bin 0 -> 267 bytes .../Storage/Shelfs/glass.rsi/locked.png | Bin 0 -> 109 bytes .../Storage/Shelfs/glass.rsi/meta.json | 29 ++ .../Storage/Shelfs/glass.rsi/open.png | Bin 0 -> 267 bytes .../Storage/Shelfs/glass.rsi/rbase.png | Bin 0 -> 549 bytes .../Storage/Shelfs/glass.rsi/unlocked.png | Bin 0 -> 107 bytes .../Storage/Shelfs/metal.rsi/base.png | Bin 0 -> 352 bytes .../Storage/Shelfs/metal.rsi/closed.png | Bin 0 -> 267 bytes .../Storage/Shelfs/metal.rsi/locked.png | Bin 0 -> 109 bytes .../Storage/Shelfs/metal.rsi/meta.json | 29 ++ .../Storage/Shelfs/metal.rsi/open.png | Bin 0 -> 267 bytes .../Storage/Shelfs/metal.rsi/rbase.png | Bin 0 -> 352 bytes .../Storage/Shelfs/metal.rsi/unlocked.png | Bin 0 -> 107 bytes .../Storage/Shelfs/wood.rsi/base.png | Bin 0 -> 525 bytes .../Storage/Shelfs/wood.rsi/closed.png | Bin 0 -> 375 bytes .../Storage/Shelfs/wood.rsi/locked.png | Bin 0 -> 108 bytes .../Storage/Shelfs/wood.rsi/meta.json | 29 ++ .../Storage/Shelfs/wood.rsi/open.png | Bin 0 -> 483 bytes .../Storage/Shelfs/wood.rsi/rbase.png | Bin 0 -> 525 bytes .../Storage/Shelfs/wood.rsi/unlocked.png | Bin 0 -> 107 bytes 70 files changed, 1149 insertions(+) create mode 100644 Resources/Prototypes/Entities/Structures/Wallmounts/shelfs.yml create mode 100644 Resources/Prototypes/Recipes/Construction/Graphs/furniture/shelfs.yml create mode 100644 Resources/Textures/Structures/Storage/Shelfs/Departments/Medical/chemistry.rsi/base.png create mode 100644 Resources/Textures/Structures/Storage/Shelfs/Departments/Medical/chemistry.rsi/chem-0.png create mode 100644 Resources/Textures/Structures/Storage/Shelfs/Departments/Medical/chemistry.rsi/chem-1.png create mode 100644 Resources/Textures/Structures/Storage/Shelfs/Departments/Medical/chemistry.rsi/chem-2.png create mode 100644 Resources/Textures/Structures/Storage/Shelfs/Departments/Medical/chemistry.rsi/chem-3.png create mode 100644 Resources/Textures/Structures/Storage/Shelfs/Departments/Medical/chemistry.rsi/chem-4.png create mode 100644 Resources/Textures/Structures/Storage/Shelfs/Departments/Medical/chemistry.rsi/chem-5.png create mode 100644 Resources/Textures/Structures/Storage/Shelfs/Departments/Medical/chemistry.rsi/chem-6.png create mode 100644 Resources/Textures/Structures/Storage/Shelfs/Departments/Medical/chemistry.rsi/closed.png create mode 100644 Resources/Textures/Structures/Storage/Shelfs/Departments/Medical/chemistry.rsi/locked.png create mode 100644 Resources/Textures/Structures/Storage/Shelfs/Departments/Medical/chemistry.rsi/meta.json create mode 100644 Resources/Textures/Structures/Storage/Shelfs/Departments/Medical/chemistry.rsi/open.png create mode 100644 Resources/Textures/Structures/Storage/Shelfs/Departments/Medical/chemistry.rsi/unlocked.png create mode 100644 Resources/Textures/Structures/Storage/Shelfs/Departments/Service/bar.rsi/bar-0.png create mode 100644 Resources/Textures/Structures/Storage/Shelfs/Departments/Service/bar.rsi/bar-1.png create mode 100644 Resources/Textures/Structures/Storage/Shelfs/Departments/Service/bar.rsi/bar-10.png create mode 100644 Resources/Textures/Structures/Storage/Shelfs/Departments/Service/bar.rsi/bar-11.png create mode 100644 Resources/Textures/Structures/Storage/Shelfs/Departments/Service/bar.rsi/bar-12.png create mode 100644 Resources/Textures/Structures/Storage/Shelfs/Departments/Service/bar.rsi/bar-2.png create mode 100644 Resources/Textures/Structures/Storage/Shelfs/Departments/Service/bar.rsi/bar-3.png create mode 100644 Resources/Textures/Structures/Storage/Shelfs/Departments/Service/bar.rsi/bar-4.png create mode 100644 Resources/Textures/Structures/Storage/Shelfs/Departments/Service/bar.rsi/bar-5.png create mode 100644 Resources/Textures/Structures/Storage/Shelfs/Departments/Service/bar.rsi/bar-6.png create mode 100644 Resources/Textures/Structures/Storage/Shelfs/Departments/Service/bar.rsi/bar-7.png create mode 100644 Resources/Textures/Structures/Storage/Shelfs/Departments/Service/bar.rsi/bar-8.png create mode 100644 Resources/Textures/Structures/Storage/Shelfs/Departments/Service/bar.rsi/bar-9.png create mode 100644 Resources/Textures/Structures/Storage/Shelfs/Departments/Service/bar.rsi/base.png create mode 100644 Resources/Textures/Structures/Storage/Shelfs/Departments/Service/bar.rsi/meta.json create mode 100644 Resources/Textures/Structures/Storage/Shelfs/Departments/Service/kitchen.rsi/base.png create mode 100644 Resources/Textures/Structures/Storage/Shelfs/Departments/Service/kitchen.rsi/kitchen-0.png create mode 100644 Resources/Textures/Structures/Storage/Shelfs/Departments/Service/kitchen.rsi/kitchen-1.png create mode 100644 Resources/Textures/Structures/Storage/Shelfs/Departments/Service/kitchen.rsi/kitchen-10.png create mode 100644 Resources/Textures/Structures/Storage/Shelfs/Departments/Service/kitchen.rsi/kitchen-11.png create mode 100644 Resources/Textures/Structures/Storage/Shelfs/Departments/Service/kitchen.rsi/kitchen-12.png create mode 100644 Resources/Textures/Structures/Storage/Shelfs/Departments/Service/kitchen.rsi/kitchen-2.png create mode 100644 Resources/Textures/Structures/Storage/Shelfs/Departments/Service/kitchen.rsi/kitchen-3.png create mode 100644 Resources/Textures/Structures/Storage/Shelfs/Departments/Service/kitchen.rsi/kitchen-4.png create mode 100644 Resources/Textures/Structures/Storage/Shelfs/Departments/Service/kitchen.rsi/kitchen-5.png create mode 100644 Resources/Textures/Structures/Storage/Shelfs/Departments/Service/kitchen.rsi/kitchen-6.png create mode 100644 Resources/Textures/Structures/Storage/Shelfs/Departments/Service/kitchen.rsi/kitchen-7.png create mode 100644 Resources/Textures/Structures/Storage/Shelfs/Departments/Service/kitchen.rsi/kitchen-8.png create mode 100644 Resources/Textures/Structures/Storage/Shelfs/Departments/Service/kitchen.rsi/kitchen-9.png create mode 100644 Resources/Textures/Structures/Storage/Shelfs/Departments/Service/kitchen.rsi/meta.json create mode 100644 Resources/Textures/Structures/Storage/Shelfs/glass.rsi/base.png create mode 100644 Resources/Textures/Structures/Storage/Shelfs/glass.rsi/closed.png create mode 100644 Resources/Textures/Structures/Storage/Shelfs/glass.rsi/locked.png create mode 100644 Resources/Textures/Structures/Storage/Shelfs/glass.rsi/meta.json create mode 100644 Resources/Textures/Structures/Storage/Shelfs/glass.rsi/open.png create mode 100644 Resources/Textures/Structures/Storage/Shelfs/glass.rsi/rbase.png create mode 100644 Resources/Textures/Structures/Storage/Shelfs/glass.rsi/unlocked.png create mode 100644 Resources/Textures/Structures/Storage/Shelfs/metal.rsi/base.png create mode 100644 Resources/Textures/Structures/Storage/Shelfs/metal.rsi/closed.png create mode 100644 Resources/Textures/Structures/Storage/Shelfs/metal.rsi/locked.png create mode 100644 Resources/Textures/Structures/Storage/Shelfs/metal.rsi/meta.json create mode 100644 Resources/Textures/Structures/Storage/Shelfs/metal.rsi/open.png create mode 100644 Resources/Textures/Structures/Storage/Shelfs/metal.rsi/rbase.png create mode 100644 Resources/Textures/Structures/Storage/Shelfs/metal.rsi/unlocked.png create mode 100644 Resources/Textures/Structures/Storage/Shelfs/wood.rsi/base.png create mode 100644 Resources/Textures/Structures/Storage/Shelfs/wood.rsi/closed.png create mode 100644 Resources/Textures/Structures/Storage/Shelfs/wood.rsi/locked.png create mode 100644 Resources/Textures/Structures/Storage/Shelfs/wood.rsi/meta.json create mode 100644 Resources/Textures/Structures/Storage/Shelfs/wood.rsi/open.png create mode 100644 Resources/Textures/Structures/Storage/Shelfs/wood.rsi/rbase.png create mode 100644 Resources/Textures/Structures/Storage/Shelfs/wood.rsi/unlocked.png diff --git a/Resources/Prototypes/Entities/Objects/Consumable/Drinks/drinks.yml b/Resources/Prototypes/Entities/Objects/Consumable/Drinks/drinks.yml index 029cc5b1637..8a9dc3a885a 100644 --- a/Resources/Prototypes/Entities/Objects/Consumable/Drinks/drinks.yml +++ b/Resources/Prototypes/Entities/Objects/Consumable/Drinks/drinks.yml @@ -78,6 +78,9 @@ solution: drink - type: FitsInDispenser solution: drink + - type: Tag + tags: + - DrinkGlass # Transformable container - normal glass - type: entity diff --git a/Resources/Prototypes/Entities/Objects/Consumable/Food/ingredients.yml b/Resources/Prototypes/Entities/Objects/Consumable/Food/ingredients.yml index be23c2e43f6..f1f30f6c46d 100644 --- a/Resources/Prototypes/Entities/Objects/Consumable/Food/ingredients.yml +++ b/Resources/Prototypes/Entities/Objects/Consumable/Food/ingredients.yml @@ -34,6 +34,9 @@ solution: food - type: TrashOnSolutionEmpty solution: food + - type: Tag + tags: + - Ingredient - type: entity abstract: true @@ -272,6 +275,9 @@ reagents: - ReagentId: Nutriment Quantity: 15 + - type: Tag + tags: + - Ingredient - type: entity name: dough @@ -684,3 +690,6 @@ reagents: - ReagentId: CocoaPowder Quantity: 2 + - type: Tag + tags: + - Ingredient diff --git a/Resources/Prototypes/Entities/Structures/Wallmounts/shelfs.yml b/Resources/Prototypes/Entities/Structures/Wallmounts/shelfs.yml new file mode 100644 index 00000000000..af68f5898d2 --- /dev/null +++ b/Resources/Prototypes/Entities/Structures/Wallmounts/shelfs.yml @@ -0,0 +1,475 @@ +# Parents +- type: entity + abstract: true + id: ShelfBase + parent: BaseStructure + name: shelf + description: a strange place to place, well, anything really. You feel like you shouldn't be seeing this.' + components: + - type: Sprite + drawdepth: WallMountedItems + sprite: Structures/Storage/Shelfs/wood.rsi + state: base + - type: Fixtures + fixtures: + fix1: + shape: + !type:PhysShapeAabb + bounds: "-0.35,-0.35,0.35,0.35" + density: 35 + layer: + - BulletImpassable + - type: Transform + - type: Damageable + damageModifierSet: Wood + damageContainer: Inorganic + - type: Destructible + thresholds: + - trigger: + !type:DamageTrigger + damage: 60 + behaviors: + - !type:PlaySoundBehavior + sound: + collection: WoodDestroyHeavy + - !type:DoActsBehavior + acts: ["Destruction"] + - type: WallMount + arc: 175 + - type: Storage + grid: + - 0,0,3,1 + - 0,3,3,4 + maxItemSize: Normal + - type: UserInterface + interfaces: + enum.StorageUiKey.Key: + type: StorageBoundUserInterface + - type: InteractionOutline + - type: ContainerContainer + containers: + storagebase: !type:Container + - type: Tag + tags: + - Structure + +- type: entity + abstract: true + id: ShelfBaseReinforced + parent: ShelfBase + name: reinforced shelf + description: It looks as strong as reality itself. + components: + - type: Lock + - type: LockVisuals + - type: Sprite + sprite: Structures/Storage/Shelfs/wood.rsi + state: base + layers: + - state: rbase + map: ["enum.StorageVisualLayers.Base"] + - state: unlocked + shader: unshaded + # used to keep the unlocked light visible while open. + - state: closed + map: ["enum.StorageVisualLayers.Door"] + - state: locked + map: ["enum.LockVisualLayers.Lock"] + shader: unshaded + - type: Appearance + - type: EntityStorageVisuals + stateDoorOpen: open + stateDoorClosed: closed + + - type: AccessReader + +# Normal +- type: entity + id: ShelfWood + parent: ShelfBase + name: wooden shelf + description: A convenient place to place, well, anything really. + components: + - type: Destructible + thresholds: + - trigger: + !type:DamageTrigger + damage: 60 + behaviors: + - !type:PlaySoundBehavior + sound: + collection: WoodDestroyHeavy + - !type:SpawnEntitiesBehavior + spawn: + MaterialWoodPlank1: + min: 1 + max: 3 + - !type:DoActsBehavior + acts: ["Destruction"] + - type: Tag + tags: + - Structure + - Wooden + - type: Construction + graph: Shelf + node: ShelfWood + +- type: entity + id: ShelfMetal + parent: ShelfBase + name: metal shelf + description: A sturdy place to place, well, anything really. + components: + - type: Sprite + sprite: Structures/Storage/Shelfs/metal.rsi + state: base + - type: Damageable + damageModifierSet: Metallic + damageContainer: Inorganic + - type: Destructible + thresholds: + - trigger: + !type:DamageTrigger + damage: 120 + behaviors: + - !type:PlaySoundBehavior + sound: + collection: MetalBreak + - !type:SpawnEntitiesBehavior + spawn: + SheetSteel1: + min: 2 + max: 4 + - !type:DoActsBehavior + acts: ["Destruction"] + - type: Tag + tags: + - Structure + - type: Construction + graph: Shelf + node: ShelfMetal + +- type: entity + id: ShelfGlass + parent: ShelfBase + name: glass shelf + description: A fragile place to place, well, anything really. + components: + - type: Sprite + sprite: Structures/Storage/Shelfs/glass.rsi + state: base + - type: Damageable + damageModifierSet: Glass + damageContainer: Inorganic + - type: Destructible + thresholds: + - trigger: + !type:DamageTrigger + damage: 50 + behaviors: + - !type:PlaySoundBehavior + sound: + collection: WindowShatter + - !type:SpawnEntitiesBehavior + spawn: + ShardGlass: + min: 0 + max: 2 + - !type:DoActsBehavior + acts: ["Destruction"] + - type: Tag + tags: + - Structure + - type: Construction + graph: Shelf + node: ShelfGlass + +# Reinforced +- type: entity + id: ShelfRWood + parent: ShelfBaseReinforced + name: sturdy wood shelf + description: A safe place to put your favorite bottle of whiskey + components: + - type: Sprite + sprite: Structures/Storage/Shelfs/wood.rsi + state: base + layers: + - state: rbase + map: ["enum.StorageVisualLayers.Base"] + - state: closed + map: ["enum.StorageVisualLayers.Door"] + - state: locked + map: ["enum.LockVisualLayers.Lock"] + shader: unshaded + - type: Destructible + thresholds: + - trigger: + !type:DamageTrigger + damage: 215 + behaviors: + - !type:PlaySoundBehavior + sound: + collection: WoodDestroyHeavy + - !type:SpawnEntitiesBehavior + spawn: + MaterialWoodPlank: + min: 2 + max: 5 + - !type:DoActsBehavior + acts: ["Destruction"] + - type: Construction + graph: Shelf + node: ShelfRWood + +- type: entity + id: ShelfRMetal + parent: ShelfBaseReinforced + name: sturdy metal shelf + description: A strong & shiny place to keep all your vials safe + components: + - type: Sprite + sprite: Structures/Storage/Shelfs/metal.rsi + - type: Destructible + thresholds: + - trigger: + !type:DamageTrigger + damage: 450 + behaviors: + - !type:PlaySoundBehavior + sound: + collection: MetalBreak + - !type:SpawnEntitiesBehavior + spawn: + SheetPlasteel1: + min: 2 + max: 3 + ShardGlass: + min: 1 + max: 2 + PartRodMetal1: + min: 1 + max: 2 + - !type:DoActsBehavior + acts: ["Destruction"] + - type: Construction + graph: Shelf + node: ShelfRMetal + +- type: entity + id: ShelfRGlass + parent: ShelfBaseReinforced + name: sturdy glass shelf + description: Crystal clear reinforced glass doors to show off all your fancy bottles you definitely didn't sell a co-worker's favorite mothroach for. + components: + - type: Sprite + sprite: Structures/Storage/Shelfs/glass.rsi + - type: Destructible + thresholds: + - trigger: + !type:DamageTrigger + damage: 250 + behaviors: + - !type:PlaySoundBehavior + sound: + collection: WindowShatter + - !type:SpawnEntitiesBehavior + spawn: + SheetPlastic1: + min: 1 + max: 3 + ShardGlass: + min: 1 + max: 2 + PartRodMetal1: + min: 0 + max: 1 + - !type:DoActsBehavior + acts: ["Destruction"] + - type: Construction + graph: Shelf + node: ShelfRGlass + +# Departmental +- type: entity + id: ShelfBar + parent: ShelfBase + name: bar shelf + description: Made out of the finest synthetic wood for all alcohol holding needs. + components: + - type: Sprite + sprite: Structures/Storage/Shelfs/Departments/Service/bar.rsi + state: base + layers: + - state: base + - state: bar-0 + - map: ["enum.StorageFillLayers.Fill"] + - type: Appearance + - type: StorageFillVisualizer + maxFillLevels: 13 + fillBaseName: bar + - type: Destructible + thresholds: + - trigger: + !type:DamageTrigger + damage: 100 + behaviors: + - !type:PlaySoundBehavior + sound: + collection: WoodDestroyHeavy + - !type:SpawnEntitiesBehavior + spawn: + MaterialWoodPlank1: + min: 1 + max: 4 + - !type:DoActsBehavior + acts: ["Destruction"] + - type: Storage + grid: + - 0,0,5,1 + - 0,3,5,4 + maxItemSize: Normal + whitelist: + tags: + - DrinkGlass + - DrinkBottle + - DrinkCan + - Beer + - type: Construction + graph: Shelf + node: ShelfBar + +- type: entity + id: ShelfKitchen + parent: ShelfBase + name: cooking shelf + description: Holds knifes, spice, and everything nice! + components: + - type: Sprite + sprite: Structures/Storage/Shelfs/Departments/Service/kitchen.rsi + state: base + layers: + - state: base + - state: kitchen-0 + - map: ["enum.StorageFillLayers.Fill"] + - type: Appearance + - type: StorageFillVisualizer + maxFillLevels: 13 + fillBaseName: kitchen + - type: Destructible + thresholds: + - trigger: + !type:DamageTrigger + damage: 150 + behaviors: + - !type:PlaySoundBehavior + sound: + collection: MetalBreak + - !type:SpawnEntitiesBehavior + spawn: + SheetSteel1: + min: 1 + max: 4 + MaterialWoodPlank1: + min: 0 + max: 1 + PartRodMetal1: + min: 0 + max: 2 + - !type:DoActsBehavior + acts: ["Destruction"] + - type: Storage + grid: + - 0,0,5,1 + - 0,3,5,4 + maxItemSize: Normal + whitelist: + tags: + - DrinkGlass + - BoxCardboard + - MonkeyCube + - Enzyme + - Mayo + - Packet + - Cleaver + - Knife + - KitchenKnife + - RollingPin + - Ingredient + - Trash + - type: Construction + graph: Shelf + node: ShelfKitchen + +- type: entity + id: ShelfChemistry + parent: ShelfBaseReinforced + name: chemical shelf + description: Keeps all your chemicals safe and out of the clow- er, public hands! + components: + - type: Sprite + sprite: Structures/Storage/Shelfs/Departments/Medical/chemistry.rsi + layers: + - state: base + map: ["enum.StorageVisualLayers.Base"] + - state: unlocked + shader: unshaded + - state: chem-0 + - map: ["enum.StorageFillLayers.Fill"] + - state: closed + map: ["enum.StorageVisualLayers.Door"] + - state: locked + map: ["enum.LockVisualLayers.Lock"] + shader: unshaded + - type: StorageFillVisualizer + maxFillLevels: 7 + fillBaseName: chem + - type: Destructible + thresholds: + - trigger: + !type:DamageTrigger + damage: 330 + behaviors: + - !type:PlaySoundBehavior + sound: + collection: MetalBreak + - !type:SpawnEntitiesBehavior + spawn: + SheetPlasteel1: + min: 1 + max: 2 + SheetPlastic1: + min: 1 + max: 2 + ShardGlass: + min: 1 + max: 1 + - !type:DoActsBehavior + acts: ["Destruction"] + - type: Storage + grid: + - 0,0,5,1 + - 0,3,5,4 + maxItemSize: Normal + whitelist: + tags: + - ChemDispensable + - GlassBeaker + - Bottle + - type: Construction + graph: Shelf + node: ShelfChemistry + + + +# Access presets +# Try to keep alphabetical sorting if adding more + +- type: entity + parent: ShelfChemistry + id: ShelfChemistryChemistrySecure + suffix: Chemistry, Secure + components: + - type: AccessReader + access: [["Chemistry"]] + diff --git a/Resources/Prototypes/Recipes/Construction/Graphs/furniture/shelfs.yml b/Resources/Prototypes/Recipes/Construction/Graphs/furniture/shelfs.yml new file mode 100644 index 00000000000..61a903f7a0a --- /dev/null +++ b/Resources/Prototypes/Recipes/Construction/Graphs/furniture/shelfs.yml @@ -0,0 +1,268 @@ +- type: constructionGraph + id: Shelf + start: start + graph: + - node: start + actions: + - !type:DeleteEntity {} + edges: +# Normal + - to: ShelfWood + completed: + - !type:SnapToGrid + southRotation: true + steps: + - material: WoodPlank + amount: 4 + doAfter: 2 + - to: ShelfMetal + completed: + - !type:SnapToGrid + southRotation: true + steps: + - material: Steel + amount: 5 + doAfter: 3 + - to: ShelfGlass + completed: + - !type:SnapToGrid + southRotation: true + steps: + - material: Glass + amount: 4 + doAfter: 2 +# Reinforced + - to: ShelfRWood + completed: + - !type:SnapToGrid + southRotation: true + steps: + - material: WoodPlank + amount: 8 + doAfter: 3 + - material: Cable + amount: 2 + doAfter: 1 + - to: ShelfRMetal + completed: + - !type:SnapToGrid + southRotation: true + steps: + - material: Plasteel + amount: 5 + doAfter: 3 + - material: ReinforcedGlass + amount: 5 + doAfter: 2 + - material: Cable + amount: 3 + doAfter: 1 + - to: ShelfRGlass + completed: + - !type:SnapToGrid + southRotation: true + steps: + - material: Plastic + amount: 5 + doAfter: 2 + - material: ReinforcedGlass + amount: 5 + doAfter: 3 + - material: Cable + amount: 2 + doAfter: 1 +# Departmental + - to: ShelfBar + completed: + - !type:SnapToGrid + southRotation: true + steps: + - material: WoodPlank + amount: 6 + doAfter: 2 + - to: ShelfKitchen + completed: + - !type:SnapToGrid + southRotation: true + steps: + - material: MetalRod + amount: 2 + doAfter: 1 + - material: Steel + amount: 5 + - material: WoodPlank + amount: 3 + doAfter: 2 + - to: ShelfChemistry + completed: + - !type:SnapToGrid + southRotation: true + steps: + - material: Plasteel + amount: 2 + doAfter: 2 + - material: ReinforcedGlass + amount: 5 + doAfter: 2 + - material: Plastic + amount: 5 + doAfter: 2 + - material: Cable + amount: 2 + doAfter: 1 + +# Normal deconstructs + - node: ShelfWood + entity: ShelfWood + edges: + - to: start + completed: + - !type:SpawnPrototype + prototype: MaterialWoodPlank1 + amount: 4 + steps: + - tool: Prying + doAfter: 2 + + - node: ShelfMetal + entity: ShelfMetal + edges: + - to: start + completed: + - !type:SpawnPrototype + prototype: SheetSteel1 + amount: 5 + steps: + - tool: Screwing + doAfter: 5 + + - node: ShelfGlass + entity: ShelfGlass + edges: + - to: start + completed: + - !type:SpawnPrototype + prototype: SheetGlass1 + amount: 4 + steps: + - tool: Screwing + doAfter: 2 +# Reinforced deconstructs + - node: ShelfRWood + entity: ShelfRWood + edges: + - to: start + completed: + - !type:SpawnPrototype + prototype: MaterialWoodPlank1 + amount: 8 + - !type:SpawnPrototype + prototype: CableApcStack1 + amount: 2 + steps: + - tool: Screwing + doAfter: 5 + - tool: Prying + doAfter: 2 + + - node: ShelfRMetal + entity: ShelfRMetal + edges: + - to: start + completed: + - !type:SpawnPrototype + prototype: SheetPlasteel1 + amount: 5 + - !type:SpawnPrototype + prototype: SheetRGlass1 + amount: 5 + - !type:SpawnPrototype + prototype: CableApcStack1 + amount: 3 + steps: + - tool: Screwing + doAfter: 2 + - tool: Welding + doAfter: 5 + + - node: ShelfRGlass + entity: ShelfRGlass + edges: + - to: start + completed: + - !type:SpawnPrototype + prototype: SheetPlastic1 + amount: 5 + - !type:SpawnPrototype + prototype: SheetRGlass1 + amount: 5 + - !type:SpawnPrototype + prototype: CableApcStack1 + amount: 2 + steps: + - tool: Welding + doAfter: 2 + - tool: Screwing + doAfter: 4 + +# Departmental deconstructs + - node: ShelfBar + entity: ShelfBar + edges: + - to: start + completed: + - !type:SpawnPrototype + prototype: MaterialWoodPlank1 + amount: 6 + steps: + - tool: Prying + doAfter: 3 + + - node: ShelfKitchen + entity: ShelfKitchen + edges: + - to: start + completed: + - !type:SpawnPrototype + prototype: PartRodMetal + amount: 2 + - !type:SpawnPrototype + prototype: SheetSteel1 + amount: 5 + - !type:SpawnPrototype + prototype: MaterialWoodPlank1 + amount: 3 + steps: + - tool: Screwing + doAfter: 2 + - tool: Welding + doAfter: 2 + - tool: Prying + doAfter: 1 + + - node: ShelfChemistry + entity: ShelfChemistry + edges: + - to: start + completed: + - !type:SpawnPrototype + prototype: SheetPlasteel1 + amount: 2 + - !type:SpawnPrototype + prototype: SheetPlastic1 + amount: 5 + - !type:SpawnPrototype + prototype: SheetRGlass1 + amount: 5 + - !type:SpawnPrototype + prototype: CableApcStack1 + amount: 2 + steps: + - tool: Welding + doAfter: 2 + - tool: Screwing + doAfter: 1 + - tool: Anchoring + doAfter: 2 + - tool: Prying + doAfter: 4 diff --git a/Resources/Prototypes/Recipes/Construction/storage.yml b/Resources/Prototypes/Recipes/Construction/storage.yml index c8edebc5096..7128c79eee8 100644 --- a/Resources/Prototypes/Recipes/Construction/storage.yml +++ b/Resources/Prototypes/Recipes/Construction/storage.yml @@ -67,3 +67,151 @@ canBuildInImpassable: false conditions: - !type:TileNotBlocked + +# Shelfs +# Normals +- type: construction + id: ShelfWood + name: wooden shelf + description: A convenient place to place, well, anything really. + graph: Shelf + startNode: start + targetNode: ShelfWood + icon: + sprite: Structures/Storage/Shelfs/wood.rsi + state: base + objectType: Structure + placementMode: SnapgridCenter + canBuildInImpassable: true + conditions: + - !type:WallmountCondition + +- type: construction + id: ShelfMetal + name: metal shelf + description: A sturdy place to place, well, anything really. + graph: Shelf + startNode: start + targetNode: ShelfMetal + icon: + sprite: Structures/Storage/Shelfs/metal.rsi + state: base + objectType: Structure + placementMode: SnapgridCenter + canBuildInImpassable: true + conditions: + - !type:WallmountCondition + +- type: construction + id: ShelfGlass + name: glass shelf + description: Just like a normal shelf! But fragile and without the walls! + graph: Shelf + startNode: start + targetNode: ShelfGlass + icon: + sprite: Structures/Storage/Shelfs/glass.rsi + state: base + objectType: Structure + placementMode: SnapgridCenter + canBuildInImpassable: true + conditions: + - !type:WallmountCondition + +# Reinforced +- type: construction + id: ShelfRWood + name: sturdy wooden shelf + description: The perfect place to store all your vintage records. + graph: Shelf + startNode: start + targetNode: ShelfRWood + icon: + sprite: Structures/Storage/Shelfs/wood.rsi + state: rbase + objectType: Structure + placementMode: SnapgridCenter + canBuildInImpassable: true + conditions: + - !type:WallmountCondition + +- type: construction + id: ShelfRMetal + name: sturdy metal shelf + description: Nice and strong, and keeps your maints loot secure. + graph: Shelf + startNode: start + targetNode: ShelfRMetal + icon: + sprite: Structures/Storage/Shelfs/metal.rsi + state: rbase + objectType: Structure + placementMode: SnapgridCenter + canBuildInImpassable: true + conditions: + - !type:WallmountCondition + +- type: construction + id: ShelfRGlass + name: sturdy glass shelf + description: See through, decent strength, shiny plastic case. Whats not to love? + graph: Shelf + startNode: start + targetNode: ShelfRGlass + icon: + sprite: Structures/Storage/Shelfs/glass.rsi + state: rbase + objectType: Structure + placementMode: SnapgridCenter + canBuildInImpassable: true + conditions: + - !type:WallmountCondition + +# Departmental +- type: construction + id: ShelfBar + name: bar shelf + description: A convenient place for all your extra booze, specifically designed to hold more bottles! + graph: Shelf + startNode: start + targetNode: ShelfBar + icon: + sprite: Structures/Storage/Shelfs/Departments/Service/bar.rsi + state: base + objectType: Structure + placementMode: SnapgridCenter + canBuildInImpassable: true + conditions: + - !type:WallmountCondition + +- type: construction + id: ShelfKitchen + name: cooking shelf + description: Holds your knifes, spice, and everything nice! + graph: Shelf + startNode: start + targetNode: ShelfKitchen + icon: + sprite: Structures/Storage/Shelfs/Departments/Service/kitchen.rsi + state: base + objectType: Structure + placementMode: SnapgridCenter + canBuildInImpassable: true + conditions: + - !type:WallmountCondition + +- type: construction + id: ShelfChemistry + name: chemical shelf + description: Perfect for keeping the most important chemicals safe, and out of the clumsy clowns hands! + graph: Shelf + startNode: start + targetNode: ShelfChemistry + icon: + sprite: Structures/Storage/Shelfs/Departments/Medical/chemistry.rsi + state: base + objectType: Structure + placementMode: SnapgridCenter + canBuildInImpassable: true + conditions: + - !type:WallmountCondition diff --git a/Resources/Prototypes/tags.yml b/Resources/Prototypes/tags.yml index 7c85152ea33..573363f9122 100644 --- a/Resources/Prototypes/tags.yml +++ b/Resources/Prototypes/tags.yml @@ -542,6 +542,9 @@ - type: Tag id: DrinkCan +- type: Tag + id: DrinkGlass + - type: Tag id: DrinkSpaceGlue @@ -764,6 +767,9 @@ - type: Tag id: Igniter +- type: Tag + id: Ingredient + - type: Tag #Drop this innate tool instead of deleting it. id: InnateDontDelete diff --git a/Resources/Textures/Structures/Storage/Shelfs/Departments/Medical/chemistry.rsi/base.png b/Resources/Textures/Structures/Storage/Shelfs/Departments/Medical/chemistry.rsi/base.png new file mode 100644 index 0000000000000000000000000000000000000000..2d67101d2fc367f5c3efabe8639b97017257635c GIT binary patch literal 692 zcmV;l0!#ggP)Px%Zb?KzR9J=WRzGMHQ5gT_PjkIX!d*;Fa-kHD#GymMrHj;)=%Q05g(3wP$?WXx ztec1g1aVOuGQ~v#MO?b1RSb=SrIbsfiOqRUV&!Zd^zQO5?=DG|bTGf^eed_Z@B6(! z-^T+c_}}5_HL}_4(KwP83I#K--%jT9d9W;N+8oDOeTKcrxitW|bveCA6Xm5%8pqc7cF?76Wds;8dauG&K)qi7 zXUXj%n$2b(M|}gsApGPiVQVWz2TylUuV9=Qcmkgj5*}7I5%Q5*y_fD2_TfHRmiv`W zs0j)9@)rWwxV|(k1RyX0=(-NCy5s2E%N_Ew5SRcCP6hD8t1ory{?|hbh(@DmwOWYH zL7q!Sab{))0I=0)U^W&905F_@ou>2Fj+kk%em?>c9}t0en^9#W_CNs!);Hc@eZw)w z$XK42sPlvXRaMQgD4bsffU`dbIsSU{~-0{~p)8KC_gX#Z}p5`cvl z7fe6TmFL8|g_qaN@mm`w@eC2$RR92_(`o8%PIJyaZk!v44_YRZ8OyJ@R4RD}drdIG anD7hV)XtMD4qp-g0000cq@Gs=6k_mn^>bP0l+XkK DN_QQ_ literal 0 HcmV?d00001 diff --git a/Resources/Textures/Structures/Storage/Shelfs/Departments/Medical/chemistry.rsi/chem-1.png b/Resources/Textures/Structures/Storage/Shelfs/Departments/Medical/chemistry.rsi/chem-1.png new file mode 100644 index 0000000000000000000000000000000000000000..47ee108f18c6ba3e19ba03b4510b862b4e703184 GIT binary patch literal 233 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz#^NA%Cx&(BWL^R}i#=T&Ln2y} z6C_v{Cy4Zv9PsdHJbY}nyM% zITnt&>;l3}{}bOZ|9i!9HTWtcpLG7Z-AkfY{m#3;*O~_i<|!4kY!hj8yMk?3WNI2EC@xv>ubG7z2%4MUMDe%1fA4?klp@F-O@RhnZU;3aSe3;Y Z7&H>pj7p#CZvi@&!PC{xWt~$(695g5P=f#f literal 0 HcmV?d00001 diff --git a/Resources/Textures/Structures/Storage/Shelfs/Departments/Medical/chemistry.rsi/chem-2.png b/Resources/Textures/Structures/Storage/Shelfs/Departments/Medical/chemistry.rsi/chem-2.png new file mode 100644 index 0000000000000000000000000000000000000000..77a54a15cef75cea27d1362369af7614827dae4b GIT binary patch literal 311 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz#^NA%Cx&(BWL^R}A3a?hLn2y} z6C_v{Cy4Zv9PsdHJbY}nyM%kg8 zR}AgF=GS9`bg$NKe}7Mw4G8=vS~h{S#+co+Ns`(WFrl%rQE{4T-_DYM$Nxu9T+}Xd zz{TU>uj@y(*h`mJB~1Q&1hfy;Bq^t0rFuBGlTO(_f$i#-`jznXYh3Ob6Mw<&;$V1`F_>_ literal 0 HcmV?d00001 diff --git a/Resources/Textures/Structures/Storage/Shelfs/Departments/Medical/chemistry.rsi/chem-3.png b/Resources/Textures/Structures/Storage/Shelfs/Departments/Medical/chemistry.rsi/chem-3.png new file mode 100644 index 0000000000000000000000000000000000000000..ddd26ba62701212cd38959dfa7b0b63db2337528 GIT binary patch literal 393 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz#^NA%Cx&(BWL^T<&YmugArY;~ z2@q8R{IPj6FO@a)gOe^0(~aC5T(Mb-W19gtN}RzA$J`3FC9 z^VZ!;#{)s)%;s^?oB#Z-W}ffd!O6J8mHp4vhp%EM9Qm%$sl3|#y0cNijf&#A7fkox z<_Rv@X6$qE=DVGbj&QDc>aG>JdR^G2u-LuFDj&Cf@0xr)@lpE~$#lEGu1QZwNGN!c`k-awM@BIx zu2=RR1|VQ@V%^t-AOHTT`26`Xt77eAd4-%jHjd=}{kwRXO)ko{dC1;o* jm)k)NNPsm>Px$!bwCyR9J;$U>F6XU=)mWz(`1e!^WFO7#J9=Ilh0mu_MA<6DFRSnfV{ao<4m# zia9PDZysU){y}&vl6tZn;IQ%LItB)YKzBusqdV{au;%>!{^a%u3kwDY28Jh3p1>U- zBO}8Iv-l4KgSERN$593b28IJSUR$&L`+EbQLx>3hxJ3v2)#2)0ki_>Oi6g5=*F!RJ z*m!fD&^5o?3{!NrGfdIh?z!T`38>{qDp{+pRQ42*Cg-uoUF-FZm+Hu3`#&>$XJBApaO7p+gt74f z7D5W@KS(ezFfcGU$gcHZ`2PMRO#Jwoc&+0fAZ%_12xE`Gx(x#~(H@3K9o^%vZbQh9 zQ81u@U>0#In)VXL-q)8UPHhL^O@!{1EAN?^s=tBpS=m?K+u0tjL`?_a4T0l#@1JO# zbJrZkuTN1vX{oGeK}`n`%!ZTW`Ch(Z6%}V-U|`sG@uN8*^`rv41ySRiyKD>$3=AT_ zU%wRj{rctU({IjG+W`aQ7{SyD*ym^+n>E~C=Pr80000< KMNUMnLSTZVlj>^# literal 0 HcmV?d00001 diff --git a/Resources/Textures/Structures/Storage/Shelfs/Departments/Medical/chemistry.rsi/chem-5.png b/Resources/Textures/Structures/Storage/Shelfs/Departments/Medical/chemistry.rsi/chem-5.png new file mode 100644 index 0000000000000000000000000000000000000000..1b7430d80959724d2f248e5c254936089d2e0ebe GIT binary patch literal 605 zcmV-j0;2tiP)Px%7fD1xR9J;$U>F6XU=)mWz(`1e!^WFO7#J9=Ilh0mu_MA<6DFRSnfV{ao<4m# zia9PDZysU){y}&vl6tZn;IQ%LItB)YKzBusqdV{au;%>!{^a%u3kwDY28Jh3p1>U- zBO}8Iv-l4KgSERN$593b28IJSUR$&L`+EbQLx>3hxJ3v2)#2)0ki_>Oi6g5=*F!RJ z*m!fD&^5o?3{!NrGfdIh?z!T`38>{qDp{+pRQ42*Cg-uoUF-FZm+Hu3`#&>$XJBApaO7p+gt74f z7D5W@KS(ezFfcGU$gcHZ`2PMRO#Jwoc&+0fAZ%_12xE`Gx(x#~(H@3K9o^%vZbQh9 zQ81u@U>0#In)VXL-q)8U4r4nPF1W|Qz`(G#KS7BS2jESF?v*R=nVG7;f$>?{SKiy% z98q%v-IN z9Q#+~TF$^gL^hlp&-d~TtEe~w0|UdhiyzGy7#JApQP$eylmgm?gCfuUA6Z= r0|NuY);4GI%lc6;3P!;w7z_Xa8xYH1*bm_900000NkvXXu0mjf_}~@3 literal 0 HcmV?d00001 diff --git a/Resources/Textures/Structures/Storage/Shelfs/Departments/Medical/chemistry.rsi/chem-6.png b/Resources/Textures/Structures/Storage/Shelfs/Departments/Medical/chemistry.rsi/chem-6.png new file mode 100644 index 0000000000000000000000000000000000000000..e415ee1a7e8898bca03da2d4cb2b7b4d7fa4e2c6 GIT binary patch literal 710 zcmV;%0y+JOP)Px%fJsC_R9J=WlU+ztVHn5%E9bT%f|3%M7qj5tH2Q$lHlx)hTMimsC3ca7H|w1@})wGLjL5m z!2eGT7Eda2(x>{;LtyarO;a`B>tWhoiz+5t`uh`m5 zmTTlsPM}n1&PJ8|CV?Ih=tBSQZ~hvCFXcV4d}{?GjWZZ&oVhs>4sRC^IpofSL+(s0 ztCC6UMC1$6=P9s5HAoEAATdvYCAs}LB-X@Kw(snRb1yA>-t5^+*14Z~*sM5FGBRBU)SEc$r$E>fwe7Hwi*Xod@~ zB%|MHhU005?|a z*>u%LHXV!QmW291d-Jzww5aXoet!e^`bi?QS5AoN5Lz68(hmGCQ^`+uHvP;f6L{l? sWwMK8y~*=SewXQzSPcmY35f&cH@C12VU!4N-T(jq07*qoM6N<$f|40ef&c&j literal 0 HcmV?d00001 diff --git a/Resources/Textures/Structures/Storage/Shelfs/Departments/Medical/chemistry.rsi/closed.png b/Resources/Textures/Structures/Storage/Shelfs/Departments/Medical/chemistry.rsi/closed.png new file mode 100644 index 0000000000000000000000000000000000000000..c79f80c0c2310f301d6313426bec0a4a53311631 GIT binary patch literal 267 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz#^NA%Cx&(BWL^R}M?GB}Ln2y} z6C_v{Cy4MEBpgvql)tpGf0meROz^`N-#M()*;s?u9&X_=y)wzbvh0@_KQr@T#v<8c zF6-Q~8UxvTtQeLvFH(A2!jXAz)29_;%*@QqJ+qj;$~yEYM-}NjG@JaIV-8=$wm%m{ zlVlDaIB?*@lWWYIWE;&{I4l>Xo%+Z=#i}Vm>cDf3`30}DPfVNim}Ai;2E&Vv>y$at zoTIFp5|mVq2^w&pEMy7noG`6VL4x&%%)*uHzcoj=_cR3>aJez+F)&okPTdx?G;ANx OLkym-elF{r5}E+_Ygr+ArY-_ z&lxf@FmNy{B(JG=WzOK>m-lcGEx2&9#OOXh14F}P)<w1lw}$KTFM5ezk1=AE4ZUOAL1I78TNam(66JpsOk(WKzsvE8}P& zcgyhpMb!FsY_Neb67e#xO~{SKtca#>qQNat5cX6F8&C9wPEE|TcC#+JYD@< J);T3K0RU(OUmpMf literal 0 HcmV?d00001 diff --git a/Resources/Textures/Structures/Storage/Shelfs/Departments/Medical/chemistry.rsi/unlocked.png b/Resources/Textures/Structures/Storage/Shelfs/Departments/Medical/chemistry.rsi/unlocked.png new file mode 100644 index 0000000000000000000000000000000000000000..39d2fb77884f3e7d5ec21c0538d18761652efca5 GIT binary patch literal 107 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz#^NA%Cx&(BWL^R}s-7;6ArY-_ z&lxf@FmN2+Pi0jO8VkuLc9xTmmm7EjISihzelF{r5}E** CYagWm literal 0 HcmV?d00001 diff --git a/Resources/Textures/Structures/Storage/Shelfs/Departments/Service/bar.rsi/bar-0.png b/Resources/Textures/Structures/Storage/Shelfs/Departments/Service/bar.rsi/bar-0.png new file mode 100644 index 0000000000000000000000000000000000000000..c090326148dd2c90eda107a749782cd9a2c9f7ba GIT binary patch literal 170 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz#^NA%Cx&(BWL^R}DV{ElArY;~ z2@I;*M#72S8xM29xHA*UEs#7;w2A)Bu|qz{1cqk>{w5yu=cqeGHzi KelF{r5}E+2SvuSR literal 0 HcmV?d00001 diff --git a/Resources/Textures/Structures/Storage/Shelfs/Departments/Service/bar.rsi/bar-1.png b/Resources/Textures/Structures/Storage/Shelfs/Departments/Service/bar.rsi/bar-1.png new file mode 100644 index 0000000000000000000000000000000000000000..7d698e0020f00e0d34ad9d97cc5a45c60703f879 GIT binary patch literal 238 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz#^NA%Cx&(BWL^R}D?D8sLn2y} z6C_v{Cy4Yg2|0K*ysgigebQx8mY-zS?ehmb)*RAF|5~nd#>b}q-@o5Rx$k`yonGzz zd}_Xtfq_BJ+$);B{<0Sp6*3dFf4sd|9_Gm$?WnZXqw|E;zs~pbK2Ff$O8|li-^&!E z*6v$*qTEWL~T~}T6mg%CuKsPgZy85}Sb4q9e020Jr>;M1& literal 0 HcmV?d00001 diff --git a/Resources/Textures/Structures/Storage/Shelfs/Departments/Service/bar.rsi/bar-10.png b/Resources/Textures/Structures/Storage/Shelfs/Departments/Service/bar.rsi/bar-10.png new file mode 100644 index 0000000000000000000000000000000000000000..5acb43b17992e3a4febbfbf730ad8712a3205eb4 GIT binary patch literal 652 zcmV;70(1R|P)Px%MoC0LR9J=WlwC+uVHn5%XFIx9Yi(_QE{i$Kp|urVj6T$xjSUQ1nRHhdeIUUG zAxn0=DuOU2(1?Z(DH^d0w?Oft79!Q^Li(_d7l6K2?z)X2=L&vy^dt}wWS*JCoNY*TtxoMwjYJ0TL1uq)gl4_y2IKe0Ngxl z%Gn6TMf5D_CUc1+JQu2Dav-&Dd(dL1rsu-5&+oG$K*T1tgKlsfiyISK%4o+im-BZg*J7v(=(m7 zfnRKEG~=360`ZqV^q!X&NUau(Y+@;2a~c6fLXoXCS`K~C=xY}NY|YC+@LuPqnA?j= zLwP3gCj2dXZY(*LJU*|&`1J)eu|?Vyp;bTIs?ci*0HEa32>_VxdGN0C5k-%q_>AGy zRlI(6|B12qigCi|kk$l{c>BB9+pZQ)_e_8n`!4J!^%ooR{)7M?uOKu$wDg=d+SE`S zEdc@L?@@vCo>>AIhAXD{&-D#vc0O7cuo3ctB&}( zBi05hiTJuBeDd-BBwBQ3L{&&*b}@J2x}){AIX^Z{ED|w>x6h mJ9ZI&yCe4Biwg({0000Px%Y)M2xR9J=WlwC+uVHn5%XCAfHvaQYUEaogl%OzcmKGd6u0|PCS?(D(}5fnm} zY+fZnm?O}L#uO=%*u^$MQK-e7*6Kp~u&{_#e!y5XwOtGab9=g|WV5n!9CUSla4z2W z{GaFlyyv{n0|*ER2=L&1O({jMl^NOeH!W90TtwEZx*ta3Jph2Ad=UYFs#+NWfZG=} zTP}p*B6{X9(7juZuWW)yvKEenp0Wm+Jjb%gB#4qJ9NEz%-_F!_K8ndz)zanzfRUcg z?9Fm>`T~KZ3}hZIl`YS&Bu-0OWB?HSd?w|fCn%{)Nru?D1bdtI#fGpfMUHaqT$gz+ z?gDEy+mu(hJL_ltgi51zfv=%s^cjc4a|N}*RON=yyr0jeu>TSOKzc_#0L=9~e3v`Huv198 zP~31GuU|cQqE5S}o>n)D3+)KJ{Zs5+eIuuPCculMmyc1|mGYS0w{+Cggib}4j(T1* zfpZr)M~2tiX{SyB>FIO;fZJvw0AL13k<`=xW^j~`KX-E%K-N3`1OTUMYREYJnA|oK zRh%dzx6MT3V=n3~QPB99EAH|98)m?HA0RW}jNUi2>ZxBPB15Zw%ch)uf!}Dd&7(O#$uCE22J4LCmSW1Kr-r@=Ed!bbI;a<2@uA zRhcADVzIco2J=V%di;@+;{oYzg(A4Lu<-n)CzWsBxUsf3`|=MQB5QlI@4uT12nfW( YcMSv4Nr;lodH?_b07*qoM6N<$f&^+mUH||9 literal 0 HcmV?d00001 diff --git a/Resources/Textures/Structures/Storage/Shelfs/Departments/Service/bar.rsi/bar-12.png b/Resources/Textures/Structures/Storage/Shelfs/Departments/Service/bar.rsi/bar-12.png new file mode 100644 index 0000000000000000000000000000000000000000..77469720a635ab8497a7de25b3a39cdf1bc8560a GIT binary patch literal 729 zcmV;~0w(>5P)Px%lSxEDR9J=Wlv_ws0T{>sXHIQ3*KG5i#hj&Rxugf_qP|QV*vMwmn>|<|f(Vw(z5wH=NYc)R_iS_~jx{?G00Ls$}F96)Wl=0U= z7&fA3Rz2OjW&J7)5{OsV*1b=K`fypiX^sgJgwopju2R`frl9VTpI2Ual?woRn(E@V z@@Dl0+#%73Ig%N^IJp!&DlQKP0MF;Ml0!otaiJs>BKtfnRq7X;%3|g5iq-S=#)*If z{9=Ee8aK*A5%i@QrpuCGQEm<#yFE->;TkMbx71gw$~pBRE;)4tz`lS2SUc)Jx%4ea zNQ+%}zZv@GdvDk~>^-+A!^q7g6nG*On@SUZ9$O;ZP5=N=HAMh0(e&_L!XP6YLFC1> z;_G<*>cJCLw?F|F~Oh+$5N{hjC^a22Ct+s%-q+fFfK;}EG1OR99^U2Wt znEKlrDCcAr^|v?BK%aw})8#bK=O9O?g>*J8IXW%>CWH~N-v`JD*nO|-D=Mi~DIk4C zrC%eRO-or-YSP)X+Xi6u38oDO_4^${OdAYp0O-=B5CBY$jiXtdhRLyUKmGF5!c17K z1j|zkGi>}h(UOr&2NF}MB_rAI>6~qi&fM%=a<(-(x%hEj5+%wQl7$E{x3UW3$LWpw zqvN3}VZ_dNR6A0e{4eIL&hCb1N00000 LNkvXXu0mjf`A1iX literal 0 HcmV?d00001 diff --git a/Resources/Textures/Structures/Storage/Shelfs/Departments/Service/bar.rsi/bar-2.png b/Resources/Textures/Structures/Storage/Shelfs/Departments/Service/bar.rsi/bar-2.png new file mode 100644 index 0000000000000000000000000000000000000000..5eab596dd4648c3d0651b52b21a060968028c6de GIT binary patch literal 306 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz#^NA%Cx&(BWL^R}Z#-QbLn2y} z6C_v{Cy4Yg2|0K*ysb~!x2WYyeN0v-tB=acXHy&>YW>!(TX==B=ZMysqOkhoht3@N z{QUiX{mb9(i4^&5tU7$+%#nZp-|wGa{ai-aG5r19@PAVp8ygc}FY(K)c_t*wG>L6n z(|x(x^r xI9J@N`B8uM*YW>!(TX==B=ZMysqOkhoht3@N z{QUiX{mb9(i4^&5tU7$+%#nZp-`l_2Tilmeam0H4A5CUv=EK)K=U)18M%9W%g*S(F zzwNJcTA2yjCk`Aq@ZtUW{rOhz_8v9hv1T z9I*B0hySb2wrieK1$n3`(16SBpoRpi2|L4W4SOCA9-aL_Z!>th`njxgN@xNAdkTZQ literal 0 HcmV?d00001 diff --git a/Resources/Textures/Structures/Storage/Shelfs/Departments/Service/bar.rsi/bar-4.png b/Resources/Textures/Structures/Storage/Shelfs/Departments/Service/bar.rsi/bar-4.png new file mode 100644 index 0000000000000000000000000000000000000000..15c03124e69b1c62484d2e10751603caa0312ce4 GIT binary patch literal 417 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz#^NA%Cx&(BWL^T<(Vi}jArY;~ z2@!%$S$vx6Qeu%wgK* zU)Jlki`S)FuHK&vlqm4qSjD{be<$asq!r)KY1hA+8~$%f7T*Mu4WfU(y|7-rq;ahR zGc)ty{r3O&y_ETTK={=0a|d?*mOXr{XnJu*)Do8z(f>!v&sTJuj}c3fJpcp>@832Z zdR|hVdgFL`!$j3D@<83$j4772;q$F|fWSXLCiGys+C{|=e-1tTzFuGc?_UrDB;}*y z6SI8(oPR?9d}lm-^yEFyL3tO^i(6JW7{(p&Si@Y_62xpM#j literal 0 HcmV?d00001 diff --git a/Resources/Textures/Structures/Storage/Shelfs/Departments/Service/bar.rsi/bar-5.png b/Resources/Textures/Structures/Storage/Shelfs/Departments/Service/bar.rsi/bar-5.png new file mode 100644 index 0000000000000000000000000000000000000000..ece06f2d7866b49989b8ee21e84ca5c1d753c47f GIT binary patch literal 445 zcmV;u0Yd(XP)Px$cS%G+R9J;$U>F6XU=)l35N{1LU;~8M2(!-*LUY@H@*{{T%}X1A}vl)f*`NPfU;(Lyvb}`BU$_ z@~2dBz-u-M21x^3!EcYgvq~D+3NkP-F#P-T@0-ri4?LlK>5dQ$&hUq1T#`Gv#p85kHCm{^#&PJcQ5CH$K(!^O$p8G=8EDxzss zfnvOXs1Oiuieq44V0bub*L5YB*xotEL>L$t7{uE3uj=P=YOQ5>eGQx5g{2vc#Mm(k z20z%nbu-@VM03mcF);jJv0xs>MK4)k1_Q(HWeg1eXD~4ArncEcm4wf$s$6bzurNHY ns&XN$dK8R;Q7{Td0cijL)3}BnsfDj;oiL;tWQV&l?6&R7k6Ei*7)o1GeO+BzdY_|@cTWVmWLD`$Ts6- z^JI=bnBTu|vzOEjE+Yd2gFnANzn^{XBEQYTnm0UicHcK#qg!s-zRcIlCG4Yr&G(-6 zA7|1Ok1-l3ynowt=y^$b>W$;&4HH$r$OGMw&6r|Y8$REf2MGN0V?qz6s~r@G*uL-g zz00R8dAzEE{>R1J{rdg0_3(R12?>cA5i@r9)m#2m{WII(@X?d^C7bL!v=(KCHYV+9 zSRo*g-<6z@kWgWfdA(G1#*KTH$6bJWB#zwry8hMkqO7&46}7yx@3k(K>^XA7kjsN< zT58z;w^DC4^;#q(I?l9#+^~ClUR%0)9KRr2qe5ZU4gWdJW%+miOt^VFJnv{z<$sVH zcBmT~zOXs5w2Qfe$yh?7Og}l{hkbKnqWRXdYFaGw!b5l7d6JM=5f}Q@DdMXJG(s*h ZFa)p_u24=pt_+Mj22WQ%mvv4FO#r6D%&Y(a literal 0 HcmV?d00001 diff --git a/Resources/Textures/Structures/Storage/Shelfs/Departments/Service/bar.rsi/bar-7.png b/Resources/Textures/Structures/Storage/Shelfs/Departments/Service/bar.rsi/bar-7.png new file mode 100644 index 0000000000000000000000000000000000000000..e9468e2cdfe0803e96cb8900071461a19c86d8a7 GIT binary patch literal 546 zcmV+-0^R+IP)Px$+(|@1R9J;$U>F6XU=)l35N{1LU;~8M2(!-*LUY@H@*{{T%}X1A}vl)f*`NPfU;(Lyvb}`BU$_ z@~2dBz-u-M21x^3!EcYgvq~D+3NkP-F#P-T@0-ri4?LlK>5dQ$&hUq1T#`Gv#p85kHCm{^#&PJcQ5CH$K(!^O$p8G=8EDxzss zfnvOXs1Oiuieq44V0bub*L5YB*xotEL>L$t7{uE3uj=P=YOQ5>eGQx5g{2vc#Mm(k zNCK8+R{!l9?I|vV7#N7mh71f047;~(hG!>U4-p1|AaQEgPn-jGZ{7Tm+1poc#e#YN z85kHCxF<0&=sd`!iUWuOGZ+|lFJoZ%KZAi`H?_?sDg>TaRk_^cU}1P(Rpmlh^#Fm} zOD5iSw|D=4d&$Jxr0AnsAz^H2{aQdsMC8M}H*e0KKPpPBKB990AyDdN^y|svdkm#s kM!%?K<|r5iqkt{|09xgT$Sc6)6#xJL07*qoM6N<$g8Fdm^#A|> literal 0 HcmV?d00001 diff --git a/Resources/Textures/Structures/Storage/Shelfs/Departments/Service/bar.rsi/bar-8.png b/Resources/Textures/Structures/Storage/Shelfs/Departments/Service/bar.rsi/bar-8.png new file mode 100644 index 0000000000000000000000000000000000000000..d01b2a6bc8774dd113d4aa31f2cba9f46c8b37b2 GIT binary patch literal 577 zcmV-H0>1r;P)Px$`$F6XU=)l35k!b_gReijJ?V{J(hWy7w&1Ogw-7{`+!_rBYB>cGg=) zW+wLkfB$i333D+9ckV$k%R8_9DFXuo!`4Zi()i3KDg<7$Niawn*b07o^quu8Po5wH z0|Uc{7a@E)M?dg{^06~;?taIxw%p|$nl>pBS;ar`-7_9i>;M>$_jY0E%VTF?el?q6 zRv{lNr@Je|KK>7kOG5uLtQB}IfUH*E)#r}1hW0N81_n8b9I$SE_r0f;a~PELr2f6W zeDpW6-03f;zl47iX1F-{J45gXQAISZDo~6UunC3i7gy0G(zzF52dRsCE}t+foVuVK@>ur!0HbT$e|0+wY~|Lq#>DK3N<7)Zzk zySHwJXD40{5e9)EacbC4oC9`m-TaW*+gEPIf_eWL7#JA1CowVTJjkVr1Be1M7#Mah zV_^6{gMnc;waq3f1fEw_x!mMnVR&9uPx%A4x<(R9J;$U>F6XU=)l35k!b_gReijJ?V{J(hWy7w&1Ogw-7{`+!_rBYB>cGg=) zW+wLkfB$i333D+9ckV$k%R8_9DFXuo!`4Zi()i3KDg<7$Niawn*b07o^quu8Po5wH z0|Uc{7a@E)M?dg{^06~;?taIxw%p|$nl>pBS;ar`-7_9i>;M>$_jY0E%VTF?el?q6 zRv{lNr@Je|KK>7kOG5uLtQB}IfUH*E)#r}1hW0N81_n8b9I$SE_r0f;a~PELr2f6W zeDpW6-03f;zl47iX1F-{J45gXQAISZDo~6UunC3i7gy0G(zzF52dRsCE}t+foVuVK@>ur!0HbT$e|0+wY~|Lq#>DK3N<7)Zzk zySHwJXD40{5e9)EacbC4oC9`m-TaW*+gEPIf_eWL7#JA1CowVTJjkVr1Be1M7#Mah zV_^6{gMnc;waq3f1fEw_x!mMnVR&9u<-)+gz_7_fiz@L?7MNqM@n2O%`~Mts4HQS* zUNZ5vyS@AW+e;?iCdE9G3yBP6$^XJ^EDUdd{b87K_c>g@v7z;A0U;5Q5AWW*IeY%7 zD5>UB3|3UPx%T1iAfR9J=WR$Xh;U=)7x(X{E(mC!n7u@}OsOu9KlLGi*HKduDv(m&yk@?N~H z>}FRA7MXJxx^C*|Hb-nNH8tN&yeN51nzw7CMKA0Fft=@@Jm=&j=kNk^{O@4G#+_x! z{~JlSPWvP;Kk9sR{}#F5xN;HQz5!VhBQf2+K^3OO$&!fe51$D4;^nJIOsoI^c>Sgh zo@KDJ{T5lCjrere0|3|qAFelS7|${gxZz9D;)B?mH?GHWQ48Q%21gwm&5lKLPei4V zjyzi_q;a7jP-EFqB4umjZDt99W0117$prxMHqHX$G-sbFA?5|dra;w9GHOq*74Wrh z!X0?vITq)n%vAR0j*G|ZGSPg0tV4G_sG2#s0AM)d08o_ku)x8wOr+8o6lG~D8=W5H z{NgXcW1VPDRed=h$ee-$-|~z5(^SJ``aY2%d?CVIs@3sFp+= zwY%imYDq-fa3>dV`okrHyC(**{}js$JXu7en$({#SVWpRAlJQ1ixE2sAJ!ZN^%De3 zW38Np?s!;{(|Eqq#e>y6_PZ9cDK-%g$De)?E#)%gJ`k%ZJpe#W>0w1qC+2C|V+#o5 z>XJyr0@RdVV*V^pKS6-4eT&-Or2I!UKK}uz9SBAZ0P2TMq`mb+=ePK<=9wK(_72F> zc>1tP_ywhjjnxWnuSesj;h$~3gFWz}>>b1kh|I?2T*kj!$)RnyPx$UP(kjR9J=WmpzJuKpe$ivSKl85rp6t9w3Fi*tn&w)!u85-~|@XV4(+C7oxR| z2th5TShC3$;;bKIh#Qqa{8jVu_q~VA{9%BFM`u-^SeA93!_;vc<}0)}4a2~0w_|fj zlDHy=!=W+1rf$FA!*$)pekT9`*tX3TyA@5-I&0hj0O0#R8!L)}EXxL&Z8jUkam?nr zu5;_wgH$J=6M#}WnHf*}{{Fz+^d7Uc>h{ zZPXAS?iY8xH-PsUL0GRKK9#R1BK&o2dOYF#=Zxd2%vja6YXCIrc>Ds2D35#B$#J^? O0000cq@Gs=6k_mn^>bP0l+XkK DN_QQ_ literal 0 HcmV?d00001 diff --git a/Resources/Textures/Structures/Storage/Shelfs/Departments/Service/kitchen.rsi/kitchen-1.png b/Resources/Textures/Structures/Storage/Shelfs/Departments/Service/kitchen.rsi/kitchen-1.png new file mode 100644 index 0000000000000000000000000000000000000000..ded931cadfcd6e0e6785420f851a6e1d88a349f8 GIT binary patch literal 188 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz#^NA%Cx&(BWL^R}Wu7jMArY;~ z2@iBll{4{D_w@$B3!j$pg4x17VQ^8v|1I-2dngR{D f+zx6$Y++(Z3s;mkZ;F}@bOD2>tDnm{r-UW|VP8OD literal 0 HcmV?d00001 diff --git a/Resources/Textures/Structures/Storage/Shelfs/Departments/Service/kitchen.rsi/kitchen-10.png b/Resources/Textures/Structures/Storage/Shelfs/Departments/Service/kitchen.rsi/kitchen-10.png new file mode 100644 index 0000000000000000000000000000000000000000..8d71c464f6e186f7c34473f5b2f9dbff18d36277 GIT binary patch literal 741 zcmVPx%pGibPR9J=Wms>~_Q5?pT42L+$YPFK(vET3KSbw*Mwm2_eC*S6pQGVkI-rn62b5rM)IuZy3l)1@d zA_D^hOeUyBvm-fVUFv?MOGD_r?1Q~$L02CN1qc94438pj*AWEz9%1x@9{^B!>Wra@ zB--MIlgUVzhJf+!Xj#f#wI(w&PieAV;1$l&958qU0N`?^K#nA#57C%4V`CCR;V5P- zr-5)3A7{U?^k$R8UO*i70%BBG={QQ%*MwMQ7?iG8Ud=5%u$N~(<1C_vFdPn(si`R) zGn>sE0JPn?rI@QedyxYGucwpzSeyp{B&|&azq^8Jm})?lW#s4Q>lgrZyW5F%>ox#@ z=eZl*?sl^0;0dm%Fb{)0O#p!HWlq}m#s)GnGL(jD1^`(6sx(*6)3QntnGu!o@lDyp zC4G*07pMk&J|Ap0n~niM*NYwiz{Z?x%{($AA}y;_8J{aUL~CIjLa$dFLZ1H>!mH=2 zl(lQE4>1IW-%a9M`c4PcvD`;$om~ONWkCG~Cv)cTrx)5@OL$ Xz2p}k6(iR800000NkvXXu0mjfKblOx literal 0 HcmV?d00001 diff --git a/Resources/Textures/Structures/Storage/Shelfs/Departments/Service/kitchen.rsi/kitchen-11.png b/Resources/Textures/Structures/Storage/Shelfs/Departments/Service/kitchen.rsi/kitchen-11.png new file mode 100644 index 0000000000000000000000000000000000000000..5885ae1c6e3c0603b261730d78d52eb6ea6cf7d8 GIT binary patch literal 804 zcmV+<1Ka$GP)Px%-bqA3R9J=Wmt9CxVHn4MM=G)8=6%u`|5+fAOfPCMsRgSzm4bKd9o zK6{@(?|I&{b0kuvqM{-(K5lJomCXKblHTM<5?H))`KrkFB)4Vj@9o*W8bZyeR+4-N(eKzCaQ1h$Q=k@^=8;uyrZ^bf0syZ!ok%Q=CX}Q(ot+^DqY7c` zE{H0;9T+xK+nmbmb3~bajxfsGQnp#dUngW%hK*AH$d|CCYgfsp&$t=sHeoax6}`Q^ z8kUunB>`Nza7Hz^bI$<@z}Ik7eEl*4K-%Q#$SWMWhII`@A`uD;3pEVjaotr>G=BjA z4fpGKTz6HhTZ&Q=S?GXTDPREx*Q8M!6I!hUtUZFZjU zhTbRL1ziJyKmeP~reOf}4;lfOH8U?Ej)nbXGhE&;SZt4+waF0D*y(@yCBki+Q`4yP+6&wSkm*;;c}Epn~OEdjV)UI8$ygi(|a z+^RqJS52mS4AaNY{CBxsUNNkM)!1UmWYgNCV%$W{GJC?VR6TuSXinFFyL2&k`(kPw z3b!ZCy&|s`#U4)r%P%h%#U2kcGNxj+T7PNA@P#B^vvaM)?*M?Jd;nnXs6toU>x8+v zqYBFw+y4B&;6{)6HyhdSmwX&y7%bx<$EI1KSFPx%>`6pHR9J=Wmt9B{Q5c4wkqT`UF-0u}h1d+qD2bAgwLi$4h(a)}y(o%)Xvv5) z=pq7ze!w;gi7>io(;M+3yU2cZ5!s?7k}&_XcBNL=)pRNpJKf~8>$o#x33cInGv|BH zJKy(m<~uWIB<2WdX=!3=+}_?U8NF|T*5sJ)lK3`MPVVLVyt=tAWYUt;#lr1&E3wIB z5-lw)hD>OR209bPqR4GTd)jC^)k=2bxJo}b=oSFI9bF`E+>N`rmacd002CZJtZO1n zYx4O1aH2hJ(DR*Zlgnn*#Kk2mMHbsF3U8!1=sW@dha&>tXc*1NAvN9I9tQm~Uh^UF z%X}CZHd5Od^0QM#es-$R(-q|J5rNlv7=>=5)IW6wE$Q|x7Q=ho2sE3}@Ar$ozCINf z6B8o=RNlC%m^*mngaqJhs1ZLV#sCOg7>Q+5o~B_<13sURl#~<|2k@-!j!0X%3V?=3 zbv&!PBR21_N^8@TdDD0ifYmuATIux-#Ky)d1p_$%CcY}g1LLUpEJnR9WxOvbK{!00 zL#~3Rf!5YmGBPq$963~oY;<#!XFIaa95 zU8ty%06Je>4APs|m&|F?&g1_;UZGXw6&Iqh~aoim(Z9{&oO&*;jnhr;)1j8C2+Dk~03f6L7pHTPTt zC!ges=9iwyK(2IGp^5{T&JB033DV63%^wp0*PCwo`#%l^a&7N>R9tUExtPvP^nX?9 wW^JH&MYW2{E4{AbUdt90*Yu@IFa13D2@k?kk3Ej8IRF3v07*qoM6N<$f-jVP-v9sr literal 0 HcmV?d00001 diff --git a/Resources/Textures/Structures/Storage/Shelfs/Departments/Service/kitchen.rsi/kitchen-2.png b/Resources/Textures/Structures/Storage/Shelfs/Departments/Service/kitchen.rsi/kitchen-2.png new file mode 100644 index 0000000000000000000000000000000000000000..03799bb6889c95e57db990a3ae4af1ba91c97d6a GIT binary patch literal 275 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz#^NA%Cx&(BWL^R}XFXjULn2y} z6C_v{Cy4Zv9Pscsc&@hnpYrFsbKh{hQe@rmU~e}DhC^UEi7aB^`O85tNDoSA7T z_-@CPo|;WEZQ+;aT9^Oh=H_19vA6d3G)Gt0*24eKj{d)DS|R}gd~fcZQP5m{;=v1P z?@h`d+8Q=&FgSdBd%ocjuykF0b9CRC<*S(W;`g0duzGd3;;{n<4s0ks@5lxMo}7gu zb}JhaCdgW~%;I?aMxb+pk~Wv#b;DfAP~qnq5LY(^8gRKCJi*A|&1wC0!uRtwK#wta My85}Sb4q9e0AJc`u>b%7 literal 0 HcmV?d00001 diff --git a/Resources/Textures/Structures/Storage/Shelfs/Departments/Service/kitchen.rsi/kitchen-3.png b/Resources/Textures/Structures/Storage/Shelfs/Departments/Service/kitchen.rsi/kitchen-3.png new file mode 100644 index 0000000000000000000000000000000000000000..5daaf7dda8978a6e6b8f0fce0a66da66843c5f3a GIT binary patch literal 342 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz#^NA%Cx&(BWL^T<0-i38ArY;~ z2@_nEs+2LzBl*IC}^%e@!*BD z_a@~JZ4DbX7#zO6J>T#MSh}vhIlAx6@>R@w@%zp!SiQPi@z{X_2R0O+cVq(rPtHOS zyOj+I6J)JgW^ufIBha})Nt;XWx?!$lsPJGJgnD_*-25xBmAd?!(>7-%C96 z@m}bedbq_uC~V66v*F#5Jf5EO{%0gwIvU%7cZ~!P aU|_IR3kqbKwOa`oPz;`~elF{r5}E*J&x+On literal 0 HcmV?d00001 diff --git a/Resources/Textures/Structures/Storage/Shelfs/Departments/Service/kitchen.rsi/kitchen-4.png b/Resources/Textures/Structures/Storage/Shelfs/Departments/Service/kitchen.rsi/kitchen-4.png new file mode 100644 index 0000000000000000000000000000000000000000..fc7be0c7da2abdb4ba0d8f50301695b36fb59dcb GIT binary patch literal 387 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz#^NA%Cx&(BWL^T_nEs+2LzBl*IC}^%e@!*BD z_a@~JZ4DbX7#zO6J>T#MSh}vhIlAx6@>R@w@%zp!SiQPi@z{X_2R0O+cVq(rPtHOS zyOj+I6J)JgW^ufIBha})Nt;XWx?!$lsPJ8(e z$2-0gTg{Vhe0*c%BsX8tcl$2BA@8qD**pTGO{|J!bT9{qXyl4ls} zwyHg4xEG_Ked_zO)kk&OmZ+Ss-?CxO0%njK{bF{V{_y7J<8tO_4Mtm^ZrM~V0t^EK b0|tgig)yZG^}o*mLzThP)z4*}Q$iB}EEJ=r literal 0 HcmV?d00001 diff --git a/Resources/Textures/Structures/Storage/Shelfs/Departments/Service/kitchen.rsi/kitchen-5.png b/Resources/Textures/Structures/Storage/Shelfs/Departments/Service/kitchen.rsi/kitchen-5.png new file mode 100644 index 0000000000000000000000000000000000000000..150e8f3ec78c5dc6bbe287407329006c4a33afbc GIT binary patch literal 465 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz#^NA%Cx&(BWL^T<-JULvArY;~ z2@_nEs+2LzBl*IC}^%e@!*BD z_a@~JZ4DbX7#zO6J>T#MSh}vhIlAx6@>R@w@%zp!SiQPi@z{X_2R0O+cVq(rPtHOS zyOj+I6J)JgW^ufIBha})Nt;XWx?!$lsPJ8&z zhkV5LYU{&aXN66XS^V#}^qq@}&(BSK*AP>!+$MY8PWWj<|5@ArvCI731$T!9e2C9J z#KNW+$H&GN8oEZY<2vIKhNtoIlJD;B>QYS0TheX*>Vs9n&t`rX>j%EYwu?)0AJ>-{ zvW5FEIxE4-%=AHR!oQun|Lw2+*!uA3<#L|lWlJwCkx4kDuBmPx$-AP12R9J=WmtQDDQ5?s=TM`dwZZf3E{7Lr00}pE=k_T@}`SV~&lEsr0lB6Vs zRwMD`-pdNmWC@5X=s690x*(j|Two zKJ&%Dj{g+EVzEH2R{MAWu(r7i07z0M3dVs-v}GofFoas|X9&AmYx%h$U51E!5llH3E#|AN$n*n3aW6m+`EcPWaC0sz3l(FN@G l>xZBLbY?9|RXZ#Izy}@eon9gux1#_6002ovPDHLkV1g^q^Pm6# literal 0 HcmV?d00001 diff --git a/Resources/Textures/Structures/Storage/Shelfs/Departments/Service/kitchen.rsi/kitchen-7.png b/Resources/Textures/Structures/Storage/Shelfs/Departments/Service/kitchen.rsi/kitchen-7.png new file mode 100644 index 0000000000000000000000000000000000000000..8fb7d79932d64e321e67d2b086b91c77069c3c0c GIT binary patch literal 564 zcmV-40?Yl0P)Px$?ny*JR9J=WmrE!_Q5?pvg=I0g@KCH>AQhx+l4}sGs^uLC=<9zt?1Y=_XAoo7l zg3~PqxD=#D(t^}T&t%|VpyCM@Rt=K&XJ_cSYm~qYp~K;z7K_EDrdF#}05Ck%Cz>m( zsQHmG<|4D%Oa(!Z)CeKaYPG7h*-;u7p9lb0Uz$Z|L=@8VN)(%5c0dpW5JFsP0DzZA z@$ir1Uo~JdnV{3@TxtNYu)F~P2-Sp0#!BI~%wUj)P_KUvVMAr1IM*>S@vGtV@_%3k zr>MPO4B2>NwOc~QyoLdvUP3IUm*#NT)GoO(aW9Xe>HM7?>I{y}ZfjA6H@DKy zHDu+=-ouMWUe(|rZ=#{>Yj z_fBB5UEJ_=XY1Wmj!vPx%14%?dR9J;$U>MBc%iFI1uWw8IH%>eAe?T1Y`nJUXkI!TNGn_I0f5e`RCXQgj zCz+GT!NC9YIs?PK9}JWKO3}i81{OjJmMr09c>9@&;TXeLnmB+U2)9xAA8w;CFlk^! z07gOzcJ4cb68!E?b_Dg10`Mln_wV2TfB5hrhM1tBAR_|<1H+sd6XA|a$;cn8B|nM824{p{9j!|hk=2Cf#JaJ%?y&ViVTjvu_QYJZwLqr3p2cZ z`xZltfq{X6;rBPV<;Z-hI^go<%M7}@x)@>%3=9lA_Z(zkU|?X7ln_VZlL`n1*`Y(I ziO|jtkq9fYqTq5J)0R;+agKtK1MnuC=+?>bM7Fd#mnMk}Z#LvaD}?ZYb-TAST(44PV%YKQGf@us*xd8qW%_g!v1*H#TtSH z8zjU6;e?bZz5*bTI~3Pom8j1p@-`CXoKQ zyZ*m@@rB{V({~JWrll~FB1RRkX48q+g?l~zA3O8(FS1xmU=)TJ0|NsCvKX-dZ^wjz zfq~(~rMnEzo;`ktEO!0DJq)q?2m1b_i&4b^WopYY#6nu8V2EA#YDcQwqkw^dfq?-4 XqfONM&j)!600000NkvXXu0mjfV|5M) literal 0 HcmV?d00001 diff --git a/Resources/Textures/Structures/Storage/Shelfs/Departments/Service/kitchen.rsi/kitchen-9.png b/Resources/Textures/Structures/Storage/Shelfs/Departments/Service/kitchen.rsi/kitchen-9.png new file mode 100644 index 0000000000000000000000000000000000000000..9f61aeeb480158a0f8cfd103194e23f0f605a558 GIT binary patch literal 650 zcmV;50(Jd~P)Px%L`g(JR9J=Wmr+PlQ5?p9cT^}Ou?D&_m=Md57N}4@$gC);hlpSxm^}m%6-oAz zK}CcL8BvCzJ=l{gU!;fjP-dl$kP$<|QG-V2h?%*j$yB0Yr>Aba-n#cL9E;lbbk6Ub zd;TAPzQes2{$|a^u8L^LD$0-fMMexnLsl{Sp;q887tgC!rNx9vYw^_49M(jFF!qJ^ z#r5f^&kDT_Zg(!RxQSur(_%nZ)s;n}y0R!U8Tc22tH=2f(R?=GkAGpR^3gflZU zA{-8@nAvQW0J?79l+D#0KP>@x2Ybc0#2f&om8)^?aA_LWG!To$u-R-X1~B017R8&l z05I6^VZhTZb{;q)m6mK^bf^`8tyPU$$LkxgSS)hEWClQDK`x#=&&#hMKIN0gwS@)3 z9r^g%E@&DE1Ohl54iy9Fdol#TI%|Pq9-s1&mtP@|Pm~_iDxn`juU8pDr}JkB&z-E1 z*RFKjlK?_5S{3{4+ZvZOv|0Uo(hSJqmUcN%chA?SB}|&vF!#ruH=z6d4+&mqQQUyy z#DZ+vH8PUAf%>X49!#DZ8~D_8Nh-W}SuADj*>CuatTH0afZVwASi~mhn2b!*)lnyJ>e{xsa_QoRHLJR|ZAqQjzv|TSxqJ6)*|O!v_3M$5k^ley|06s98c+j& zNswPK!`72P5jeOwztIjTUs-Lb@{pyRfpfy1FvYhK+_sMvG4v z8yOlJDXnB+_-;!N6PNr6|FxA;rv4=gPFZ_2cV$pn(jYu6{1- HoD!MXo%+Z=#i}Vm>cDf3`30}DPfVNim}Ai;2E&Vv>y$at zoTIFp5|mVq2^w&pEMy7noG`6VL4x&%%)*uHzcoj=_cR3>aJez+F)&okPTdx?G;ANx OLkym-elF{r5}E+_Ygr+ArY-_ z&lxf@FmNy{B(JG=WzOK>m-lcGEx2&9#OOXh14F}P)<w1lw}$KTFM5ezk1=AE4ZUOAL1I78TNam(66JpsOk(WKzsvE8}P& zcgyhpMb!FsY_Neb67e#xO~{SKtca#>qQNat5cX6F8&C9wPEE|TcC#+JYD@< J);T3K0RU(OUmpMf literal 0 HcmV?d00001 diff --git a/Resources/Textures/Structures/Storage/Shelfs/glass.rsi/rbase.png b/Resources/Textures/Structures/Storage/Shelfs/glass.rsi/rbase.png new file mode 100644 index 0000000000000000000000000000000000000000..584a185caabdcd79c22e51feea45a1cb9f52088a GIT binary patch literal 549 zcmV+=0^0qFP)Px$-$_J4R9J=Wl(BBwP!xtg(^6@09&P~OP7e9mx-bZ zsY{n`JV2KWU9vQ&3W9csP-KVHG&l&_NHlc82*a(x0?|m}lPvk%dvyNa$M+ss^4O7v zgKRe2TZCw_SRClCjBXYR1!P$s#Gz0~SftbGxZ-K@TCEnjT+X#WW&ogCtqP0HimIwe zlB?-%1H+r|K7Bt0h}?YHfBWV&reXLKOC)&z;UhPZ=cfRNuTuM>yntxYX`6L>_sf^6 z0H?<2FZ-u~dc8h3@lg|vMq{#pMf2Yc2yekK*Kv*Ga>ajTyMi6p;D>jbX9wh1H?zLI zh6MEP?|nTIu)e*99P4JhG{!m*jYerUo9ynP?n;PfZ4chn@QV|GXMf82EQ9FVlk`b{Ngve! z!5I+U)p@a;15+6goz!{Z>lQd%#Wjw;p8Hq(*_?e4ZK+*diEa27@1w*v*iyT?SB|g) zhGEQS5CQScO=_#QZWsp1WOA|r(=-8isRW_@8`_ruXaMc2L7sT5h|!dwtG1^BfK)2w nqx@`)8OZ1J3lm?mi0jO8VkuLc9xTmmm7EjISihzelF{r5}E** CYagWm literal 0 HcmV?d00001 diff --git a/Resources/Textures/Structures/Storage/Shelfs/metal.rsi/base.png b/Resources/Textures/Structures/Storage/Shelfs/metal.rsi/base.png new file mode 100644 index 0000000000000000000000000000000000000000..430b603aa3af9356e29b3ea3dce738733060e9ed GIT binary patch literal 352 zcmV-m0iXVfP)Px$8c9S!R9J=Wlrf5hFc^eqm&GEL2x8*_EbPU`*48U}1J7Wg7qC!k8xcfPq}?r+ z1bt@3?0XU6`BnK%oEanzaP#hbEQcgXzRxhtvP}4XJ#I!(1kdxtY+066WE{uUeB@kR z*U0mHwZ91f0BM>^#hxVyg3U8&001bpC%qVJJQKsidlbO#sH2 zHZz&_^}fK_{CNpEgb*;sU>JsyFk?)-`|kjbT0040u!}tBC z%sEw6fl?~8cLQ)Jr6`KxB?0zW1(@eqtaTO9(gV1A;EDlcH}zF0{RPXH-m8c>I*RB} yfTn2x=qVzuy&C}dEs?X>1Zdm#H1nIAOYj3E`*YfR{bVBm0000Xo%+Z=#i}Vm>cDf3`30}DPfVNim}Ai;2E&Vv>y$at zoTIFp5|mVq2^w&pEMy7noG`6VL4x&%%)*uHzcoj=_cR3>aJez+F)&okPTdx?G;ANx OLkym-elF{r5}E+_Ygr+ArY-_ z&lxf@FmNy{B(JG=WzOK>m-lcGEx2&9#OOXh14F}P)<w1lw}$KTFM5ezk1=AE4ZUOAL1I78TNam(66JpsOk(WKzsvE8}P& zcgyhpMb!FsY_Neb67e#xO~{SKtca#>qQNat5cX6F8&C9wPEE|TcC#+JYD@< J);T3K0RU(OUmpMf literal 0 HcmV?d00001 diff --git a/Resources/Textures/Structures/Storage/Shelfs/metal.rsi/rbase.png b/Resources/Textures/Structures/Storage/Shelfs/metal.rsi/rbase.png new file mode 100644 index 0000000000000000000000000000000000000000..430b603aa3af9356e29b3ea3dce738733060e9ed GIT binary patch literal 352 zcmV-m0iXVfP)Px$8c9S!R9J=Wlrf5hFc^eqm&GEL2x8*_EbPU`*48U}1J7Wg7qC!k8xcfPq}?r+ z1bt@3?0XU6`BnK%oEanzaP#hbEQcgXzRxhtvP}4XJ#I!(1kdxtY+066WE{uUeB@kR z*U0mHwZ91f0BM>^#hxVyg3U8&001bpC%qVJJQKsidlbO#sH2 zHZz&_^}fK_{CNpEgb*;sU>JsyFk?)-`|kjbT0040u!}tBC z%sEw6fl?~8cLQ)Jr6`KxB?0zW1(@eqtaTO9(gV1A;EDlcH}zF0{RPXH-m8c>I*RB} yfTn2x=qVzuy&C}dEs?X>1Zdm#H1nIAOYj3E`*YfR{bVBm0000i0jO8VkuLc9xTmmm7EjISihzelF{r5}E** CYagWm literal 0 HcmV?d00001 diff --git a/Resources/Textures/Structures/Storage/Shelfs/wood.rsi/base.png b/Resources/Textures/Structures/Storage/Shelfs/wood.rsi/base.png new file mode 100644 index 0000000000000000000000000000000000000000..a1054e575dd9260e6df82eacddc12818bc603784 GIT binary patch literal 525 zcmV+o0`mQdP)Px$$4Nv%R9J=WR!d6)Q562>;pD_vN@5~Kwuuq~p@LdT1g-n0wT>WMNI?(8K*Nw+ zg-D?`laFB>TMTni=lH_uLHVubo_pqe-<>(<;{r4McW~W{L|Ey32WhgTF@aU=|?hpVtKcgEMRMUN?3Gw3s$R_MYEG(niY-3KCOsn3u-p!WiksT>vmY zsmvqvb_bHcu`V9hh-?Fr1P%)#k5`j+`5pnK4}%pveWPx$F-b&0R9J=Wl{rp>F%X5H7c5~ANI-!ET@FIU4RVPThyze_07Sthasw(3LI)BB zi4>MZ*qN9D0RcQ-5(y~$RhHiK%=>?DK%>$4V+1E0?rjDLR{kV}qDGguqi8YBO^{Mx zXG6j$0juQ~Z9JX9QNZ9aAOvK6_YX5R7#qN74Wk0=$@%ej%>uyb(b2x6zXOb?{N^boS0fp~5r4#n&lDZk)JO*KL@iF;x7h4;X9{~|iBsgVtkTEDF|6&=^q$OcI5fl_ic z7QP8fS?VTCt>3&>>WjhtpM%}?u)l4RuiVYR0RT#TS9ec!&oO|H202Q7jYgvp;}s)= Vg1{w;ek%X~002ovPDHLkV1g*Km?;1N literal 0 HcmV?d00001 diff --git a/Resources/Textures/Structures/Storage/Shelfs/wood.rsi/locked.png b/Resources/Textures/Structures/Storage/Shelfs/wood.rsi/locked.png new file mode 100644 index 0000000000000000000000000000000000000000..421688fcda8a1eb453d5a02967f22689105b4a0c GIT binary patch literal 108 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz#^NA%Cx&(BWL^R}YMw5RArY-_ z&p8S*Ft9Kf7=Br=!5}-wdcN*KB?bnIfSG@585*`Sw#73kb8gP^1?ph%boFyt=akR{ E030V9oB#j- literal 0 HcmV?d00001 diff --git a/Resources/Textures/Structures/Storage/Shelfs/wood.rsi/meta.json b/Resources/Textures/Structures/Storage/Shelfs/wood.rsi/meta.json new file mode 100644 index 00000000000..544b43a1e80 --- /dev/null +++ b/Resources/Textures/Structures/Storage/Shelfs/wood.rsi/meta.json @@ -0,0 +1,29 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Made by Kezu", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "base" + }, + { + "name": "rbase" + }, + { + "name": "locked" + }, + { + "name": "unlocked" + }, + { + "name": "closed" + }, + { + "name": "open" + } + ] +} \ No newline at end of file diff --git a/Resources/Textures/Structures/Storage/Shelfs/wood.rsi/open.png b/Resources/Textures/Structures/Storage/Shelfs/wood.rsi/open.png new file mode 100644 index 0000000000000000000000000000000000000000..c0e25c446bdc9bd77db14ca156f03395faa3d608 GIT binary patch literal 483 zcmV<90UZ8`P)Px$ok>JNR9J=Wl}}2;KorKm%uFYtmLyuNg;qC}UZbnx1$v2sn5Bz?3&8`l2wuV) zxN_?mbf+K@q{ct3Go8joO)+I6VuzxT-!8nD@B8xJFadIMa{elN+v``RwAwW<&Z@Dj zX3nT7e>l7_*S)xVva|t`hMjT&!*>-40oPap0B(ug`Zle%kq$!IH7{=0ytwRAG`BdM z-XQR8YSbJ6e4Eyt-XLghag<$(#Fr6bVbdk>j!uK5*-UGZ%)HEx)tsSO~M+3|m;sSUuX1*w!VbEy$ z31qdZrMTi3;Bt!Va6EtE^8Ur>No-Y1^AYS;97IAP9Lm`Q!l6V6Y25TH3)<#)oRjl! Z`2ZmpllAvCI~4!`002ovPDHLkV1gx{+;ji{ literal 0 HcmV?d00001 diff --git a/Resources/Textures/Structures/Storage/Shelfs/wood.rsi/rbase.png b/Resources/Textures/Structures/Storage/Shelfs/wood.rsi/rbase.png new file mode 100644 index 0000000000000000000000000000000000000000..a1054e575dd9260e6df82eacddc12818bc603784 GIT binary patch literal 525 zcmV+o0`mQdP)Px$$4Nv%R9J=WR!d6)Q562>;pD_vN@5~Kwuuq~p@LdT1g-n0wT>WMNI?(8K*Nw+ zg-D?`laFB>TMTni=lH_uLHVubo_pqe-<>(<;{r4McW~W{L|Ey32WhgTF@aU=|?hpVtKcgEMRMUN?3Gw3s$R_MYEG(niY-3KCOsn3u-p!WiksT>vmY zsmvqvb_bHcu`V9hh-?Fr1P%)#k5`j+`5pnK4}%pveWo&qkIIMuq}~x&Q1K4%}jJHDXHr^zz&@paup{S3j3^P6 Date: Sun, 21 Jul 2024 17:18:04 +0000 Subject: [PATCH 337/765] Automatic changelog update --- Resources/Changelog/Changelog.yml | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index f625cdfdbc1..3066419802b 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,13 +1,4 @@ Entries: -- author: TheShuEd - changes: - - message: Added tomato killers in floral anomaly berries - type: Add - - message: tweak size and damage of killer tomatoes - type: Tweak - id: 6459 - time: '2024-04-27T10:35:13.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/27265 - author: Plykiya changes: - message: You can no longer print singular bullets at the security techfab. @@ -3800,3 +3791,10 @@ id: 6958 time: '2024-07-21T16:20:09.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/30232 +- author: Sphiral&Kezu + changes: + - message: 'Added a variety of new wall based storages: Shelfs! Build some today!' + type: Add + id: 6959 + time: '2024-07-21T17:16:58.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/27858 From 271c0384d84d561b99fcda19ece0b2db54e6e93e Mon Sep 17 00:00:00 2001 From: slarticodefast <161409025+slarticodefast@users.noreply.github.com> Date: Mon, 22 Jul 2024 04:50:21 +0200 Subject: [PATCH 338/765] vital clown bugfix PR (#30243) vital bugfix --- .../Prototypes/Entities/Objects/Consumable/Food/Baked/pie.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Resources/Prototypes/Entities/Objects/Consumable/Food/Baked/pie.yml b/Resources/Prototypes/Entities/Objects/Consumable/Food/Baked/pie.yml index cb04869c2c7..09ec706e1fe 100644 --- a/Resources/Prototypes/Entities/Objects/Consumable/Food/Baked/pie.yml +++ b/Resources/Prototypes/Entities/Objects/Consumable/Food/Baked/pie.yml @@ -148,6 +148,8 @@ - state: tin - state: plain - type: CreamPie + - type: ThrowingAngle + angle: 180 - type: LandAtCursor - type: ContainerContainer containers: From 5deefe3989a730e82282becf2f596c8a548153af Mon Sep 17 00:00:00 2001 From: justdie12 <125140938+justdie12@users.noreply.github.com> Date: Mon, 22 Jul 2024 05:53:10 +0300 Subject: [PATCH 339/765] Update water.yml (#29596) * Update water.yml Water should put out the fire. That's why now the water tiles are extinguishing you. * Update water.yml --- Resources/Prototypes/Entities/Tiles/water.yml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Resources/Prototypes/Entities/Tiles/water.yml b/Resources/Prototypes/Entities/Tiles/water.yml index 2fd1c8547de..c488df231b2 100644 --- a/Resources/Prototypes/Entities/Tiles/water.yml +++ b/Resources/Prototypes/Entities/Tiles/water.yml @@ -54,3 +54,12 @@ collection: FootstepWater params: volume: 8 + - type: StepTrigger + requiredTriggeredSpeed: 0 + intersectRatio: 0.1 + blacklist: + tags: + - Catwalk + - type: TileEntityEffect + effects: + - !type:ExtinguishReaction From 1560c55190f8d3e1a125c981d9da95562fd95b4f Mon Sep 17 00:00:00 2001 From: slarticodefast <161409025+slarticodefast@users.noreply.github.com> Date: Mon, 22 Jul 2024 05:55:34 +0200 Subject: [PATCH 340/765] fix borgs being unable to state laws with an active flashlight (#30183) fix borg laws --- .../Silicons/Laws/SiliconLawPrototype.cs | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/Content.Shared/Silicons/Laws/SiliconLawPrototype.cs b/Content.Shared/Silicons/Laws/SiliconLawPrototype.cs index d10b86c2417..5924c95cdc1 100644 --- a/Content.Shared/Silicons/Laws/SiliconLawPrototype.cs +++ b/Content.Shared/Silicons/Laws/SiliconLawPrototype.cs @@ -6,7 +6,7 @@ namespace Content.Shared.Silicons.Laws; [Virtual, DataDefinition] [Serializable, NetSerializable] -public partial class SiliconLaw : IComparable +public partial class SiliconLaw : IComparable, IEquatable { /// /// A locale string which is the actual text of the law. @@ -39,13 +39,27 @@ public int CompareTo(SiliconLaw? other) return Order.CompareTo(other.Order); } - public bool Equals(SiliconLaw other) + public bool Equals(SiliconLaw? other) { + if (other == null) + return false; return LawString == other.LawString && Order == other.Order && LawIdentifierOverride == other.LawIdentifierOverride; } + public override bool Equals(object? obj) + { + if (obj == null) + return false; + return Equals(obj as SiliconLaw); + } + + public override int GetHashCode() + { + return HashCode.Combine(LawString, Order, LawIdentifierOverride); + } + /// /// Return a shallow clone of this law. /// From 432a103ead1c021f12abdd1a9620be2f1016077e Mon Sep 17 00:00:00 2001 From: PJBot Date: Mon, 22 Jul 2024 03:56:42 +0000 Subject: [PATCH 341/765] Automatic changelog update --- Resources/Changelog/Changelog.yml | 21 +++++++-------------- 1 file changed, 7 insertions(+), 14 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 3066419802b..5026331c1e1 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,18 +1,4 @@ Entries: -- author: Plykiya - changes: - - message: You can no longer print singular bullets at the security techfab. - type: Remove - - message: The security techfab now has recipes for ammunition boxes and pre-filled - magazines of every type of ammo. - type: Add - - message: You can now print empty magazines at the security techfab. - type: Add - - message: Material costs for printing all ammo and mags were rebalanced. - type: Tweak - id: 6460 - time: '2024-04-27T10:38:59.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/26178 - author: Ramlik changes: - message: Added security walkie talkies to the vendor. @@ -3798,3 +3784,10 @@ id: 6959 time: '2024-07-21T17:16:58.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/27858 +- author: valquaint, slarticodefast + changes: + - message: Fixed borgs being unable to state laws with an activated flashlight. + type: Fix + id: 6960 + time: '2024-07-22T03:55:35.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/30183 From 2a643d26066a75db85f09dd802632c245b151cc8 Mon Sep 17 00:00:00 2001 From: LankLTE <135308300+LankLTE@users.noreply.github.com> Date: Sun, 21 Jul 2024 22:38:56 -0700 Subject: [PATCH 342/765] Darts can now pop balloons. (#30088) Basic implementation. --- .../Weapons/Melee/Balloon/BalloonPopperSystem.cs | 12 +++++++++++- Resources/Prototypes/Entities/Objects/Fun/darts.yml | 1 + .../Entities/Objects/Weapons/Melee/needle.yml | 7 +++++++ 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/Content.Server/Weapons/Melee/Balloon/BalloonPopperSystem.cs b/Content.Server/Weapons/Melee/Balloon/BalloonPopperSystem.cs index 45c6a3d9d55..a8460a8c660 100644 --- a/Content.Server/Weapons/Melee/Balloon/BalloonPopperSystem.cs +++ b/Content.Server/Weapons/Melee/Balloon/BalloonPopperSystem.cs @@ -4,7 +4,7 @@ using Content.Shared.Popups; using Content.Shared.Tag; using Content.Shared.Weapons.Melee.Events; -using Robust.Shared.Audio; +using Content.Shared.Throwing; using Robust.Shared.Audio.Systems; namespace Content.Server.Weapons.Melee.Balloon; @@ -23,6 +23,7 @@ public sealed class BalloonPopperSystem : EntitySystem public override void Initialize() { SubscribeLocalEvent(OnMeleeHit); + SubscribeLocalEvent(OnThrowHit); } private void OnMeleeHit(EntityUid uid, BalloonPopperComponent component, MeleeHitEvent args) @@ -40,6 +41,15 @@ private void OnMeleeHit(EntityUid uid, BalloonPopperComponent component, MeleeHi } } + private void OnThrowHit(EntityUid uid, BalloonPopperComponent component, ThrowDoHitEvent args) + { + foreach (var held in _hands.EnumerateHeld(args.Target)) + { + if (_tag.HasTag(held, component.BalloonTag)) + PopBallooon(uid, held, component); + } + } + /// /// Pops a target balloon, making a popup and playing a sound. /// diff --git a/Resources/Prototypes/Entities/Objects/Fun/darts.yml b/Resources/Prototypes/Entities/Objects/Fun/darts.yml index dd25d503ce2..31fd4fd8e27 100644 --- a/Resources/Prototypes/Entities/Objects/Fun/darts.yml +++ b/Resources/Prototypes/Entities/Objects/Fun/darts.yml @@ -84,6 +84,7 @@ max: 1 - !type:DoActsBehavior acts: [ "Destruction" ] + - type: BalloonPopper - type: entity parent: Dart diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Melee/needle.yml b/Resources/Prototypes/Entities/Objects/Weapons/Melee/needle.yml index 11efeba5f8c..e472157081a 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Melee/needle.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Melee/needle.yml @@ -12,6 +12,13 @@ damage: types: Piercing: 1 + - type: DamageOtherOnHit + damage: + types: + Piercing: 1 - type: Item size: Tiny - type: BalloonPopper + - type: ThrowingAngle + angle: -135 + - type: LandAtCursor From b801dee0f85bcad713c02c39d56e7bf20518554a Mon Sep 17 00:00:00 2001 From: PJBot Date: Mon, 22 Jul 2024 05:40:03 +0000 Subject: [PATCH 343/765] Automatic changelog update --- Resources/Changelog/Changelog.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 5026331c1e1..1639a1bd617 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,11 +1,4 @@ Entries: -- author: Ramlik - changes: - - message: Added security walkie talkies to the vendor. - type: Add - id: 6461 - time: '2024-04-27T13:27:18.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/25913 - author: brainfood1183 changes: - message: Centcom advises all crewmembers to please stop putting rodents in the @@ -3791,3 +3784,10 @@ id: 6960 time: '2024-07-22T03:55:35.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/30183 +- author: Lank + changes: + - message: Darts can now pop balloons. Keep them away from any monkeys. + type: Add + id: 6961 + time: '2024-07-22T05:38:56.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/30088 From 7a709ba4c461fd727e959435fea615f242c21720 Mon Sep 17 00:00:00 2001 From: Plykiya <58439124+Plykiya@users.noreply.github.com> Date: Mon, 22 Jul 2024 02:17:57 -0700 Subject: [PATCH 344/765] Eating and Drinking Doafter Change (#30060) My lawyer told me to do this Co-authored-by: plykiya --- Content.Server/Nutrition/EntitySystems/DrinkSystem.cs | 1 + Content.Server/Nutrition/EntitySystems/FoodSystem.cs | 1 + 2 files changed, 2 insertions(+) diff --git a/Content.Server/Nutrition/EntitySystems/DrinkSystem.cs b/Content.Server/Nutrition/EntitySystems/DrinkSystem.cs index d9122ff278c..36c4ef4b551 100644 --- a/Content.Server/Nutrition/EntitySystems/DrinkSystem.cs +++ b/Content.Server/Nutrition/EntitySystems/DrinkSystem.cs @@ -211,6 +211,7 @@ private bool TryDrink(EntityUid user, EntityUid target, DrinkComponent drink, En target: target, used: item) { + BreakOnHandChange = false, BreakOnMove = forceDrink, BreakOnDamage = true, MovementThreshold = 0.01f, diff --git a/Content.Server/Nutrition/EntitySystems/FoodSystem.cs b/Content.Server/Nutrition/EntitySystems/FoodSystem.cs index d609f737e72..4d670a3eb77 100644 --- a/Content.Server/Nutrition/EntitySystems/FoodSystem.cs +++ b/Content.Server/Nutrition/EntitySystems/FoodSystem.cs @@ -198,6 +198,7 @@ private void OnFeedFood(Entity entity, ref AfterInteractEvent arg target: target, used: food) { + BreakOnHandChange = false, BreakOnMove = forceFeed, BreakOnDamage = true, MovementThreshold = 0.01f, From 5b919c8b0b7e5cd9176c1017e5d395d2163b3324 Mon Sep 17 00:00:00 2001 From: PJBot Date: Mon, 22 Jul 2024 09:19:03 +0000 Subject: [PATCH 345/765] Automatic changelog update --- Resources/Changelog/Changelog.yml | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 1639a1bd617..92e056bc76f 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,12 +1,4 @@ Entries: -- author: brainfood1183 - changes: - - message: Centcom advises all crewmembers to please stop putting rodents in the - fax machines (rodents can now be inserted into fax machine). - type: Add - id: 6462 - time: '2024-04-27T13:50:57.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/21461 - author: MilenVolf changes: - message: Glass Box now can be constructed and deconstructed! @@ -3791,3 +3783,10 @@ id: 6961 time: '2024-07-22T05:38:56.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/30088 +- author: Plykiya + changes: + - message: You can now eat or drink and swap hands without it being interrupted. + type: Tweak + id: 6962 + time: '2024-07-22T09:17:57.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/30060 From c08fb32d5383e78e4997f8df9e305d79fcae1d83 Mon Sep 17 00:00:00 2001 From: PJBot Date: Mon, 22 Jul 2024 09:34:08 +0000 Subject: [PATCH 346/765] Automatic changelog update --- Resources/Changelog/Changelog.yml | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 92e056bc76f..8cc9f88966f 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,15 +1,4 @@ Entries: -- author: MilenVolf - changes: - - message: Glass Box now can be constructed and deconstructed! - type: Add - - message: Glass Box now makes an alarm sound on destruction. - type: Tweak - - message: Now Antique Laser can be put back in the Glass Box. - type: Fix - id: 6463 - time: '2024-04-27T13:53:16.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/25365 - author: metalgearsloth changes: - message: Fix a lot of UI bugs. @@ -3790,3 +3779,10 @@ id: 6962 time: '2024-07-22T09:17:57.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/30060 +- author: IProduceWidgets + changes: + - message: Zookeepers can now possess Nonlethal shotguns according to spacelaw. + type: Tweak + id: 6963 + time: '2024-07-22T09:33:03.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/30237 From cd2fd77dbdd4f4189a8323f0b5a878dc1126792e Mon Sep 17 00:00:00 2001 From: Plykiya <58439124+Plykiya@users.noreply.github.com> Date: Mon, 22 Jul 2024 02:54:15 -0700 Subject: [PATCH 347/765] Quieter bag sounds (#30225) Co-authored-by: plykiya --- .../Storage/EntitySystems/SharedStorageSystem.cs | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/Content.Shared/Storage/EntitySystems/SharedStorageSystem.cs b/Content.Shared/Storage/EntitySystems/SharedStorageSystem.cs index 1343305a4bf..0af33cfcc8b 100644 --- a/Content.Shared/Storage/EntitySystems/SharedStorageSystem.cs +++ b/Content.Shared/Storage/EntitySystems/SharedStorageSystem.cs @@ -23,6 +23,7 @@ using Content.Shared.Timing; using Content.Shared.Verbs; using Content.Shared.Whitelist; +using Robust.Shared.Audio; using Robust.Shared.Audio.Systems; using Robust.Shared.Containers; using Robust.Shared.GameStates; @@ -66,6 +67,9 @@ public abstract class SharedStorageSystem : EntitySystem public const string DefaultStorageMaxItemSize = "Normal"; public const float AreaInsertDelayPerItem = 0.075f; + private static AudioParams _audioParams = AudioParams.Default + .WithMaxDistance(7f) + .WithVolume(-2f); private ItemSizePrototype _defaultStorageMaxItemSize = default!; @@ -543,7 +547,7 @@ private void OnDoAfter(EntityUid uid, StorageComponent component, AreaPickupDoAf // If we picked up at least one thing, play a sound and do a cool animation! if (successfullyInserted.Count > 0) { - Audio.PlayPredicted(component.StorageInsertSound, uid, args.User); + Audio.PlayPredicted(component.StorageInsertSound, uid, args.User, _audioParams); EntityManager.RaiseSharedEvent(new AnimateInsertingEntitiesEvent( GetNetEntity(uid), GetNetEntityList(successfullyInserted), @@ -604,7 +608,7 @@ private void OnInteractWithItem(StorageInteractWithItemEvent msg, EntitySessionE { if (_sharedHandsSystem.TryPickupAnyHand(player, entity, handsComp: hands) && storageComp.StorageRemoveSound != null) - Audio.PlayPredicted(storageComp.StorageRemoveSound, uid, player); + Audio.PlayPredicted(storageComp.StorageRemoveSound, uid, player, _audioParams); { return; } @@ -664,7 +668,7 @@ private void OnRemoveItem(StorageRemoveItemEvent msg, EntitySessionEventArgs arg return; TransformSystem.DropNextTo(itemEnt, player); - Audio.PlayPredicted(storageComp.StorageRemoveSound, storageEnt, player); + Audio.PlayPredicted(storageComp.StorageRemoveSound, storageEnt, player, _audioParams); } private void OnInsertItemIntoLocation(StorageInsertItemIntoLocationEvent msg, EntitySessionEventArgs args) @@ -840,7 +844,7 @@ public void TransferEntities(EntityUid source, EntityUid target, EntityUid? user Insert(target, entity, out _, user: user, targetComp, playSound: false); } - Audio.PlayPredicted(sourceComp.StorageInsertSound, target, user); + Audio.PlayPredicted(sourceComp.StorageInsertSound, target, user, _audioParams); } /// @@ -1019,7 +1023,7 @@ public bool Insert( return false; if (playSound) - Audio.PlayPredicted(storageComp.StorageInsertSound, uid, user); + Audio.PlayPredicted(storageComp.StorageInsertSound, uid, user, _audioParams); return true; } @@ -1049,7 +1053,7 @@ public bool Insert( } if (playSound) - Audio.PlayPredicted(storageComp.StorageInsertSound, uid, user); + Audio.PlayPredicted(storageComp.StorageInsertSound, uid, user, _audioParams); return true; } From 23bc66a34055e7623b6a007a921eae72226aa0d9 Mon Sep 17 00:00:00 2001 From: PJBot Date: Mon, 22 Jul 2024 09:55:21 +0000 Subject: [PATCH 348/765] Automatic changelog update --- Resources/Changelog/Changelog.yml | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 8cc9f88966f..a35b9c25dea 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,11 +1,4 @@ Entries: -- author: metalgearsloth - changes: - - message: Fix a lot of UI bugs. - type: Fix - id: 6464 - time: '2024-04-27T16:32:57.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/27401 - author: RiceMar1244 changes: - message: Resprited the captain's antique laser pistol. @@ -3786,3 +3779,11 @@ id: 6963 time: '2024-07-22T09:33:03.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/30237 +- author: Plykiya + changes: + - message: Bag sounds can now only be heard from half the distance and is quieter + in general. + type: Tweak + id: 6964 + time: '2024-07-22T09:54:15.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/30225 From 651c940ee1fa8fc3ca698b1d02c085b545d9c98e Mon Sep 17 00:00:00 2001 From: 3nderall <101940324+3nderall@users.noreply.github.com> Date: Mon, 22 Jul 2024 10:55:44 +0100 Subject: [PATCH 349/765] Stops foam counting as a connection for walls (#30236) Stops walls from connecting to foam Co-authored-by: 3nderall <3nderall@gmail.com> --- Resources/Prototypes/Entities/Effects/chemistry_effects.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/Resources/Prototypes/Entities/Effects/chemistry_effects.yml b/Resources/Prototypes/Entities/Effects/chemistry_effects.yml index ee300e9aeaf..4f925ed311a 100644 --- a/Resources/Prototypes/Entities/Effects/chemistry_effects.yml +++ b/Resources/Prototypes/Entities/Effects/chemistry_effects.yml @@ -70,7 +70,6 @@ state: foam-west - type: SmoothEdge - type: IconSmooth - key: walls mode: NoSprite - type: FoamVisuals animationTime: 0.6 From e00711315e7d40f0d021f9865d8d3d3d4b59ba2f Mon Sep 17 00:00:00 2001 From: lzk <124214523+lzk228@users.noreply.github.com> Date: Mon, 22 Jul 2024 11:56:48 +0200 Subject: [PATCH 350/765] improve info about :cl: symbol in pr template (#30204) * Improve PR template * fix typo --- .github/PULL_REQUEST_TEMPLATE.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index a397604185a..88ad911c075 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -34,7 +34,7 @@ Make players aware of new features and changes that could affect how they play t --> Stutter (#29898) * Change Social Anxiety ----> Stutter * Update traits.ftl --------- Co-authored-by: Plykiya <58439124+Plykiya@users.noreply.github.com> --- Resources/Locale/en-US/traits/traits.ftl | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Resources/Locale/en-US/traits/traits.ftl b/Resources/Locale/en-US/traits/traits.ftl index 6dd834e8a1b..d9f09cc68aa 100644 --- a/Resources/Locale/en-US/traits/traits.ftl +++ b/Resources/Locale/en-US/traits/traits.ftl @@ -5,7 +5,7 @@ trait-poor-vision-name = Short-sighted trait-poor-vision-desc = Your eyes are not what they once were, you have difficulty seeing things far away without corrective glasses. trait-narcolepsy-name = Narcolepsy -trait-narcolepsy-desc = You fall asleep randomly +trait-narcolepsy-desc = You fall asleep randomly. trait-pacifist-name = Pacifist trait-pacifist-desc = You cannot attack or hurt any living beings. @@ -13,13 +13,13 @@ trait-pacifist-desc = You cannot attack or hurt any living beings. permanent-blindness-trait-examined = [color=lightblue]{CAPITALIZE(POSS-ADJ($target))} eyes are glassy and unfocused. It doesn't seem like {SUBJECT($target)} can see you well, if at all.[/color] trait-lightweight-name = Lightweight drunk -trait-lightweight-desc = Alcohol has a stronger effect on you +trait-lightweight-desc = Alcohol has a stronger effect on you. trait-muted-name = Muted -trait-muted-desc = You can't speak +trait-muted-desc = You can't speak. trait-paracusia-name = Paracusia -trait-paracusia-desc = You hear sounds that aren't really there +trait-paracusia-desc = You hear sounds that aren't really there. trait-unrevivable-name = Unrevivable trait-unrevivable-desc = You are unable to be revived by defibrillators. @@ -31,10 +31,10 @@ trait-accentless-name = Accentless trait-accentless-desc = You don't have the accent that your species would usually have trait-frontal-lisp-name = Frontal lisp -trait-frontal-lisp-desc = You thpeak with a lithp +trait-frontal-lisp-desc = You thpeak with a lithp. -trait-socialanxiety-name = Social anxiety -trait-socialanxiety-desc = You are anxious when you speak and stutter. +trait-socialanxiety-name = Stutter +trait-socialanxiety-desc = You speak with a stutter. trait-southern-name = Southern drawl trait-southern-desc = You have a different way of speakin'. From e620ae9017975dd9c81f37b5f9bcc8cd11563bf3 Mon Sep 17 00:00:00 2001 From: PJBot Date: Thu, 1 Aug 2024 02:59:22 +0000 Subject: [PATCH 524/765] Automatic changelog update --- Resources/Changelog/Changelog.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index ad4389560da..599ee14fcb6 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,11 +1,4 @@ Entries: -- author: DuskyJay - changes: - - message: Allowed EMP implants to be used while stunned or cuffed. - type: Tweak - id: 6522 - time: '2024-05-03T07:51:33.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/27644 - author: Just-a-Unity-Dev changes: - message: Fixed Geras not having their speed buff. @@ -3778,3 +3771,10 @@ id: 7021 time: '2024-08-01T02:55:02.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/30419 +- author: PixelTheAertist + changes: + - message: The Social Anxiety trait is now renamed to "Stutter" + type: Tweak + id: 7022 + time: '2024-08-01T02:58:16.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/29898 From 219bbda8e7265240d52536ab68490bb47ff241f0 Mon Sep 17 00:00:00 2001 From: Plykiya <58439124+Plykiya@users.noreply.github.com> Date: Wed, 31 Jul 2024 19:59:54 -0700 Subject: [PATCH 525/765] Adds hand labelers to the ChemDrobe, LawDrobe, and PTech (#29958) * Adds hand labelers to the chemdrobe and ptech * LawDrobe too * Update cart.yml --------- Co-authored-by: plykiya --- .../Catalog/VendingMachines/Inventories/cart.yml | 1 + .../Catalog/VendingMachines/Inventories/chemdrobe.yml | 1 + .../Catalog/VendingMachines/Inventories/lawdrobe.yml | 9 ++++++--- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/Resources/Prototypes/Catalog/VendingMachines/Inventories/cart.yml b/Resources/Prototypes/Catalog/VendingMachines/Inventories/cart.yml index 6dc9c19bc8d..c8dfa9203ac 100644 --- a/Resources/Prototypes/Catalog/VendingMachines/Inventories/cart.yml +++ b/Resources/Prototypes/Catalog/VendingMachines/Inventories/cart.yml @@ -25,6 +25,7 @@ RubberStampDenied: 1 Paper: 10 Envelope: 10 + HandLabeler: 2 # Begin Delta-V subtractions # EncryptionKeyCargo: 2 # EncryptionKeyEngineering: 2 diff --git a/Resources/Prototypes/Catalog/VendingMachines/Inventories/chemdrobe.yml b/Resources/Prototypes/Catalog/VendingMachines/Inventories/chemdrobe.yml index 433210dce7b..2323d2f88b6 100644 --- a/Resources/Prototypes/Catalog/VendingMachines/Inventories/chemdrobe.yml +++ b/Resources/Prototypes/Catalog/VendingMachines/Inventories/chemdrobe.yml @@ -9,6 +9,7 @@ ClothingBackpackSatchelChemistry: 2 ClothingBackpackDuffelChemistry: 2 ChemBag: 2 + HandLabeler: 3 ClothingBeltMedical: 2 ClothingHandsGlovesLatex: 2 ClothingHeadsetMedical: 2 diff --git a/Resources/Prototypes/Catalog/VendingMachines/Inventories/lawdrobe.yml b/Resources/Prototypes/Catalog/VendingMachines/Inventories/lawdrobe.yml index 1638f07dad9..5c3fd1d9a3c 100644 --- a/Resources/Prototypes/Catalog/VendingMachines/Inventories/lawdrobe.yml +++ b/Resources/Prototypes/Catalog/VendingMachines/Inventories/lawdrobe.yml @@ -17,9 +17,12 @@ BriefcaseBrown: 2 BookSpaceLaw: 3 LuxuryPen: 2 - RubberStampLawyer: 3 # DeltaV - add lawyer stamp to lawdrobe - ClothingOuterCoatOvercoat: 2 # DeltaV - add overcoat to LawDrobe - BoxFolderClipboard: 5 # DeltaV - add clipboards for Justice Dept + HandLabeler: 2 + # Begin DeltaV additions + RubberStampLawyer: 3 + ClothingOuterCoatOvercoat: 2 + BoxFolderClipboard: 5 + # End DeltaV additions contrabandInventory: ClothingOuterRobesJudge: 1 ClothingHeadHatPwig: 1 From f6205577380e1d6346a10e90bde8b42a6781f188 Mon Sep 17 00:00:00 2001 From: PJBot Date: Thu, 1 Aug 2024 03:01:00 +0000 Subject: [PATCH 526/765] Automatic changelog update --- Resources/Changelog/Changelog.yml | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 599ee14fcb6..6f784b09404 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,17 +1,4 @@ Entries: -- author: Just-a-Unity-Dev - changes: - - message: Fixed Geras not having their speed buff. - type: Fix - - message: Geras are no longer immune to other AI mobs. - type: Fix - - message: Slimes can no longer morph into a Geras when zombified. - type: Fix - - message: Lowered the Geras death threshold. - type: Tweak - id: 6523 - time: '2024-05-03T17:26:09.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/27308 - author: nikthechampiongr changes: - message: Ninjas will no longer be pointed to random wreckage in space. @@ -3778,3 +3765,10 @@ id: 7022 time: '2024-08-01T02:58:16.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/29898 +- author: Plykiya + changes: + - message: Adds hand labelers to the PTech, ChemDrobe, and LawDrobe. + type: Add + id: 7023 + time: '2024-08-01T02:59:54.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/29958 From e6e0c5c9456cee208819291c210cb74305b0e1a3 Mon Sep 17 00:00:00 2001 From: Mervill Date: Wed, 31 Jul 2024 20:27:17 -0700 Subject: [PATCH 527/765] Remove obsolete code from LightningSystem (#30546) --- Content.Server/Lightning/LightningSystem.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Content.Server/Lightning/LightningSystem.cs b/Content.Server/Lightning/LightningSystem.cs index 94f3ab88023..8b0a18afb35 100644 --- a/Content.Server/Lightning/LightningSystem.cs +++ b/Content.Server/Lightning/LightningSystem.cs @@ -76,9 +76,9 @@ public void ShootRandomLightnings(EntityUid user, float range, int boltCount, st //TODO: This is still pretty bad for perf but better than before and at least it doesn't re-allocate // several hashsets every time - var targets = _lookup.GetComponentsInRange(_transform.GetMapCoordinates(user), range).ToList(); + var targets = _lookup.GetEntitiesInRange(_transform.GetMapCoordinates(user), range).ToList(); _random.Shuffle(targets); - targets.Sort((x, y) => y.Priority.CompareTo(x.Priority)); + targets.Sort((x, y) => y.Comp.Priority.CompareTo(x.Comp.Priority)); int shootedCount = 0; int count = -1; @@ -89,13 +89,13 @@ public void ShootRandomLightnings(EntityUid user, float range, int boltCount, st if (count >= targets.Count) { break; } var curTarget = targets[count]; - if (!_random.Prob(curTarget.HitProbability)) //Chance to ignore target + if (!_random.Prob(curTarget.Comp.HitProbability)) //Chance to ignore target continue; ShootLightning(user, targets[count].Owner, lightningPrototype, triggerLightningEvents); - if (arcDepth - targets[count].LightningResistance > 0) + if (arcDepth - targets[count].Comp.LightningResistance > 0) { - ShootRandomLightnings(targets[count].Owner, range, 1, lightningPrototype, arcDepth - targets[count].LightningResistance, triggerLightningEvents); + ShootRandomLightnings(targets[count].Owner, range, 1, lightningPrototype, arcDepth - targets[count].Comp.LightningResistance, triggerLightningEvents); } shootedCount++; } From 00fa5136938bd46cb3d6b2d4957634150495cede Mon Sep 17 00:00:00 2001 From: Nemanja <98561806+EmoGarbage404@users.noreply.github.com> Date: Thu, 1 Aug 2024 00:15:05 -0400 Subject: [PATCH 528/765] Add support for printing reagents in lathes (#30476) * Add support for reagents in lathes * missing locale --- Content.Client/Lathe/UI/LatheMenu.xaml | 9 +- Content.Client/Lathe/UI/LatheMenu.xaml.cs | 63 ++++++++----- Content.Client/Lathe/UI/RecipeControl.xaml | 4 +- Content.Client/Lathe/UI/RecipeControl.xaml.cs | 8 +- .../Tests/MaterialArbitrageTest.cs | 6 +- Content.Server/Cargo/Systems/PricingSystem.cs | 21 +++++ Content.Server/Lathe/LatheSystem.cs | 50 +++++++++-- .../UserInterface/StatValuesCommand.cs | 7 +- .../Construction/MachinePartSystem.cs | 8 +- Content.Shared/Lathe/LatheComponent.cs | 3 + Content.Shared/Lathe/SharedLatheSystem.cs | 70 ++++++++++++++- .../Prototypes/LatheRecipePrototype.cs | 89 +++++-------------- .../Research/Systems/SharedResearchSystem.cs | 4 +- .../Systems/TechnologyDiskSystem.cs | 5 +- Resources/Locale/en-US/lathe/recipes.ftl | 8 ++ .../Locale/en-US/lathe/ui/lathe-menu.ftl | 3 + .../Prototypes/Recipes/Lathes/medical.yml | 16 ++-- 17 files changed, 243 insertions(+), 131 deletions(-) create mode 100644 Resources/Locale/en-US/lathe/recipes.ftl diff --git a/Content.Client/Lathe/UI/LatheMenu.xaml b/Content.Client/Lathe/UI/LatheMenu.xaml index 6f484d8c7be..7e978c1ae56 100644 --- a/Content.Client/Lathe/UI/LatheMenu.xaml +++ b/Content.Client/Lathe/UI/LatheMenu.xaml @@ -100,12 +100,9 @@ Margin="5 0 0 0" Text="{Loc 'lathe-menu-fabricating-message'}"> - - +