From 8548e062edd23a3dfd63de447a0e9ed8ebe4d937 Mon Sep 17 00:00:00 2001 From: Kirby <205904127+154942@users.noreply.github.com> Date: Wed, 2 Apr 2025 06:42:05 -0400 Subject: [PATCH 01/42] Light replacer description typo fix (#36256) Replacer description typo fix --- Resources/Prototypes/Entities/Objects/Tools/light_replacer.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Resources/Prototypes/Entities/Objects/Tools/light_replacer.yml b/Resources/Prototypes/Entities/Objects/Tools/light_replacer.yml index 646f6a6378..34dcd66b71 100644 --- a/Resources/Prototypes/Entities/Objects/Tools/light_replacer.yml +++ b/Resources/Prototypes/Entities/Objects/Tools/light_replacer.yml @@ -2,7 +2,7 @@ parent: BaseItem name: light replacer id: LightReplacer - description: An item which uses magnets to easily replace broken lights. Refill By adding more lights into the replacer. + description: An item which uses magnets to easily replace broken lights. Refill by adding more lights into the replacer. components: - type: Sprite sprite: Objects/Specific/Janitorial/light_replacer.rsi From 3f8deb7aa4cb2d0b838ef5550b3e4da124438417 Mon Sep 17 00:00:00 2001 From: Fildrance Date: Wed, 2 Apr 2025 19:11:34 +0300 Subject: [PATCH 02/42] fix: re-add missing RCD deconstruct action #36243 (#36255) Co-authored-by: pa.pecherskij --- Resources/Prototypes/RCD/rcd.yml | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/Resources/Prototypes/RCD/rcd.yml b/Resources/Prototypes/RCD/rcd.yml index 88a99451cf..f476f06dc4 100644 --- a/Resources/Prototypes/RCD/rcd.yml +++ b/Resources/Prototypes/RCD/rcd.yml @@ -2,25 +2,25 @@ - type: rcd id: Invalid # Hidden prototype - do not add to RCDs mode: Invalid - + - type: rcd id: Deconstruct name: rcd-component-deconstruct - category: Main + category: WallsAndFlooring sprite: /Textures/Interface/Radial/RCD/deconstruct.png mode: Deconstruct prototype: EffectRCDDeconstructPreview rotation: Camera - type: rcd - id: DeconstructLattice # Hidden prototype - do not add to RCDs + id: DeconstructLattice # Hidden prototype - do not add to RCDs name: rcd-component-deconstruct mode: Deconstruct cost: 2 delay: 0 rotation: Camera fx: EffectRCDConstruct0 - + - type: rcd id: DeconstructTile # Hidden prototype - do not add to RCDs name: rcd-component-deconstruct @@ -30,7 +30,7 @@ rotation: Camera fx: EffectRCDDeconstruct4 -# Flooring +# Flooring - type: rcd id: Plating name: rcd-component-plating @@ -44,7 +44,7 @@ rules: - CanBuildOnEmptyTile fx: EffectRCDConstruct1 - + - type: rcd id: FloorSteel name: rcd-component-floor-steel @@ -80,7 +80,7 @@ category: WallsAndFlooring sprite: /Textures/Interface/Radial/RCD/solid_wall.png mode: ConstructObject - prototype: WallSolid + prototype: WallSolid cost: 4 delay: 2 collisionMask: FullTileMask @@ -113,7 +113,7 @@ - IsWindow rotation: Fixed fx: EffectRCDConstruct2 - + - type: rcd id: WindowDirectional category: WindowsAndGrilles @@ -128,7 +128,7 @@ - IsWindow rotation: User fx: EffectRCDConstruct1 - + - type: rcd id: ReinforcedWindow category: WindowsAndGrilles @@ -142,7 +142,7 @@ - IsWindow rotation: User fx: EffectRCDConstruct3 - + - type: rcd id: WindowReinforcedDirectional category: WindowsAndGrilles @@ -170,7 +170,7 @@ collisionMask: FullTileMask rotation: Camera fx: EffectRCDConstruct4 - + - type: rcd id: AirlockGlass category: Airlocks @@ -182,7 +182,7 @@ collisionMask: FullTileMask rotation: Camera fx: EffectRCDConstruct4 - + - type: rcd id: Firelock category: Airlocks @@ -208,7 +208,7 @@ collisionBounds: "-0.23,-0.49,0.23,-0.36" rotation: User fx: EffectRCDConstruct1 - + - type: rcd id: BulbLight category: Lighting @@ -235,7 +235,7 @@ - MustBuildOnSubfloor rotation: Fixed fx: EffectRCDConstruct0 - + - type: rcd id: MVCable category: Electrical @@ -248,7 +248,7 @@ - MustBuildOnSubfloor rotation: Fixed fx: EffectRCDConstruct0 - + - type: rcd id: HVCable category: Electrical @@ -261,7 +261,7 @@ - MustBuildOnSubfloor rotation: Fixed fx: EffectRCDConstruct0 - + - type: rcd id: CableTerminal category: Electrical From e920558bb6953ad08df54e9b96ae2dcdb58b79dc Mon Sep 17 00:00:00 2001 From: PJBot Date: Wed, 2 Apr 2025 16:12:41 +0000 Subject: [PATCH 03/42] 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 3e4a0be541..0676e638cc 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,11 +1,4 @@ Entries: -- author: ArZarLordOfMango - changes: - - message: Most toggleable clothing must now be equipped to toggle their actions. - type: Fix - id: 7623 - time: '2024-11-19T20:31:38.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/32826 - author: Plykiya changes: - message: The SWAT crate from cargo now requires armory access to open. @@ -3900,3 +3893,10 @@ id: 8122 time: '2025-04-01T23:26:53.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/35191 +- author: Fildrance + changes: + - message: fixed missing deconstruct on RCD + type: Fix + id: 8123 + time: '2025-04-02T16:11:35.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/36255 From b204fd9b0e2e0264e532d7d20887f32dd24d83fe Mon Sep 17 00:00:00 2001 From: qwerltaz Date: Wed, 2 Apr 2025 20:37:34 +0200 Subject: [PATCH 04/42] add: Dragon rift color changes based on charge (#36216) * use dragon rift sprite colours * Entity --- Content.Server/Dragon/DragonRiftSystem.cs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Content.Server/Dragon/DragonRiftSystem.cs b/Content.Server/Dragon/DragonRiftSystem.cs index 998834835e..9cab018fd7 100644 --- a/Content.Server/Dragon/DragonRiftSystem.cs +++ b/Content.Server/Dragon/DragonRiftSystem.cs @@ -13,6 +13,7 @@ using Robust.Shared.Serialization.Manager; using System.Numerics; using Robust.Shared.Audio; using Robust.Shared.Audio.Systems; +using Robust.Shared.GameStates; using Robust.Shared.Utility; namespace Content.Server.Dragon; @@ -33,11 +34,20 @@ public sealed class DragonRiftSystem : EntitySystem { base.Initialize(); + SubscribeLocalEvent(OnGetState); SubscribeLocalEvent(OnExamined); SubscribeLocalEvent(OnAnchorChange); SubscribeLocalEvent(OnShutdown); } + private void OnGetState(Entity ent, ref ComponentGetState args) + { + args.State = new DragonRiftComponentState + { + State = ent.Comp.State, + }; + } + public override void Update(float frameTime) { base.Update(frameTime); From b72a9170b0774116c931a39ecb1e6575ec27422b Mon Sep 17 00:00:00 2001 From: PJBot Date: Wed, 2 Apr 2025 18:38:43 +0000 Subject: [PATCH 05/42] 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 0676e638cc..17ef3994ca 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,11 +1,4 @@ Entries: -- author: Plykiya - changes: - - message: The SWAT crate from cargo now requires armory access to open. - type: Fix - id: 7624 - time: '2024-11-20T00:57:01.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/33415 - author: SlamBamActionman changes: - message: It's no longer possible to drag an item out of a container's UI to drop @@ -3900,3 +3893,10 @@ id: 8123 time: '2025-04-02T16:11:35.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/36255 +- author: qwerltaz + changes: + - message: Dragon rifts now shine a different color depending on charge progress. + type: Add + id: 8124 + time: '2025-04-02T18:37:35.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/36216 From 933984fe6f78f276f42074cd4d72a9e7f2488b95 Mon Sep 17 00:00:00 2001 From: Vasilis The Pikachu Date: Wed, 2 Apr 2025 23:54:20 +0200 Subject: [PATCH 06/42] :3 This is so we can publish stable again From 7f781e7bdad2196b9800b5fd6e81065ba42e95d6 Mon Sep 17 00:00:00 2001 From: Tayrtahn Date: Wed, 2 Apr 2025 19:26:36 -0400 Subject: [PATCH 07/42] Convert AgentIDCard message to use a Fluent selector (#36263) Convert AgentIDCard message to use a selector --- .../Access/Systems/AgentIDCardSystem.cs | 16 ++-------------- .../components/agent-id-card-component.ftl | 9 ++++++--- 2 files changed, 8 insertions(+), 17 deletions(-) diff --git a/Content.Server/Access/Systems/AgentIDCardSystem.cs b/Content.Server/Access/Systems/AgentIDCardSystem.cs index a38aefce93..9ede128a5a 100644 --- a/Content.Server/Access/Systems/AgentIDCardSystem.cs +++ b/Content.Server/Access/Systems/AgentIDCardSystem.cs @@ -42,21 +42,9 @@ namespace Content.Server.Access.Systems access.Tags.UnionWith(targetAccess.Tags); var addedLength = access.Tags.Count - beforeLength; - if (addedLength == 0) - { - _popupSystem.PopupEntity(Loc.GetString("agent-id-no-new", ("card", args.Target)), args.Target.Value, args.User); - return; - } - - Dirty(uid, access); - - if (addedLength == 1) - { - _popupSystem.PopupEntity(Loc.GetString("agent-id-new-1", ("card", args.Target)), args.Target.Value, args.User); - return; - } - _popupSystem.PopupEntity(Loc.GetString("agent-id-new", ("number", addedLength), ("card", args.Target)), args.Target.Value, args.User); + if (addedLength > 0) + Dirty(uid, access); } private void AfterUIOpen(EntityUid uid, AgentIDCardComponent component, AfterActivatableUIOpenEvent args) diff --git a/Resources/Locale/en-US/access/components/agent-id-card-component.ftl b/Resources/Locale/en-US/access/components/agent-id-card-component.ftl index 17a92f6012..5e1e3cd7cf 100644 --- a/Resources/Locale/en-US/access/components/agent-id-card-component.ftl +++ b/Resources/Locale/en-US/access/components/agent-id-card-component.ftl @@ -1,6 +1,9 @@ -agent-id-no-new = Didn't gain any new accesses from {THE($card)}. -agent-id-new-1 = Gained one new access from {THE($card)}. -agent-id-new = Gained {$number} new accesses from {THE($card)}. +agent-id-new = { $number -> + [0] Didn't gain any new accesses from {THE($card)}. + [one] Gained one new access from {THE($card)}. + *[other] Gained {$number} new accesses from {THE($card)}. +} + agent-id-card-current-name = Name: agent-id-card-current-job = Job: agent-id-card-job-icon-label = Job icon: From 7e4cf87820e63b103df93a793b3ddecec7468316 Mon Sep 17 00:00:00 2001 From: J Date: Thu, 3 Apr 2025 00:12:25 +0000 Subject: [PATCH 08/42] NPC Warnings cleanup (#36189) * NPC Warnings cleanup * Reverting unnecessary changes * Reverting unnecessary changes, missed * Using entity GetGrid override instead --- .../NPC/HTN/PrimitiveTasks/Operators/MoveToOperator.cs | 6 +++--- Content.Server/NPC/Pathfinding/PathfindingSystem.Grid.cs | 8 ++------ Content.Server/NPC/Systems/NPCSteeringSystem.cs | 2 +- 3 files changed, 6 insertions(+), 10 deletions(-) diff --git a/Content.Server/NPC/HTN/PrimitiveTasks/Operators/MoveToOperator.cs b/Content.Server/NPC/HTN/PrimitiveTasks/Operators/MoveToOperator.cs index e64343fdd8..aeedb326e9 100644 --- a/Content.Server/NPC/HTN/PrimitiveTasks/Operators/MoveToOperator.cs +++ b/Content.Server/NPC/HTN/PrimitiveTasks/Operators/MoveToOperator.cs @@ -86,7 +86,7 @@ public sealed partial class MoveToOperator : HTNOperator, IHtnConditionalShutdow return (false, null); if (!_entManager.TryGetComponent(xform.GridUid, out var ownerGrid) || - !_entManager.TryGetComponent(targetCoordinates.GetGridUid(_entManager), out var targetGrid)) + !_entManager.TryGetComponent(_transform.GetGrid(targetCoordinates), out var targetGrid)) { return (false, null); } @@ -155,8 +155,8 @@ public sealed partial class MoveToOperator : HTNOperator, IHtnConditionalShutdow { if (blackboard.TryGetValue(NPCBlackboard.OwnerCoordinates, out var coordinates, _entManager)) { - var mapCoords = coordinates.ToMap(_entManager, _transform); - _steering.PrunePath(uid, mapCoords, targetCoordinates.ToMapPos(_entManager, _transform) - mapCoords.Position, result.Path); + var mapCoords = _transform.ToMapCoordinates(coordinates); + _steering.PrunePath(uid, mapCoords, _transform.ToMapCoordinates(targetCoordinates).Position - mapCoords.Position, result.Path); } comp.CurrentPath = new Queue(result.Path); diff --git a/Content.Server/NPC/Pathfinding/PathfindingSystem.Grid.cs b/Content.Server/NPC/Pathfinding/PathfindingSystem.Grid.cs index f4af65c617..7105bda0a2 100644 --- a/Content.Server/NPC/Pathfinding/PathfindingSystem.Grid.cs +++ b/Content.Server/NPC/Pathfinding/PathfindingSystem.Grid.cs @@ -2,10 +2,6 @@ using System.Diagnostics.CodeAnalysis; using System.Numerics; using System.Threading; using System.Threading.Tasks; -using Content.Server.Destructible; -using Content.Shared.Access.Components; -using Content.Shared.Climbing.Components; -using Content.Shared.Doors.Components; using Content.Shared.NPC; using Content.Shared.Physics; using Robust.Shared.Collections; @@ -281,7 +277,7 @@ public sealed partial class PathfindingSystem var gridUid = ev.Component.GridUid; var oldGridUid = ev.OldPosition.EntityId == ev.NewPosition.EntityId ? gridUid - : ev.OldPosition.GetGridUid(EntityManager); + : _transform.GetGrid((ev.Entity.Owner, ev.Component)); if (oldGridUid != null && oldGridUid != gridUid) { @@ -395,7 +391,7 @@ public sealed partial class PathfindingSystem private Vector2i GetOrigin(EntityCoordinates coordinates, EntityUid gridUid) { - var localPos = Vector2.Transform(coordinates.ToMapPos(EntityManager, _transform), _transform.GetInvWorldMatrix(gridUid)); + var localPos = Vector2.Transform(_transform.ToMapCoordinates(coordinates).Position, _transform.GetInvWorldMatrix(gridUid)); return new Vector2i((int) Math.Floor(localPos.X / ChunkSize), (int) Math.Floor(localPos.Y / ChunkSize)); } diff --git a/Content.Server/NPC/Systems/NPCSteeringSystem.cs b/Content.Server/NPC/Systems/NPCSteeringSystem.cs index a8124c0249..78610be77e 100644 --- a/Content.Server/NPC/Systems/NPCSteeringSystem.cs +++ b/Content.Server/NPC/Systems/NPCSteeringSystem.cs @@ -461,7 +461,7 @@ public sealed partial class NPCSteeringSystem : SharedNPCSteeringSystem return; } - var targetPos = steering.Coordinates.ToMap(EntityManager, _transform); + var targetPos = _transform.ToMapCoordinates(steering.Coordinates); var ourPos = _transform.GetMapCoordinates(uid, xform: xform); PrunePath(uid, ourPos, targetPos.Position - ourPos.Position, result.Path); From bb864f2b5693d1cd1f7be99e381036f1deac901b Mon Sep 17 00:00:00 2001 From: Tayrtahn Date: Wed, 2 Apr 2025 22:02:09 -0400 Subject: [PATCH 09/42] Fix entities burning to ash not using identity, and bad formatting (#36268) * Make burning to ash use identity * CAPITALIZE(THE()) --- .../Destructible/Thresholds/Behaviors/BurnBodyBehavior.cs | 4 +++- Resources/Locale/en-US/burning/bodyburn.ftl | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Content.Server/Destructible/Thresholds/Behaviors/BurnBodyBehavior.cs b/Content.Server/Destructible/Thresholds/Behaviors/BurnBodyBehavior.cs index f0499dc6a2..1d3c1993f9 100644 --- a/Content.Server/Destructible/Thresholds/Behaviors/BurnBodyBehavior.cs +++ b/Content.Server/Destructible/Thresholds/Behaviors/BurnBodyBehavior.cs @@ -1,4 +1,5 @@ using Content.Shared.Body.Components; +using Content.Shared.IdentityManagement; using Content.Shared.Inventory; using Content.Shared.Popups; using JetBrains.Annotations; @@ -25,7 +26,8 @@ public sealed partial class BurnBodyBehavior : IThresholdBehavior } } - sharedPopupSystem.PopupCoordinates(Loc.GetString("bodyburn-text-others", ("name", bodyId)), transformSystem.GetMoverCoordinates(bodyId), PopupType.LargeCaution); + var bodyIdentity = Identity.Entity(bodyId, system.EntityManager); + sharedPopupSystem.PopupCoordinates(Loc.GetString("bodyburn-text-others", ("name", bodyIdentity)), transformSystem.GetMoverCoordinates(bodyId), PopupType.LargeCaution); system.EntityManager.QueueDeleteEntity(bodyId); } diff --git a/Resources/Locale/en-US/burning/bodyburn.ftl b/Resources/Locale/en-US/burning/bodyburn.ftl index 58b98c09bb..929b2344cf 100644 --- a/Resources/Locale/en-US/burning/bodyburn.ftl +++ b/Resources/Locale/en-US/burning/bodyburn.ftl @@ -1 +1 @@ -bodyburn-text-others = {$name} burns to ash! +bodyburn-text-others = {CAPITALIZE(THE($name))} burns to ash! From e4d7f164f63016cc3d20f1a3322e3bcc018e1b9e Mon Sep 17 00:00:00 2001 From: Tayrtahn Date: Wed, 2 Apr 2025 22:38:26 -0400 Subject: [PATCH 10/42] Localize air alarm states (#36266) --- .../Atmos/Monitor/UI/AirAlarmWindow.xaml.cs | 2 +- .../Atmos/Monitor/UI/Widgets/SensorInfo.xaml.cs | 8 ++++---- Resources/Locale/en-US/atmos/air-alarm-ui.ftl | 13 +++++++++++-- 3 files changed, 16 insertions(+), 7 deletions(-) diff --git a/Content.Client/Atmos/Monitor/UI/AirAlarmWindow.xaml.cs b/Content.Client/Atmos/Monitor/UI/AirAlarmWindow.xaml.cs index f0201dc81b..ed15579937 100644 --- a/Content.Client/Atmos/Monitor/UI/AirAlarmWindow.xaml.cs +++ b/Content.Client/Atmos/Monitor/UI/AirAlarmWindow.xaml.cs @@ -103,7 +103,7 @@ public sealed partial class AirAlarmWindow : FancyWindow _temperature.SetMarkup(Loc.GetString("air-alarm-ui-window-temperature", ("tempC", $"{TemperatureHelpers.KelvinToCelsius(state.TemperatureAverage):0.#}"), ("temperature", $"{state.TemperatureAverage:0.##}"))); _alarmState.SetMarkup(Loc.GetString("air-alarm-ui-window-alarm-state", ("color", ColorForAlarm(state.AlarmType)), - ("state", $"{state.AlarmType}"))); + ("state", state.AlarmType))); UpdateModeSelector(state.Mode); UpdateAutoMode(state.AutoMode); foreach (var (addr, dev) in state.DeviceData) diff --git a/Content.Client/Atmos/Monitor/UI/Widgets/SensorInfo.xaml.cs b/Content.Client/Atmos/Monitor/UI/Widgets/SensorInfo.xaml.cs index f906bd3930..9e88b0bff4 100644 --- a/Content.Client/Atmos/Monitor/UI/Widgets/SensorInfo.xaml.cs +++ b/Content.Client/Atmos/Monitor/UI/Widgets/SensorInfo.xaml.cs @@ -27,11 +27,11 @@ public sealed partial class SensorInfo : BoxContainer _address = address; - SensorAddress.Title = $"{address} : {data.AlarmState}"; + SensorAddress.Title = Loc.GetString("air-alarm-ui-window-listing-title", ("address", _address), ("state", data.AlarmState)); AlarmStateLabel.SetMarkup(Loc.GetString("air-alarm-ui-window-alarm-state-indicator", ("color", AirAlarmWindow.ColorForAlarm(data.AlarmState)), - ("state", $"{data.AlarmState}"))); + ("state", data.AlarmState))); PressureLabel.SetMarkup(Loc.GetString("air-alarm-ui-window-pressure-indicator", ("color", AirAlarmWindow.ColorForThreshold(data.Pressure, data.PressureThreshold)), ("pressure", $"{data.Pressure:0.##}"))); @@ -90,11 +90,11 @@ public sealed partial class SensorInfo : BoxContainer public void ChangeData(AtmosSensorData data) { - SensorAddress.Title = $"{_address} : {data.AlarmState}"; + SensorAddress.Title = Loc.GetString("air-alarm-ui-window-listing-title", ("address", _address), ("state", data.AlarmState)); AlarmStateLabel.SetMarkup(Loc.GetString("air-alarm-ui-window-alarm-state-indicator", ("color", AirAlarmWindow.ColorForAlarm(data.AlarmState)), - ("state", $"{data.AlarmState}"))); + ("state", data.AlarmState))); PressureLabel.SetMarkup(Loc.GetString("air-alarm-ui-window-pressure-indicator", ("color", AirAlarmWindow.ColorForThreshold(data.Pressure, data.PressureThreshold)), diff --git a/Resources/Locale/en-US/atmos/air-alarm-ui.ftl b/Resources/Locale/en-US/atmos/air-alarm-ui.ftl index 15043e4984..57e47cf4cf 100644 --- a/Resources/Locale/en-US/atmos/air-alarm-ui.ftl +++ b/Resources/Locale/en-US/atmos/air-alarm-ui.ftl @@ -15,12 +15,21 @@ air-alarm-ui-window-resync-devices-label = Resync air-alarm-ui-window-mode-label = Mode air-alarm-ui-window-auto-mode-label = Auto mode +-air-alarm-state-name = { $state -> + [normal] Normal + [warning] Warning + [danger] Danger + [emagged] Emagged + *[invalid] Invalid +} + +air-alarm-ui-window-listing-title = {$address} : {-air-alarm-state-name(state:$state)} air-alarm-ui-window-pressure = {$pressure} kPa air-alarm-ui-window-pressure-indicator = Pressure: [color={$color}]{$pressure} kPa[/color] air-alarm-ui-window-temperature = {$tempC} C ({$temperature} K) air-alarm-ui-window-temperature-indicator = Temperature: [color={$color}]{$tempC} C ({$temperature} K)[/color] -air-alarm-ui-window-alarm-state = [color={$color}]{$state}[/color] -air-alarm-ui-window-alarm-state-indicator = Status: [color={$color}]{$state}[/color] +air-alarm-ui-window-alarm-state = [color={$color}]{-air-alarm-state-name(state:$state)}[/color] +air-alarm-ui-window-alarm-state-indicator = Status: [color={$color}]{-air-alarm-state-name(state:$state)}[/color] air-alarm-ui-window-tab-vents = Vents air-alarm-ui-window-tab-scrubbers = Scrubbers From 8007a4ebf7517484fffad0814355c1440f21f4f5 Mon Sep 17 00:00:00 2001 From: Tayrtahn Date: Wed, 2 Apr 2025 23:30:30 -0400 Subject: [PATCH 11/42] Fix a few loc bugs with magic mirror/scissors (#36269) * Use identity for magic mirror popups * THE() * Use correct pronouns in blocked-by-hat message --- Content.Server/MagicMirror/MagicMirrorSystem.cs | 10 +++++----- .../components/magic-mirror-component.ftl | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/Content.Server/MagicMirror/MagicMirrorSystem.cs b/Content.Server/MagicMirror/MagicMirrorSystem.cs index 082fc81bd2..f3be03b4b0 100644 --- a/Content.Server/MagicMirror/MagicMirrorSystem.cs +++ b/Content.Server/MagicMirror/MagicMirrorSystem.cs @@ -59,7 +59,7 @@ public sealed class MagicMirrorSystem : SharedMagicMirrorSystem _popup.PopupEntity( component.Target == message.Actor ? Loc.GetString("magic-mirror-blocked-by-hat-self") - : Loc.GetString("magic-mirror-blocked-by-hat-self-target"), + : Loc.GetString("magic-mirror-blocked-by-hat-self-target", ("target", Identity.Entity(message.Actor, EntityManager))), message.Actor, message.Actor, PopupType.Medium); @@ -95,7 +95,7 @@ public sealed class MagicMirrorSystem : SharedMagicMirrorSystem } else { - _popup.PopupEntity(Loc.GetString("magic-mirror-change-slot-target", ("user", Identity.Name(message.Actor, EntityManager))), component.Target.Value, component.Target.Value, PopupType.Medium); + _popup.PopupEntity(Loc.GetString("magic-mirror-change-slot-target", ("user", Identity.Entity(message.Actor, EntityManager))), component.Target.Value, component.Target.Value, PopupType.Medium); } component.DoAfter = doAfterId; @@ -175,7 +175,7 @@ public sealed class MagicMirrorSystem : SharedMagicMirrorSystem } else { - _popup.PopupEntity(Loc.GetString("magic-mirror-change-color-target", ("user", Identity.Name(message.Actor, EntityManager))), component.Target.Value, component.Target.Value, PopupType.Medium); + _popup.PopupEntity(Loc.GetString("magic-mirror-change-color-target", ("user", Identity.Entity(message.Actor, EntityManager))), component.Target.Value, component.Target.Value, PopupType.Medium); } component.DoAfter = doAfterId; @@ -253,7 +253,7 @@ public sealed class MagicMirrorSystem : SharedMagicMirrorSystem } else { - _popup.PopupEntity(Loc.GetString("magic-mirror-remove-slot-target", ("user", Identity.Name(message.Actor, EntityManager))), component.Target.Value, component.Target.Value, PopupType.Medium); + _popup.PopupEntity(Loc.GetString("magic-mirror-remove-slot-target", ("user", Identity.Entity(message.Actor, EntityManager))), component.Target.Value, component.Target.Value, PopupType.Medium); } component.DoAfter = doAfterId; @@ -331,7 +331,7 @@ public sealed class MagicMirrorSystem : SharedMagicMirrorSystem } else { - _popup.PopupEntity(Loc.GetString("magic-mirror-add-slot-target", ("user", Identity.Name(message.Actor, EntityManager))), component.Target.Value, component.Target.Value, PopupType.Medium); + _popup.PopupEntity(Loc.GetString("magic-mirror-add-slot-target", ("user", Identity.Entity(message.Actor, EntityManager))), component.Target.Value, component.Target.Value, PopupType.Medium); } component.DoAfter = doAfterId; diff --git a/Resources/Locale/en-US/character-appearance/components/magic-mirror-component.ftl b/Resources/Locale/en-US/character-appearance/components/magic-mirror-component.ftl index 0906cccee5..1b22fbf828 100644 --- a/Resources/Locale/en-US/character-appearance/components/magic-mirror-component.ftl +++ b/Resources/Locale/en-US/character-appearance/components/magic-mirror-component.ftl @@ -6,10 +6,10 @@ magic-mirror-remove-slot-self = You're removing some of your hair. magic-mirror-change-slot-self = You're changing your hairstyle. magic-mirror-change-color-self = You're changing your hair color. -magic-mirror-add-slot-target = Hair is being added to you by {$user}. -magic-mirror-remove-slot-target = Your hair is being cut off by {$user}. -magic-mirror-change-slot-target = Your hairstyle is being changed by {$user}. -magic-mirror-change-color-target = Your hair color is being changed by {$user}. +magic-mirror-add-slot-target = Hair is being added to you by {THE($user)}. +magic-mirror-remove-slot-target = Your hair is being cut off by {THE($user)}. +magic-mirror-change-slot-target = Your hairstyle is being changed by {THE($user)}. +magic-mirror-change-color-target = Your hair color is being changed by {THE($user)}. magic-mirror-blocked-by-hat-self = You need to take off your hat before changing your hair. -magic-mirror-blocked-by-hat-self-target = You try to change their hair but their clothes gets in the way. +magic-mirror-blocked-by-hat-self-target = You try to change {POSS-ADJ($target)} hair but {POSS-ADJ($target)} clothes get in the way. From 8ad7c9c281cb0aa40934365b3faeccb15dd1d6f5 Mon Sep 17 00:00:00 2001 From: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com> Date: Thu, 3 Apr 2025 14:32:14 +1100 Subject: [PATCH 12/42] Add autocomplete to controlmob (#36234) Expensive for what it is just really annoying in debug to not have it. Worst case I just make it debug only and we don't add it for release. --- Content.Server/Administration/Commands/ControlMob.cs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Content.Server/Administration/Commands/ControlMob.cs b/Content.Server/Administration/Commands/ControlMob.cs index 8613fafeae..26cd83510b 100644 --- a/Content.Server/Administration/Commands/ControlMob.cs +++ b/Content.Server/Administration/Commands/ControlMob.cs @@ -43,5 +43,13 @@ namespace Content.Server.Administration.Commands _entities.System().ControlMob(player.UserId, target.Value); } + + public CompletionResult GetCompletion(IConsoleShell shell, string[] args) + { + if (args.Length != 1) + return CompletionResult.Empty; + + return CompletionResult.FromOptions(CompletionHelper.NetEntities(args[0], entManager: _entities)); + } } } From b2f7196e26f8e5b3bedcf14191355c4db987c7f8 Mon Sep 17 00:00:00 2001 From: Polter <62557990+PolterTzi@users.noreply.github.com> Date: Thu, 3 Apr 2025 08:03:36 +0200 Subject: [PATCH 13/42] Change the name and description of the templar helmet. (#36258) Changed the name and description of the knight helmet. Co-authored-by: Flesh --- Resources/Prototypes/Entities/Clothing/Head/helmets.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Resources/Prototypes/Entities/Clothing/Head/helmets.yml b/Resources/Prototypes/Entities/Clothing/Head/helmets.yml index 91cf83d61b..0dfc37a627 100644 --- a/Resources/Prototypes/Entities/Clothing/Head/helmets.yml +++ b/Resources/Prototypes/Entities/Clothing/Head/helmets.yml @@ -187,12 +187,12 @@ - HeadTop - HeadSide -#Templar Helmet +#Knight Helmet - type: entity parent: ClothingHeadBase id: ClothingHeadHelmetTemplar - name: templar helmet - description: DEUS VULT! + name: knight helmet + description: Decorative helmet fashioned to resemble the knights of old. components: - type: Sprite sprite: Clothing/Head/Helmets/templar.rsi From 4c73dcc2c8b4cb647a79944cc8717402d11e0915 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C4=81da?= Date: Thu, 3 Apr 2025 01:29:52 -0500 Subject: [PATCH 14/42] Diphenhydramine causes drowsiness (#36212) * nap time in medbay * suggested changes * fake test fail --- Resources/Locale/en-US/reagents/meta/medicine.ftl | 2 +- Resources/Prototypes/Reagents/medicine.yml | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/Resources/Locale/en-US/reagents/meta/medicine.ftl b/Resources/Locale/en-US/reagents/meta/medicine.ftl index 0b6695be34..9e5dcc88d4 100644 --- a/Resources/Locale/en-US/reagents/meta/medicine.ftl +++ b/Resources/Locale/en-US/reagents/meta/medicine.ftl @@ -5,7 +5,7 @@ reagent-name-dylovene = dylovene reagent-desc-dylovene = A broad-spectrum anti-toxin, which treats toxin damage in organisms. Overdosing will cause vomiting, dizzyness and pain. reagent-name-diphenhydramine = diphenhydramine -reagent-desc-diphenhydramine = Rapidly purges the body of histamine, reduces jitteriness, and treats poison damage. +reagent-desc-diphenhydramine = Rapidly purges the body of histamine, reduces jitteriness, causes drowsiness, and treats poison damage. Often included in sleep medication. reagent-name-arithrazine = arithrazine reagent-desc-arithrazine = A mildly unstable medication used for the most extreme case of radiation poisoning. Exerts minor stress on the body. diff --git a/Resources/Prototypes/Reagents/medicine.yml b/Resources/Prototypes/Reagents/medicine.yml index 26ca6fa266..6c676f0105 100644 --- a/Resources/Prototypes/Reagents/medicine.yml +++ b/Resources/Prototypes/Reagents/medicine.yml @@ -83,6 +83,12 @@ key: Jitter time: 3.0 type: Remove + - !type:GenericStatusEffect + key: Drowsiness + component: Drowsiness + time: 1.5 + type: Add + refresh: false - !type:HealthChange damage: types: From ce53629f1ddc4fdce68cf0c64e43505f92e8bc1d Mon Sep 17 00:00:00 2001 From: PJBot Date: Thu, 3 Apr 2025 06:31:00 +0000 Subject: [PATCH 15/42] 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 17ef3994ca..1e22adcdd6 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,12 +1,4 @@ Entries: -- author: SlamBamActionman - changes: - - message: It's no longer possible to drag an item out of a container's UI to drop - it. - type: Tweak - id: 7625 - time: '2024-11-20T01:00:38.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/32706 - author: Plykiya changes: - message: The crew monitoring crate now contains a flatpack of the server and computers, @@ -3900,3 +3892,10 @@ id: 8124 time: '2025-04-02T18:37:35.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/36216 +- author: aada + changes: + - message: Diphenhydramine now causes light drowsiness. + type: Tweak + id: 8125 + time: '2025-04-03T06:29:52.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/36212 From e9b89a1c6bd093d72ff5a76240b76bed99c70953 Mon Sep 17 00:00:00 2001 From: pathetic meowmeow Date: Thu, 3 Apr 2025 02:58:05 -0400 Subject: [PATCH 16/42] Improve sprite fading behaviour (#35863) * Click through faded sprites * Count the mouse position for which sprites to fade --- Content.Client/Clickable/ClickableSystem.cs | 13 +- Content.Client/Gameplay/GameplayStateBase.cs | 12 +- Content.Client/Sprite/SpriteFadeSystem.cs | 112 ++++++++++++++---- .../Tests/ClickableTest.cs | 2 +- 4 files changed, 105 insertions(+), 34 deletions(-) diff --git a/Content.Client/Clickable/ClickableSystem.cs b/Content.Client/Clickable/ClickableSystem.cs index 15d13df625..454bff4349 100644 --- a/Content.Client/Clickable/ClickableSystem.cs +++ b/Content.Client/Clickable/ClickableSystem.cs @@ -1,4 +1,5 @@ using System.Numerics; +using Content.Client.Sprite; using Robust.Client.GameObjects; using Robust.Client.Graphics; using Robust.Client.Utility; @@ -17,12 +18,14 @@ public sealed class ClickableSystem : EntitySystem private EntityQuery _clickableQuery; private EntityQuery _xformQuery; + private EntityQuery _fadingSpriteQuery; public override void Initialize() { base.Initialize(); _clickableQuery = GetEntityQuery(); _xformQuery = GetEntityQuery(); + _fadingSpriteQuery = GetEntityQuery(); } /// @@ -34,7 +37,7 @@ public sealed class ClickableSystem : EntitySystem /// The draw depth for the sprite that captured the click. /// /// True if the click worked, false otherwise. - public bool CheckClick(Entity entity, Vector2 worldPos, IEye eye, out int drawDepth, out uint renderOrder, out float bottom) + public bool CheckClick(Entity entity, Vector2 worldPos, IEye eye, bool excludeFaded, out int drawDepth, out uint renderOrder, out float bottom) { if (!_clickableQuery.Resolve(entity.Owner, ref entity.Comp1, false)) { @@ -52,6 +55,14 @@ public sealed class ClickableSystem : EntitySystem return false; } + if (excludeFaded && _fadingSpriteQuery.Resolve(entity.Owner, ref entity.Comp4, false)) + { + drawDepth = default; + renderOrder = default; + bottom = default; + return false; + } + var sprite = entity.Comp2; var transform = entity.Comp3; diff --git a/Content.Client/Gameplay/GameplayStateBase.cs b/Content.Client/Gameplay/GameplayStateBase.cs index 162c45d412..69e6e0b58b 100644 --- a/Content.Client/Gameplay/GameplayStateBase.cs +++ b/Content.Client/Gameplay/GameplayStateBase.cs @@ -113,18 +113,18 @@ namespace Content.Client.Gameplay return first.IsValid() ? first : null; } - public IEnumerable GetClickableEntities(EntityCoordinates coordinates) + public IEnumerable GetClickableEntities(EntityCoordinates coordinates, bool excludeFaded = true) { var transformSystem = _entitySystemManager.GetEntitySystem(); - return GetClickableEntities(transformSystem.ToMapCoordinates(coordinates)); + return GetClickableEntities(transformSystem.ToMapCoordinates(coordinates), excludeFaded); } - public IEnumerable GetClickableEntities(MapCoordinates coordinates) + public IEnumerable GetClickableEntities(MapCoordinates coordinates, bool excludeFaded = true) { - return GetClickableEntities(coordinates, _eyeManager.CurrentEye); + return GetClickableEntities(coordinates, _eyeManager.CurrentEye, excludeFaded); } - public IEnumerable GetClickableEntities(MapCoordinates coordinates, IEye? eye) + public IEnumerable GetClickableEntities(MapCoordinates coordinates, IEye? eye, bool excludeFaded = true) { /* * TODO: @@ -147,7 +147,7 @@ namespace Content.Client.Gameplay foreach (var entity in entities) { if (clickQuery.TryGetComponent(entity.Uid, out var component) && - clickables.CheckClick((entity.Uid, component, entity.Component, entity.Transform), coordinates.Position, eye, out var drawDepthClicked, out var renderOrder, out var bottom)) + clickables.CheckClick((entity.Uid, component, entity.Component, entity.Transform), coordinates.Position, eye, excludeFaded, out var drawDepthClicked, out var renderOrder, out var bottom)) { foundEntities.Add((entity.Uid, drawDepthClicked, renderOrder, bottom)); } diff --git a/Content.Client/Sprite/SpriteFadeSystem.cs b/Content.Client/Sprite/SpriteFadeSystem.cs index 3323dd660f..949012d04a 100644 --- a/Content.Client/Sprite/SpriteFadeSystem.cs +++ b/Content.Client/Sprite/SpriteFadeSystem.cs @@ -1,8 +1,14 @@ +using System.Numerics; using Content.Client.Gameplay; using Content.Shared.Sprite; using Robust.Client.GameObjects; +using Robust.Client.Input; using Robust.Client.Player; using Robust.Client.State; +using Robust.Client.UserInterface.CustomControls; +using Robust.Client.UserInterface; +using Robust.Shared.Map; +using Robust.Shared.Physics.Systems; using Robust.Shared.Physics; namespace Content.Client.Sprite; @@ -17,6 +23,9 @@ public sealed class SpriteFadeSystem : EntitySystem [Dependency] private readonly IPlayerManager _playerManager = default!; [Dependency] private readonly IStateManager _stateManager = default!; [Dependency] private readonly SharedTransformSystem _transform = default!; + [Dependency] private readonly IUserInterfaceManager _uiManager = default!; + [Dependency] private readonly IInputManager _inputManager = default!; + [Dependency] private readonly SharedPhysicsSystem _physics = default!; private readonly HashSet _comps = new(); @@ -24,6 +33,11 @@ public sealed class SpriteFadeSystem : EntitySystem private EntityQuery _fadeQuery; private EntityQuery _fadingQuery; + /// + /// Radius of the mouse point for the intersection test + /// + private static Vector2 MouseRadius = new Vector2(10f * float.Epsilon, 10f * float.Epsilon); + private const float TargetAlpha = 0.4f; private const float ChangeRate = 1f; @@ -46,46 +60,82 @@ public sealed class SpriteFadeSystem : EntitySystem sprite.Color = sprite.Color.WithAlpha(component.OriginalAlpha); } - public override void FrameUpdate(float frameTime) + /// + /// Adds sprites to the fade set, and brings their alpha downwards + /// + private void FadeIn(float change) { - base.FrameUpdate(frameTime); - var player = _playerManager.LocalEntity; - var change = ChangeRate * frameTime; + // ExcludeBoundingBox is set if we don't want to fade this sprite within the collision bounding boxes for the given POI + var pointsOfInterest = new List<(MapCoordinates Point, bool ExcludeBoundingBox)>(); - if (TryComp(player, out TransformComponent? playerXform) && - _stateManager.CurrentState is GameplayState state && - _spriteQuery.TryGetComponent(player, out var playerSprite)) + if (_uiManager.CurrentlyHovered is IViewportControl vp + && _inputManager.MouseScreenPosition.IsValid) { - var mapPos = _transform.GetMapCoordinates(_playerManager.LocalEntity!.Value, xform: playerXform); + pointsOfInterest.Add((vp.PixelToMap(_inputManager.MouseScreenPosition.Position), true)); + } - // Also want to handle large entities even if they may not be clickable. - foreach (var ent in state.GetClickableEntities(mapPos)) + if (TryComp(player, out TransformComponent? playerXform)) + { + pointsOfInterest.Add((_transform.GetMapCoordinates(_playerManager.LocalEntity!.Value, xform: playerXform), false)); + } + + if (_stateManager.CurrentState is GameplayState state && _spriteQuery.TryGetComponent(player, out var playerSprite)) + { + foreach (var (mapPos, excludeBB) in pointsOfInterest) { - if (ent == player || - !_fadeQuery.HasComponent(ent) || - !_spriteQuery.TryGetComponent(ent, out var sprite) || - sprite.DrawDepth < playerSprite.DrawDepth) + // Also want to handle large entities even if they may not be clickable. + foreach (var ent in state.GetClickableEntities(mapPos, excludeFaded: false)) { - continue; - } + if (ent == player || + !_fadeQuery.HasComponent(ent) || + !_spriteQuery.TryGetComponent(ent, out var sprite) || + sprite.DrawDepth < playerSprite.DrawDepth) + { + continue; + } - if (!_fadingQuery.TryComp(ent, out var fading)) - { - fading = AddComp(ent); - fading.OriginalAlpha = sprite.Color.A; - } + if (excludeBB) + { + var test = new Box2Rotated(mapPos.Position - MouseRadius, mapPos.Position + MouseRadius); + var collided = false; + foreach (var fixture in _physics.GetCollidingEntities(mapPos.MapId, test)) + { + if (fixture.Owner == ent) + { + collided = true; + break; + } + } + if (collided) + { + break; + } + } - _comps.Add(fading); - var newColor = Math.Max(sprite.Color.A - change, TargetAlpha); + if (!_fadingQuery.TryComp(ent, out var fading)) + { + fading = AddComp(ent); + fading.OriginalAlpha = sprite.Color.A; + } - if (!sprite.Color.A.Equals(newColor)) - { - sprite.Color = sprite.Color.WithAlpha(newColor); + _comps.Add(fading); + var newColor = Math.Max(sprite.Color.A - change, TargetAlpha); + + if (!sprite.Color.A.Equals(newColor)) + { + sprite.Color = sprite.Color.WithAlpha(newColor); + } } } } + } + /// + /// Bring sprites back up to their original alpha if they aren't in the fade set, and removes their fade component when done + /// + private void FadeOut(float change) + { var query = AllEntityQuery(); while (query.MoveNext(out var uid, out var comp)) { @@ -106,6 +156,16 @@ public sealed class SpriteFadeSystem : EntitySystem RemCompDeferred(uid); } } + } + + public override void FrameUpdate(float frameTime) + { + base.FrameUpdate(frameTime); + + var change = ChangeRate * frameTime; + + FadeIn(change); + FadeOut(change); _comps.Clear(); } diff --git a/Content.IntegrationTests/Tests/ClickableTest.cs b/Content.IntegrationTests/Tests/ClickableTest.cs index 5983650908..e6d94a43f9 100644 --- a/Content.IntegrationTests/Tests/ClickableTest.cs +++ b/Content.IntegrationTests/Tests/ClickableTest.cs @@ -80,7 +80,7 @@ namespace Content.IntegrationTests.Tests var pos = clientEntManager.System().GetWorldPosition(clientEnt); - hit = clientEntManager.System().CheckClick((clientEnt, null, sprite, null), new Vector2(clickPosX, clickPosY) + pos, eye, out _, out _, out _); + hit = clientEntManager.System().CheckClick((clientEnt, null, sprite, null), new Vector2(clickPosX, clickPosY) + pos, eye, false, out _, out _, out _); }); await server.WaitPost(() => From c877941aba9ba6963b280e241c57aa21b361346f Mon Sep 17 00:00:00 2001 From: PJBot Date: Thu, 3 Apr 2025 06:59:12 +0000 Subject: [PATCH 17/42] Automatic changelog update --- Resources/Changelog/Changelog.yml | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 1e22adcdd6..dedd88d179 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,12 +1,4 @@ Entries: -- author: Plykiya - changes: - - message: The crew monitoring crate now contains a flatpack of the server and computers, - and can be opened with science access instead of engineering access now. - type: Tweak - id: 7626 - time: '2024-11-20T01:05:20.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/33417 - author: Beck Thompson changes: - message: Toggle verbs are no longer duplicated on magboots and fire extinguishers! @@ -3899,3 +3891,12 @@ id: 8125 time: '2025-04-03T06:29:52.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/36212 +- author: sowelipililimute + changes: + - message: You can now more easily interact with objects behind faded ones, and + you can look behind fadeable objects in your FOV by hovering them with your + mouse pointer + type: Add + id: 8126 + time: '2025-04-03T06:58:05.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/35863 From 983cf150e0ee4efc17c396239a6d93536378741c Mon Sep 17 00:00:00 2001 From: Whatstone <166147148+whatston3@users.noreply.github.com> Date: Thu, 3 Apr 2025 10:45:04 -0400 Subject: [PATCH 18/42] Recipes for curtains and tables using carpets now respect stacks. (#33721) * Carpet curtain/table recipes now respect stacks * remove unused colour carpet tags * Remove the tags outright --- .../Entities/Objects/Misc/carpets.yml | 30 ------- .../Graphs/furniture/curtains.yml | 85 +++++++------------ .../Construction/Graphs/furniture/tables.yml | 63 ++++---------- Resources/Prototypes/tags.yml | 30 ------- 4 files changed, 47 insertions(+), 161 deletions(-) diff --git a/Resources/Prototypes/Entities/Objects/Misc/carpets.yml b/Resources/Prototypes/Entities/Objects/Misc/carpets.yml index dca2d40aed..5cc8035875 100644 --- a/Resources/Prototypes/Entities/Objects/Misc/carpets.yml +++ b/Resources/Prototypes/Entities/Objects/Misc/carpets.yml @@ -14,9 +14,6 @@ - Plating - type: Stack stackType: FloorCarpetRed - - type: Tag - tags: - - CarpetRed - type: SpawnAfterInteract #Nuke after convert to FloorTile prototype: Carpet doAfter: 0.5 @@ -33,9 +30,6 @@ heldPrefix: carpet-black - type: Stack stackType: FloorCarpetBlack - - type: Tag - tags: - - CarpetBlack - type: SpawnAfterInteract #Nuke after convert to FloorTile prototype: CarpetBlack doAfter: 0.5 @@ -52,9 +46,6 @@ heldPrefix: carpet-blue - type: Stack stackType: FloorCarpetBlue - - type: Tag - tags: - - CarpetBlue - type: SpawnAfterInteract #Nuke after convert to FloorTile prototype: CarpetBlue doAfter: 0.5 @@ -71,9 +62,6 @@ heldPrefix: carpet-green - type: Stack stackType: FloorCarpetGreen - - type: Tag - tags: - - CarpetGreen - type: SpawnAfterInteract #Nuke after convert to FloorTile prototype: CarpetGreen doAfter: 0.5 @@ -90,9 +78,6 @@ heldPrefix: carpet-orange - type: Stack stackType: FloorCarpetOrange - - type: Tag - tags: - - CarpetOrange - type: SpawnAfterInteract #Nuke after convert to FloorTile prototype: CarpetOrange doAfter: 0.5 @@ -109,9 +94,6 @@ heldPrefix: carpet-skyblue - type: Stack stackType: FloorCarpetSkyBlue - - type: Tag - tags: - - CarpetSBlue - type: SpawnAfterInteract #Nuke after convert to FloorTile prototype: CarpetSBlue doAfter: 0.5 @@ -128,9 +110,6 @@ heldPrefix: carpet-purple - type: Stack stackType: FloorCarpetPurple - - type: Tag - tags: - - CarpetPurple - type: SpawnAfterInteract #Nuke after convert to FloorTile prototype: CarpetPurple doAfter: 0.5 @@ -147,9 +126,6 @@ heldPrefix: carpet-pink - type: Stack stackType: FloorCarpetPink - - type: Tag - tags: - - CarpetPink - type: SpawnAfterInteract #Nuke after convert to FloorTile prototype: CarpetPink doAfter: 0.5 @@ -166,9 +142,6 @@ heldPrefix: carpet-cyan - type: Stack stackType: FloorCarpetCyan - - type: Tag - tags: - - CarpetCyan - type: SpawnAfterInteract #Nuke after convert to FloorTile prototype: CarpetCyan doAfter: 0.5 @@ -185,9 +158,6 @@ heldPrefix: carpet-white - type: Stack stackType: FloorCarpetWhite - - type: Tag - tags: - - CarpetWhite - type: SpawnAfterInteract #Nuke after convert to FloorTile prototype: CarpetWhite doAfter: 0.5 diff --git a/Resources/Prototypes/Recipes/Construction/Graphs/furniture/curtains.yml b/Resources/Prototypes/Recipes/Construction/Graphs/furniture/curtains.yml index 90e77d6720..21492af6a9 100644 --- a/Resources/Prototypes/Recipes/Construction/Graphs/furniture/curtains.yml +++ b/Resources/Prototypes/Recipes/Construction/Graphs/furniture/curtains.yml @@ -17,93 +17,66 @@ completed: - !type:SnapToGrid { } steps: - - tag: CarpetBlack + - material: FloorCarpetBlack + amount: 1 doAfter: 1 - name: black carpet - icon: - sprite: Objects/Tiles/tile.rsi - state: carpet-black - to: CurtainsBlue completed: - !type:SnapToGrid { } steps: - - tag: CarpetBlue + - material: FloorCarpetBlue + amount: 1 doAfter: 1 - name: blue carpet - icon: - sprite: Objects/Tiles/tile.rsi - state: carpet-blue - to: CurtainsCyan completed: - !type:SnapToGrid { } steps: - - tag: CarpetCyan + - material: FloorCarpetCyan + amount: 1 doAfter: 1 - name: cyan carpet - icon: - sprite: Objects/Tiles/tile.rsi - state: carpet-cyan - to: CurtainsGreen completed: - !type:SnapToGrid { } steps: - - tag: CarpetGreen + - material: FloorCarpetGreen + amount: 1 doAfter: 1 - name: green carpet - icon: - sprite: Objects/Tiles/tile.rsi - state: carpet-green - to: CurtainsOrange completed: - !type:SnapToGrid { } steps: - - tag: CarpetOrange + - material: FloorCarpetOrange + amount: 1 doAfter: 1 - name: orange carpet - icon: - sprite: Objects/Tiles/tile.rsi - state: carpet-orange - to: CurtainsPink completed: - !type:SnapToGrid { } steps: - - tag: CarpetPink + - material: FloorCarpetPink + amount: 1 doAfter: 1 - name: pink carpet - icon: - sprite: Objects/Tiles/tile.rsi - state: carpet-pink - to: CurtainsPurple completed: - !type:SnapToGrid { } steps: - - tag: CarpetPurple + - material: FloorCarpetPurple + amount: 1 doAfter: 1 - name: purple carpet - icon: - sprite: Objects/Tiles/tile.rsi - state: carpet-purple - to: CurtainsRed completed: - !type:SnapToGrid { } steps: - - tag: CarpetRed + - material: FloorCarpetRed + amount: 1 doAfter: 1 - name: red carpet - icon: - sprite: Objects/Tiles/tile.rsi - state: carpet-red - to: CurtainsWhite completed: - !type:SnapToGrid { } steps: - - tag: CarpetWhite + - material: FloorCarpetWhite + amount: 1 doAfter: 1 - name: white carpet - icon: - sprite: Objects/Tiles/tile.rsi - state: carpet-white - + - node: Curtains entity: HospitalCurtains edges: @@ -126,7 +99,7 @@ steps: - tool: Cutting doAfter: 1 - + - node: CurtainsBlack entity: CurtainsBlack edges: @@ -148,8 +121,8 @@ amount: 1 steps: - tool: Cutting - doAfter: 1 - + doAfter: 1 + - node: CurtainsBlue entity: CurtainsBlue edges: @@ -172,7 +145,7 @@ steps: - tool: Cutting doAfter: 1 - + - node: CurtainsCyan entity: CurtainsCyan edges: @@ -195,7 +168,7 @@ steps: - tool: Cutting doAfter: 1 - + - node: CurtainsGreen entity: CurtainsGreen edges: @@ -218,7 +191,7 @@ steps: - tool: Cutting doAfter: 1 - + - node: CurtainsOrange entity: CurtainsOrange edges: @@ -241,7 +214,7 @@ steps: - tool: Cutting doAfter: 1 - + - node: CurtainsPink entity: CurtainsPink edges: @@ -264,7 +237,7 @@ steps: - tool: Cutting doAfter: 1 - + - node: CurtainsPurple entity: CurtainsPurple edges: @@ -287,7 +260,7 @@ steps: - tool: Cutting doAfter: 1 - + - node: CurtainsRed entity: CurtainsRed edges: @@ -310,7 +283,7 @@ steps: - tool: Cutting doAfter: 1 - + - node: CurtainsWhite entity: CurtainsWhite edges: diff --git a/Resources/Prototypes/Recipes/Construction/Graphs/furniture/tables.yml b/Resources/Prototypes/Recipes/Construction/Graphs/furniture/tables.yml index d7ef51e96b..4cee536bf9 100644 --- a/Resources/Prototypes/Recipes/Construction/Graphs/furniture/tables.yml +++ b/Resources/Prototypes/Recipes/Construction/Graphs/furniture/tables.yml @@ -218,75 +218,48 @@ - to: TableFancyBlack steps: - - tag: CarpetBlack - name: black carpet - icon: - sprite: Objects/Tiles/tile.rsi - state: carpet-black + - material: FloorCarpetBlack + amount: 1 - to: TableFancyBlue steps: - - tag: CarpetBlue - name: blue carpet - icon: - sprite: Objects/Tiles/tile.rsi - state: carpet-blue + - material: FloorCarpetBlue + amount: 1 - to: TableFancyCyan steps: - - tag: CarpetCyan - name: cyan carpet - icon: - sprite: Objects/Tiles/tile.rsi - state: carpet-cyan + - material: FloorCarpetCyan + amount: 1 - to: TableFancyGreen steps: - - tag: CarpetGreen - name: green carpet - icon: - sprite: Objects/Tiles/tile.rsi - state: carpet-green + - material: FloorCarpetGreen + amount: 1 - to: TableFancyOrange steps: - - tag: CarpetOrange - name: orange carpet - icon: - sprite: Objects/Tiles/tile.rsi - state: carpet-orange + - material: FloorCarpetOrange + amount: 1 - to: TableFancyPurple steps: - - tag: CarpetPurple - name: purple carpet - icon: - sprite: Objects/Tiles/tile.rsi - state: carpet-purple + - material: FloorCarpetPurple + amount: 1 - to: TableFancyPink steps: - - tag: CarpetPink - name: pink carpet - icon: - sprite: Objects/Tiles/tile.rsi - state: carpet-pink + - material: FloorCarpetPink + amount: 1 - to: TableFancyRed steps: - - tag: CarpetRed - name: red carpet - icon: - sprite: Objects/Tiles/tile.rsi - state: carpet-red + - material: FloorCarpetRed + amount: 1 - to: TableFancyWhite steps: - - tag: CarpetWhite - name: white carpet - icon: - sprite: Objects/Tiles/tile.rsi - state: carpet-white + - material: FloorCarpetWhite + amount: 1 - node: TableCarpet entity: TableCarpet diff --git a/Resources/Prototypes/tags.yml b/Resources/Prototypes/tags.yml index 6577b7eb89..952ab4f909 100644 --- a/Resources/Prototypes/tags.yml +++ b/Resources/Prototypes/tags.yml @@ -222,36 +222,6 @@ - type: Tag id: Carpet -- type: Tag - id: CarpetBlack - -- type: Tag - id: CarpetBlue - -- type: Tag - id: CarpetCyan - -- type: Tag - id: CarpetGreen - -- type: Tag - id: CarpetOrange - -- type: Tag - id: CarpetPink - -- type: Tag - id: CarpetPurple - -- type: Tag - id: CarpetRed - -- type: Tag - id: CarpetSBlue - -- type: Tag - id: CarpetWhite - - type: Tag id: Carrot From f2391cbcc932390f2f0c83cf5a057a5bf1265dc5 Mon Sep 17 00:00:00 2001 From: PJBot Date: Thu, 3 Apr 2025 14:46:11 +0000 Subject: [PATCH 19/42] 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 dedd88d179..41ef180a9b 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,11 +1,4 @@ Entries: -- author: Beck Thompson - changes: - - message: Toggle verbs are no longer duplicated on magboots and fire extinguishers! - type: Fix - id: 7627 - time: '2024-11-20T01:53:53.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/32138 - author: qwerltaz changes: - message: A new grid item view is available in the construction menu, togglable @@ -3900,3 +3893,10 @@ id: 8126 time: '2025-04-03T06:58:05.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/35863 +- author: whatston3 + changes: + - message: Fancy tables and curtains now respect carpet stacks. + type: Fix + id: 8127 + time: '2025-04-03T14:45:04.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/33721 From db623366188a8475aaa8b4f9f1bcf240db8068a9 Mon Sep 17 00:00:00 2001 From: "Luna \"YuNii\" Henrich" Date: Fri, 4 Apr 2025 00:24:30 +0200 Subject: [PATCH 20/42] Stop ghosts from being logged to Airlocks (#36261) * stop ghosts from being logged * thanks rider for the random import * add new tag PreventAccessLogging * once again removing random auto imports * inverted if for code readability * switch to ProtoId<> usage --- .../Access/Systems/AccessReaderSystem.cs | 16 ++++++++++------ .../Entities/Mobs/Player/admin_ghost.yml | 1 + Resources/Prototypes/tags.yml | 7 +++++-- 3 files changed, 16 insertions(+), 8 deletions(-) diff --git a/Content.Shared/Access/Systems/AccessReaderSystem.cs b/Content.Shared/Access/Systems/AccessReaderSystem.cs index 84de549b66..74cf74274d 100644 --- a/Content.Shared/Access/Systems/AccessReaderSystem.cs +++ b/Content.Shared/Access/Systems/AccessReaderSystem.cs @@ -12,6 +12,7 @@ using Robust.Shared.Containers; using Robust.Shared.GameStates; using Content.Shared.GameTicking; using Content.Shared.IdentityManagement; +using Content.Shared.Tag; using Robust.Shared.Collections; using Robust.Shared.Prototypes; using Robust.Shared.Timing; @@ -24,11 +25,14 @@ public sealed class AccessReaderSystem : EntitySystem [Dependency] private readonly InventorySystem _inventorySystem = default!; [Dependency] private readonly IGameTiming _gameTiming = default!; [Dependency] private readonly EmagSystem _emag = default!; + [Dependency] private readonly TagSystem _tag = default!; [Dependency] private readonly SharedGameTicker _gameTicker = default!; [Dependency] private readonly SharedHandsSystem _handsSystem = default!; [Dependency] private readonly SharedContainerSystem _containerSystem = default!; [Dependency] private readonly SharedStationRecordsSystem _recordsSystem = default!; + private static readonly ProtoId PreventAccessLoggingTag = "PreventAccessLogging"; + public override void Initialize() { base.Initialize(); @@ -115,13 +119,13 @@ public sealed class AccessReaderSystem : EntitySystem var access = FindAccessTags(user, accessSources); FindStationRecordKeys(user, out var stationKeys, accessSources); - if (IsAllowed(access, stationKeys, target, reader)) - { - LogAccess((target, reader), user); - return true; - } + if (!IsAllowed(access, stationKeys, target, reader)) + return false; - return false; + if (!_tag.HasTag(user, PreventAccessLoggingTag)) + LogAccess((target, reader), user); + + return true; } public bool GetMainAccessReader(EntityUid uid, [NotNullWhen(true)] out Entity? ent) diff --git a/Resources/Prototypes/Entities/Mobs/Player/admin_ghost.yml b/Resources/Prototypes/Entities/Mobs/Player/admin_ghost.yml index 8fecb53818..e4ce500487 100644 --- a/Resources/Prototypes/Entities/Mobs/Player/admin_ghost.yml +++ b/Resources/Prototypes/Entities/Mobs/Player/admin_ghost.yml @@ -14,6 +14,7 @@ - BypassDropChecks - NoConsoleSound - SilentStorageUser + - PreventAccessLogging - type: Input context: "aghost" - type: Ghost diff --git a/Resources/Prototypes/tags.yml b/Resources/Prototypes/tags.yml index 952ab4f909..8b2ae35873 100644 --- a/Resources/Prototypes/tags.yml +++ b/Resources/Prototypes/tags.yml @@ -1026,6 +1026,9 @@ - type: Tag id: Powerdrill +- type: Tag + id: PreventAccessLogging + - type: Tag id: PrisonUniform @@ -1287,10 +1290,10 @@ - type: Tag id: Truncheon - + - type: Tag id: TurretCompatibleWeapon # Used in the construction of sentry turrets - + - type: Tag id: TurretControlElectronics # Used in the construction of sentry turret control panels From 5d8e0bf95414ccc03584430009044e234b4c16f5 Mon Sep 17 00:00:00 2001 From: PJBot Date: Thu, 3 Apr 2025 22:25:39 +0000 Subject: [PATCH 21/42] Automatic changelog update --- Resources/Changelog/Changelog.yml | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 41ef180a9b..ba225543bc 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,14 +1,4 @@ Entries: -- author: qwerltaz - changes: - - message: A new grid item view is available in the construction menu, togglable - with a button. - type: Add - - message: Construction menu default window size was tweaked. - type: Tweak - id: 7628 - time: '2024-11-20T01:54:49.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/32577 - author: SpaceLizard24 changes: - message: Reduced crafting costs of colored light tubes. @@ -3900,3 +3890,10 @@ id: 8127 time: '2025-04-03T14:45:04.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/33721 +- author: YuNii + changes: + - message: Stop ghosts from being logged to airlocks + type: Fix + id: 8128 + time: '2025-04-03T22:24:30.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/36261 From 5a25ef08b112f2a3e20c72444dd0f5eb60f65440 Mon Sep 17 00:00:00 2001 From: Tayrtahn Date: Thu, 3 Apr 2025 21:28:26 -0400 Subject: [PATCH 22/42] Fix loc issues with syringes (#36285) Fix injector loc issues --- .../chemistry/components/injector-component.ftl | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Resources/Locale/en-US/chemistry/components/injector-component.ftl b/Resources/Locale/en-US/chemistry/components/injector-component.ftl index 24f524081e..0c3152774f 100644 --- a/Resources/Locale/en-US/chemistry/components/injector-component.ftl +++ b/Resources/Locale/en-US/chemistry/components/injector-component.ftl @@ -10,14 +10,14 @@ injector-volume-label = Volume: [color=white]{$currentVolume}/{$totalVolume}[/co injector-component-drawing-text = Now drawing injector-component-injecting-text = Now injecting -injector-component-cannot-transfer-message = You aren't able to transfer to {$target}! -injector-component-cannot-draw-message = You aren't able to draw from {$target}! -injector-component-cannot-inject-message = You aren't able to inject to {$target}! -injector-component-inject-success-message = You inject {$amount}u into {$target}! -injector-component-transfer-success-message = You transfer {$amount}u into {$target}. -injector-component-draw-success-message = You draw {$amount}u from {$target}. -injector-component-target-already-full-message = {$target} is already full! -injector-component-target-is-empty-message = {$target} is empty! +injector-component-cannot-transfer-message = You aren't able to transfer to {THE($target)}! +injector-component-cannot-draw-message = You aren't able to draw from {THE($target)}! +injector-component-cannot-inject-message = You aren't able to inject to {THE($target)}! +injector-component-inject-success-message = You inject {$amount}u into {THE($target)}! +injector-component-transfer-success-message = You transfer {$amount}u into {THE($target)}. +injector-component-draw-success-message = You draw {$amount}u from {THE($target)}. +injector-component-target-already-full-message = {CAPITALIZE(THE($target))} is already full! +injector-component-target-is-empty-message = {CAPITALIZE(THE($target))} is empty! injector-component-cannot-toggle-draw-message = Too full to draw! injector-component-cannot-toggle-inject-message = Nothing to inject! From 444ef029bc0c7383e6cec5d113dda3b1045188e6 Mon Sep 17 00:00:00 2001 From: SlamBamActionman <83650252+SlamBamActionman@users.noreply.github.com> Date: Fri, 4 Apr 2025 11:18:02 +0200 Subject: [PATCH 23/42] [Hotfix] Change ID card console admin log severity to Medium (#36283) It's that simple --- Content.Server/Access/Systems/IdCardConsoleSystem.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Content.Server/Access/Systems/IdCardConsoleSystem.cs b/Content.Server/Access/Systems/IdCardConsoleSystem.cs index c8fbe2ba9d..a9e5d9a6d3 100644 --- a/Content.Server/Access/Systems/IdCardConsoleSystem.cs +++ b/Content.Server/Access/Systems/IdCardConsoleSystem.cs @@ -168,7 +168,7 @@ public sealed class IdCardConsoleSystem : SharedIdCardConsoleSystem /*TODO: ECS SharedIdCardConsoleComponent and then log on card ejection, together with the save. This current implementation is pretty shit as it logs 27 entries (27 lines) if someone decides to give themselves AA*/ - _adminLogger.Add(LogType.Action, LogImpact.High, + _adminLogger.Add(LogType.Action, LogImpact.Medium, $"{ToPrettyString(player):player} has modified {ToPrettyString(targetId):entity} with the following accesses: [{string.Join(", ", addedTags.Union(removedTags))}] [{string.Join(", ", newAccessList)}]"); } From d295aed7911127d9928b6fb37b99fe8411038fc8 Mon Sep 17 00:00:00 2001 From: Tayrtahn Date: Fri, 4 Apr 2025 05:41:21 -0400 Subject: [PATCH 24/42] Fix loc issues with suicide popup (#36284) --- Content.Server/Chat/SuicideSystem.cs | 3 ++- Resources/Locale/en-US/chat/commands/suicide-command.ftl | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Content.Server/Chat/SuicideSystem.cs b/Content.Server/Chat/SuicideSystem.cs index 4eda532385..497c9a1fe4 100644 --- a/Content.Server/Chat/SuicideSystem.cs +++ b/Content.Server/Chat/SuicideSystem.cs @@ -4,6 +4,7 @@ using Content.Shared.Chat; using Content.Shared.Damage; using Content.Shared.Database; using Content.Shared.Hands.Components; +using Content.Shared.IdentityManagement; using Content.Shared.Interaction.Events; using Content.Shared.Item; using Content.Shared.Mind; @@ -149,7 +150,7 @@ public sealed class SuicideSystem : EntitySystem if (args.Handled) return; - var othersMessage = Loc.GetString("suicide-command-default-text-others", ("name", victim)); + var othersMessage = Loc.GetString("suicide-command-default-text-others", ("name", Identity.Entity(victim, EntityManager))); _popup.PopupEntity(othersMessage, victim, Filter.PvsExcept(victim), true); var selfMessage = Loc.GetString("suicide-command-default-text-self"); diff --git a/Resources/Locale/en-US/chat/commands/suicide-command.ftl b/Resources/Locale/en-US/chat/commands/suicide-command.ftl index 36e861169b..4b2fb5c00e 100644 --- a/Resources/Locale/en-US/chat/commands/suicide-command.ftl +++ b/Resources/Locale/en-US/chat/commands/suicide-command.ftl @@ -3,7 +3,7 @@ suicide-command-help-text = The suicide command gives you a quick way out of a r The method varies, first it will attempt to use the held item in your active hand. If that fails, it will attempt to use an object in the environment. Finally, if neither of the above worked, you will die by biting your tongue. -suicide-command-default-text-others = {$name} is attempting to bite their own tongue! +suicide-command-default-text-others = {CAPITALIZE(THE($name))} is attempting to bite {POSS-ADJ($name)} own tongue! suicide-command-default-text-self = You attempt to bite your own tongue! suicide-command-already-dead = You can't suicide. You're dead. suicide-command-no-mind = You have no mind! From dfbcfaf45dea6673ad0000450ad269fa7f90517a Mon Sep 17 00:00:00 2001 From: K-Dynamic <20566341+K-Dynamic@users.noreply.github.com> Date: Sat, 5 Apr 2025 01:12:04 +1200 Subject: [PATCH 25/42] Add PKA and PTK-800 shuttle gun recipes to sec techfab (#34566) * add Magboots and PKA to sec lathe * add kinetic shuttle gun to sec lathe * use pack recipe * remove magboot from prior commit --- .../Prototypes/Entities/Structures/Machines/lathe.yml | 2 ++ Resources/Prototypes/Recipes/Lathes/Packs/shared.yml | 10 ++++++++++ 2 files changed, 12 insertions(+) diff --git a/Resources/Prototypes/Entities/Structures/Machines/lathe.yml b/Resources/Prototypes/Entities/Structures/Machines/lathe.yml index 106448b2e3..cf3bcac302 100644 --- a/Resources/Prototypes/Entities/Structures/Machines/lathe.yml +++ b/Resources/Prototypes/Entities/Structures/Machines/lathe.yml @@ -394,6 +394,8 @@ - SecurityAmmoStatic - SecurityWeaponsStatic dynamicPacks: + - SalvageSecurityBoards + - SalvageSecurityWeapons - SecurityEquipment - SecurityBoards - SecurityExplosives diff --git a/Resources/Prototypes/Recipes/Lathes/Packs/shared.yml b/Resources/Prototypes/Recipes/Lathes/Packs/shared.yml index 44ba33cf8b..6fb00c0257 100644 --- a/Resources/Prototypes/Recipes/Lathes/Packs/shared.yml +++ b/Resources/Prototypes/Recipes/Lathes/Packs/shared.yml @@ -49,3 +49,13 @@ - HandHeldMassScanner - ClothingMaskWeldingGas - SignallerAdvanced + +- type: latheRecipePack + id: SalvageSecurityBoards + recipes: + - ShuttleGunKineticCircuitboard + +- type: latheRecipePack + id: SalvageSecurityWeapons + recipes: + - WeaponProtoKineticAccelerator From ba2a89ecfcc3941734279bbf3eb6731ed809f303 Mon Sep 17 00:00:00 2001 From: PJBot Date: Fri, 4 Apr 2025 13:13:11 +0000 Subject: [PATCH 26/42] 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 ba225543bc..e14d881fa7 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,11 +1,4 @@ Entries: -- author: SpaceLizard24 - changes: - - message: Reduced crafting costs of colored light tubes. - type: Tweak - id: 7629 - time: '2024-11-20T01:59:31.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/33376 - author: thetolbean changes: - message: Items with a damage of 0 now have correct damage examination text. @@ -3897,3 +3890,11 @@ id: 8128 time: '2025-04-03T22:24:30.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/36261 +- author: K-Dynamic + changes: + - message: Proto-Kinetic Accelerators and PTK-800 Shuttle Gun recipes are now available + to the security techfab when researched by science. + type: Add + id: 8129 + time: '2025-04-04T13:12:04.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/34566 From 593804b51792b70c37fe8c58db6b74ba4978d437 Mon Sep 17 00:00:00 2001 From: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com> Date: Sat, 5 Apr 2025 00:33:52 +1100 Subject: [PATCH 27/42] Mob collisions (#34580) * Conveyor optimisations - Optimise movement for moving stuff. Better flags + less resolves + slapped parallelrobustjob on it. - Sleeping for entities getting conveyed into walls. * Blocker version * Finish * Final * Mob collisions * impulses * Collision smoothing * Locked in * 30tps working * r * fixes * Best * Fixes + CVars * CVars in place * Pushies * Opt attempt 1 * Revert "Opt attempt 1" This reverts commit 5ccd72dcbea09261a992aa1f7f05df169a1ce676. * Fix mispredicts * Ready-ish * better * Cleanup * Fix conveyor power mispredict * Forgetting to actually do deltas * Fix buckle pushes * Bagel save * Revert "Bagel save" This reverts commit 1b93fda81fb852d89b89b0beae0b80f8a61165f2. * Conveyor resave * Fix prediction * Mob movement rewrite * Bandaid * Working version * Tentatively working * Friction to fix cornering * More fixes * Revert bagel * Revert this * Bad parity * Working * Fixes * Woops * Doc comments * Pen cap cvar * StandingState cleanup and sub * Fix downed mobs * fish * client * Disable pushing on tests * More variables * Movement mods * Mass diff * 1 more tweak * Cvar --- Content.Client/Buckle/BuckleSystem.cs | 10 + .../Movement/Systems/MobCollisionSystem.cs | 42 +++ .../Physics/Controllers/MoverController.cs | 8 +- Content.IntegrationTests/PoolManager.Cvars.cs | 1 + .../Commands/ToggleMobCollisionCommand.cs | 24 ++ .../Movement/Systems/MobCollisionSystem.cs | 51 +++ Content.Shared/CCVar/CCVars.Movement.cs | 50 +++ Content.Shared/CCVar/CCVars.Physics.cs | 9 - .../Components/MobCollisionComponent.cs | 60 ++++ .../Systems/SharedMobCollisionSystem.cs | 338 ++++++++++++++++++ .../Systems/SharedMoverController.Relay.cs | 20 +- .../Movement/Systems/SharedMoverController.cs | 9 +- .../Controllers/SharedConveyorController.cs | 1 - .../Standing/StandingStateSystem.cs | 24 ++ .../ConfigPresets/Build/development.toml | 3 + .../ConfigPresets/WizardsDen/wizardsDen.toml | 3 + Resources/Prototypes/Entities/Mobs/base.yml | 1 + .../Storage/Canisters/gas_canisters.yml | 2 + 18 files changed, 631 insertions(+), 25 deletions(-) create mode 100644 Content.Client/Movement/Systems/MobCollisionSystem.cs create mode 100644 Content.Server/Movement/Commands/ToggleMobCollisionCommand.cs create mode 100644 Content.Server/Movement/Systems/MobCollisionSystem.cs create mode 100644 Content.Shared/CCVar/CCVars.Movement.cs create mode 100644 Content.Shared/Movement/Components/MobCollisionComponent.cs create mode 100644 Content.Shared/Movement/Systems/SharedMobCollisionSystem.cs diff --git a/Content.Client/Buckle/BuckleSystem.cs b/Content.Client/Buckle/BuckleSystem.cs index 40b2092a26..748f15922f 100644 --- a/Content.Client/Buckle/BuckleSystem.cs +++ b/Content.Client/Buckle/BuckleSystem.cs @@ -1,6 +1,7 @@ using Content.Client.Rotation; using Content.Shared.Buckle; using Content.Shared.Buckle.Components; +using Content.Shared.Movement.Systems; using Content.Shared.Rotation; using Robust.Client.GameObjects; using Robust.Client.Graphics; @@ -21,6 +22,15 @@ internal sealed class BuckleSystem : SharedBuckleSystem SubscribeLocalEvent(OnStrapMoveEvent); SubscribeLocalEvent(OnBuckledEvent); SubscribeLocalEvent(OnUnbuckledEvent); + SubscribeLocalEvent(OnMobCollide); + } + + private void OnMobCollide(Entity ent, ref AttemptMobCollideEvent args) + { + if (ent.Comp.Buckled) + { + args.Cancelled = true; + } } private void OnStrapMoveEvent(EntityUid uid, StrapComponent component, ref MoveEvent args) diff --git a/Content.Client/Movement/Systems/MobCollisionSystem.cs b/Content.Client/Movement/Systems/MobCollisionSystem.cs new file mode 100644 index 0000000000..b7d464afab --- /dev/null +++ b/Content.Client/Movement/Systems/MobCollisionSystem.cs @@ -0,0 +1,42 @@ +using System.Numerics; +using Content.Shared.CCVar; +using Content.Shared.Movement.Components; +using Content.Shared.Movement.Systems; +using Robust.Client.Player; +using Robust.Shared.Physics.Components; +using Robust.Shared.Timing; + +namespace Content.Client.Movement.Systems; + +public sealed class MobCollisionSystem : SharedMobCollisionSystem +{ + [Dependency] private readonly IGameTiming _timing = default!; + [Dependency] private readonly IPlayerManager _player = default!; + + public override void Update(float frameTime) + { + if (!CfgManager.GetCVar(CCVars.MovementMobPushing)) + return; + + if (_timing.IsFirstTimePredicted) + { + var player = _player.LocalEntity; + + if (MobQuery.TryComp(player, out var comp) && PhysicsQuery.TryComp(player, out var physics)) + { + HandleCollisions((player.Value, comp, physics), frameTime); + } + } + + base.Update(frameTime); + } + + protected override void RaiseCollisionEvent(EntityUid uid, Vector2 direction, float speedMod) + { + RaisePredictiveEvent(new MobCollisionMessage() + { + Direction = direction, + SpeedModifier = speedMod, + }); + } +} diff --git a/Content.Client/Physics/Controllers/MoverController.cs b/Content.Client/Physics/Controllers/MoverController.cs index d2ac0cdefd..37e3d83ddb 100644 --- a/Content.Client/Physics/Controllers/MoverController.cs +++ b/Content.Client/Physics/Controllers/MoverController.cs @@ -62,16 +62,16 @@ public sealed class MoverController : SharedMoverController private void OnRelayPlayerAttached(Entity entity, ref LocalPlayerAttachedEvent args) { - Physics.UpdateIsPredicted(entity.Owner); - Physics.UpdateIsPredicted(entity.Comp.RelayEntity); + PhysicsSystem.UpdateIsPredicted(entity.Owner); + PhysicsSystem.UpdateIsPredicted(entity.Comp.RelayEntity); if (MoverQuery.TryGetComponent(entity.Comp.RelayEntity, out var inputMover)) SetMoveInput((entity.Comp.RelayEntity, inputMover), MoveButtons.None); } private void OnRelayPlayerDetached(Entity entity, ref LocalPlayerDetachedEvent args) { - Physics.UpdateIsPredicted(entity.Owner); - Physics.UpdateIsPredicted(entity.Comp.RelayEntity); + PhysicsSystem.UpdateIsPredicted(entity.Owner); + PhysicsSystem.UpdateIsPredicted(entity.Comp.RelayEntity); if (MoverQuery.TryGetComponent(entity.Comp.RelayEntity, out var inputMover)) SetMoveInput((entity.Comp.RelayEntity, inputMover), MoveButtons.None); } diff --git a/Content.IntegrationTests/PoolManager.Cvars.cs b/Content.IntegrationTests/PoolManager.Cvars.cs index 23f0ded7df..2c51bdbc3a 100644 --- a/Content.IntegrationTests/PoolManager.Cvars.cs +++ b/Content.IntegrationTests/PoolManager.Cvars.cs @@ -39,6 +39,7 @@ public static partial class PoolManager (CVars.NetBufferSize.Name, "0"), (CCVars.InteractionRateLimitCount.Name, "9999999"), (CCVars.InteractionRateLimitPeriod.Name, "0.1"), + (CCVars.MovementMobPushing.Name, "false"), }; public static async Task SetupCVars(RobustIntegrationTest.IntegrationInstance instance, PoolSettings settings) diff --git a/Content.Server/Movement/Commands/ToggleMobCollisionCommand.cs b/Content.Server/Movement/Commands/ToggleMobCollisionCommand.cs new file mode 100644 index 0000000000..8276291cb8 --- /dev/null +++ b/Content.Server/Movement/Commands/ToggleMobCollisionCommand.cs @@ -0,0 +1,24 @@ +using Content.Server.Administration; +using Content.Shared.Administration; +using Content.Shared.CCVar; +using Robust.Shared.Configuration; +using Robust.Shared.Console; + +namespace Content.Server.Movement.Commands; + +/// +/// Temporary command to enable admins to toggle the mob collision cvar. +/// +[AdminCommand(AdminFlags.VarEdit)] +public sealed class ToggleMobCollisionCommand : IConsoleCommand +{ + [Dependency] private readonly IConfigurationManager _cfgManager = default!; + + public string Command => "toggle_mob_collision"; + public string Description => "Toggles mob collision"; + public string Help => Description; + public void Execute(IConsoleShell shell, string argStr, string[] args) + { + _cfgManager.SetCVar(CCVars.MovementMobPushing, !_cfgManager.GetCVar(CCVars.MovementMobPushing)); + } +} diff --git a/Content.Server/Movement/Systems/MobCollisionSystem.cs b/Content.Server/Movement/Systems/MobCollisionSystem.cs new file mode 100644 index 0000000000..2badac5676 --- /dev/null +++ b/Content.Server/Movement/Systems/MobCollisionSystem.cs @@ -0,0 +1,51 @@ +using System.Numerics; +using Content.Shared.CCVar; +using Content.Shared.Movement.Components; +using Content.Shared.Movement.Systems; +using Robust.Shared.Player; + +namespace Content.Server.Movement.Systems; + +public sealed class MobCollisionSystem : SharedMobCollisionSystem +{ + private EntityQuery _actorQuery; + + public override void Initialize() + { + base.Initialize(); + _actorQuery = GetEntityQuery(); + SubscribeLocalEvent(OnServerMobCollision); + } + + private void OnServerMobCollision(Entity ent, ref MobCollisionMessage args) + { + MoveMob((ent.Owner, ent.Comp, Transform(ent.Owner)), args.Direction, args.SpeedModifier); + } + + public override void Update(float frameTime) + { + if (!CfgManager.GetCVar(CCVars.MovementMobPushing)) + return; + + var query = EntityQueryEnumerator(); + + while (query.MoveNext(out var uid, out var comp)) + { + if (_actorQuery.HasComp(uid) || !PhysicsQuery.TryComp(uid, out var physics)) + continue; + + HandleCollisions((uid, comp, physics), frameTime); + } + + base.Update(frameTime); + } + + protected override void RaiseCollisionEvent(EntityUid uid, Vector2 direction, float speedMod) + { + RaiseLocalEvent(uid, new MobCollisionMessage() + { + Direction = direction, + SpeedModifier = speedMod, + }); + } +} diff --git a/Content.Shared/CCVar/CCVars.Movement.cs b/Content.Shared/CCVar/CCVars.Movement.cs new file mode 100644 index 0000000000..539a27c100 --- /dev/null +++ b/Content.Shared/CCVar/CCVars.Movement.cs @@ -0,0 +1,50 @@ +using Robust.Shared.Configuration; + +namespace Content.Shared.CCVar; + +public sealed partial class CCVars +{ + /// + /// Is mob pushing enabled. + /// + public static readonly CVarDef MovementMobPushing = + CVarDef.Create("movement.mob_pushing", false, CVar.SERVER | CVar.REPLICATED); + + /// + /// Can we push mobs not moving. + /// + public static readonly CVarDef MovementPushingStatic = + CVarDef.Create("movement.pushing_static", true, CVar.SERVER | CVar.REPLICATED); + + /// + /// Dot product for the pushed entity's velocity to a target entity's velocity before it gets moved. + /// + public static readonly CVarDef MovementPushingVelocityProduct = + CVarDef.Create("movement.pushing_velocity_product", 0.0f, CVar.SERVER | CVar.REPLICATED); + + /// + /// Cap for how much an entity can be pushed per second. + /// + public static readonly CVarDef MovementPushingCap = + CVarDef.Create("movement.pushing_cap", 100f, CVar.SERVER | CVar.REPLICATED); + + /// + /// Minimum pushing impulse per tick. If the value is below this it rounds to 0. + /// This is an optimisation to avoid pushing small values that won't actually move the mobs. + /// + public static readonly CVarDef MovementMinimumPush = + CVarDef.Create("movement.minimum_push", 0.1f, CVar.SERVER | CVar.REPLICATED); + + // Really this just exists because hot reloading is cooked on rider. + /// + /// Penetration depth cap for considering mob collisions. + /// + public static readonly CVarDef MovementPenetrationCap = + CVarDef.Create("movement.penetration_cap", 0.3f, CVar.SERVER | CVar.REPLICATED); + + /// + /// Based on the mass difference multiplies the push amount by this proportionally. + /// + public static readonly CVarDef MovementPushMassCap = + CVarDef.Create("movement.push_mass_cap", 1.75f, CVar.SERVER | CVar.REPLICATED); +} diff --git a/Content.Shared/CCVar/CCVars.Physics.cs b/Content.Shared/CCVar/CCVars.Physics.cs index 379676b5df..32f81f023d 100644 --- a/Content.Shared/CCVar/CCVars.Physics.cs +++ b/Content.Shared/CCVar/CCVars.Physics.cs @@ -15,13 +15,4 @@ public sealed partial class CCVars public static readonly CVarDef StopSpeed = CVarDef.Create("physics.stop_speed", 0.1f, CVar.ARCHIVE | CVar.REPLICATED | CVar.SERVER); - - /// - /// Whether mobs can push objects like lockers. - /// - /// - /// Technically client doesn't need to know about it but this may prevent a bug in the distant future so it stays. - /// - public static readonly CVarDef MobPushing = - CVarDef.Create("physics.mob_pushing", false, CVar.REPLICATED | CVar.SERVER); } diff --git a/Content.Shared/Movement/Components/MobCollisionComponent.cs b/Content.Shared/Movement/Components/MobCollisionComponent.cs new file mode 100644 index 0000000000..437cdfd409 --- /dev/null +++ b/Content.Shared/Movement/Components/MobCollisionComponent.cs @@ -0,0 +1,60 @@ +using System.Numerics; +using Content.Shared.Movement.Systems; +using Robust.Shared.GameStates; + +namespace Content.Shared.Movement.Components; + +/// +/// Handles mobs pushing against each other. +/// +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState(fieldDeltas: true)] +public sealed partial class MobCollisionComponent : Component +{ + // If you want to tweak the feel of the pushing use SpeedModifier and Strength. + // Strength goes both ways and affects how much the other mob is pushed by so controls static pushing a lot. + // Speed mod affects your own mob primarily. + + /// + /// Is this mob currently colliding? Used for SpeedModifier. + /// + [DataField, AutoNetworkedField] + public bool Colliding; + + // TODO: I hate this but also I couldn't quite figure out a way to avoid having to dirty it every tick. + // The issue is it's a time target that changes constantly so we can't just use a timespan. + // However that doesn't mean it should be modified every tick if we're still colliding. + + /// + /// Buffer time for to keep applying after the entities are no longer colliding. + /// Without this you will get jittering unless you are very specific with your values. + /// + [DataField, AutoNetworkedField] + public float BufferAccumulator = SharedMobCollisionSystem.BufferTime; + + /// + /// The speed modifier for mobs currently pushing. + /// By setting this low you can ensure you don't have to set the push-strength too high if you can push static entities. + /// + [DataField, AutoNetworkedField] + public float SpeedModifier = 1f; + + [DataField, AutoNetworkedField] + public float MinimumSpeedModifier = 0.35f; + + /// + /// Strength of the pushback for entities. This is combined between the 2 entities being pushed. + /// + [DataField, AutoNetworkedField] + public float Strength = 50f; + + // Yes I know, I will deal with it if I ever refactor collision layers due to misuse. + // If anything it probably needs some assurance on mobcollisionsystem for it. + /// + /// Fixture to listen to for mob collisions. + /// + [DataField, AutoNetworkedField] + public string FixtureId = "flammable"; + + [DataField, AutoNetworkedField] + public Vector2 Direction; +} diff --git a/Content.Shared/Movement/Systems/SharedMobCollisionSystem.cs b/Content.Shared/Movement/Systems/SharedMobCollisionSystem.cs new file mode 100644 index 0000000000..bcc1fd6d04 --- /dev/null +++ b/Content.Shared/Movement/Systems/SharedMobCollisionSystem.cs @@ -0,0 +1,338 @@ +using System.Numerics; +using Content.Shared.CCVar; +using Content.Shared.Movement.Components; +using Robust.Shared; +using Robust.Shared.Configuration; +using Robust.Shared.Physics; +using Robust.Shared.Physics.Components; +using Robust.Shared.Physics.Systems; +using Robust.Shared.Random; +using Robust.Shared.Serialization; +using Robust.Shared.Utility; + +namespace Content.Shared.Movement.Systems; + +public abstract class SharedMobCollisionSystem : EntitySystem +{ + [Dependency] protected readonly IConfigurationManager CfgManager = default!; + [Dependency] private readonly IRobustRandom _random = default!; + [Dependency] private readonly MovementSpeedModifierSystem _moveMod = default!; + [Dependency] protected readonly SharedPhysicsSystem Physics = default!; + [Dependency] private readonly SharedTransformSystem _xformSystem = default!; + + protected EntityQuery MobQuery; + protected EntityQuery PhysicsQuery; + + /// + /// + /// + private float _pushingCap; + + /// + /// + /// + private float _pushingDotProduct; + + /// + /// + /// + private float _minimumPushSquared = 0.01f; + + private float _penCap; + + /// + /// Time after we stop colliding with another mob before adjusting the movespeedmodifier. + /// This is required so if we stop colliding for a frame we don't fully reset and get jerky movement. + /// + public const float BufferTime = 0.2f; + + private float _massDiffCap; + + public override void Initialize() + { + base.Initialize(); + + UpdatePushCap(); + Subs.CVar(CfgManager, CVars.NetTickrate, _ => UpdatePushCap()); + Subs.CVar(CfgManager, CCVars.MovementMinimumPush, val => _minimumPushSquared = val * val, true); + Subs.CVar(CfgManager, CCVars.MovementPenetrationCap, val => _penCap = val, true); + Subs.CVar(CfgManager, CCVars.MovementPushingCap, _ => UpdatePushCap()); + Subs.CVar(CfgManager, CCVars.MovementPushingVelocityProduct, + value => + { + _pushingDotProduct = value; + }, true); + Subs.CVar(CfgManager, CCVars.MovementPushMassCap, val => _massDiffCap = val, true); + + MobQuery = GetEntityQuery(); + PhysicsQuery = GetEntityQuery(); + SubscribeAllEvent(OnCollision); + SubscribeLocalEvent(OnMoveModifier); + + UpdatesBefore.Add(typeof(SharedPhysicsSystem)); + } + + private void UpdatePushCap() + { + _pushingCap = (1f / CfgManager.GetCVar(CVars.NetTickrate)) * CfgManager.GetCVar(CCVars.MovementPushingCap); + } + + public override void Update(float frameTime) + { + base.Update(frameTime); + + var query = AllEntityQuery(); + + while (query.MoveNext(out var uid, out var comp)) + { + if (!comp.Colliding) + continue; + + comp.BufferAccumulator -= frameTime; + DirtyField(uid, comp, nameof(MobCollisionComponent.BufferAccumulator)); + var direction = comp.Direction; + + if (comp.BufferAccumulator <= 0f) + { + SetColliding((uid, comp), false, 1f); + } + // Apply the mob collision; if it's too low ignore it (e.g. if mob friction would overcome it). + // This is so we don't spam velocity changes every tick. It's not that expensive for physics but + // avoids the networking side. + else if (direction != Vector2.Zero && PhysicsQuery.TryComp(uid, out var physics)) + { + DebugTools.Assert(direction.LengthSquared() >= _minimumPushSquared); + + if (direction.Length() > _pushingCap) + { + direction = direction.Normalized() * _pushingCap; + } + + Physics.ApplyLinearImpulse(uid, direction * physics.Mass, body: physics); + comp.Direction = Vector2.Zero; + DirtyField(uid, comp, nameof(MobCollisionComponent.Direction)); + } + } + } + + private void OnMoveModifier(Entity ent, ref RefreshMovementSpeedModifiersEvent args) + { + if (!ent.Comp.Colliding) + return; + + args.ModifySpeed(ent.Comp.SpeedModifier); + } + + private void SetColliding(Entity entity, bool value, float speedMod) + { + if (value) + { + entity.Comp.BufferAccumulator = BufferTime; + DirtyField(entity.Owner, entity.Comp, nameof(MobCollisionComponent.BufferAccumulator)); + } + else + { + DebugTools.Assert(speedMod.Equals(1f)); + } + + if (entity.Comp.Colliding != value) + { + entity.Comp.Colliding = value; + DirtyField(entity.Owner, entity.Comp, nameof(MobCollisionComponent.Colliding)); + } + + if (!entity.Comp.SpeedModifier.Equals(speedMod)) + { + entity.Comp.SpeedModifier = speedMod; + _moveMod.RefreshMovementSpeedModifiers(entity.Owner); + DirtyField(entity.Owner, entity.Comp, nameof(MobCollisionComponent.SpeedModifier)); + } + } + + private void OnCollision(MobCollisionMessage msg, EntitySessionEventArgs args) + { + var player = args.SenderSession.AttachedEntity; + + if (!MobQuery.TryComp(player, out var comp)) + return; + + var xform = Transform(player.Value); + + // If not parented directly to a grid then fail it. + if (xform.ParentUid != xform.GridUid && xform.ParentUid != xform.MapUid) + return; + + var direction = msg.Direction; + + MoveMob((player.Value, comp, xform), direction, msg.SpeedModifier); + } + + protected void MoveMob(Entity entity, Vector2 direction, float speedMod) + { + // Length too short to do anything. + var pushing = true; + + if (direction.LengthSquared() < _minimumPushSquared) + { + pushing = false; + direction = Vector2.Zero; + speedMod = 1f; + } + else if (float.IsNaN(direction.X) || float.IsNaN(direction.Y)) + { + direction = Vector2.Zero; + } + + speedMod = Math.Clamp(speedMod, 0f, 1f); + + SetColliding(entity, pushing, speedMod); + + if (direction == entity.Comp1.Direction) + return; + + entity.Comp1.Direction = direction; + DirtyField(entity.Owner, entity.Comp1, nameof(MobCollisionComponent.Direction)); + } + + protected bool HandleCollisions(Entity entity, float frameTime) + { + var physics = entity.Comp2; + + if (physics.ContactCount == 0) + return false; + + var ourVelocity = entity.Comp2.LinearVelocity; + + if (ourVelocity == Vector2.Zero && !CfgManager.GetCVar(CCVars.MovementPushingStatic)) + return false; + + var xform = Transform(entity.Owner); + + if (xform.ParentUid != xform.GridUid && xform.ParentUid != xform.MapUid) + return false; + + var ev = new AttemptMobCollideEvent(); + + RaiseLocalEvent(entity.Owner, ref ev); + + if (ev.Cancelled) + return false; + + var (worldPos, worldRot) = _xformSystem.GetWorldPositionRotation(xform); + var ourTransform = new Transform(worldPos, worldRot); + var contacts = Physics.GetContacts(entity.Owner); + var direction = Vector2.Zero; + var contactCount = 0; + var ourMass = physics.FixturesMass; + var speedMod = 1f; + + while (contacts.MoveNext(out var contact)) + { + if (!contact.IsTouching) + continue; + + var ourFixture = contact.OurFixture(entity.Owner); + + if (ourFixture.Id != entity.Comp1.FixtureId) + continue; + + var other = contact.OtherEnt(entity.Owner); + + if (!MobQuery.TryComp(other, out var otherComp) || !PhysicsQuery.TryComp(other, out var otherPhysics)) + continue; + + var velocityProduct = Vector2.Dot(ourVelocity, otherPhysics.LinearVelocity); + + // If we're moving opposite directions for example then ignore (based on cvar). + if (velocityProduct < _pushingDotProduct) + { + continue; + } + + var targetEv = new AttemptMobTargetCollideEvent(); + RaiseLocalEvent(other, ref targetEv); + + if (targetEv.Cancelled) + continue; + + // TODO: More robust overlap detection. + var otherTransform = Physics.GetPhysicsTransform(other); + var diff = ourTransform.Position - otherTransform.Position; + + if (diff == Vector2.Zero) + { + diff = _random.NextVector2(0.01f); + } + + // 0.7 for 0.35 + 0.35 for mob bounds (see TODO above). + // Clamp so we don't get a heap of penetration depth and suddenly lurch other mobs. + // This is also so we don't have to trigger the speed-cap above. + // Maybe we just do speedcap and dump this? Though it's less configurable and the cap is just there for cheaters. + var penDepth = Math.Clamp(0.7f - diff.Length(), 0f, _penCap); + + // Sum the strengths so we get pushes back the same amount (impulse-wise, ignoring prediction). + var mobMovement = penDepth * diff.Normalized() * (entity.Comp1.Strength + otherComp.Strength); + + // Big mob push smaller mob, needs fine-tuning and potentially another co-efficient. + if (_massDiffCap > 0f) + { + var modifier = Math.Clamp( + otherPhysics.FixturesMass / ourMass, + 1f / _massDiffCap, + _massDiffCap); + + mobMovement *= modifier; + + var speedReduction = 1f - entity.Comp1.MinimumSpeedModifier; + var speedModifier = Math.Clamp( + 1f - speedReduction * modifier, + entity.Comp1.MinimumSpeedModifier, 1f); + + speedMod = MathF.Min(speedModifier, 1f); + } + + // Need the push strength proportional to penetration depth. + direction += mobMovement; + contactCount++; + } + + if (direction == Vector2.Zero) + { + return contactCount > 0; + } + + direction *= frameTime; + RaiseCollisionEvent(entity.Owner, direction, speedMod); + return true; + } + + protected abstract void RaiseCollisionEvent(EntityUid uid, Vector2 direction, float speedmodifier); + + /// + /// Raised from client -> server indicating mob push direction OR server -> server for NPC mob pushes. + /// + [Serializable, NetSerializable] + protected sealed class MobCollisionMessage : EntityEventArgs + { + public Vector2 Direction; + public float SpeedModifier; + } +} + +/// +/// Raised on the entity itself when attempting to handle mob collisions. +/// +[ByRefEvent] +public record struct AttemptMobCollideEvent +{ + public bool Cancelled; +} + +/// +/// Raised on the other entity when attempting mob collisions. +/// +[ByRefEvent] +public record struct AttemptMobTargetCollideEvent +{ + public bool Cancelled; +} diff --git a/Content.Shared/Movement/Systems/SharedMoverController.Relay.cs b/Content.Shared/Movement/Systems/SharedMoverController.Relay.cs index 8156955377..f843b66435 100644 --- a/Content.Shared/Movement/Systems/SharedMoverController.Relay.cs +++ b/Content.Shared/Movement/Systems/SharedMoverController.Relay.cs @@ -14,12 +14,12 @@ public abstract partial class SharedMoverController private void OnAfterRelayTargetState(Entity entity, ref AfterAutoHandleStateEvent args) { - Physics.UpdateIsPredicted(entity.Owner); + PhysicsSystem.UpdateIsPredicted(entity.Owner); } private void OnAfterRelayState(Entity entity, ref AfterAutoHandleStateEvent args) { - Physics.UpdateIsPredicted(entity.Owner); + PhysicsSystem.UpdateIsPredicted(entity.Owner); } /// @@ -42,7 +42,7 @@ public abstract partial class SharedMoverController { oldTarget.Source = EntityUid.Invalid; RemComp(component.RelayEntity, oldTarget); - Physics.UpdateIsPredicted(component.RelayEntity); + PhysicsSystem.UpdateIsPredicted(component.RelayEntity); } var targetComp = EnsureComp(relayEntity); @@ -50,11 +50,11 @@ public abstract partial class SharedMoverController { oldRelay.RelayEntity = EntityUid.Invalid; RemComp(targetComp.Source, oldRelay); - Physics.UpdateIsPredicted(targetComp.Source); + PhysicsSystem.UpdateIsPredicted(targetComp.Source); } - Physics.UpdateIsPredicted(uid); - Physics.UpdateIsPredicted(relayEntity); + PhysicsSystem.UpdateIsPredicted(uid); + PhysicsSystem.UpdateIsPredicted(relayEntity); component.RelayEntity = relayEntity; targetComp.Source = uid; Dirty(uid, component); @@ -63,8 +63,8 @@ public abstract partial class SharedMoverController private void OnRelayShutdown(Entity entity, ref ComponentShutdown args) { - Physics.UpdateIsPredicted(entity.Owner); - Physics.UpdateIsPredicted(entity.Comp.RelayEntity); + PhysicsSystem.UpdateIsPredicted(entity.Owner); + PhysicsSystem.UpdateIsPredicted(entity.Comp.RelayEntity); if (TryComp(entity.Comp.RelayEntity, out var inputMover)) SetMoveInput((entity.Comp.RelayEntity, inputMover), MoveButtons.None); @@ -78,8 +78,8 @@ public abstract partial class SharedMoverController private void OnTargetRelayShutdown(Entity entity, ref ComponentShutdown args) { - Physics.UpdateIsPredicted(entity.Owner); - Physics.UpdateIsPredicted(entity.Comp.Source); + PhysicsSystem.UpdateIsPredicted(entity.Owner); + PhysicsSystem.UpdateIsPredicted(entity.Comp.Source); if (Timing.ApplyingState) return; diff --git a/Content.Shared/Movement/Systems/SharedMoverController.cs b/Content.Shared/Movement/Systems/SharedMoverController.cs index 6456444080..76e2f34368 100644 --- a/Content.Shared/Movement/Systems/SharedMoverController.cs +++ b/Content.Shared/Movement/Systems/SharedMoverController.cs @@ -43,7 +43,6 @@ public abstract partial class SharedMoverController : VirtualController [Dependency] private readonly SharedContainerSystem _container = default!; [Dependency] private readonly SharedMapSystem _mapSystem = default!; [Dependency] private readonly SharedGravitySystem _gravity = default!; - [Dependency] protected readonly SharedPhysicsSystem Physics = default!; [Dependency] private readonly SharedTransformSystem _transform = default!; [Dependency] private readonly TagSystem _tags = default!; @@ -105,6 +104,14 @@ public abstract partial class SharedMoverController : VirtualController public override void UpdateAfterSolve(bool prediction, float frameTime) { base.UpdateAfterSolve(prediction, frameTime); + + var query = AllEntityQuery(); + + while (query.MoveNext(out var uid, out var _, out var physics)) + { + //PhysicsSystem.SetLinearVelocity(uid, Vector2.Zero, body: physics); + } + UsedMobMovement.Clear(); } diff --git a/Content.Shared/Physics/Controllers/SharedConveyorController.cs b/Content.Shared/Physics/Controllers/SharedConveyorController.cs index 07bf6c7332..4b2523b1d7 100644 --- a/Content.Shared/Physics/Controllers/SharedConveyorController.cs +++ b/Content.Shared/Physics/Controllers/SharedConveyorController.cs @@ -1,7 +1,6 @@ using System.Numerics; using Content.Shared.Conveyor; using Content.Shared.Gravity; -using Content.Shared.Magic; using Content.Shared.Movement.Components; using Content.Shared.Movement.Events; using Content.Shared.Movement.Systems; diff --git a/Content.Shared/Standing/StandingStateSystem.cs b/Content.Shared/Standing/StandingStateSystem.cs index c534f47955..86d2b961eb 100644 --- a/Content.Shared/Standing/StandingStateSystem.cs +++ b/Content.Shared/Standing/StandingStateSystem.cs @@ -1,4 +1,5 @@ using Content.Shared.Hands.Components; +using Content.Shared.Movement.Systems; using Content.Shared.Physics; using Content.Shared.Rotation; using Robust.Shared.Audio.Systems; @@ -16,6 +17,29 @@ public sealed class StandingStateSystem : EntitySystem // If StandingCollisionLayer value is ever changed to more than one layer, the logic needs to be edited. private const int StandingCollisionLayer = (int) CollisionGroup.MidImpassable; + public override void Initialize() + { + base.Initialize(); + SubscribeLocalEvent(OnMobCollide); + SubscribeLocalEvent(OnMobTargetCollide); + } + + private void OnMobTargetCollide(Entity ent, ref AttemptMobTargetCollideEvent args) + { + if (!ent.Comp.Standing) + { + args.Cancelled = true; + } + } + + private void OnMobCollide(Entity ent, ref AttemptMobCollideEvent args) + { + if (!ent.Comp.Standing) + { + args.Cancelled = true; + } + } + public bool IsDown(EntityUid uid, StandingStateComponent? standingState = null) { if (!Resolve(uid, ref standingState, false)) diff --git a/Resources/ConfigPresets/Build/development.toml b/Resources/ConfigPresets/Build/development.toml index 7990b3545b..4465ea8ee0 100644 --- a/Resources/ConfigPresets/Build/development.toml +++ b/Resources/ConfigPresets/Build/development.toml @@ -15,6 +15,9 @@ quick_lottery = true [gateway] generator_enabled = false +[movement] +mob_pushing = true + [physics] # Makes mapping annoying grid_splitting = false diff --git a/Resources/ConfigPresets/WizardsDen/wizardsDen.toml b/Resources/ConfigPresets/WizardsDen/wizardsDen.toml index 558e60da69..b29ee87d5c 100644 --- a/Resources/ConfigPresets/WizardsDen/wizardsDen.toml +++ b/Resources/ConfigPresets/WizardsDen/wizardsDen.toml @@ -31,6 +31,9 @@ appeal = "https://appeal.ss14.io" [server] rules_file = "StandardRuleset" +[movement] +mob_pushing = true + [net] max_connections = 1024 diff --git a/Resources/Prototypes/Entities/Mobs/base.yml b/Resources/Prototypes/Entities/Mobs/base.yml index 970ec52cd7..f7c2f74411 100644 --- a/Resources/Prototypes/Entities/Mobs/base.yml +++ b/Resources/Prototypes/Entities/Mobs/base.yml @@ -8,6 +8,7 @@ - type: Sprite noRot: true drawdepth: Mobs + - type: MobCollision - type: Physics bodyType: KinematicController - type: Fixtures diff --git a/Resources/Prototypes/Entities/Structures/Storage/Canisters/gas_canisters.yml b/Resources/Prototypes/Entities/Structures/Storage/Canisters/gas_canisters.yml index 33c4dfbe17..12b3261dfa 100644 --- a/Resources/Prototypes/Entities/Structures/Storage/Canisters/gas_canisters.yml +++ b/Resources/Prototypes/Entities/Structures/Storage/Canisters/gas_canisters.yml @@ -65,6 +65,7 @@ - type: Damageable damageContainer: Inorganic damageModifierSet: Metallic + - type: MobCollision - type: Physics bodyType: Dynamic - type: Fixtures @@ -74,6 +75,7 @@ !type:PhysShapeAabb bounds: "-0.25,-0.25,0.25,0.25" density: 190 + hard: false mask: - SmallMobMask layer: From b501026dcda092e88aaf5a5745e5b6dc2f9922db Mon Sep 17 00:00:00 2001 From: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com> Date: Sat, 5 Apr 2025 02:14:04 +1100 Subject: [PATCH 28/42] Mob collision tweaks (#36296) * Mob collision tweaks - Remove the dot product default so moving also pops it. - Cleanup the cvars so admins can adjust * Gas canister revert --- .../Commands/ToggleMobCollisionCommand.cs | 24 ------------------- Content.Shared/CCVar/CCVars.Movement.cs | 11 ++++++++- .../Storage/Canisters/gas_canisters.yml | 2 -- 3 files changed, 10 insertions(+), 27 deletions(-) delete mode 100644 Content.Server/Movement/Commands/ToggleMobCollisionCommand.cs diff --git a/Content.Server/Movement/Commands/ToggleMobCollisionCommand.cs b/Content.Server/Movement/Commands/ToggleMobCollisionCommand.cs deleted file mode 100644 index 8276291cb8..0000000000 --- a/Content.Server/Movement/Commands/ToggleMobCollisionCommand.cs +++ /dev/null @@ -1,24 +0,0 @@ -using Content.Server.Administration; -using Content.Shared.Administration; -using Content.Shared.CCVar; -using Robust.Shared.Configuration; -using Robust.Shared.Console; - -namespace Content.Server.Movement.Commands; - -/// -/// Temporary command to enable admins to toggle the mob collision cvar. -/// -[AdminCommand(AdminFlags.VarEdit)] -public sealed class ToggleMobCollisionCommand : IConsoleCommand -{ - [Dependency] private readonly IConfigurationManager _cfgManager = default!; - - public string Command => "toggle_mob_collision"; - public string Description => "Toggles mob collision"; - public string Help => Description; - public void Execute(IConsoleShell shell, string argStr, string[] args) - { - _cfgManager.SetCVar(CCVars.MovementMobPushing, !_cfgManager.GetCVar(CCVars.MovementMobPushing)); - } -} diff --git a/Content.Shared/CCVar/CCVars.Movement.cs b/Content.Shared/CCVar/CCVars.Movement.cs index 539a27c100..39b9836c40 100644 --- a/Content.Shared/CCVar/CCVars.Movement.cs +++ b/Content.Shared/CCVar/CCVars.Movement.cs @@ -1,3 +1,5 @@ +using Content.Shared.Administration; +using Content.Shared.CCVar.CVarAccess; using Robust.Shared.Configuration; namespace Content.Shared.CCVar; @@ -7,24 +9,28 @@ public sealed partial class CCVars /// /// Is mob pushing enabled. /// + [CVarControl(AdminFlags.VarEdit)] public static readonly CVarDef MovementMobPushing = CVarDef.Create("movement.mob_pushing", false, CVar.SERVER | CVar.REPLICATED); /// /// Can we push mobs not moving. /// + [CVarControl(AdminFlags.VarEdit)] public static readonly CVarDef MovementPushingStatic = CVarDef.Create("movement.pushing_static", true, CVar.SERVER | CVar.REPLICATED); /// /// Dot product for the pushed entity's velocity to a target entity's velocity before it gets moved. /// + [CVarControl(AdminFlags.VarEdit)] public static readonly CVarDef MovementPushingVelocityProduct = - CVarDef.Create("movement.pushing_velocity_product", 0.0f, CVar.SERVER | CVar.REPLICATED); + CVarDef.Create("movement.pushing_velocity_product", -1f, CVar.SERVER | CVar.REPLICATED); /// /// Cap for how much an entity can be pushed per second. /// + [CVarControl(AdminFlags.VarEdit)] public static readonly CVarDef MovementPushingCap = CVarDef.Create("movement.pushing_cap", 100f, CVar.SERVER | CVar.REPLICATED); @@ -32,6 +38,7 @@ public sealed partial class CCVars /// Minimum pushing impulse per tick. If the value is below this it rounds to 0. /// This is an optimisation to avoid pushing small values that won't actually move the mobs. /// + [CVarControl(AdminFlags.VarEdit)] public static readonly CVarDef MovementMinimumPush = CVarDef.Create("movement.minimum_push", 0.1f, CVar.SERVER | CVar.REPLICATED); @@ -39,12 +46,14 @@ public sealed partial class CCVars /// /// Penetration depth cap for considering mob collisions. /// + [CVarControl(AdminFlags.VarEdit)] public static readonly CVarDef MovementPenetrationCap = CVarDef.Create("movement.penetration_cap", 0.3f, CVar.SERVER | CVar.REPLICATED); /// /// Based on the mass difference multiplies the push amount by this proportionally. /// + [CVarControl(AdminFlags.VarEdit)] public static readonly CVarDef MovementPushMassCap = CVarDef.Create("movement.push_mass_cap", 1.75f, CVar.SERVER | CVar.REPLICATED); } diff --git a/Resources/Prototypes/Entities/Structures/Storage/Canisters/gas_canisters.yml b/Resources/Prototypes/Entities/Structures/Storage/Canisters/gas_canisters.yml index 12b3261dfa..33c4dfbe17 100644 --- a/Resources/Prototypes/Entities/Structures/Storage/Canisters/gas_canisters.yml +++ b/Resources/Prototypes/Entities/Structures/Storage/Canisters/gas_canisters.yml @@ -65,7 +65,6 @@ - type: Damageable damageContainer: Inorganic damageModifierSet: Metallic - - type: MobCollision - type: Physics bodyType: Dynamic - type: Fixtures @@ -75,7 +74,6 @@ !type:PhysShapeAabb bounds: "-0.25,-0.25,0.25,0.25" density: 190 - hard: false mask: - SmallMobMask layer: From 4e33a288d2d4b59890fbe7cdae42b4f31776b471 Mon Sep 17 00:00:00 2001 From: lzk <124214523+lzk228@users.noreply.github.com> Date: Fri, 4 Apr 2025 17:36:28 +0200 Subject: [PATCH 29/42] fix implanting borgs and bots (#36218) * fix implanting borgs * fix --- .../Prototypes/Entities/Mobs/Cyborgs/base_borg_chassis.yml | 1 + Resources/Prototypes/Entities/Mobs/NPCs/silicon.yml | 2 ++ 2 files changed, 3 insertions(+) diff --git a/Resources/Prototypes/Entities/Mobs/Cyborgs/base_borg_chassis.yml b/Resources/Prototypes/Entities/Mobs/Cyborgs/base_borg_chassis.yml index 96e8eda43d..ce1fecd03a 100644 --- a/Resources/Prototypes/Entities/Mobs/Cyborgs/base_borg_chassis.yml +++ b/Resources/Prototypes/Entities/Mobs/Cyborgs/base_borg_chassis.yml @@ -236,6 +236,7 @@ - DoorBumpOpener - FootstepSound - CanPilot + - Unimplantable - type: Emoting - type: GuideHelp guides: diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/silicon.yml b/Resources/Prototypes/Entities/Mobs/NPCs/silicon.yml index 280df955af..3dae7023d9 100644 --- a/Resources/Prototypes/Entities/Mobs/NPCs/silicon.yml +++ b/Resources/Prototypes/Entities/Mobs/NPCs/silicon.yml @@ -66,6 +66,7 @@ tags: - DoorBumpOpener - Bot + - Unimplantable - type: MobState allowedStates: - Alive @@ -451,6 +452,7 @@ - DoorBumpOpener - FootstepSound - Bot + - Unimplantable - type: ActiveRadio channels: - Common From ed4d709c9e8cb56f0c95159ebcf993aa0a6ebadc Mon Sep 17 00:00:00 2001 From: PJBot Date: Fri, 4 Apr 2025 15:37:35 +0000 Subject: [PATCH 30/42] 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 e14d881fa7..4de5007bba 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,11 +1,4 @@ Entries: -- author: thetolbean - changes: - - message: Items with a damage of 0 now have correct damage examination text. - type: Fix - id: 7630 - time: '2024-11-20T02:05:15.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/33064 - author: SaphireLattice changes: - message: The Singularity/Tesla generator now requires being surrounded by containment @@ -3898,3 +3891,10 @@ id: 8129 time: '2025-04-04T13:12:04.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/34566 +- author: lzk228 + changes: + - message: Fix ability to use implants on borgs and bots. + type: Fix + id: 8130 + time: '2025-04-04T15:36:28.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/36218 From 21bad6ade157864ac31c89c0eb67ac651ce41878 Mon Sep 17 00:00:00 2001 From: TheBlueYowie Date: Sat, 5 Apr 2025 02:56:30 +1100 Subject: [PATCH 31/42] Rotate Adv Mineral Scanner in Inventory (#36294) --- .../Prototypes/Entities/Objects/Specific/Salvage/scanner.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Resources/Prototypes/Entities/Objects/Specific/Salvage/scanner.yml b/Resources/Prototypes/Entities/Objects/Specific/Salvage/scanner.yml index 9c3e783c51..d65c1e8bff 100644 --- a/Resources/Prototypes/Entities/Objects/Specific/Salvage/scanner.yml +++ b/Resources/Prototypes/Entities/Objects/Specific/Salvage/scanner.yml @@ -67,6 +67,8 @@ shader: unshaded visible: false map: ["enum.ToggleVisuals.Layer"] + - type: Item + storedRotation: -90 - type: MiningScanner range: 10 From b72674e738c87c2b88ad7fb81255fea657c8d41f Mon Sep 17 00:00:00 2001 From: PJBot Date: Fri, 4 Apr 2025 15:57:37 +0000 Subject: [PATCH 32/42] 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 4de5007bba..eaec751c86 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,12 +1,4 @@ Entries: -- author: SaphireLattice - changes: - - message: The Singularity/Tesla generator now requires being surrounded by containment - fields to activate. This can be disabled with an Emag. - type: Tweak - id: 7631 - time: '2024-11-20T05:55:58.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/33358 - author: TheWaffleJesus changes: - message: You can now craft items with stacks of capacitors without it eating it @@ -3898,3 +3890,10 @@ id: 8130 time: '2025-04-04T15:36:28.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/36218 +- author: TheBlueYowie + changes: + - message: Aligned Adv. Mineral Scanner rotation in inventory + type: Tweak + id: 8131 + time: '2025-04-04T15:56:30.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/36294 From 6000855bb21d0ffc8449dc84ef9d9a43e33abb39 Mon Sep 17 00:00:00 2001 From: Tayrtahn Date: Fri, 4 Apr 2025 13:46:59 -0400 Subject: [PATCH 33/42] Fix ninjas not being able to hack criminal records (#36299) Index reason placeholders prototype as a LocalizedDataset --- .../CriminalRecords/Systems/CriminalRecordsHackerSystem.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Content.Server/CriminalRecords/Systems/CriminalRecordsHackerSystem.cs b/Content.Server/CriminalRecords/Systems/CriminalRecordsHackerSystem.cs index b0181a0adc..04e08fac50 100644 --- a/Content.Server/CriminalRecords/Systems/CriminalRecordsHackerSystem.cs +++ b/Content.Server/CriminalRecords/Systems/CriminalRecordsHackerSystem.cs @@ -4,7 +4,7 @@ using Content.Server.StationRecords.Systems; using Content.Shared.CriminalRecords; using Content.Shared.CriminalRecords.Components; using Content.Shared.CriminalRecords.Systems; -using Content.Shared.Dataset; +using Content.Shared.Random.Helpers; using Content.Shared.Security; using Content.Shared.StationRecords; using Robust.Shared.Prototypes; @@ -36,10 +36,10 @@ public sealed class CriminalRecordsHackerSystem : SharedCriminalRecordsHackerSys if (_station.GetOwningStation(ent) is not {} station) return; - var reasons = _proto.Index(ent.Comp.Reasons); + var reasons = _proto.Index(ent.Comp.Reasons); foreach (var (key, record) in _records.GetRecordsOfType(station)) { - var reason = _random.Pick(reasons.Values); + var reason = _random.Pick(reasons); _criminalRecords.OverwriteStatus(new StationRecordKey(key, station), record, SecurityStatus.Wanted, reason); // no radio message since spam // no history since lazy and its easy to remove anyway From be809b9f655c4a688347f5f3e83a462713f6540d Mon Sep 17 00:00:00 2001 From: PJBot Date: Fri, 4 Apr 2025 17:48:06 +0000 Subject: [PATCH 34/42] 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 eaec751c86..1df1981b64 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,12 +1,4 @@ Entries: -- author: TheWaffleJesus - changes: - - message: You can now craft items with stacks of capacitors without it eating it - all! - type: Fix - id: 7632 - time: '2024-11-20T07:18:38.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/31966 - author: ScarKy0, GoldenCan changes: - message: Ion stormed lawsets no longer persist between shifts. @@ -3897,3 +3889,10 @@ id: 8131 time: '2025-04-04T15:56:30.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/36294 +- author: Tayrtahn + changes: + - message: Fixed ninjas being unable to hack criminal records consoles. + type: Fix + id: 8132 + time: '2025-04-04T17:46:59.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/36299 From d844ec250e1752084f583a140c02b93769c56836 Mon Sep 17 00:00:00 2001 From: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com> Date: Sat, 5 Apr 2025 04:49:21 +1100 Subject: [PATCH 35/42] Remove embed mispredict (#36297) * Remove embed mispredict I don't know why this is here but it doesn't seem to cause issues and transforms should be fully predicted so if there are bugs I will deal with them as they come up. * a --- Content.Shared/Projectiles/SharedProjectileSystem.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Content.Shared/Projectiles/SharedProjectileSystem.cs b/Content.Shared/Projectiles/SharedProjectileSystem.cs index 7161a39e0a..3fcff5ae56 100644 --- a/Content.Shared/Projectiles/SharedProjectileSystem.cs +++ b/Content.Shared/Projectiles/SharedProjectileSystem.cs @@ -66,8 +66,7 @@ public abstract partial class SharedProjectileSystem : EntitySystem private void OnEmbedRemove(Entity embeddable, ref RemoveEmbeddedProjectileEvent args) { - // Whacky prediction issues. - if (args.Cancelled || _net.IsClient) + if (args.Cancelled) return; EmbedDetach(embeddable, embeddable.Comp, args.User); From fe1664b46dfbc79b8e9fb94f0b1ce256d5f16b83 Mon Sep 17 00:00:00 2001 From: Myra Date: Fri, 4 Apr 2025 20:42:13 +0200 Subject: [PATCH 36/42] IPIntel now rounds to 2 decimal points (#36298) * IPIntel now rounds to 2 decimal points * Nvm i understood what pjb wanted now --- Content.Server/Connection/IPIntel/IPIntel.cs | 4 ++-- Resources/Locale/en-US/administration/admin-alerts.ftl | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Content.Server/Connection/IPIntel/IPIntel.cs b/Content.Server/Connection/IPIntel/IPIntel.cs index 51a0b74089..a2e7bc580c 100644 --- a/Content.Server/Connection/IPIntel/IPIntel.cs +++ b/Content.Server/Connection/IPIntel/IPIntel.cs @@ -259,7 +259,7 @@ public sealed class IPIntel { _chatManager.SendAdminAlert(Loc.GetString("admin-alert-ipintel-warning", ("player", username), - ("percent", Math.Round(score)))); + ("percent", score))); } if (!decisionIsReject) @@ -269,7 +269,7 @@ public sealed class IPIntel { _chatManager.SendAdminAlert(Loc.GetString("admin-alert-ipintel-blocked", ("player", username), - ("percent", Math.Round(score)))); + ("percent", score))); } return _rejectBad ? (true, Loc.GetString("ipintel-suspicious")) : (false, string.Empty); diff --git a/Resources/Locale/en-US/administration/admin-alerts.ftl b/Resources/Locale/en-US/administration/admin-alerts.ftl index a7c7f6f402..dd6ea2d892 100644 --- a/Resources/Locale/en-US/administration/admin-alerts.ftl +++ b/Resources/Locale/en-US/administration/admin-alerts.ftl @@ -1,3 +1,3 @@ admin-alert-shared-connection = {$player} is sharing a connection with {$otherCount} connected player(s): {$otherList} -admin-alert-ipintel-blocked = {$player} was rejected from joining due to their IP having a {TOSTRING($percent, "P0")} confidence of being a VPN/Datacenter. -admin-alert-ipintel-warning = {$player} IP has a {TOSTRING($percent, "P0")} confidence of being a VPN/Datacenter. Please watch them. +admin-alert-ipintel-blocked = {$player} was rejected from joining due to their IP having a {TOSTRING($percent, "P2")} confidence of being a VPN/Datacenter. +admin-alert-ipintel-warning = {$player} IP has a {TOSTRING($percent, "P2")} confidence of being a VPN/Datacenter. Please watch them. From 9993cf82270b36da1d58646eea2dfd22e55ad7e8 Mon Sep 17 00:00:00 2001 From: ScarKy0 <106310278+ScarKy0@users.noreply.github.com> Date: Fri, 4 Apr 2025 22:24:04 +0200 Subject: [PATCH 37/42] Antagonist roles now require 1h playtime. (#36276) * init * whitespace --- Resources/Prototypes/Roles/Antags/revolutionary.yml | 3 +++ Resources/Prototypes/Roles/Antags/thief.yml | 3 +++ Resources/Prototypes/Roles/Antags/traitor.yml | 6 ++++++ Resources/Prototypes/Roles/Antags/zombie.yml | 3 +++ 4 files changed, 15 insertions(+) diff --git a/Resources/Prototypes/Roles/Antags/revolutionary.yml b/Resources/Prototypes/Roles/Antags/revolutionary.yml index 502a68ea9e..eeef73b2d5 100644 --- a/Resources/Prototypes/Roles/Antags/revolutionary.yml +++ b/Resources/Prototypes/Roles/Antags/revolutionary.yml @@ -5,6 +5,9 @@ setPreference: true objective: roles-antag-rev-head-objective guides: [ Revolutionaries ] + requirements: + - !type:OverallPlaytimeRequirement + time: 3600 # 1h - type: antag id: Rev diff --git a/Resources/Prototypes/Roles/Antags/thief.yml b/Resources/Prototypes/Roles/Antags/thief.yml index 12fdefba2b..b8d21d2e83 100644 --- a/Resources/Prototypes/Roles/Antags/thief.yml +++ b/Resources/Prototypes/Roles/Antags/thief.yml @@ -5,6 +5,9 @@ setPreference: true objective: roles-antag-thief-objective guides: [ Thieves ] + requirements: + - !type:OverallPlaytimeRequirement + time: 3600 # 1h - type: startingGear id: ThiefGear diff --git a/Resources/Prototypes/Roles/Antags/traitor.yml b/Resources/Prototypes/Roles/Antags/traitor.yml index 6fc5314629..572adea1e4 100644 --- a/Resources/Prototypes/Roles/Antags/traitor.yml +++ b/Resources/Prototypes/Roles/Antags/traitor.yml @@ -5,6 +5,9 @@ setPreference: true objective: roles-antag-syndicate-agent-objective guides: [ Traitors ] + requirements: + - !type:OverallPlaytimeRequirement + time: 3600 # 1h - type: antag id: TraitorSleeper @@ -13,6 +16,9 @@ setPreference: true objective: roles-antag-syndicate-agent-sleeper-objective guides: [ Traitors ] + requirements: + - !type:OverallPlaytimeRequirement + time: 3600 # 1h # Syndicate Operative Outfit - Monkey - type: startingGear diff --git a/Resources/Prototypes/Roles/Antags/zombie.yml b/Resources/Prototypes/Roles/Antags/zombie.yml index bc3c2d7f22..4629e6b509 100644 --- a/Resources/Prototypes/Roles/Antags/zombie.yml +++ b/Resources/Prototypes/Roles/Antags/zombie.yml @@ -5,6 +5,9 @@ setPreference: true objective: roles-antag-initial-infected-objective guides: [ Zombies ] + requirements: + - !type:OverallPlaytimeRequirement + time: 3600 # 1h - type: antag id: Zombie From e58ab56e428580606c5d86ad64c541accda25f13 Mon Sep 17 00:00:00 2001 From: PJBot Date: Fri, 4 Apr 2025 20:25:11 +0000 Subject: [PATCH 38/42] 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 1df1981b64..a7e81662a2 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,13 +1,4 @@ Entries: -- author: ScarKy0, GoldenCan - changes: - - message: Ion stormed lawsets no longer persist between shifts. - type: Fix - - message: Cyborgs are now notified when inserted into a chassis with modified laws. - type: Tweak - id: 7633 - time: '2024-11-20T07:55:12.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/33311 - author: ScarKy0, GoldenCan changes: - message: The Derelict Cyborg - a broken cyborg with altered laws due to year of @@ -3896,3 +3887,10 @@ id: 8132 time: '2025-04-04T17:46:59.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/36299 +- author: ScarKy0 + changes: + - message: Players now require 1h of playtime before selecting any antagonist role. + type: Tweak + id: 8133 + time: '2025-04-04T20:24:05.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/36276 From af9526197a86b562bfee763eb7e68e169d64fc25 Mon Sep 17 00:00:00 2001 From: J Date: Sat, 5 Apr 2025 00:20:19 +0000 Subject: [PATCH 39/42] Extracts magic strings from Tag calls (#36305) * Extracts magic strings from Tag calls When #36281 gets merged, the `TagSystem` methods will all give warnings. Let's fix those warnings before they even happen! * Adds missing libraries * Remove not yet implemented TagSystem changes * Fix tag spelling error Genuinely surprised there was only 1! * Styling and proper type changes * Styling Co-authored-by: Tayrtahn --------- Co-authored-by: Tayrtahn --- Content.Client/Verbs/VerbSystem.cs | 5 ++++- .../Tests/Commands/SuicideCommandTests.cs | 6 +++--- Content.Server/Botany/Systems/PlantHolderSystem.cs | 7 +++++-- Content.Server/Chat/SuicideSystem.cs | 7 +++++-- .../EntitySystems/SolutionInjectOnEventSystem.cs | 5 ++++- .../Construction/Commands/FixRotationsCommand.cs | 11 ++++++++--- Content.Server/Electrocution/ElectrocutionSystem.cs | 4 +++- Content.Server/Flash/FlashSystem.cs | 5 ++++- .../Forensics/Systems/ForensicScannerSystem.cs | 5 ++++- .../GameTicking/Rules/SurvivorRuleSystem.cs | 5 ++++- Content.Server/Ghost/GhostSystem.cs | 4 +++- .../Kitchen/EntitySystems/MicrowaveSystem.cs | 7 +++++-- .../Light/EntitySystems/ExpendableLightSystem.cs | 5 ++++- Content.Server/Magic/MagicSystem.cs | 6 ++++-- Content.Server/MagicMirror/MagicMirrorSystem.cs | 5 ++++- .../EntitySystems/TrashOnSolutionEmptySystem.cs | 9 ++++++--- Content.Server/Payload/EntitySystems/PayloadSystem.cs | 7 +++++-- .../Procedural/DungeonJob/DungeonJob.PostGen.cs | 6 +++++- .../EntitySystems/RevenantSystem.Abilities.cs | 5 ++++- .../Shuttles/Systems/ShuttleConsoleSystem.cs | 5 ++++- .../Singularity/EntitySystems/EventHorizonSystem.cs | 5 ++++- Content.Server/Tools/Innate/InnateToolSystem.cs | 5 ++++- Content.Server/Zombies/ZombieSystem.Transform.cs | 5 ++++- .../EntitySystems/SharedChameleonClothingSystem.cs | 4 +++- .../Construction/Conditions/NoWindowsInTile.cs | 7 +++++-- .../Construction/Conditions/WallmountCondition.cs | 7 +++++-- Content.Shared/Delivery/SharedDeliverySystem.cs | 6 +++++- Content.Shared/DoAfter/SharedDoAfterSystem.cs | 5 ++++- Content.Shared/Follower/FollowerSystem.cs | 5 ++++- .../Hands/EntitySystems/SharedHandsSystem.Drop.cs | 6 +++++- .../Implants/SharedSubdermalImplantSystem.cs | 8 ++++++-- Content.Shared/Interaction/SharedInteractionSystem.cs | 5 ++++- Content.Shared/Magic/SharedMagicSystem.cs | 4 +++- .../Movement/Systems/SharedMoverController.cs | 5 ++++- Content.Shared/Paper/PaperSystem.cs | 8 ++++++-- Content.Shared/RCD/Systems/RCDSystem.cs | 3 ++- 36 files changed, 156 insertions(+), 51 deletions(-) diff --git a/Content.Client/Verbs/VerbSystem.cs b/Content.Client/Verbs/VerbSystem.cs index d6513c0a78..92596f9dc0 100644 --- a/Content.Client/Verbs/VerbSystem.cs +++ b/Content.Client/Verbs/VerbSystem.cs @@ -16,6 +16,7 @@ using Robust.Client.State; using Robust.Shared.Configuration; using Robust.Shared.Containers; using Robust.Shared.Map; +using Robust.Shared.Prototypes; using Robust.Shared.Utility; namespace Content.Client.Verbs @@ -36,6 +37,8 @@ namespace Content.Client.Verbs private float _lookupSize; + private static readonly ProtoId HideContextMenuTag = "HideContextMenu"; + /// /// These flags determine what entities the user can see on the context menu. /// @@ -147,7 +150,7 @@ namespace Content.Client.Verbs for (var i = entities.Count - 1; i >= 0; i--) { - if (_tagSystem.HasTag(entities[i], "HideContextMenu")) + if (_tagSystem.HasTag(entities[i], HideContextMenuTag)) entities.RemoveSwap(i); } diff --git a/Content.IntegrationTests/Tests/Commands/SuicideCommandTests.cs b/Content.IntegrationTests/Tests/Commands/SuicideCommandTests.cs index cf88f3aacd..94dd98425b 100644 --- a/Content.IntegrationTests/Tests/Commands/SuicideCommandTests.cs +++ b/Content.IntegrationTests/Tests/Commands/SuicideCommandTests.cs @@ -1,4 +1,4 @@ -using System.Linq; +using System.Linq; using Content.Shared.Damage; using Content.Shared.Damage.Prototypes; using Content.Shared.Execution; @@ -52,7 +52,7 @@ public sealed class SuicideCommandTests name: test version of the material reclaimer components: - type: MaterialReclaimer"; - + private static readonly ProtoId CannotSuicideTag = "CannotSuicide"; /// /// Run the suicide command in the console /// Should successfully kill the player and ghost them @@ -201,7 +201,7 @@ public sealed class SuicideCommandTests mobStateComp = entManager.GetComponent(player); }); - tagSystem.AddTag(player, "CannotSuicide"); + tagSystem.AddTag(player, CannotSuicideTag); // Check that running the suicide command kills the player // and properly ghosts them without them being able to return to their body diff --git a/Content.Server/Botany/Systems/PlantHolderSystem.cs b/Content.Server/Botany/Systems/PlantHolderSystem.cs index 15cb82ef00..5dbafae5af 100644 --- a/Content.Server/Botany/Systems/PlantHolderSystem.cs +++ b/Content.Server/Botany/Systems/PlantHolderSystem.cs @@ -50,6 +50,9 @@ public sealed class PlantHolderSystem : EntitySystem public const float HydroponicsSpeedMultiplier = 1f; public const float HydroponicsConsumptionMultiplier = 2f; + private static readonly ProtoId HoeTag = "Hoe"; + private static readonly ProtoId PlantSampleTakerTag = "PlantSampleTaker"; + public override void Initialize() { base.Initialize(); @@ -203,7 +206,7 @@ public sealed class PlantHolderSystem : EntitySystem return; } - if (_tagSystem.HasTag(args.Used, "Hoe")) + if (_tagSystem.HasTag(args.Used, HoeTag)) { args.Handled = true; if (component.WeedLevel > 0) @@ -243,7 +246,7 @@ public sealed class PlantHolderSystem : EntitySystem return; } - if (_tagSystem.HasTag(args.Used, "PlantSampleTaker")) + if (_tagSystem.HasTag(args.Used, PlantSampleTakerTag)) { args.Handled = true; if (component.Seed == null) diff --git a/Content.Server/Chat/SuicideSystem.cs b/Content.Server/Chat/SuicideSystem.cs index 497c9a1fe4..b9a3ede2bd 100644 --- a/Content.Server/Chat/SuicideSystem.cs +++ b/Content.Server/Chat/SuicideSystem.cs @@ -14,6 +14,7 @@ using Content.Shared.Mobs.Systems; using Content.Shared.Popups; using Content.Shared.Tag; using Robust.Shared.Player; +using Robust.Shared.Prototypes; namespace Content.Server.Chat; @@ -27,6 +28,8 @@ public sealed class SuicideSystem : EntitySystem [Dependency] private readonly GhostSystem _ghostSystem = default!; [Dependency] private readonly SharedSuicideSystem _suicide = default!; + private static readonly ProtoId CannotSuicideTag = "CannotSuicide"; + public override void Initialize() { base.Initialize(); @@ -60,7 +63,7 @@ public sealed class SuicideSystem : EntitySystem // Suicide is considered a fail if the user wasn't able to ghost // Suiciding with the CannotSuicide tag will ghost the player but not kill the body - if (!suicideGhostEvent.Handled || _tagSystem.HasTag(victim, "CannotSuicide")) + if (!suicideGhostEvent.Handled || _tagSystem.HasTag(victim, CannotSuicideTag)) return false; var suicideEvent = new SuicideEvent(victim); @@ -95,7 +98,7 @@ public sealed class SuicideSystem : EntitySystem // CannotSuicide tag will allow the user to ghost, but also return to their mind // This is kind of weird, not sure what it applies to? - if (_tagSystem.HasTag(victim, "CannotSuicide")) + if (_tagSystem.HasTag(victim, CannotSuicideTag)) args.CanReturnToBody = true; if (_ghostSystem.OnGhostAttempt(victim.Comp.Mind.Value, args.CanReturnToBody, mind: mindComponent)) diff --git a/Content.Server/Chemistry/EntitySystems/SolutionInjectOnEventSystem.cs b/Content.Server/Chemistry/EntitySystems/SolutionInjectOnEventSystem.cs index f15edcf067..503a0ebde6 100644 --- a/Content.Server/Chemistry/EntitySystems/SolutionInjectOnEventSystem.cs +++ b/Content.Server/Chemistry/EntitySystems/SolutionInjectOnEventSystem.cs @@ -9,6 +9,7 @@ using Content.Shared.Projectiles; using Content.Shared.Tag; using Content.Shared.Weapons.Melee.Events; using Robust.Shared.Collections; +using Robust.Shared.Prototypes; namespace Content.Server.Chemistry.EntitySystems; @@ -24,6 +25,8 @@ public sealed class SolutionInjectOnCollideSystem : EntitySystem [Dependency] private readonly SharedSolutionContainerSystem _solutionContainer = default!; [Dependency] private readonly TagSystem _tag = default!; + private static readonly ProtoId HardsuitTag = "Hardsuit"; + public override void Initialize() { base.Initialize(); @@ -93,7 +96,7 @@ public sealed class SolutionInjectOnCollideSystem : EntitySystem // Yuck, this is way to hardcodey for my tastes // TODO blocking injection with a hardsuit should probably done with a cancellable event or something - if (!injector.Comp.PierceArmor && _inventory.TryGetSlotEntity(target, "outerClothing", out var suit) && _tag.HasTag(suit.Value, "Hardsuit")) + if (!injector.Comp.PierceArmor && _inventory.TryGetSlotEntity(target, "outerClothing", out var suit) && _tag.HasTag(suit.Value, HardsuitTag)) { // Only show popup to attacker if (source != null) diff --git a/Content.Server/Construction/Commands/FixRotationsCommand.cs b/Content.Server/Construction/Commands/FixRotationsCommand.cs index 3232f12ed8..807f81b498 100644 --- a/Content.Server/Construction/Commands/FixRotationsCommand.cs +++ b/Content.Server/Construction/Commands/FixRotationsCommand.cs @@ -5,6 +5,7 @@ using Content.Shared.Construction; using Content.Shared.Tag; using Robust.Shared.Console; using Robust.Shared.Map.Components; +using Robust.Shared.Prototypes; namespace Content.Server.Construction.Commands; @@ -13,6 +14,10 @@ public sealed class FixRotationsCommand : IConsoleCommand { [Dependency] private readonly IEntityManager _entManager = default!; + private static readonly ProtoId ForceFixRotationsTag = "ForceFixRotations"; + private static readonly ProtoId ForceNoFixRotationsTag = "ForceNoFixRotations"; + private static readonly ProtoId DiagonalTag = "Diagonal"; + // ReSharper disable once StringLiteralTypo public string Command => "fixrotations"; public string Description => "Sets the rotation of all occluders, low walls and windows to south."; @@ -86,11 +91,11 @@ public sealed class FixRotationsCommand : IConsoleCommand // cables valid |= _entManager.HasComponent(child); // anything else that might need this forced - valid |= tagSystem.HasTag(child, "ForceFixRotations"); + valid |= tagSystem.HasTag(child, ForceFixRotationsTag); // override - valid &= !tagSystem.HasTag(child, "ForceNoFixRotations"); + valid &= !tagSystem.HasTag(child, ForceNoFixRotationsTag); // remove diagonal entities as well - valid &= !tagSystem.HasTag(child, "Diagonal"); + valid &= !tagSystem.HasTag(child, DiagonalTag); if (!valid) continue; diff --git a/Content.Server/Electrocution/ElectrocutionSystem.cs b/Content.Server/Electrocution/ElectrocutionSystem.cs index eb10f8d280..c7adb311d3 100644 --- a/Content.Server/Electrocution/ElectrocutionSystem.cs +++ b/Content.Server/Electrocution/ElectrocutionSystem.cs @@ -62,6 +62,8 @@ public sealed class ElectrocutionSystem : SharedElectrocutionSystem [ValidatePrototypeId] private const string DamageType = "Shock"; + private static readonly ProtoId WindowTag = "Window"; + // Multiply and shift the log scale for shock damage. private const float RecursiveDamageMultiplier = 0.75f; private const float RecursiveTimeMultiplier = 0.8f; @@ -139,7 +141,7 @@ public sealed class ElectrocutionSystem : SharedElectrocutionSystem { foreach (var entity in _entityLookup.GetLocalEntitiesIntersecting(tileRef.Value, flags: LookupFlags.StaticSundries)) { - if (_tag.HasTag(entity, "Window")) + if (_tag.HasTag(entity, WindowTag)) return false; } } diff --git a/Content.Server/Flash/FlashSystem.cs b/Content.Server/Flash/FlashSystem.cs index fb449a372c..60c09efaea 100644 --- a/Content.Server/Flash/FlashSystem.cs +++ b/Content.Server/Flash/FlashSystem.cs @@ -21,6 +21,7 @@ using Robust.Server.GameObjects; using Robust.Shared.Audio; using Robust.Shared.Random; using InventoryComponent = Content.Shared.Inventory.InventoryComponent; +using Robust.Shared.Prototypes; namespace Content.Server.Flash { @@ -39,6 +40,8 @@ namespace Content.Server.Flash [Dependency] private readonly IRobustRandom _random = default!; [Dependency] private readonly StatusEffectsSystem _statusEffectsSystem = default!; + private static readonly ProtoId TrashTag = "Trash"; + public override void Initialize() { base.Initialize(); @@ -94,7 +97,7 @@ namespace Content.Server.Flash if (_charges.IsEmpty(uid, charges)) { _appearance.SetData(uid, FlashVisuals.Burnt, true); - _tag.AddTag(uid, "Trash"); + _tag.AddTag(uid, TrashTag); _popup.PopupEntity(Loc.GetString("flash-component-becomes-empty"), user); } diff --git a/Content.Server/Forensics/Systems/ForensicScannerSystem.cs b/Content.Server/Forensics/Systems/ForensicScannerSystem.cs index 984334ee8e..f0eb12c34d 100644 --- a/Content.Server/Forensics/Systems/ForensicScannerSystem.cs +++ b/Content.Server/Forensics/Systems/ForensicScannerSystem.cs @@ -16,6 +16,7 @@ using Robust.Shared.Audio; using Robust.Shared.Player; using Robust.Shared.Timing; using Content.Server.Chemistry.Containers.EntitySystems; +using Robust.Shared.Prototypes; // todo: remove this stinky LINQy namespace Content.Server.Forensics @@ -33,6 +34,8 @@ namespace Content.Server.Forensics [Dependency] private readonly ForensicsSystem _forensicsSystem = default!; [Dependency] private readonly TagSystem _tag = default!; + private static readonly ProtoId DNASolutionScannableTag = "DNASolutionScannable"; + public override void Initialize() { base.Initialize(); @@ -86,7 +89,7 @@ namespace Content.Server.Forensics scanner.Residues = forensics.Residues.ToList(); } - if (_tag.HasTag(args.Args.Target.Value, "DNASolutionScannable")) + if (_tag.HasTag(args.Args.Target.Value, DNASolutionScannableTag)) { scanner.SolutionDNAs = _forensicsSystem.GetSolutionsDNA(args.Args.Target.Value); } else diff --git a/Content.Server/GameTicking/Rules/SurvivorRuleSystem.cs b/Content.Server/GameTicking/Rules/SurvivorRuleSystem.cs index 81ad2b1be7..4990b98b91 100644 --- a/Content.Server/GameTicking/Rules/SurvivorRuleSystem.cs +++ b/Content.Server/GameTicking/Rules/SurvivorRuleSystem.cs @@ -9,6 +9,7 @@ using Content.Shared.Mobs.Systems; using Content.Shared.Survivor.Components; using Content.Shared.Tag; using Robust.Server.GameObjects; +using Robust.Shared.Prototypes; namespace Content.Server.GameTicking.Rules; @@ -22,6 +23,8 @@ public sealed class SurvivorRuleSystem : GameRuleSystem [Dependency] private readonly TagSystem _tag = default!; [Dependency] private readonly MobStateSystem _mobState = default!; + private static readonly ProtoId InvalidForSurvivorAntagTag = "InvalidForSurvivorAntag"; + public override void Initialize() { base.Initialize(); @@ -44,7 +47,7 @@ public sealed class SurvivorRuleSystem : GameRuleSystem var mind = humanMind.Owner; var ent = humanMind.Comp.OwnedEntity.Value; - if (HasComp(mind) || _tag.HasTag(mind, "InvalidForSurvivorAntag")) + if (HasComp(mind) || _tag.HasTag(mind, InvalidForSurvivorAntagTag)) continue; EnsureComp(mind); diff --git a/Content.Server/Ghost/GhostSystem.cs b/Content.Server/Ghost/GhostSystem.cs index e7125ee4f2..435584e908 100644 --- a/Content.Server/Ghost/GhostSystem.cs +++ b/Content.Server/Ghost/GhostSystem.cs @@ -72,6 +72,8 @@ namespace Content.Server.Ghost private EntityQuery _ghostQuery; private EntityQuery _physicsQuery; + private static readonly ProtoId AllowGhostShownByEventTag = "AllowGhostShownByEvent"; + public override void Initialize() { base.Initialize(); @@ -403,7 +405,7 @@ namespace Content.Server.Ghost var entityQuery = EntityQueryEnumerator(); while (entityQuery.MoveNext(out var uid, out var _, out var vis)) { - if (!_tag.HasTag(uid, "AllowGhostShownByEvent")) + if (!_tag.HasTag(uid, AllowGhostShownByEventTag)) continue; if (visible) diff --git a/Content.Server/Kitchen/EntitySystems/MicrowaveSystem.cs b/Content.Server/Kitchen/EntitySystems/MicrowaveSystem.cs index 7f0778cbdd..4f71cc4721 100644 --- a/Content.Server/Kitchen/EntitySystems/MicrowaveSystem.cs +++ b/Content.Server/Kitchen/EntitySystems/MicrowaveSystem.cs @@ -73,6 +73,9 @@ namespace Content.Server.Kitchen.EntitySystems [ValidatePrototypeId] private const string MalfunctionSpark = "Spark"; + private static readonly ProtoId MetalTag = "Metal"; + private static readonly ProtoId PlasticTag = "Plastic"; + public override void Initialize() { base.Initialize(); @@ -550,12 +553,12 @@ namespace Content.Server.Kitchen.EntitySystems return; } - if (_tag.HasTag(item, "Metal")) + if (_tag.HasTag(item, MetalTag)) { malfunctioning = true; } - if (_tag.HasTag(item, "Plastic")) + if (_tag.HasTag(item, PlasticTag)) { var junk = Spawn(component.BadRecipeEntityId, Transform(uid).Coordinates); _container.Insert(junk, component.Storage); diff --git a/Content.Server/Light/EntitySystems/ExpendableLightSystem.cs b/Content.Server/Light/EntitySystems/ExpendableLightSystem.cs index b56da84f03..7aacf3e7ad 100644 --- a/Content.Server/Light/EntitySystems/ExpendableLightSystem.cs +++ b/Content.Server/Light/EntitySystems/ExpendableLightSystem.cs @@ -10,6 +10,7 @@ using Content.Shared.Verbs; using JetBrains.Annotations; using Robust.Server.GameObjects; using Robust.Shared.Audio.Systems; +using Robust.Shared.Prototypes; using Robust.Shared.Utility; namespace Content.Server.Light.EntitySystems @@ -24,6 +25,8 @@ namespace Content.Server.Light.EntitySystems [Dependency] private readonly SharedAppearanceSystem _appearance = default!; [Dependency] private readonly MetaDataSystem _metaData = default!; + private static readonly ProtoId TrashTag = "Trash"; + public override void Initialize() { base.Initialize(); @@ -69,7 +72,7 @@ namespace Content.Server.Light.EntitySystems _metaData.SetEntityName(ent, Loc.GetString(component.SpentName), meta); _metaData.SetEntityDescription(ent, Loc.GetString(component.SpentDesc), meta); - _tagSystem.AddTag(ent, "Trash"); + _tagSystem.AddTag(ent, TrashTag); UpdateSounds(ent); UpdateVisualizer(ent); diff --git a/Content.Server/Magic/MagicSystem.cs b/Content.Server/Magic/MagicSystem.cs index 34c12954c6..dafd88dd5f 100644 --- a/Content.Server/Magic/MagicSystem.cs +++ b/Content.Server/Magic/MagicSystem.cs @@ -16,6 +16,8 @@ public sealed class MagicSystem : SharedMagicSystem [Dependency] private readonly TagSystem _tag = default!; [Dependency] private readonly SharedMindSystem _mind = default!; + private static readonly ProtoId InvalidForSurvivorAntagTag = "InvalidForSurvivorAntag"; + public override void Initialize() { base.Initialize(); @@ -48,8 +50,8 @@ public sealed class MagicSystem : SharedMagicSystem if (!ev.MakeSurvivorAntagonist) return; - if (_mind.TryGetMind(ev.Performer, out var mind, out _) && !_tag.HasTag(mind, "InvalidForSurvivorAntag")) - _tag.AddTag(mind, "InvalidForSurvivorAntag"); + if (_mind.TryGetMind(ev.Performer, out var mind, out _) && !_tag.HasTag(mind, InvalidForSurvivorAntagTag)) + _tag.AddTag(mind, InvalidForSurvivorAntagTag); EntProtoId survivorRule = "Survivor"; diff --git a/Content.Server/MagicMirror/MagicMirrorSystem.cs b/Content.Server/MagicMirror/MagicMirrorSystem.cs index f3be03b4b0..37302999ed 100644 --- a/Content.Server/MagicMirror/MagicMirrorSystem.cs +++ b/Content.Server/MagicMirror/MagicMirrorSystem.cs @@ -11,6 +11,7 @@ using Content.Shared.MagicMirror; using Content.Shared.Popups; using Content.Shared.Tag; using Robust.Shared.Audio.Systems; +using Robust.Shared.Prototypes; namespace Content.Server.MagicMirror; @@ -27,6 +28,8 @@ public sealed class MagicMirrorSystem : SharedMagicMirrorSystem [Dependency] private readonly InventorySystem _inventory = default!; [Dependency] private readonly TagSystem _tagSystem = default!; + private static readonly ProtoId HidesHairTag = "HidesHair"; + public override void Initialize() { base.Initialize(); @@ -391,7 +394,7 @@ public sealed class MagicMirrorSystem : SharedMagicMirrorSystem var slots = _inventory.GetSlotEnumerator((target, inventoryComp), SlotFlags.WITHOUT_POCKET); while (slots.MoveNext(out var slot)) { - if (slot.ContainedEntity != null && _tagSystem.HasTag(slot.ContainedEntity.Value, "HidesHair")) + if (slot.ContainedEntity != null && _tagSystem.HasTag(slot.ContainedEntity.Value, HidesHairTag)) { return true; } diff --git a/Content.Server/Nutrition/EntitySystems/TrashOnSolutionEmptySystem.cs b/Content.Server/Nutrition/EntitySystems/TrashOnSolutionEmptySystem.cs index b2e12036f9..ea3a8be9cb 100644 --- a/Content.Server/Nutrition/EntitySystems/TrashOnSolutionEmptySystem.cs +++ b/Content.Server/Nutrition/EntitySystems/TrashOnSolutionEmptySystem.cs @@ -3,6 +3,7 @@ using Content.Shared.Chemistry.Components; using Content.Shared.Chemistry.Components.SolutionManager; using Content.Shared.Chemistry.EntitySystems; using Content.Shared.Tag; +using Robust.Shared.Prototypes; namespace Content.Server.Nutrition.EntitySystems { @@ -11,6 +12,8 @@ namespace Content.Server.Nutrition.EntitySystems [Dependency] private readonly SharedSolutionContainerSystem _solutionContainerSystem = default!; [Dependency] private readonly TagSystem _tagSystem = default!; + private static readonly ProtoId TrashTag = "Trash"; + public override void Initialize() { base.Initialize(); @@ -41,11 +44,11 @@ namespace Content.Server.Nutrition.EntitySystems { if (solution.Volume <= 0) { - _tagSystem.AddTag(entity.Owner, "Trash"); + _tagSystem.AddTag(entity.Owner, TrashTag); return; } - if (_tagSystem.HasTag(entity.Owner, "Trash")) - _tagSystem.RemoveTag(entity.Owner, "Trash"); + + _tagSystem.RemoveTag(entity.Owner, TrashTag); } } } diff --git a/Content.Server/Payload/EntitySystems/PayloadSystem.cs b/Content.Server/Payload/EntitySystems/PayloadSystem.cs index f5159bf223..bf562f747f 100644 --- a/Content.Server/Payload/EntitySystems/PayloadSystem.cs +++ b/Content.Server/Payload/EntitySystems/PayloadSystem.cs @@ -11,6 +11,7 @@ using Robust.Shared.Serialization.Manager; using Robust.Shared.Utility; using System.Linq; using Robust.Server.GameObjects; +using Robust.Shared.Prototypes; namespace Content.Server.Payload.EntitySystems; @@ -23,6 +24,8 @@ public sealed class PayloadSystem : EntitySystem [Dependency] private readonly IComponentFactory _componentFactory = default!; [Dependency] private readonly ISerializationManager _serializationManager = default!; + private static readonly ProtoId PayloadTag = "Payload"; + public override void Initialize() { base.Initialize(); @@ -44,7 +47,7 @@ public sealed class PayloadSystem : EntitySystem { foreach (var entity in container.ContainedEntities) { - if (_tagSystem.HasTag(entity, "Payload")) + if (_tagSystem.HasTag(entity, PayloadTag)) yield return entity; } } @@ -71,7 +74,7 @@ public sealed class PayloadSystem : EntitySystem return; // Ensure we don't enter a trigger-loop - DebugTools.Assert(!_tagSystem.HasTag(uid, "Payload")); + DebugTools.Assert(!_tagSystem.HasTag(uid, PayloadTag)); RaiseLocalEvent(parent, args, false); } diff --git a/Content.Server/Procedural/DungeonJob/DungeonJob.PostGen.cs b/Content.Server/Procedural/DungeonJob/DungeonJob.PostGen.cs index b1c83346d8..84e7563f33 100644 --- a/Content.Server/Procedural/DungeonJob/DungeonJob.PostGen.cs +++ b/Content.Server/Procedural/DungeonJob/DungeonJob.PostGen.cs @@ -1,8 +1,10 @@ using System.Numerics; using Content.Shared.Procedural; +using Content.Shared.Tag; using Robust.Shared.Collections; using Robust.Shared.Map.Components; using Robust.Shared.Physics.Components; +using Robust.Shared.Prototypes; namespace Content.Server.Procedural.DungeonJob; @@ -12,13 +14,15 @@ public sealed partial class DungeonJob * Run after the main dungeon generation */ + private static readonly ProtoId WallTag = "Wall"; + private bool HasWall(Vector2i tile) { var anchored = _maps.GetAnchoredEntitiesEnumerator(_gridUid, _grid, tile); while (anchored.MoveNext(out var uid)) { - if (_tags.HasTag(uid.Value, "Wall")) + if (_tags.HasTag(uid.Value, WallTag)) return true; } diff --git a/Content.Server/Revenant/EntitySystems/RevenantSystem.Abilities.cs b/Content.Server/Revenant/EntitySystems/RevenantSystem.Abilities.cs index 1eb9aabed6..51cbb6d4d5 100644 --- a/Content.Server/Revenant/EntitySystems/RevenantSystem.Abilities.cs +++ b/Content.Server/Revenant/EntitySystems/RevenantSystem.Abilities.cs @@ -29,6 +29,7 @@ using Robust.Shared.Physics.Components; using Robust.Shared.Utility; using Robust.Shared.Map.Components; using Content.Shared.Whitelist; +using Robust.Shared.Prototypes; namespace Content.Server.Revenant.EntitySystems; @@ -44,6 +45,8 @@ public sealed partial class RevenantSystem [Dependency] private readonly SharedTransformSystem _transformSystem = default!; [Dependency] private readonly SharedMapSystem _mapSystem = default!; + private static readonly ProtoId WindowTag = "Window"; + private void InitializeAbilities() { SubscribeLocalEvent(OnInteract); @@ -253,7 +256,7 @@ public sealed partial class RevenantSystem foreach (var ent in lookup) { //break windows - if (tags.HasComponent(ent) && _tag.HasTag(ent, "Window")) + if (tags.HasComponent(ent) && _tag.HasTag(ent, WindowTag)) { //hardcoded damage specifiers til i die. var dspec = new DamageSpecifier(); diff --git a/Content.Server/Shuttles/Systems/ShuttleConsoleSystem.cs b/Content.Server/Shuttles/Systems/ShuttleConsoleSystem.cs index f02ea945d0..478b002e58 100644 --- a/Content.Server/Shuttles/Systems/ShuttleConsoleSystem.cs +++ b/Content.Server/Shuttles/Systems/ShuttleConsoleSystem.cs @@ -21,6 +21,7 @@ using Robust.Shared.GameStates; using Robust.Shared.Map; using Robust.Shared.Utility; using Content.Shared.UserInterface; +using Robust.Shared.Prototypes; namespace Content.Server.Shuttles.Systems; @@ -43,6 +44,8 @@ public sealed partial class ShuttleConsoleSystem : SharedShuttleConsoleSystem private readonly HashSet> _consoles = new(); + private static readonly ProtoId CanPilotTag = "CanPilot"; + public override void Initialize() { base.Initialize(); @@ -168,7 +171,7 @@ public sealed partial class ShuttleConsoleSystem : SharedShuttleConsoleSystem private bool TryPilot(EntityUid user, EntityUid uid) { - if (!_tags.HasTag(user, "CanPilot") || + if (!_tags.HasTag(user, CanPilotTag) || !TryComp(uid, out var component) || !this.IsPowered(uid, EntityManager) || !Transform(uid).Anchored || diff --git a/Content.Server/Singularity/EntitySystems/EventHorizonSystem.cs b/Content.Server/Singularity/EntitySystems/EventHorizonSystem.cs index 729328b8bd..68543cc175 100644 --- a/Content.Server/Singularity/EntitySystems/EventHorizonSystem.cs +++ b/Content.Server/Singularity/EntitySystems/EventHorizonSystem.cs @@ -14,6 +14,7 @@ using Robust.Shared.Map.Components; using Robust.Shared.Physics.Components; using Robust.Shared.Physics.Events; using Robust.Shared.Physics.Systems; +using Robust.Shared.Prototypes; using Robust.Shared.Timing; namespace Content.Server.Singularity.EntitySystems; @@ -36,6 +37,8 @@ public sealed class EventHorizonSystem : SharedEventHorizonSystem [Dependency] private readonly TagSystem _tagSystem = default!; #endregion Dependencies + private static readonly ProtoId HighRiskItemTag = "HighRiskItem"; + private EntityQuery _physicsQuery; public override void Initialize() @@ -127,7 +130,7 @@ public sealed class EventHorizonSystem : SharedEventHorizonSystem return; if (HasComp(morsel) - || _tagSystem.HasTag(morsel, "HighRiskItem") + || _tagSystem.HasTag(morsel, HighRiskItemTag) || HasComp(morsel)) { _adminLogger.Add(LogType.EntityDelete, LogImpact.High, $"{ToPrettyString(morsel):player} entered the event horizon of {ToPrettyString(hungry)} and was deleted"); diff --git a/Content.Server/Tools/Innate/InnateToolSystem.cs b/Content.Server/Tools/Innate/InnateToolSystem.cs index e7e5be38c4..b8d1dd935c 100644 --- a/Content.Server/Tools/Innate/InnateToolSystem.cs +++ b/Content.Server/Tools/Innate/InnateToolSystem.cs @@ -8,6 +8,7 @@ using Content.Shared.Interaction.Components; using Content.Shared.Storage; using Content.Shared.Tag; using Robust.Shared.Network; +using Robust.Shared.Prototypes; using Robust.Shared.Random; namespace Content.Server.Tools.Innate; @@ -22,6 +23,8 @@ public sealed class InnateToolSystem : EntitySystem [Dependency] private readonly SharedHandsSystem _sharedHandsSystem = default!; [Dependency] private readonly TagSystem _tagSystem = default!; + private static readonly ProtoId InnateDontDeleteTag = "InnateDontDelete"; + public override void Initialize() { base.Initialize(); @@ -76,7 +79,7 @@ public sealed class InnateToolSystem : EntitySystem { foreach (var tool in component.ToolUids) { - if (_tagSystem.HasTag(tool, "InnateDontDelete")) + if (_tagSystem.HasTag(tool, InnateDontDeleteTag)) { RemComp(tool); } diff --git a/Content.Server/Zombies/ZombieSystem.Transform.cs b/Content.Server/Zombies/ZombieSystem.Transform.cs index 47d94984c0..155796481b 100644 --- a/Content.Server/Zombies/ZombieSystem.Transform.cs +++ b/Content.Server/Zombies/ZombieSystem.Transform.cs @@ -36,6 +36,7 @@ using Content.Shared.Traits.Assorted; using Robust.Shared.Audio.Systems; using Content.Shared.Ghost.Roles.Components; using Content.Shared.Tag; +using Robust.Shared.Prototypes; namespace Content.Server.Zombies; @@ -61,6 +62,8 @@ public sealed partial class ZombieSystem [Dependency] private readonly TagSystem _tag = default!; [Dependency] private readonly NameModifierSystem _nameMod = default!; + private static readonly ProtoId InvalidForGlobalSpawnSpellTag = "InvalidForGlobalSpawnSpell"; + /// /// Handles an entity turning into a zombie when they die or go into crit /// @@ -290,6 +293,6 @@ public sealed partial class ZombieSystem //Need to prevent them from getting an item, they have no hands. // Also prevents them from becoming a Survivor. They're undead. - _tag.AddTag(target, "InvalidForGlobalSpawnSpell"); + _tag.AddTag(target, InvalidForGlobalSpawnSpellTag); } } diff --git a/Content.Shared/Clothing/EntitySystems/SharedChameleonClothingSystem.cs b/Content.Shared/Clothing/EntitySystems/SharedChameleonClothingSystem.cs index 725b034766..f996c65fe8 100644 --- a/Content.Shared/Clothing/EntitySystems/SharedChameleonClothingSystem.cs +++ b/Content.Shared/Clothing/EntitySystems/SharedChameleonClothingSystem.cs @@ -23,6 +23,8 @@ public abstract class SharedChameleonClothingSystem : EntitySystem [Dependency] private readonly TagSystem _tag = default!; [Dependency] protected readonly SharedUserInterfaceSystem UI = default!; + private static readonly ProtoId WhitelistChameleonTag = "WhitelistChameleon"; + public override void Initialize() { base.Initialize(); @@ -124,7 +126,7 @@ public abstract class SharedChameleonClothingSystem : EntitySystem return false; // check if it is marked as valid chameleon target - if (!proto.TryGetComponent(out TagComponent? tag, _factory) || !_tag.HasTag(tag, "WhitelistChameleon")) + if (!proto.TryGetComponent(out TagComponent? tag, _factory) || !_tag.HasTag(tag, WhitelistChameleonTag)) return false; if (requiredTag != null && !_tag.HasTag(tag, requiredTag)) diff --git a/Content.Shared/Construction/Conditions/NoWindowsInTile.cs b/Content.Shared/Construction/Conditions/NoWindowsInTile.cs index 3ae3b59362..2d37ecebe6 100644 --- a/Content.Shared/Construction/Conditions/NoWindowsInTile.cs +++ b/Content.Shared/Construction/Conditions/NoWindowsInTile.cs @@ -1,7 +1,8 @@ -using Content.Shared.Maps; +using Content.Shared.Maps; using Content.Shared.Tag; using JetBrains.Annotations; using Robust.Shared.Map; +using Robust.Shared.Prototypes; namespace Content.Shared.Construction.Conditions { @@ -9,6 +10,8 @@ namespace Content.Shared.Construction.Conditions [DataDefinition] public sealed partial class NoWindowsInTile : IConstructionCondition { + private static readonly ProtoId WindowTag = "Window"; + public bool Condition(EntityUid user, EntityCoordinates location, Direction direction) { var entManager = IoCManager.Resolve(); @@ -17,7 +20,7 @@ namespace Content.Shared.Construction.Conditions foreach (var entity in location.GetEntitiesInTile(LookupFlags.Static)) { - if (tagSystem.HasTag(entity, "Window")) + if (tagSystem.HasTag(entity, WindowTag)) return false; } diff --git a/Content.Shared/Construction/Conditions/WallmountCondition.cs b/Content.Shared/Construction/Conditions/WallmountCondition.cs index f1d056165e..f32cc19eea 100644 --- a/Content.Shared/Construction/Conditions/WallmountCondition.cs +++ b/Content.Shared/Construction/Conditions/WallmountCondition.cs @@ -6,6 +6,7 @@ using JetBrains.Annotations; using Robust.Shared.Map; using Robust.Shared.Physics; using Robust.Shared.Physics.Systems; +using Robust.Shared.Prototypes; using Robust.Shared.Utility; namespace Content.Shared.Construction.Conditions @@ -14,6 +15,8 @@ namespace Content.Shared.Construction.Conditions [DataDefinition] public sealed partial class WallmountCondition : IConstructionCondition { + private static readonly ProtoId WallTag = "Wall"; + public bool Condition(EntityUid user, EntityCoordinates location, Direction direction) { var entManager = IoCManager.Resolve(); @@ -42,7 +45,7 @@ namespace Content.Shared.Construction.Conditions var tagSystem = entManager.System(); var userToObjRaycastResults = physics.IntersectRayWithPredicate(entManager.GetComponent(user).MapID, rUserToObj, maxLength: length, - predicate: (e) => !tagSystem.HasTag(e, "Wall")); + predicate: (e) => !tagSystem.HasTag(e, WallTag)); var targetWall = userToObjRaycastResults.FirstOrNull(); @@ -53,7 +56,7 @@ namespace Content.Shared.Construction.Conditions // check that we didn't try to build wallmount that facing another adjacent wall var rAdjWall = new CollisionRay(objWorldPosition, directionWithOffset.Normalized(), (int) CollisionGroup.Impassable); var adjWallRaycastResults = physics.IntersectRayWithPredicate(entManager.GetComponent(user).MapID, rAdjWall, maxLength: 0.5f, - predicate: e => e == targetWall.Value.HitEntity || !tagSystem.HasTag(e, "Wall")); + predicate: e => e == targetWall.Value.HitEntity || !tagSystem.HasTag(e, WallTag)); return !adjWallRaycastResults.Any(); } diff --git a/Content.Shared/Delivery/SharedDeliverySystem.cs b/Content.Shared/Delivery/SharedDeliverySystem.cs index 52c9db40a1..319bf41fce 100644 --- a/Content.Shared/Delivery/SharedDeliverySystem.cs +++ b/Content.Shared/Delivery/SharedDeliverySystem.cs @@ -12,6 +12,7 @@ using Content.Shared.Tag; using Content.Shared.Verbs; using Robust.Shared.Audio.Systems; using Robust.Shared.Containers; +using Robust.Shared.Prototypes; namespace Content.Shared.Delivery; @@ -30,6 +31,9 @@ public abstract class SharedDeliverySystem : EntitySystem [Dependency] private readonly SharedHandsSystem _hands = default!; [Dependency] private readonly NameModifierSystem _nameModifier = default!; + private static readonly ProtoId TrashTag = "Trash"; + private static readonly ProtoId RecyclableTag = "Recyclable"; + public override void Initialize() { base.Initialize(); @@ -129,7 +133,7 @@ public abstract class SharedDeliverySystem : EntitySystem ent.Comp.IsOpened = true; _appearance.SetData(ent, DeliveryVisuals.IsTrash, ent.Comp.IsOpened); - _tag.AddTags(ent, "Trash", "Recyclable"); + _tag.AddTags(ent, TrashTag, RecyclableTag); EnsureComp(ent); RemComp(ent); // opened mail should not count for the objective diff --git a/Content.Shared/DoAfter/SharedDoAfterSystem.cs b/Content.Shared/DoAfter/SharedDoAfterSystem.cs index c246c2844a..9765bac912 100644 --- a/Content.Shared/DoAfter/SharedDoAfterSystem.cs +++ b/Content.Shared/DoAfter/SharedDoAfterSystem.cs @@ -5,6 +5,7 @@ using Content.Shared.Damage; using Content.Shared.Hands.Components; using Content.Shared.Tag; using Robust.Shared.GameStates; +using Robust.Shared.Prototypes; using Robust.Shared.Serialization; using Robust.Shared.Timing; using Robust.Shared.Utility; @@ -23,6 +24,8 @@ public abstract partial class SharedDoAfterSystem : EntitySystem /// private static readonly TimeSpan ExcessTime = TimeSpan.FromSeconds(0.5f); + private static readonly ProtoId InstantDoAftersTag = "InstantDoAfters"; + public override void Initialize() { base.Initialize(); @@ -233,7 +236,7 @@ public abstract partial class SharedDoAfterSystem : EntitySystem // TODO DO AFTER // Why does this tag exist? Just make this a bool on the component? - if (args.Delay <= TimeSpan.Zero || _tag.HasTag(args.User, "InstantDoAfters")) + if (args.Delay <= TimeSpan.Zero || _tag.HasTag(args.User, InstantDoAftersTag)) { RaiseDoAfterEvents(doAfter, comp); // We don't store instant do-afters. This is just a lazy way of hiding them from client-side visuals. diff --git a/Content.Shared/Follower/FollowerSystem.cs b/Content.Shared/Follower/FollowerSystem.cs index 243886dbb7..75310a6737 100644 --- a/Content.Shared/Follower/FollowerSystem.cs +++ b/Content.Shared/Follower/FollowerSystem.cs @@ -18,6 +18,7 @@ using Robust.Shared.Network; using Robust.Shared.Physics; using Robust.Shared.Physics.Systems; using Robust.Shared.Player; +using Robust.Shared.Prototypes; using Robust.Shared.Utility; namespace Content.Shared.Follower; @@ -32,6 +33,8 @@ public sealed class FollowerSystem : EntitySystem [Dependency] private readonly INetManager _netMan = default!; [Dependency] private readonly ISharedAdminManager _adminManager = default!; + private static readonly ProtoId ForceableFollowTag = "ForceableFollow"; + public override void Initialize() { base.Initialize(); @@ -106,7 +109,7 @@ public sealed class FollowerSystem : EntitySystem ev.Verbs.Add(verb); } - if (_tagSystem.HasTag(ev.Target, "ForceableFollow")) + if (_tagSystem.HasTag(ev.Target, ForceableFollowTag)) { if (!ev.CanAccess || !ev.CanInteract) return; diff --git a/Content.Shared/Hands/EntitySystems/SharedHandsSystem.Drop.cs b/Content.Shared/Hands/EntitySystems/SharedHandsSystem.Drop.cs index 223c2d4a37..95773697db 100644 --- a/Content.Shared/Hands/EntitySystems/SharedHandsSystem.Drop.cs +++ b/Content.Shared/Hands/EntitySystems/SharedHandsSystem.Drop.cs @@ -6,12 +6,16 @@ using Content.Shared.Inventory.VirtualItem; using Content.Shared.Tag; using Robust.Shared.Containers; using Robust.Shared.Map; +using Robust.Shared.Prototypes; namespace Content.Shared.Hands.EntitySystems; public abstract partial class SharedHandsSystem { [Dependency] private readonly TagSystem _tagSystem = default!; + + private static readonly ProtoId BypassDropChecksTag = "BypassDropChecks"; + private void InitializeDrop() { SubscribeLocalEvent(HandleEntityRemoved); @@ -37,7 +41,7 @@ public abstract partial class SharedHandsSystem private bool ShouldIgnoreRestrictions(EntityUid user) { //Checks if the Entity is something that shouldn't care about drop distance or walls ie Aghost - return !_tagSystem.HasTag(user, "BypassDropChecks"); + return !_tagSystem.HasTag(user, BypassDropChecksTag); } /// diff --git a/Content.Shared/Implants/SharedSubdermalImplantSystem.cs b/Content.Shared/Implants/SharedSubdermalImplantSystem.cs index bb166b3c5c..e23357448f 100644 --- a/Content.Shared/Implants/SharedSubdermalImplantSystem.cs +++ b/Content.Shared/Implants/SharedSubdermalImplantSystem.cs @@ -7,6 +7,7 @@ using Content.Shared.Tag; using JetBrains.Annotations; using Robust.Shared.Containers; using Robust.Shared.Network; +using Robust.Shared.Prototypes; using System.Linq; namespace Content.Shared.Implants; @@ -21,6 +22,9 @@ public abstract class SharedSubdermalImplantSystem : EntitySystem public const string BaseStorageId = "storagebase"; + private static readonly ProtoId MicroBombTag = "MicroBomb"; + private static readonly ProtoId MacroBombTag = "MacroBomb"; + public override void Initialize() { SubscribeLocalEvent(OnInsert); @@ -43,11 +47,11 @@ public abstract class SharedSubdermalImplantSystem : EntitySystem } //replace micro bomb with macro bomb - if (_container.TryGetContainer(component.ImplantedEntity.Value, ImplanterComponent.ImplantSlotId, out var implantContainer) && _tag.HasTag(uid, "MacroBomb")) + if (_container.TryGetContainer(component.ImplantedEntity.Value, ImplanterComponent.ImplantSlotId, out var implantContainer) && _tag.HasTag(uid, MacroBombTag)) { foreach (var implant in implantContainer.ContainedEntities) { - if (_tag.HasTag(implant, "MicroBomb")) + if (_tag.HasTag(implant, MicroBombTag)) { _container.Remove(implant, implantContainer); QueueDel(implant); diff --git a/Content.Shared/Interaction/SharedInteractionSystem.cs b/Content.Shared/Interaction/SharedInteractionSystem.cs index 2f09f3e549..ff9f41e1f9 100644 --- a/Content.Shared/Interaction/SharedInteractionSystem.cs +++ b/Content.Shared/Interaction/SharedInteractionSystem.cs @@ -37,6 +37,7 @@ using Robust.Shared.Physics; using Robust.Shared.Physics.Components; using Robust.Shared.Physics.Systems; using Robust.Shared.Player; +using Robust.Shared.Prototypes; using Robust.Shared.Serialization; using Robust.Shared.Timing; using Robust.Shared.Utility; @@ -87,6 +88,8 @@ namespace Content.Shared.Interaction public const float MaxRaycastRange = 100f; public const string RateLimitKey = "Interaction"; + private static readonly ProtoId BypassInteractionRangeChecksTag = "BypassInteractionRangeChecks"; + public delegate bool Ignored(EntityUid entity); public override void Initialize() @@ -318,7 +321,7 @@ namespace Content.Shared.Interaction { // This is for Admin/mapping convenience. If ever there are other ghosts that can still interact, this check // might need to be more selective. - return !_tagSystem.HasTag(user, "BypassInteractionRangeChecks"); + return !_tagSystem.HasTag(user, BypassInteractionRangeChecksTag); } /// diff --git a/Content.Shared/Magic/SharedMagicSystem.cs b/Content.Shared/Magic/SharedMagicSystem.cs index b502ff2fbb..9a44407e91 100644 --- a/Content.Shared/Magic/SharedMagicSystem.cs +++ b/Content.Shared/Magic/SharedMagicSystem.cs @@ -65,6 +65,8 @@ public abstract class SharedMagicSystem : EntitySystem [Dependency] private readonly SharedMindSystem _mind = default!; [Dependency] private readonly SharedStunSystem _stun = default!; + private static readonly ProtoId InvalidForGlobalSpawnSpellTag = "InvalidForGlobalSpawnSpell"; + public override void Initialize() { base.Initialize(); @@ -484,7 +486,7 @@ public abstract class SharedMagicSystem : EntitySystem var ent = human.Comp.OwnedEntity.Value; - if (_tag.HasTag(ent, "InvalidForGlobalSpawnSpell")) + if (_tag.HasTag(ent, InvalidForGlobalSpawnSpellTag)) continue; var mapCoords = _transform.GetMapCoordinates(ent); diff --git a/Content.Shared/Movement/Systems/SharedMoverController.cs b/Content.Shared/Movement/Systems/SharedMoverController.cs index 76e2f34368..a5c32b2992 100644 --- a/Content.Shared/Movement/Systems/SharedMoverController.cs +++ b/Content.Shared/Movement/Systems/SharedMoverController.cs @@ -20,6 +20,7 @@ using Robust.Shared.Physics; using Robust.Shared.Physics.Components; using Robust.Shared.Physics.Controllers; using Robust.Shared.Physics.Systems; +using Robust.Shared.Prototypes; using Robust.Shared.Timing; using Robust.Shared.Utility; using PullableComponent = Content.Shared.Movement.Pulling.Components.PullableComponent; @@ -59,6 +60,8 @@ public abstract partial class SharedMoverController : VirtualController protected EntityQuery FootstepModifierQuery; protected EntityQuery MapGridQuery; + private static readonly ProtoId FootstepSoundTag = "FootstepSound"; + /// /// /// @@ -431,7 +434,7 @@ public abstract partial class SharedMoverController : VirtualController { sound = null; - if (!CanSound() || !_tags.HasTag(uid, "FootstepSound")) + if (!CanSound() || !_tags.HasTag(uid, FootstepSoundTag)) return false; var coordinates = xform.Coordinates; diff --git a/Content.Shared/Paper/PaperSystem.cs b/Content.Shared/Paper/PaperSystem.cs index 712133c0e6..6fda16b1f3 100644 --- a/Content.Shared/Paper/PaperSystem.cs +++ b/Content.Shared/Paper/PaperSystem.cs @@ -9,6 +9,7 @@ using Content.Shared.Tag; using Robust.Shared.Player; using Robust.Shared.Audio.Systems; using static Content.Shared.Paper.PaperComponent; +using Robust.Shared.Prototypes; namespace Content.Shared.Paper; @@ -23,6 +24,9 @@ public sealed class PaperSystem : EntitySystem [Dependency] private readonly MetaDataSystem _metaSystem = default!; [Dependency] private readonly SharedAudioSystem _audio = default!; + private static readonly ProtoId WriteIgnoreStampsTag = "WriteIgnoreStamps"; + private static readonly ProtoId WriteTag = "Write"; + public override void Initialize() { base.Initialize(); @@ -100,8 +104,8 @@ public sealed class PaperSystem : EntitySystem private void OnInteractUsing(Entity entity, ref InteractUsingEvent args) { // only allow editing if there are no stamps or when using a cyberpen - var editable = entity.Comp.StampedBy.Count == 0 || _tagSystem.HasTag(args.Used, "WriteIgnoreStamps"); - if (_tagSystem.HasTag(args.Used, "Write")) + var editable = entity.Comp.StampedBy.Count == 0 || _tagSystem.HasTag(args.Used, WriteIgnoreStampsTag); + if (_tagSystem.HasTag(args.Used, WriteTag)) { if (editable) { diff --git a/Content.Shared/RCD/Systems/RCDSystem.cs b/Content.Shared/RCD/Systems/RCDSystem.cs index 62ad2f3be0..9e5096c77c 100644 --- a/Content.Shared/RCD/Systems/RCDSystem.cs +++ b/Content.Shared/RCD/Systems/RCDSystem.cs @@ -51,6 +51,7 @@ public class RCDSystem : EntitySystem private readonly EntProtoId _instantConstructionFx = "EffectRCDConstruct0"; private readonly ProtoId _deconstructTileProto = "DeconstructTile"; private readonly ProtoId _deconstructLatticeProto = "DeconstructLattice"; + private static readonly ProtoId CatwalkTag = "Catwalk"; private HashSet _intersectingEntities = new(); @@ -411,7 +412,7 @@ public class RCDSystem : EntitySystem if (isWindow && HasComp(ent)) continue; - if (isCatwalk && _tags.HasTag(ent, "Catwalk")) + if (isCatwalk && _tags.HasTag(ent, CatwalkTag)) { if (popMsgs) _popup.PopupClient(Loc.GetString("rcd-component-cannot-build-on-occupied-tile-message"), uid, user); From 6ed0644fc0f4a9acbb2de949dfc24e290979b1ae Mon Sep 17 00:00:00 2001 From: BWTCK <193008538+BWTCK@users.noreply.github.com> Date: Fri, 4 Apr 2025 21:00:47 -0600 Subject: [PATCH 40/42] Fix shutter construction ghost rotation (#36082) * Fixed shutter construction frame not aligning with construction ghost * removed metadata change that should be in a different PR --- .../Prototypes/Entities/Structures/Doors/Shutter/shutters.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Resources/Prototypes/Entities/Structures/Doors/Shutter/shutters.yml b/Resources/Prototypes/Entities/Structures/Doors/Shutter/shutters.yml index 41e85e6c3f..f322de7283 100644 --- a/Resources/Prototypes/Entities/Structures/Doors/Shutter/shutters.yml +++ b/Resources/Prototypes/Entities/Structures/Doors/Shutter/shutters.yml @@ -240,4 +240,4 @@ layer: - HighImpassable - type: Transform - noRot: true + noRot: false From f66fd152cfe21d95958f0741840ee7c0d6e68915 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C4=81da?= Date: Fri, 4 Apr 2025 22:22:12 -0500 Subject: [PATCH 41/42] Add 10u of plasma to SyndieJuice (#36280) Gift for the agent --- .../Prototypes/Catalog/VendingMachines/Inventories/chemvend.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/Resources/Prototypes/Catalog/VendingMachines/Inventories/chemvend.yml b/Resources/Prototypes/Catalog/VendingMachines/Inventories/chemvend.yml index 0a1c562dd7..42a484e4ab 100644 --- a/Resources/Prototypes/Catalog/VendingMachines/Inventories/chemvend.yml +++ b/Resources/Prototypes/Catalog/VendingMachines/Inventories/chemvend.yml @@ -53,6 +53,7 @@ JugSugar: 3 JugSulfur: 1 JugWeldingFuel: 1 + PlasmaChemistryVial: 1 contrabandInventory: DrinkLithiumFlask: 1 StrangePill: 3 From a4ba5ff4081a92b6b4a69267ce7103c723e462d6 Mon Sep 17 00:00:00 2001 From: PJBot Date: Sat, 5 Apr 2025 03:23:21 +0000 Subject: [PATCH 42/42] 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 a7e81662a2..a33491b645 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,17 +1,4 @@ Entries: -- author: ScarKy0, GoldenCan - changes: - - message: The Derelict Cyborg - a broken cyborg with altered laws due to year of - exposure to ion storms - can now appear as a ghost role through a new midround - event. - type: Add - - message: An ion storm affecting a Cyborg can no longer alter the law order of - the AI, cyborgs created later in the round or AI's and cyborgs in subsequent - rounds. - type: Fix - id: 7634 - time: '2024-11-20T07:55:13.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/32499 - author: IProduceWidgets changes: - message: Presents no longer make non-items into items @@ -3894,3 +3881,10 @@ id: 8133 time: '2025-04-04T20:24:05.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/36276 +- author: aada + changes: + - message: SyndieJuice now comes with 10 units of liquid plasma. + type: Add + id: 8134 + time: '2025-04-05T03:22:12.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/36280