From 24993c3ffef9aaa48174a4ab3b59f02ed2d3cb3a Mon Sep 17 00:00:00 2001 From: Samuka <47865393+Samuka-C@users.noreply.github.com> Date: Tue, 2 Dec 2025 11:28:33 -0300 Subject: [PATCH 001/360] Fix xenoborg evac calling announcment (#41437) * no longer calls evac if evac is called or if the round is over * can't recall shuttle * some commentary * can recall next round * cancel evac recalling * add this back * only call once * admins can recall anyway now * 1 bool is better than 2 i guess * some cleanup --------- Co-authored-by: Princess Cheeseballs <66055347+Pronana@users.noreply.github.com> --- .../Commands/ShuttleCommands.cs | 2 +- .../Components/XenoborgsRuleComponent.cs | 7 +++ .../GameTicking/Rules/XenoborgsRuleSystem.cs | 15 +++--- Content.Server/RoundEnd/RoundEndSystem.cs | 46 +++++++++++++++---- 4 files changed, 55 insertions(+), 15 deletions(-) diff --git a/Content.Server/Administration/Commands/ShuttleCommands.cs b/Content.Server/Administration/Commands/ShuttleCommands.cs index 677c38ac4e..6dffe1f52c 100644 --- a/Content.Server/Administration/Commands/ShuttleCommands.cs +++ b/Content.Server/Administration/Commands/ShuttleCommands.cs @@ -35,7 +35,7 @@ namespace Content.Server.Administration.Commands public override void Execute(IConsoleShell shell, string argStr, string[] args) { - _roundEndSystem.CancelRoundEndCountdown(shell.Player?.AttachedEntity, false); + _roundEndSystem.CancelRoundEndCountdown(shell.Player?.AttachedEntity, forceRecall: true); } } } diff --git a/Content.Server/GameTicking/Rules/Components/XenoborgsRuleComponent.cs b/Content.Server/GameTicking/Rules/Components/XenoborgsRuleComponent.cs index c7496bb0fb..4a018d7e6c 100644 --- a/Content.Server/GameTicking/Rules/Components/XenoborgsRuleComponent.cs +++ b/Content.Server/GameTicking/Rules/Components/XenoborgsRuleComponent.cs @@ -36,4 +36,11 @@ public sealed partial class XenoborgsRuleComponent : Component /// [DataField] public bool MothershipCoreDeathAnnouncmentSent = false; + + /// + /// If the emergency shuttle trigged by was already called. + /// Will only call once. if a admin recalls it. it won't call again unless this is set to false by a admin + /// + [DataField] + public bool XenoborgShuttleCalled = false; } diff --git a/Content.Server/GameTicking/Rules/XenoborgsRuleSystem.cs b/Content.Server/GameTicking/Rules/XenoborgsRuleSystem.cs index 97a6efb471..cda1bce258 100644 --- a/Content.Server/GameTicking/Rules/XenoborgsRuleSystem.cs +++ b/Content.Server/GameTicking/Rules/XenoborgsRuleSystem.cs @@ -100,14 +100,17 @@ public sealed class XenoborgsRuleSystem : GameRuleSystem xenoborgsRuleComponent.MaxNumberXenoborgs = Math.Max(xenoborgsRuleComponent.MaxNumberXenoborgs, numXenoborgs); - if ((float)numXenoborgs / (numHumans + numXenoborgs) > xenoborgsRuleComponent.XenoborgShuttleCallPercentage) + if (xenoborgsRuleComponent.XenoborgShuttleCalled + || (float)numXenoborgs / (numHumans + numXenoborgs) <= xenoborgsRuleComponent.XenoborgShuttleCallPercentage + || _roundEnd.IsRoundEndRequested()) + return; + + foreach (var station in _station.GetStations()) { - foreach (var station in _station.GetStations()) - { - _chatSystem.DispatchStationAnnouncement(station, Loc.GetString("xenoborg-shuttle-call"), colorOverride: Color.BlueViolet); - } - _roundEnd.RequestRoundEnd(null, false); + _chatSystem.DispatchStationAnnouncement(station, Loc.GetString("xenoborg-shuttle-call"), colorOverride: Color.BlueViolet); } + _roundEnd.RequestRoundEnd(null, false, cantRecall: true); + xenoborgsRuleComponent.XenoborgShuttleCalled = true; } protected override void Started(EntityUid uid, XenoborgsRuleComponent component, GameRuleComponent gameRule, GameRuleStartedEvent args) diff --git a/Content.Server/RoundEnd/RoundEndSystem.cs b/Content.Server/RoundEnd/RoundEndSystem.cs index f59203c50c..8e728a962f 100644 --- a/Content.Server/RoundEnd/RoundEndSystem.cs +++ b/Content.Server/RoundEnd/RoundEndSystem.cs @@ -56,6 +56,11 @@ namespace Content.Server.RoundEnd public TimeSpan? ExpectedShuttleLength => ExpectedCountdownEnd - LastCountdownStart; public TimeSpan? ShuttleTimeLeft => ExpectedCountdownEnd - _gameTiming.CurTime; + /// + /// If the shuttle can't be recalled. if set to true, the station wont be able to recall + /// + public bool CantRecall = false; + public TimeSpan AutoCallStartTime; private bool _autoCalledBefore = false; @@ -85,6 +90,8 @@ namespace Content.Server.RoundEnd _cooldownTokenSource = null; } + CantRecall = false; + LastCountdownStart = null; ExpectedCountdownEnd = null; SetAutoCallTime(); @@ -116,7 +123,7 @@ namespace Content.Server.RoundEnd public bool CanCallOrRecall() { - return _cooldownTokenSource == null; + return _cooldownTokenSource == null && !CantRecall; } public bool IsRoundEndRequested() @@ -124,7 +131,15 @@ namespace Content.Server.RoundEnd return _countdownTokenSource != null; } - public void RequestRoundEnd(EntityUid? requester = null, bool checkCooldown = true, string text = "round-end-system-shuttle-called-announcement", string name = "round-end-system-shuttle-sender-announcement") + /// + /// Starts the process of ending the round by calling evac + /// + /// + /// + /// text in the announcement of shuttle calling + /// name in the announcement of shuttle calling + /// if the station shouldn't be able to recall the shuttle + public void RequestRoundEnd(EntityUid? requester = null, bool checkCooldown = true, string text = "round-end-system-shuttle-called-announcement", string name = "round-end-system-shuttle-sender-announcement", bool cantRecall = false) { var duration = DefaultCountdownDuration; @@ -139,10 +154,19 @@ namespace Content.Server.RoundEnd } } - RequestRoundEnd(duration, requester, checkCooldown, text, name); + RequestRoundEnd(duration, requester, checkCooldown, text, name, cantRecall); } - public void RequestRoundEnd(TimeSpan countdownTime, EntityUid? requester = null, bool checkCooldown = true, string text = "round-end-system-shuttle-called-announcement", string name = "round-end-system-shuttle-sender-announcement") + /// + /// Starts the process of ending the round by calling evac + /// + /// time for evac to arrive + /// + /// + /// text in the announcement of shuttle calling + /// name in the announcement of shuttle calling + /// if the station shouldn't be able to recall the shuttle + public void RequestRoundEnd(TimeSpan countdownTime, EntityUid? requester = null, bool checkCooldown = true, string text = "round-end-system-shuttle-called-announcement", string name = "round-end-system-shuttle-sender-announcement", bool cantRecall = false) { if (_gameTicker.RunLevel != GameRunLevel.InRound) return; @@ -154,6 +178,7 @@ namespace Content.Server.RoundEnd return; _countdownTokenSource = new(); + CantRecall = cantRecall; if (requester != null) { @@ -214,12 +239,17 @@ namespace Content.Server.RoundEnd } } - public void CancelRoundEndCountdown(EntityUid? requester = null, bool checkCooldown = true) + public void CancelRoundEndCountdown(EntityUid? requester = null, bool forceRecall = false) { - if (_gameTicker.RunLevel != GameRunLevel.InRound) return; - if (checkCooldown && _cooldownTokenSource != null) return; + if (_gameTicker.RunLevel != GameRunLevel.InRound) + return; + + if (!forceRecall && (CantRecall || _cooldownTokenSource != null)) + return; + + if (_countdownTokenSource == null) + return; - if (_countdownTokenSource == null) return; _countdownTokenSource.Cancel(); _countdownTokenSource = null; From 6486b81397fded692195f407ddbc64170bbd34a5 Mon Sep 17 00:00:00 2001 From: BarryNorfolk Date: Thu, 22 Jan 2026 19:54:42 +0100 Subject: [PATCH 002/360] Downstream fix for xenoborg evac calls --- Content.Server/_DV/CosmicCult/CosmicCultSystem.Finale.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Content.Server/_DV/CosmicCult/CosmicCultSystem.Finale.cs b/Content.Server/_DV/CosmicCult/CosmicCultSystem.Finale.cs index bb6ae0ad07..c0968ead8a 100644 --- a/Content.Server/_DV/CosmicCult/CosmicCultSystem.Finale.cs +++ b/Content.Server/_DV/CosmicCult/CosmicCultSystem.Finale.cs @@ -104,7 +104,7 @@ public sealed partial class CosmicCultSystem : SharedCosmicCultSystem Dirty(uid, monument); _ui.SetUiState(uid.Owner, MonumentKey.Key, new MonumentBuiState(monument)); - if (!_evac.EmergencyShuttleArrived && _roundEnd.IsRoundEndRequested()) _roundEnd.CancelRoundEndCountdown(checkCooldown: false); + if (!_evac.EmergencyShuttleArrived && _roundEnd.IsRoundEndRequested()) _roundEnd.CancelRoundEndCountdown(); var query = EntityQueryEnumerator(); while (query.MoveNext(out var cultist, out var cultComp)) { From d531f34b9c41cacd3b1847ba63e655d4d4ed1d82 Mon Sep 17 00:00:00 2001 From: Princess Cheeseballs <66055347+Princess-Cheeseballs@users.noreply.github.com> Date: Tue, 2 Dec 2025 06:51:59 -0800 Subject: [PATCH 003/360] Fix Mothership cannot use their tools and BorgSystem cleanup. (#41673) Fixe Co-authored-by: Princess Cheeseballs <66055347+Pronana@users.noreply.github.com> --- .../Silicons/Borgs/SharedBorgSystem.API.cs | 13 ++++++------- .../Silicons/Borgs/SharedBorgSystem.cs | 17 +++++------------ 2 files changed, 11 insertions(+), 19 deletions(-) diff --git a/Content.Shared/Silicons/Borgs/SharedBorgSystem.API.cs b/Content.Shared/Silicons/Borgs/SharedBorgSystem.API.cs index 821ef35d8d..3f86abb568 100644 --- a/Content.Shared/Silicons/Borgs/SharedBorgSystem.API.cs +++ b/Content.Shared/Silicons/Borgs/SharedBorgSystem.API.cs @@ -24,7 +24,7 @@ public abstract partial class SharedBorgSystem if (!_mind.TryGetMind(chassis.Owner, out _, out _)) return false; - if (!_mobState.IsAlive(chassis.Owner)) + if (_mobState.IsIncapacitated(chassis.Owner)) return false; return true; @@ -39,13 +39,12 @@ public abstract partial class SharedBorgSystem if (chassis.Comp.Active) return false; // Already active. - if (CanActivate(chassis)) - { - SetActive(chassis, true, user); - return true; - } + if (!CanActivate(chassis)) + return false; + + SetActive(chassis, true, user); + return true; - return false; } /// diff --git a/Content.Shared/Silicons/Borgs/SharedBorgSystem.cs b/Content.Shared/Silicons/Borgs/SharedBorgSystem.cs index d965a362ff..71818ca211 100644 --- a/Content.Shared/Silicons/Borgs/SharedBorgSystem.cs +++ b/Content.Shared/Silicons/Borgs/SharedBorgSystem.cs @@ -197,8 +197,8 @@ public abstract partial class SharedBorgSystem : EntitySystem // Unpredicted because the event is raised on the server. _popup.PopupEntity(Loc.GetString("borg-mind-added", ("name", Identity.Name(chassis.Owner, EntityManager))), chassis.Owner); - if (CanActivate(chassis)) - SetActive(chassis, true); + TryActivate(chassis); + _appearance.SetData(chassis.Owner, BorgVisuals.HasPlayer, true); } @@ -285,14 +285,9 @@ public abstract partial class SharedBorgSystem : EntitySystem private void OnMobStateChanged(Entity chassis, ref MobStateChangedEvent args) { if (args.NewMobState == MobState.Alive) - { - if (CanActivate(chassis)) - SetActive(chassis, true, user: args.Origin); - } + TryActivate(chassis, args.Origin); else - { SetActive(chassis, false, user: args.Origin); - } } private void OnBeingGibbed(Entity chassis, ref BeingGibbedEvent args) @@ -357,8 +352,7 @@ public abstract partial class SharedBorgSystem : EntitySystem // Raised when a power cell is inserted. private void OnPowerCellChanged(Entity chassis, ref PowerCellChangedEvent args) { - if (CanActivate(chassis)) - SetActive(chassis, true); + TryActivate(chassis); } public override void Update(float frameTime) @@ -374,8 +368,7 @@ public abstract partial class SharedBorgSystem : EntitySystem Dirty(uid, borgChassis); // If we aren't drawing and suddenly get enough power to draw again, reenable. - if (CanActivate((uid, borgChassis))) - SetActive((uid, borgChassis), true); + TryActivate((uid, borgChassis)); } } } From 6e7df0e06b2fcc384049fd2784a6b9277953865d Mon Sep 17 00:00:00 2001 From: Hitlinemoss <209321380+Hitlinemoss@users.noreply.github.com> Date: Tue, 2 Dec 2025 11:43:43 -0500 Subject: [PATCH 004/360] Minor cleanup of crowbars.yml (#41672) * Minor cleanup of crowbars.yml * Or, not and * I think the CrowbarRed tag actually is used for belt sprite stuff? Removing a code comment calling it a legacy tag. --- .../Prototypes/Entities/Objects/Tools/crowbars.yml | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/Resources/Prototypes/Entities/Objects/Tools/crowbars.yml b/Resources/Prototypes/Entities/Objects/Tools/crowbars.yml index 31a6b8ef06..50ba2b9f7f 100644 --- a/Resources/Prototypes/Entities/Objects/Tools/crowbars.yml +++ b/Resources/Prototypes/Entities/Objects/Tools/crowbars.yml @@ -1,8 +1,9 @@ - type: entity - name: crowbar + abstract: true parent: BaseItem id: BaseCrowbar - abstract: true + name: crowbar + description: A multipurpose tool used for many tasks, such as prying doors or bludgeoning interdimensional invaders. components: - type: EmitSoundOnLand sound: @@ -50,7 +51,6 @@ - type: entity parent: BaseCrowbar id: Crowbar - description: A multipurpose tool to pry open doors and fight interdimensional invaders. components: - type: Sprite state: icon @@ -61,10 +61,8 @@ # Emergency (red) Crowbar - type: entity - name: emergency crowbar parent: BaseCrowbar id: CrowbarRed - description: An emergency crowbar designed to pry open doors and firelocks during power outages. components: - type: Tag tags: @@ -99,7 +97,6 @@ - type: entity parent: BaseCrowbar id: CrowbarGreen - description: A multipurpose tool to pry open doors and fight interdimensional invaders, printed from an autolathe. components: - type: Sprite layers: @@ -130,7 +127,6 @@ - type: entity parent: BaseCrowbar id: CrowbarOrange - description: A multipurpose tool to pry open doors and fight interdimensional invaders, found in toolboxes. components: - type: Sprite layers: @@ -161,7 +157,6 @@ - type: entity parent: BaseCrowbar id: CrowbarYellow - description: A multipurpose tool to pry open doors and fight interdimensional invaders, dispensed from Engineering. components: - type: Sprite layers: From 22c086c901847b417b76c7544fd8bcae7e73f627 Mon Sep 17 00:00:00 2001 From: slarticodefast <161409025+slarticodefast@users.noreply.github.com> Date: Tue, 2 Dec 2025 19:33:40 +0100 Subject: [PATCH 005/360] cleanup EntityStorageSystem (#40163) --- .../Storage/Systems/EntityStorageSystem.cs | 42 +----- .../EntitySystems/EntityStorageSystem.cs | 88 ++---------- .../Components/EntityStorageComponent.cs | 93 ++++++------- .../InsideEntityStorageComponent.cs | 12 +- .../SharedEntityStorageSystem.cs | 125 ++++++++++-------- 5 files changed, 133 insertions(+), 227 deletions(-) diff --git a/Content.Client/Storage/Systems/EntityStorageSystem.cs b/Content.Client/Storage/Systems/EntityStorageSystem.cs index ca2b986667..96dc353c48 100644 --- a/Content.Client/Storage/Systems/EntityStorageSystem.cs +++ b/Content.Client/Storage/Systems/EntityStorageSystem.cs @@ -1,43 +1,5 @@ -using System.Diagnostics.CodeAnalysis; -using Content.Client.Storage.Components; -using Content.Shared.Destructible; -using Content.Shared.Foldable; -using Content.Shared.Interaction; -using Content.Shared.Lock; -using Content.Shared.Movement.Events; -using Content.Shared.Storage.Components; -using Content.Shared.Storage.EntitySystems; -using Content.Shared.Verbs; -using Robust.Shared.GameStates; +using Content.Shared.Storage.EntitySystems; namespace Content.Client.Storage.Systems; -public sealed class EntityStorageSystem : SharedEntityStorageSystem -{ - public override void Initialize() - { - base.Initialize(); - SubscribeLocalEvent(OnEntityUnpausedEvent); - SubscribeLocalEvent(OnComponentInit); - SubscribeLocalEvent(OnComponentStartup); - SubscribeLocalEvent(OnInteract, after: new[] { typeof(LockSystem) }); - SubscribeLocalEvent(OnLockToggleAttempt); - SubscribeLocalEvent(OnDestruction); - SubscribeLocalEvent>(AddToggleOpenVerb); - SubscribeLocalEvent(OnRelayMovement); - SubscribeLocalEvent(OnFoldAttempt); - - SubscribeLocalEvent(OnGetState); - SubscribeLocalEvent(OnHandleState); - } - - public override bool ResolveStorage(EntityUid uid, [NotNullWhen(true)] ref EntityStorageComponent? component) - { - if (component != null) - return true; - - TryComp(uid, out var storage); - component = storage; - return component != null; - } -} +public sealed class EntityStorageSystem : SharedEntityStorageSystem; diff --git a/Content.Server/Storage/EntitySystems/EntityStorageSystem.cs b/Content.Server/Storage/EntitySystems/EntityStorageSystem.cs index c38a3e9b17..e22a4f5d7e 100644 --- a/Content.Server/Storage/EntitySystems/EntityStorageSystem.cs +++ b/Content.Server/Storage/EntitySystems/EntityStorageSystem.cs @@ -1,22 +1,10 @@ -using System.Diagnostics.CodeAnalysis; using Content.Server.Atmos.EntitySystems; using Content.Server.Body.Systems; using Content.Server.Construction; using Content.Server.Construction.Components; -using Content.Server.Storage.Components; -using Content.Shared.Destructible; -using Content.Shared.Explosion; -using Content.Shared.Foldable; -using Content.Shared.Interaction; -using Content.Shared.Lock; -using Content.Shared.Movement.Events; using Content.Shared.Storage.Components; using Content.Shared.Storage.EntitySystems; -using Content.Shared.Tools.Systems; -using Content.Shared.Verbs; using Robust.Server.GameObjects; -using Robust.Shared.Containers; -using Robust.Shared.GameStates; using Robust.Shared.Map; namespace Content.Server.Storage.EntitySystems; @@ -32,30 +20,11 @@ public sealed class EntityStorageSystem : SharedEntityStorageSystem { base.Initialize(); - /* CompRef things */ - SubscribeLocalEvent(OnEntityUnpausedEvent); - SubscribeLocalEvent(OnComponentInit); - SubscribeLocalEvent(OnComponentStartup); - SubscribeLocalEvent(OnInteract, after: new[] { typeof(LockSystem) }); - SubscribeLocalEvent(OnLockToggleAttempt); - SubscribeLocalEvent(OnDestruction); - SubscribeLocalEvent>(AddToggleOpenVerb); - SubscribeLocalEvent(OnRelayMovement); - SubscribeLocalEvent(OnFoldAttempt); - - SubscribeLocalEvent(OnGetState); - SubscribeLocalEvent(OnHandleState); - /* CompRef things */ - SubscribeLocalEvent(OnMapInit); - SubscribeLocalEvent(OnWeldableAttempt); - SubscribeLocalEvent(OnExploded); SubscribeLocalEvent(OnInsideInhale); SubscribeLocalEvent(OnInsideExhale); SubscribeLocalEvent(OnInsideExposed); - - SubscribeLocalEvent(OnRemoved); } private void OnMapInit(EntityUid uid, EntityStorageComponent component, MapInitEvent args) @@ -76,64 +45,30 @@ public sealed class EntityStorageSystem : SharedEntityStorageSystem _construction.AddContainer(uid, ContainerName, construction); } - public override bool ResolveStorage(EntityUid uid, [NotNullWhen(true)] ref EntityStorageComponent? component) - { - if (component != null) - return true; - - TryComp(uid, out var storage); - component = storage; - return component != null; - } - - private void OnWeldableAttempt(EntityUid uid, EntityStorageComponent component, WeldableAttemptEvent args) - { - if (component.Open) - { - args.Cancel(); - return; - } - - if (component.Contents.Contains(args.User)) - { - var msg = Loc.GetString("entity-storage-component-already-contains-user-message"); - Popup.PopupEntity(msg, args.User, args.User); - args.Cancel(); - } - } - - private void OnExploded(Entity ent, ref BeforeExplodeEvent args) - { - args.Contents.AddRange(ent.Comp.Contents.ContainedEntities); - } - protected override void TakeGas(EntityUid uid, EntityStorageComponent component) { if (!component.Airtight) return; - var serverComp = (EntityStorageComponent) component; - var tile = GetOffsetTileRef(uid, serverComp); + var tile = GetOffsetTileRef(uid, component); - if (tile != null && _atmos.GetTileMixture(tile.Value.GridUid, null, tile.Value.GridIndices, true) is {} environment) + if (tile != null && _atmos.GetTileMixture(tile.Value.GridUid, null, tile.Value.GridIndices, true) is { } environment) { - _atmos.Merge(serverComp.Air, environment.RemoveVolume(serverComp.Air.Volume)); + _atmos.Merge(component.Air, environment.RemoveVolume(component.Air.Volume)); } } public override void ReleaseGas(EntityUid uid, EntityStorageComponent component) { - var serverComp = (EntityStorageComponent) component; - - if (!serverComp.Airtight) + if (!component.Airtight) return; - var tile = GetOffsetTileRef(uid, serverComp); + var tile = GetOffsetTileRef(uid, component); - if (tile != null && _atmos.GetTileMixture(tile.Value.GridUid, null, tile.Value.GridIndices, true) is {} environment) + if (tile != null && _atmos.GetTileMixture(tile.Value.GridUid, null, tile.Value.GridIndices, true) is { } environment) { - _atmos.Merge(environment, serverComp.Air); - serverComp.Air.Clear(); + _atmos.Merge(environment, component.Air); + component.Air.Clear(); } } @@ -149,13 +84,6 @@ public sealed class EntityStorageSystem : SharedEntityStorageSystem return null; } - private void OnRemoved(EntityUid uid, InsideEntityStorageComponent component, EntGotRemovedFromContainerMessage args) - { - if (args.Container.Owner != component.Storage) - return; - RemComp(uid, component); - } - #region Gas mix event handlers private void OnInsideInhale(EntityUid uid, InsideEntityStorageComponent component, InhaleLocationEvent args) diff --git a/Content.Shared/Storage/Components/EntityStorageComponent.cs b/Content.Shared/Storage/Components/EntityStorageComponent.cs index 009083b2d8..ecfcccc45b 100644 --- a/Content.Shared/Storage/Components/EntityStorageComponent.cs +++ b/Content.Shared/Storage/Components/EntityStorageComponent.cs @@ -5,42 +5,61 @@ using Content.Shared.Whitelist; using Robust.Shared.Audio; using Robust.Shared.Containers; using Robust.Shared.GameStates; -using Robust.Shared.Serialization; namespace Content.Shared.Storage.Components; +/// +/// A storage component that stores nearby entities in a container when this object is opened or closed. +/// This does not have an UI like grid storage, but just makes them disappear inside. +/// Used for lockers, crates etc. +/// [RegisterComponent, NetworkedComponent] +[AutoGenerateComponentState, AutoGenerateComponentPause] // TODO: Field deltas public sealed partial class EntityStorageComponent : Component, IGasMixtureHolder { - public readonly float MaxSize = 1.0f; // maximum width or height of an entity allowed inside the storage. + /// + /// Maximum width or height of an entity allowed inside the storage. + /// + [DataField, AutoNetworkedField] + public float MaxSize = 1.0f; - public static readonly TimeSpan InternalOpenAttemptDelay = TimeSpan.FromSeconds(0.5); + /// + /// The delay between opening attempts when stuck inside an entity storage. + /// + [DataField, AutoNetworkedField] + public TimeSpan InternalOpenAttemptDelay = TimeSpan.FromSeconds(0.5); + + /// + /// The next time a player stuck inside the entity storage can attempt to open it from inside. + /// + [DataField, AutoNetworkedField, AutoPausedField] public TimeSpan NextInternalOpenAttempt; /// - /// Collision masks that get removed when the storage gets opened. + /// Collision masks that get removed when the storage gets opened. /// - public readonly int MasksToRemove = (int)( + [DataField] + public int MasksToRemove = (int)( CollisionGroup.MidImpassable | CollisionGroup.HighImpassable | CollisionGroup.LowImpassable); /// - /// Collision masks that were removed from ANY layer when the storage was opened; + /// Collision masks that were removed from ANY layer when the storage was opened; /// [DataField] public int RemovedMasks; /// - /// The total amount of items that can fit in one entitystorage + /// The total amount of items that can fit in one entitystorage. /// - [DataField] + [DataField, AutoNetworkedField] public int Capacity = 30; /// - /// Whether or not the entity still has collision when open + /// Whether or not the entity still has collision when open. /// - [DataField] + [DataField, AutoNetworkedField] public bool IsCollidableWhenOpen; /// @@ -48,7 +67,7 @@ public sealed partial class EntityStorageComponent : Component, IGasMixtureHolde /// If false, it prevents the storage from opening when the entity inside of it moves. /// This is for objects that you want the player to move while inside, like large cardboard boxes, without opening the storage. /// - [DataField] + [DataField, AutoNetworkedField] public bool OpenOnMove = true; //The offset for where items are emptied/vacuumed for the EntityStorage. @@ -60,62 +79,62 @@ public sealed partial class EntityStorageComponent : Component, IGasMixtureHolde public CollisionGroup EnteringOffsetCollisionFlags = CollisionGroup.Impassable | CollisionGroup.MidImpassable; /// - /// How close you have to be to the "entering" spot to be able to enter + /// How close you have to be to the "entering" spot to be able to enter. /// - [DataField] + [DataField, AutoNetworkedField] public float EnteringRange = 0.18f; /// - /// Whether or not to show the contents when the storage is closed + /// Whether or not to show the contents when the storage is closed. /// [DataField] public bool ShowContents; /// - /// Whether or not light is occluded by the storage + /// Whether or not light is occluded by the storage. /// [DataField] public bool OccludesLight = true; /// - /// Whether or not all the contents stored should be deleted with the entitystorage + /// Whether or not all the contents stored should be deleted with the entitystorage. /// [DataField] public bool DeleteContentsOnDestruction; /// - /// Whether or not the container is sealed and traps air inside of it + /// Whether or not the container is sealed and traps air inside of it. /// [DataField] public bool Airtight = true; /// - /// Whether or not the entitystorage is open or closed + /// Whether or not the entitystorage is open or closed. /// - [DataField] + [DataField, AutoNetworkedField] public bool Open; /// - /// The sound made when closed + /// The sound made when closed. /// [DataField] public SoundSpecifier CloseSound = new SoundPathSpecifier("/Audio/Effects/closetclose.ogg"); /// - /// The sound made when open + /// The sound made when opened. /// [DataField] public SoundSpecifier OpenSound = new SoundPathSpecifier("/Audio/Effects/closetopen.ogg"); /// - /// Whitelist for what entities are allowed to be inserted into this container. If this is not null, the - /// standard requirement that the entity must be an item or mob is waived. + /// Whitelist for what entities are allowed to be inserted into this container. If this is not null, the + /// standard requirement that the entity must be an item or mob is waived. /// [DataField] public EntityWhitelist? Whitelist; /// - /// The contents of the storage + /// The contents of the storage. /// [ViewVariables] public Container Contents = default!; @@ -128,32 +147,6 @@ public sealed partial class EntityStorageComponent : Component, IGasMixtureHolde public GasMixture Air { get; set; } = new(200); } -[Serializable, NetSerializable] -public sealed class EntityStorageComponentState : ComponentState -{ - public bool Open; - - public int Capacity; - - public bool IsCollidableWhenOpen; - - public bool OpenOnMove; - - public float EnteringRange; - - public TimeSpan NextInternalOpenAttempt; - - public EntityStorageComponentState(bool open, int capacity, bool isCollidableWhenOpen, bool openOnMove, float enteringRange, TimeSpan nextInternalOpenAttempt) - { - Open = open; - Capacity = capacity; - IsCollidableWhenOpen = isCollidableWhenOpen; - OpenOnMove = openOnMove; - EnteringRange = enteringRange; - NextInternalOpenAttempt = nextInternalOpenAttempt; - } -} - /// /// Raised on the entity being inserted whenever checking if an entity can be inserted into an entity storage. /// diff --git a/Content.Shared/Storage/Components/InsideEntityStorageComponent.cs b/Content.Shared/Storage/Components/InsideEntityStorageComponent.cs index 258ea07ec6..8d0b45a4a2 100644 --- a/Content.Shared/Storage/Components/InsideEntityStorageComponent.cs +++ b/Content.Shared/Storage/Components/InsideEntityStorageComponent.cs @@ -1,10 +1,16 @@ -namespace Content.Shared.Storage.Components; +using Robust.Shared.GameStates; + +namespace Content.Shared.Storage.Components; /// -/// Added to entities contained within entity storage, for directed event purposes. +/// Added to entities contained within entity storage, for directed event purposes. /// -[RegisterComponent] +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] public sealed partial class InsideEntityStorageComponent : Component { + /// + /// The entity storage this entity is inside. + /// + [DataField, AutoNetworkedField] public EntityUid Storage; } diff --git a/Content.Shared/Storage/EntitySystems/SharedEntityStorageSystem.cs b/Content.Shared/Storage/EntitySystems/SharedEntityStorageSystem.cs index dd6f1a223e..93a534843a 100644 --- a/Content.Shared/Storage/EntitySystems/SharedEntityStorageSystem.cs +++ b/Content.Shared/Storage/EntitySystems/SharedEntityStorageSystem.cs @@ -1,10 +1,9 @@ -using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Numerics; -using Content.Shared.Body.Components; using Content.Shared.Destructible; using Content.Shared.Foldable; using Content.Shared.Hands.Components; +using Content.Shared.Explosion; using Content.Shared.Interaction; using Content.Shared.Item; using Content.Shared.Lock; @@ -19,7 +18,6 @@ using Content.Shared.ActionBlocker; using Content.Shared.Mobs.Components; using Robust.Shared.Audio.Systems; using Robust.Shared.Containers; -using Robust.Shared.GameStates; using Robust.Shared.Map; using Robust.Shared.Network; using Robust.Shared.Physics; @@ -48,31 +46,23 @@ public abstract class SharedEntityStorageSystem : EntitySystem public const string ContainerName = "entity_storage"; - protected void OnEntityUnpausedEvent(EntityUid uid, EntityStorageComponent component, EntityUnpausedEvent args) + public override void Initialize() { - component.NextInternalOpenAttempt += args.PausedTime; - } + base.Initialize(); - protected void OnGetState(EntityUid uid, EntityStorageComponent component, ref ComponentGetState args) - { - args.State = new EntityStorageComponentState(component.Open, - component.Capacity, - component.IsCollidableWhenOpen, - component.OpenOnMove, - component.EnteringRange, - component.NextInternalOpenAttempt); - } + SubscribeLocalEvent(OnComponentInit); + SubscribeLocalEvent(OnComponentStartup); + SubscribeLocalEvent(OnInteract, after: new[] { typeof(LockSystem) }); + SubscribeLocalEvent(OnLockToggleAttempt); + SubscribeLocalEvent(OnDestruction); + SubscribeLocalEvent>(AddToggleOpenVerb); + SubscribeLocalEvent(OnRelayMovement); + SubscribeLocalEvent(OnFoldAttempt); - protected void OnHandleState(EntityUid uid, EntityStorageComponent component, ref ComponentHandleState args) - { - if (args.Current is not EntityStorageComponentState state) - return; - component.Open = state.Open; - component.Capacity = state.Capacity; - component.IsCollidableWhenOpen = state.IsCollidableWhenOpen; - component.OpenOnMove = state.OpenOnMove; - component.EnteringRange = state.EnteringRange; - component.NextInternalOpenAttempt = state.NextInternalOpenAttempt; + SubscribeLocalEvent(OnWeldableAttempt); + SubscribeLocalEvent(OnExploded); + + SubscribeLocalEvent(OnRemoved); } protected virtual void OnComponentInit(EntityUid uid, EntityStorageComponent component, ComponentInit args) @@ -82,12 +72,12 @@ public abstract class SharedEntityStorageSystem : EntitySystem component.Contents.OccludesLight = component.OccludesLight; } - protected virtual void OnComponentStartup(EntityUid uid, EntityStorageComponent component, ComponentStartup args) + private void OnComponentStartup(EntityUid uid, EntityStorageComponent component, ComponentStartup args) { _appearance.SetData(uid, StorageVisuals.Open, component.Open); } - protected void OnInteract(EntityUid uid, EntityStorageComponent component, ActivateInWorldEvent args) + private void OnInteract(EntityUid uid, EntityStorageComponent component, ActivateInWorldEvent args) { if (args.Handled || !args.Complex) return; @@ -96,9 +86,7 @@ public abstract class SharedEntityStorageSystem : EntitySystem ToggleOpen(args.User, uid, component); } - public abstract bool ResolveStorage(EntityUid uid, [NotNullWhen(true)] ref EntityStorageComponent? component); - - protected void OnLockToggleAttempt(EntityUid uid, EntityStorageComponent target, ref LockToggleAttemptEvent args) + private void OnLockToggleAttempt(EntityUid uid, EntityStorageComponent target, ref LockToggleAttemptEvent args) { // Cannot (un)lock open lockers. if (target.Open) @@ -109,7 +97,7 @@ public abstract class SharedEntityStorageSystem : EntitySystem args.Cancelled = true; } - protected void OnDestruction(EntityUid uid, EntityStorageComponent component, DestructionEventArgs args) + private void OnDestruction(EntityUid uid, EntityStorageComponent component, DestructionEventArgs args) { component.Open = true; Dirty(uid, component); @@ -125,7 +113,7 @@ public abstract class SharedEntityStorageSystem : EntitySystem } } - protected void OnRelayMovement(EntityUid uid, EntityStorageComponent component, ref ContainerRelayMovementEntityEvent args) + private void OnRelayMovement(EntityUid uid, EntityStorageComponent component, ref ContainerRelayMovementEntityEvent args) { if (!HasComp(args.Entity)) return; @@ -136,21 +124,54 @@ public abstract class SharedEntityStorageSystem : EntitySystem if (_timing.CurTime < component.NextInternalOpenAttempt) return; - component.NextInternalOpenAttempt = _timing.CurTime + EntityStorageComponent.InternalOpenAttemptDelay; + component.NextInternalOpenAttempt = _timing.CurTime + component.InternalOpenAttemptDelay; Dirty(uid, component); if (component.OpenOnMove) TryOpenStorage(args.Entity, uid); } - protected void OnFoldAttempt(EntityUid uid, EntityStorageComponent component, ref FoldAttemptEvent args) + private void OnFoldAttempt(EntityUid uid, EntityStorageComponent component, ref FoldAttemptEvent args) { if (args.Cancelled) return; + args.Cancelled = component.Open || component.Contents.ContainedEntities.Count != 0; } - protected void AddToggleOpenVerb(EntityUid uid, EntityStorageComponent component, GetVerbsEvent args) + private void OnWeldableAttempt(EntityUid uid, EntityStorageComponent component, WeldableAttemptEvent args) + { + if (component.Open) + { + args.Cancel(); + return; + } + + if (component.Contents.Contains(args.User)) + { + var msg = Loc.GetString("entity-storage-component-already-contains-user-message"); + Popup.PopupEntity(msg, args.User, args.User); + args.Cancel(); + } + } + + private void OnExploded(Entity ent, ref BeforeExplodeEvent args) + { + args.Contents.AddRange(ent.Comp.Contents.ContainedEntities); + } + + private void OnRemoved(EntityUid uid, InsideEntityStorageComponent component, EntGotRemovedFromContainerMessage args) + { + if (_timing.ApplyingState) + return; // the component removal is already networked on its own + + if (args.Container.Owner != component.Storage) + return; + + RemComp(uid, component); + } + + private void AddToggleOpenVerb(EntityUid uid, EntityStorageComponent component, GetVerbsEvent args) { if (!args.CanAccess || !args.CanInteract) return; @@ -177,7 +198,7 @@ public abstract class SharedEntityStorageSystem : EntitySystem public void ToggleOpen(EntityUid user, EntityUid target, EntityStorageComponent? component = null) { - if (!ResolveStorage(target, ref component)) + if (!Resolve(target, ref component)) return; if (component.Open) @@ -192,7 +213,7 @@ public abstract class SharedEntityStorageSystem : EntitySystem public void EmptyContents(EntityUid uid, EntityStorageComponent? component = null) { - if (!ResolveStorage(uid, ref component)) + if (!Resolve(uid, ref component)) return; var uidXform = Transform(uid); @@ -205,7 +226,7 @@ public abstract class SharedEntityStorageSystem : EntitySystem public void OpenStorage(EntityUid uid, EntityStorageComponent? component = null) { - if (!ResolveStorage(uid, ref component)) + if (!Resolve(uid, ref component)) return; if (component.Open) @@ -226,7 +247,7 @@ public abstract class SharedEntityStorageSystem : EntitySystem public void CloseStorage(EntityUid uid, EntityStorageComponent? component = null) { - if (!ResolveStorage(uid, ref component)) + if (!Resolve(uid, ref component)) return; if (!component.Open) @@ -277,7 +298,7 @@ public abstract class SharedEntityStorageSystem : EntitySystem public bool Insert(EntityUid toInsert, EntityUid container, EntityStorageComponent? component = null) { - if (!ResolveStorage(container, ref component)) + if (!Resolve(container, ref component)) return false; if (component.Open) @@ -286,12 +307,14 @@ public abstract class SharedEntityStorageSystem : EntitySystem return true; } + // TODO: This should be done automatically for all containers _joints.RecursiveClearJoints(toInsert); if (!_container.Insert(toInsert, component.Contents)) return false; var inside = EnsureComp(toInsert); inside.Storage = container; + Dirty(toInsert, inside); return true; } @@ -300,7 +323,7 @@ public abstract class SharedEntityStorageSystem : EntitySystem if (!Resolve(container, ref xform, false)) return false; - if (!ResolveStorage(container, ref component)) + if (!Resolve(container, ref component)) return false; _container.Remove(toRemove, component.Contents); @@ -327,7 +350,7 @@ public abstract class SharedEntityStorageSystem : EntitySystem public bool CanInsert(EntityUid toInsert, EntityUid container, EntityStorageComponent? component = null) { - if (!ResolveStorage(container, ref component)) + if (!Resolve(container, ref component)) return false; if (component.Open) @@ -384,7 +407,7 @@ public abstract class SharedEntityStorageSystem : EntitySystem public bool IsOpen(EntityUid target, EntityStorageComponent? component = null) { - if (!ResolveStorage(target, ref component)) + if (!Resolve(target, ref component)) return false; return component.Open; @@ -392,7 +415,7 @@ public abstract class SharedEntityStorageSystem : EntitySystem public bool CanOpen(EntityUid user, EntityUid target, bool silent = false, EntityStorageComponent? component = null) { - if (!ResolveStorage(target, ref component)) + if (!Resolve(target, ref component)) return false; if (!HasComp(user)) @@ -434,7 +457,7 @@ public abstract class SharedEntityStorageSystem : EntitySystem public bool AddToContents(EntityUid toAdd, EntityUid container, EntityStorageComponent? component = null) { - if (!ResolveStorage(container, ref component)) + if (!Resolve(container, ref component)) return false; if (toAdd == container) @@ -445,7 +468,7 @@ public abstract class SharedEntityStorageSystem : EntitySystem private void ModifyComponents(EntityUid uid, EntityStorageComponent? component = null) { - if (!ResolveStorage(uid, ref component)) + if (!Resolve(uid, ref component)) return; if (!component.IsCollidableWhenOpen && TryComp(uid, out var fixtures) && @@ -475,13 +498,7 @@ public abstract class SharedEntityStorageSystem : EntitySystem _appearance.SetData(uid, StorageVisuals.HasContents, component.Contents.ContainedEntities.Count > 0); } - protected virtual void TakeGas(EntityUid uid, EntityStorageComponent component) - { + protected virtual void TakeGas(EntityUid uid, EntityStorageComponent component) { } - } - - public virtual void ReleaseGas(EntityUid uid, EntityStorageComponent component) - { - - } + public virtual void ReleaseGas(EntityUid uid, EntityStorageComponent component) { } } From 4b3e6e73a7980a3d1630ae320600f78e5b498484 Mon Sep 17 00:00:00 2001 From: BarryNorfolk Date: Thu, 22 Jan 2026 19:50:34 +0100 Subject: [PATCH 006/360] Downstream fix for EntityStorageSystem changes --- Content.Server/_DV/Autoclave/AutoclaveSystem.cs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/Content.Server/_DV/Autoclave/AutoclaveSystem.cs b/Content.Server/_DV/Autoclave/AutoclaveSystem.cs index b594990b7e..8468ed7827 100644 --- a/Content.Server/_DV/Autoclave/AutoclaveSystem.cs +++ b/Content.Server/_DV/Autoclave/AutoclaveSystem.cs @@ -2,6 +2,7 @@ using Content.Server.Power.EntitySystems; using Content.Shared._DV.Autoclave; using Content.Shared._DV.Surgery; using Content.Shared.Power; +using Content.Shared.Storage; using Content.Shared.Storage.Components; using Content.Shared.Storage.EntitySystems; using Robust.Shared.GameObjects; @@ -46,8 +47,7 @@ public sealed class AutoclaveSystem : EntitySystem if (!(isPowered && isClosed)) continue; - EntityStorageComponent? storageComponent = null; - if (!_entityStorage.ResolveStorage(uid, ref storageComponent)) + if (!TryComp(uid, out var storageComponent)) continue; foreach (var containedEntity in storageComponent.Contents.ContainedEntities) @@ -61,9 +61,8 @@ public sealed class AutoclaveSystem : EntitySystem private void UpdateVisuals(EntityUid ent, bool isPowered, bool isClosed) { - EntityStorageComponent? storageComponent = null; - bool hasDirtyContents = - _entityStorage.ResolveStorage(ent, ref storageComponent) + var hasDirtyContents = + TryComp(ent, out var storageComponent) && storageComponent.Contents.ContainedEntities.Any(contained => _surgeryClean.RequiresCleaning(contained)); var (greenLight, redLight) = (isPowered, isClosed, hasDirtyContents) switch From cfb0ac862df3cf0b0ff298b723d910d217f88fe1 Mon Sep 17 00:00:00 2001 From: Pok <113675512+Pok27@users.noreply.github.com> Date: Tue, 2 Dec 2025 21:39:21 +0200 Subject: [PATCH 007/360] Move some admin components to shared (#41677) * AdminSystem-move-to-shared * review --- .../Components/KillSignComponent.cs | 7 ------- .../Administration/Systems/BufferingSystem.cs | 7 +++++++ .../Administration/Systems/KillSignSystem.cs | 2 +- .../Tests/PostMapInitTest.cs | 15 +++++++-------- .../Components/AdminMinigunComponent.cs | 7 ------- .../Components/KillSignComponent.cs | 7 ------- .../Components/SuperBonkComponent.cs | 3 ++- .../Systems/AdminVerbSystem.Smites.cs | 8 ++++---- .../Systems/AdminVerbSystem.Tools.cs | 5 ++--- .../Administration/Systems/BufferingSystem.cs | 5 +++-- .../Components/AdminMinigunComponent.cs | 6 ++++++ .../Components/BufferingComponent.cs | 19 +++++++++++++------ .../Components/DisarmProneComponent.cs | 5 +---- ...tandComponent.cs => HeadstandComponent.cs} | 0 .../Components/KillSignComponent.cs | 6 ++++++ .../Components/SharedKillSignComponent.cs | 9 --------- .../StationInfiniteBatteryTargetComponent.cs | 11 +++++------ .../Administration/Systems/AdminGunSystem.cs | 4 ++-- .../Systems/SharedBufferingSystem.cs | 5 +++++ 19 files changed, 64 insertions(+), 67 deletions(-) delete mode 100644 Content.Client/Administration/Components/KillSignComponent.cs create mode 100644 Content.Client/Administration/Systems/BufferingSystem.cs delete mode 100644 Content.Server/Administration/Components/AdminMinigunComponent.cs delete mode 100644 Content.Server/Administration/Components/KillSignComponent.cs create mode 100644 Content.Shared/Administration/Components/AdminMinigunComponent.cs rename {Content.Server => Content.Shared}/Administration/Components/BufferingComponent.cs (67%) rename Content.Shared/Administration/Components/{SharedHeadstandComponent.cs => HeadstandComponent.cs} (100%) create mode 100644 Content.Shared/Administration/Components/KillSignComponent.cs delete mode 100644 Content.Shared/Administration/Components/SharedKillSignComponent.cs rename {Content.Server => Content.Shared}/Administration/Components/StationInfiniteBatteryTargetComponent.cs (55%) rename {Content.Server => Content.Shared}/Administration/Systems/AdminGunSystem.cs (80%) create mode 100644 Content.Shared/Administration/Systems/SharedBufferingSystem.cs diff --git a/Content.Client/Administration/Components/KillSignComponent.cs b/Content.Client/Administration/Components/KillSignComponent.cs deleted file mode 100644 index 91c44ef3f2..0000000000 --- a/Content.Client/Administration/Components/KillSignComponent.cs +++ /dev/null @@ -1,7 +0,0 @@ -using Content.Shared.Administration.Components; -using Robust.Shared.GameStates; - -namespace Content.Client.Administration.Components; - -[RegisterComponent] -public sealed partial class KillSignComponent : SharedKillSignComponent; diff --git a/Content.Client/Administration/Systems/BufferingSystem.cs b/Content.Client/Administration/Systems/BufferingSystem.cs new file mode 100644 index 0000000000..e511bbff36 --- /dev/null +++ b/Content.Client/Administration/Systems/BufferingSystem.cs @@ -0,0 +1,7 @@ +using Content.Shared.Administration.Systems; + +namespace Content.Client.Administration.Systems; + +public sealed class BufferingSystem : SharedBufferingSystem +{ +} diff --git a/Content.Client/Administration/Systems/KillSignSystem.cs b/Content.Client/Administration/Systems/KillSignSystem.cs index c12f65f1f0..f15cfe6442 100644 --- a/Content.Client/Administration/Systems/KillSignSystem.cs +++ b/Content.Client/Administration/Systems/KillSignSystem.cs @@ -1,5 +1,5 @@ using System.Numerics; -using Content.Client.Administration.Components; +using Content.Shared.Administration.Components; using Robust.Client.GameObjects; using Robust.Shared.Utility; diff --git a/Content.IntegrationTests/Tests/PostMapInitTest.cs b/Content.IntegrationTests/Tests/PostMapInitTest.cs index 95860b1720..1459214bba 100644 --- a/Content.IntegrationTests/Tests/PostMapInitTest.cs +++ b/Content.IntegrationTests/Tests/PostMapInitTest.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.IO; using System.Linq; using System.Text.RegularExpressions; +using YamlDotNet.RepresentationModel; using Content.Server.Administration.Systems; using Content.Server.GameTicking; using Content.Server.Maps; @@ -11,20 +12,18 @@ using Content.Server.Spawners.Components; using Content.Server.Station.Components; using Content.Shared.CCVar; using Content.Shared.Roles; +using Content.Shared.Station.Components; using Robust.Shared.Configuration; using Robust.Shared.ContentPack; -using Robust.Shared.GameObjects; -using Robust.Shared.Map; -using Robust.Shared.Map.Components; -using Robust.Shared.Prototypes; -using Content.Shared.Station.Components; using Robust.Shared.EntitySerialization; using Robust.Shared.EntitySerialization.Systems; +using Robust.Shared.GameObjects; using Robust.Shared.IoC; -using Robust.Shared.Utility; -using YamlDotNet.RepresentationModel; +using Robust.Shared.Map; +using Robust.Shared.Map.Components; using Robust.Shared.Map.Events; - +using Robust.Shared.Prototypes; +using Robust.Shared.Utility; namespace Content.IntegrationTests.Tests { [TestFixture] diff --git a/Content.Server/Administration/Components/AdminMinigunComponent.cs b/Content.Server/Administration/Components/AdminMinigunComponent.cs deleted file mode 100644 index 368d3d3ba7..0000000000 --- a/Content.Server/Administration/Components/AdminMinigunComponent.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace Content.Server.Administration.Components; - -[RegisterComponent] -public sealed partial class AdminMinigunComponent : Component -{ - -} diff --git a/Content.Server/Administration/Components/KillSignComponent.cs b/Content.Server/Administration/Components/KillSignComponent.cs deleted file mode 100644 index 11479c32fc..0000000000 --- a/Content.Server/Administration/Components/KillSignComponent.cs +++ /dev/null @@ -1,7 +0,0 @@ -using Content.Shared.Administration.Components; -using Robust.Shared.GameStates; - -namespace Content.Server.Administration.Components; - -[RegisterComponent] -public sealed partial class KillSignComponent : SharedKillSignComponent; diff --git a/Content.Server/Administration/Components/SuperBonkComponent.cs b/Content.Server/Administration/Components/SuperBonkComponent.cs index 0ceeccd136..9c20c4d88a 100644 --- a/Content.Server/Administration/Components/SuperBonkComponent.cs +++ b/Content.Server/Administration/Components/SuperBonkComponent.cs @@ -6,7 +6,8 @@ namespace Content.Server.Administration.Components; /// /// Component to track the timer for the SuperBonk smite. /// -[RegisterComponent, AutoGenerateComponentPause, Access(typeof(SuperBonkSystem))] +[RegisterComponent, AutoGenerateComponentPause] +[Access(typeof(SuperBonkSystem))] public sealed partial class SuperBonkComponent : Component { /// diff --git a/Content.Server/Administration/Systems/AdminVerbSystem.Smites.cs b/Content.Server/Administration/Systems/AdminVerbSystem.Smites.cs index 36f7399d87..2ad927aac9 100644 --- a/Content.Server/Administration/Systems/AdminVerbSystem.Smites.cs +++ b/Content.Server/Administration/Systems/AdminVerbSystem.Smites.cs @@ -1,4 +1,5 @@ -using Content.Server.Administration.Components; +using System.Numerics; +using System.Threading; using Content.Server.Atmos.EntitySystems; using Content.Server.Body.Systems; using Content.Server.Electrocution; @@ -17,12 +18,14 @@ using Content.Server.Tabletop.Components; using Content.Shared.Actions; using Content.Shared.Administration; using Content.Shared.Administration.Components; +using Content.Shared.Administration.Systems; using Content.Shared.Atmos.Components; using Content.Shared.Body.Components; using Content.Shared.Body.Part; using Content.Shared.Clothing.Components; using Content.Shared.Clumsy; using Content.Shared.Cluwne; +using Content.Shared.Damage.Components; using Content.Shared.Damage.Systems; using Content.Shared.Database; using Content.Shared.Electrocution; @@ -54,9 +57,6 @@ using Robust.Shared.Prototypes; using Robust.Shared.Random; using Robust.Shared.Spawners; using Robust.Shared.Utility; -using System.Numerics; -using System.Threading; -using Content.Shared.Damage.Components; using Timer = Robust.Shared.Timing.Timer; namespace Content.Server.Administration.Systems; diff --git a/Content.Server/Administration/Systems/AdminVerbSystem.Tools.cs b/Content.Server/Administration/Systems/AdminVerbSystem.Tools.cs index 8c7d3f33d1..f510ed52e9 100644 --- a/Content.Server/Administration/Systems/AdminVerbSystem.Tools.cs +++ b/Content.Server/Administration/Systems/AdminVerbSystem.Tools.cs @@ -1,11 +1,9 @@ using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Numerics; -using Content.Server.Administration.Components; using Content.Server.Cargo.Components; using Content.Server.Doors.Systems; using Content.Server.Hands.Systems; -using Content.Server.Power.Components; using Content.Server.Revenant.Components; // Imp using Content.Server.Revenant.EntitySystems; // Imp using Content.Server.Stack; @@ -15,10 +13,11 @@ using Content.Shared.Access; using Content.Shared.Access.Components; using Content.Shared.Access.Systems; using Content.Shared.Administration; +using Content.Shared.Administration.Components; +using Content.Shared.Administration.Systems; using Content.Shared.Atmos; using Content.Shared.Atmos.Components; using Content.Shared.Construction.Components; -using Content.Shared.Damage; using Content.Shared.Damage.Components; using Content.Shared.Database; using Content.Shared.Doors.Components; diff --git a/Content.Server/Administration/Systems/BufferingSystem.cs b/Content.Server/Administration/Systems/BufferingSystem.cs index f3df34e7d2..71e5c4d5c6 100644 --- a/Content.Server/Administration/Systems/BufferingSystem.cs +++ b/Content.Server/Administration/Systems/BufferingSystem.cs @@ -1,12 +1,13 @@ using System.Numerics; -using Content.Server.Administration.Components; using Content.Shared.Administration; +using Content.Shared.Administration.Components; +using Content.Shared.Administration.Systems; using Robust.Shared.Map; using Robust.Shared.Random; namespace Content.Server.Administration.Systems; -public sealed class BufferingSystem : EntitySystem +public sealed class BufferingSystem : SharedBufferingSystem { [Dependency] private readonly IRobustRandom _random = default!; diff --git a/Content.Shared/Administration/Components/AdminMinigunComponent.cs b/Content.Shared/Administration/Components/AdminMinigunComponent.cs new file mode 100644 index 0000000000..04a7aacd69 --- /dev/null +++ b/Content.Shared/Administration/Components/AdminMinigunComponent.cs @@ -0,0 +1,6 @@ +using Robust.Shared.GameStates; + +namespace Content.Shared.Administration.Components; + +[RegisterComponent, NetworkedComponent] +public sealed partial class AdminMinigunComponent : Component; diff --git a/Content.Server/Administration/Components/BufferingComponent.cs b/Content.Shared/Administration/Components/BufferingComponent.cs similarity index 67% rename from Content.Server/Administration/Components/BufferingComponent.cs rename to Content.Shared/Administration/Components/BufferingComponent.cs index 1f80376596..3d365d00aa 100644 --- a/Content.Server/Administration/Components/BufferingComponent.cs +++ b/Content.Shared/Administration/Components/BufferingComponent.cs @@ -1,22 +1,29 @@ -using Content.Server.Administration.Systems; +using Content.Shared.Administration.Systems; -namespace Content.Server.Administration.Components; +namespace Content.Shared.Administration.Components; -[RegisterComponent, Access(typeof(BufferingSystem))] +[RegisterComponent] +[Access(typeof(SharedBufferingSystem))] public sealed partial class BufferingComponent : Component { [DataField("minBufferTime")] public float MinimumBufferTime = 0.5f; + [DataField("maxBufferTime")] public float MaximumBufferTime = 1.5f; + [DataField("minTimeTilNextBuffer")] public float MinimumTimeTilNextBuffer = 10.0f; + [DataField("maxTimeTilNextBuffer")] public float MaximumTimeTilNextBuffer = 120.0f; - [DataField("timeTilNextBuffer")] + + [DataField] public float TimeTilNextBuffer = 15.0f; - [DataField("bufferingIcon")] + + [DataField] public EntityUid? BufferingIcon = null; - [DataField("bufferingTimer")] + + [DataField] public float BufferingTimer = 0.0f; } diff --git a/Content.Shared/Administration/Components/DisarmProneComponent.cs b/Content.Shared/Administration/Components/DisarmProneComponent.cs index 4ba11df8e2..86addab4f6 100644 --- a/Content.Shared/Administration/Components/DisarmProneComponent.cs +++ b/Content.Shared/Administration/Components/DisarmProneComponent.cs @@ -8,7 +8,4 @@ namespace Content.Shared.Administration.Components; /// [RegisterComponent, NetworkedComponent] [Access(typeof(SharedMeleeWeaponSystem))] -public sealed partial class DisarmProneComponent : Component -{ - -} +public sealed partial class DisarmProneComponent : Component; diff --git a/Content.Shared/Administration/Components/SharedHeadstandComponent.cs b/Content.Shared/Administration/Components/HeadstandComponent.cs similarity index 100% rename from Content.Shared/Administration/Components/SharedHeadstandComponent.cs rename to Content.Shared/Administration/Components/HeadstandComponent.cs diff --git a/Content.Shared/Administration/Components/KillSignComponent.cs b/Content.Shared/Administration/Components/KillSignComponent.cs new file mode 100644 index 0000000000..34c36759cc --- /dev/null +++ b/Content.Shared/Administration/Components/KillSignComponent.cs @@ -0,0 +1,6 @@ +using Robust.Shared.GameStates; + +namespace Content.Shared.Administration.Components; + +[RegisterComponent, NetworkedComponent] +public sealed partial class KillSignComponent : Component; diff --git a/Content.Shared/Administration/Components/SharedKillSignComponent.cs b/Content.Shared/Administration/Components/SharedKillSignComponent.cs deleted file mode 100644 index 9a95454f72..0000000000 --- a/Content.Shared/Administration/Components/SharedKillSignComponent.cs +++ /dev/null @@ -1,9 +0,0 @@ -using Robust.Shared.GameStates; - -namespace Content.Shared.Administration.Components; - -[NetworkedComponent] -public abstract partial class SharedKillSignComponent : Component -{ - -} diff --git a/Content.Server/Administration/Components/StationInfiniteBatteryTargetComponent.cs b/Content.Shared/Administration/Components/StationInfiniteBatteryTargetComponent.cs similarity index 55% rename from Content.Server/Administration/Components/StationInfiniteBatteryTargetComponent.cs rename to Content.Shared/Administration/Components/StationInfiniteBatteryTargetComponent.cs index 5543d5ed8c..d26527a472 100644 --- a/Content.Server/Administration/Components/StationInfiniteBatteryTargetComponent.cs +++ b/Content.Shared/Administration/Components/StationInfiniteBatteryTargetComponent.cs @@ -1,10 +1,9 @@ -namespace Content.Server.Administration.Components; +using Robust.Shared.GameStates; + +namespace Content.Shared.Administration.Components; /// /// This is used for the admin map-wide/station-wide/grid-wide infinite power trick. /// -[RegisterComponent] -public sealed partial class StationInfiniteBatteryTargetComponent : Component -{ - -} +[RegisterComponent, NetworkedComponent] +public sealed partial class StationInfiniteBatteryTargetComponent : Component; diff --git a/Content.Server/Administration/Systems/AdminGunSystem.cs b/Content.Shared/Administration/Systems/AdminGunSystem.cs similarity index 80% rename from Content.Server/Administration/Systems/AdminGunSystem.cs rename to Content.Shared/Administration/Systems/AdminGunSystem.cs index 6270481a3c..28ff142709 100644 --- a/Content.Server/Administration/Systems/AdminGunSystem.cs +++ b/Content.Shared/Administration/Systems/AdminGunSystem.cs @@ -1,7 +1,7 @@ -using Content.Server.Administration.Components; +using Content.Shared.Administration.Components; using Content.Shared.Weapons.Ranged.Events; -namespace Content.Server.Administration.Systems; +namespace Content.Shared.Administration.Systems; public sealed class AdminGunSystem : EntitySystem { diff --git a/Content.Shared/Administration/Systems/SharedBufferingSystem.cs b/Content.Shared/Administration/Systems/SharedBufferingSystem.cs new file mode 100644 index 0000000000..a1f375ebfd --- /dev/null +++ b/Content.Shared/Administration/Systems/SharedBufferingSystem.cs @@ -0,0 +1,5 @@ +namespace Content.Shared.Administration.Systems; + +public abstract class SharedBufferingSystem : EntitySystem +{ +} From bede43b560670b7184b34d5d54cf0704021b9747 Mon Sep 17 00:00:00 2001 From: imatsoup <93290208+imatsoup@users.noreply.github.com> Date: Wed, 3 Dec 2025 03:25:03 +0000 Subject: [PATCH 008/360] Change default Rat King order from 'Loose' to 'Follow' (#41680) Update RatKingComponent.cs --- Content.Shared/RatKing/RatKingComponent.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Content.Shared/RatKing/RatKingComponent.cs b/Content.Shared/RatKing/RatKingComponent.cs index 712d4ae3a1..f3830cf4f7 100644 --- a/Content.Shared/RatKing/RatKingComponent.cs +++ b/Content.Shared/RatKing/RatKingComponent.cs @@ -56,7 +56,7 @@ public sealed partial class RatKingComponent : Component /// [DataField("currentOrders"), ViewVariables(VVAccess.ReadWrite)] [AutoNetworkedField] - public RatKingOrderType CurrentOrder = RatKingOrderType.Loose; + public RatKingOrderType CurrentOrder = RatKingOrderType.Follow; /// /// The servants that the rat king is currently controlling From 42e7e8fe88339bd684636e71c7d4f2381d814c72 Mon Sep 17 00:00:00 2001 From: SlamBamActionman <83650252+SlamBamActionman@users.noreply.github.com> Date: Wed, 3 Dec 2025 12:55:29 +0100 Subject: [PATCH 009/360] Add status effect support to Traits, change PainNumbness to be a status effect (#41646) * Initial commit * Review comments * Jobify * Prototype(effect) --- .../DamageOverlayUiController.cs | 4 ++- Content.Server/Cloning/CloningSystem.cs | 35 +++++++++++++++++++ .../Jobs/ApplyStatusEffectSpecial.cs | 27 ++++++++++++++ Content.Server/Traits/TraitSystem.cs | 11 +++++- .../Cloning/CloningSettingsPrototype.cs | 6 ++++ Content.Shared/Roles/JobSpecial.cs | 4 ++- .../StatusEffectNew/StatusEffectSystem.API.cs | 1 + .../StatusEffectSystem.Relay.cs | 5 +++ .../Traits/Assorted/PainNumbnessComponent.cs | 16 --------- .../PainNumbnessStatusEffectComponent.cs | 20 +++++++++++ .../Traits/Assorted/PainNumbnessSystem.cs | 32 +++++++++-------- Content.Shared/Traits/TraitPrototype.cs | 9 +++++ .../Prototypes/Entities/Mobs/Player/clone.yml | 1 - .../Entities/StatusEffects/body.yml | 25 +++++++++---- Resources/Prototypes/Traits/disabilities.yml | 6 ++-- 15 files changed, 158 insertions(+), 44 deletions(-) create mode 100644 Content.Server/Jobs/ApplyStatusEffectSpecial.cs delete mode 100644 Content.Shared/Traits/Assorted/PainNumbnessComponent.cs create mode 100644 Content.Shared/Traits/Assorted/PainNumbnessStatusEffectComponent.cs diff --git a/Content.Client/UserInterface/Systems/DamageOverlays/DamageOverlayUiController.cs b/Content.Client/UserInterface/Systems/DamageOverlays/DamageOverlayUiController.cs index 20db76554d..f709df4b77 100644 --- a/Content.Client/UserInterface/Systems/DamageOverlays/DamageOverlayUiController.cs +++ b/Content.Client/UserInterface/Systems/DamageOverlays/DamageOverlayUiController.cs @@ -3,6 +3,7 @@ using Content.Shared.FixedPoint; using Content.Shared.Mobs; using Content.Shared.Mobs.Components; using Content.Shared.Mobs.Systems; +using Content.Shared.StatusEffectNew; using Content.Shared.Traits.Assorted; using JetBrains.Annotations; using Robust.Client.Graphics; @@ -20,6 +21,7 @@ public sealed class DamageOverlayUiController : UIController [Dependency] private readonly IPlayerManager _playerManager = default!; [UISystemDependency] private readonly MobThresholdSystem _mobThresholdSystem = default!; + [UISystemDependency] private readonly StatusEffectsSystem _statusEffects = default!; private Overlays.DamageOverlay _overlay = default!; public override void Initialize() @@ -98,7 +100,7 @@ public sealed class DamageOverlayUiController : UIController FixedPoint2 painLevel = 0; _overlay.PainLevel = 0; - if (!EntityManager.HasComponent(entity)) + if (!_statusEffects.TryEffectsWithComp(entity, out _)) { foreach (var painDamageType in damageable.PainDamageGroups) { diff --git a/Content.Server/Cloning/CloningSystem.cs b/Content.Server/Cloning/CloningSystem.cs index 654a2de07e..bd53e32567 100644 --- a/Content.Server/Cloning/CloningSystem.cs +++ b/Content.Server/Cloning/CloningSystem.cs @@ -9,6 +9,7 @@ using Content.Shared.Implants; using Content.Shared.Implants.Components; using Content.Shared.NameModifier.EntitySystems; using Content.Shared.StatusEffect; +using Content.Shared.StatusEffectNew.Components; using Content.Shared.Storage; using Content.Shared.Storage.EntitySystems; using Content.Shared.Whitelist; @@ -37,6 +38,7 @@ public sealed partial class CloningSystem : SharedCloningSystem [Dependency] private readonly SharedStorageSystem _storage = default!; [Dependency] private readonly SharedSubdermalImplantSystem _subdermalImplant = default!; [Dependency] private readonly NameModifierSystem _nameMod = default!; + [Dependency] private readonly Shared.StatusEffectNew.StatusEffectsSystem _statusEffects = default!; //TODO: This system has to support both the old and new status effect systems, until the old is able to be fully removed. /// /// Spawns a clone of the given humanoid mob at the specified location or in nullspace. @@ -76,6 +78,10 @@ public sealed partial class CloningSystem : SharedCloningSystem if (settings.CopyImplants) CopyImplants(original, clone.Value, settings.CopyInternalStorage, settings.Whitelist, settings.Blacklist); + // Copy permanent status effects + if (settings.CopyStatusEffects) + CopyStatusEffects(original, clone.Value); + var originalName = _nameMod.GetBaseName(original); // Set the clone's name. The raised events will also adjust their PDA and ID card names. @@ -268,4 +274,33 @@ public sealed partial class CloningSystem : SharedCloningSystem } } + + /// + /// Scans all permanent status effects applied to the original entity and transfers them to the clone. + /// + public void CopyStatusEffects(Entity original, Entity target) + { + if (!Resolve(original, ref original.Comp, false)) + return; + + if (original.Comp.ActiveStatusEffects is null) + return; + + foreach (var effect in original.Comp.ActiveStatusEffects.ContainedEntities) + { + if (!TryComp(effect, out var effectComp)) + continue; + + //We are not interested in temporary effects, only permanent ones. + if (effectComp.EndEffectTime is not null) + continue; + + var effectProto = Prototype(effect); + + if (effectProto is null) + continue; + + _statusEffects.TrySetStatusEffectDuration(target, effectProto); + } + } } diff --git a/Content.Server/Jobs/ApplyStatusEffectSpecial.cs b/Content.Server/Jobs/ApplyStatusEffectSpecial.cs new file mode 100644 index 0000000000..b06ce114ba --- /dev/null +++ b/Content.Server/Jobs/ApplyStatusEffectSpecial.cs @@ -0,0 +1,27 @@ +using Content.Shared.Roles; +using Content.Shared.StatusEffectNew; +using JetBrains.Annotations; +using Robust.Shared.Prototypes; + +namespace Content.Server.Jobs; + +/// +/// Adds permanent status effects to the entity. +/// TODO: Move this, and other JobSpecials, from Server to Shared. +/// +[UsedImplicitly] +public sealed partial class ApplyStatusEffectSpecial : JobSpecial +{ + [DataField(required: true)] + public HashSet StatusEffects { get; private set; } = new(); + + public override void AfterEquip(EntityUid mob) + { + var entMan = IoCManager.Resolve(); + var statusSystem = entMan.System(); + foreach (var effect in StatusEffects) + { + statusSystem.TrySetStatusEffectDuration(mob, effect); + } + } +} diff --git a/Content.Server/Traits/TraitSystem.cs b/Content.Server/Traits/TraitSystem.cs index 5e7675b76b..8e062785e2 100644 --- a/Content.Server/Traits/TraitSystem.cs +++ b/Content.Server/Traits/TraitSystem.cs @@ -2,6 +2,7 @@ // using Content.Shared.Hands.Components; // using Content.Shared.Hands.EntitySystems; // using Content.Shared.Roles; +// using Content.Shared.StatusEffectNew; // using Content.Shared.Traits; // using Content.Shared.Whitelist; // using Robust.Shared.Prototypes; @@ -13,6 +14,7 @@ // [Dependency] private readonly IPrototypeManager _prototypeManager = default!; // [Dependency] private readonly SharedHandsSystem _sharedHandsSystem = default!; // [Dependency] private readonly EntityWhitelistSystem _whitelistSystem = default!; +// [Dependency] private readonly StatusEffectsSystem _statusEffects = default!; // // public override void Initialize() // { @@ -45,7 +47,14 @@ // continue; // // // Add all components required by the prototype -// EntityManager.AddComponents(args.Mob, traitPrototype.Components, false); +// if (traitPrototype.Components.Count > 0) +// EntityManager.AddComponents(args.Mob, traitPrototype.Components, false); +// +// // Add all JobSpecials required by the prototype +// foreach (var special in traitPrototype.Specials) +// { +// special.AfterEquip(args.Mob); +// } // // // Begin DeltaV - Add overridden components // if(traitPrototype.OverriddenComponents != null) diff --git a/Content.Shared/Cloning/CloningSettingsPrototype.cs b/Content.Shared/Cloning/CloningSettingsPrototype.cs index b422f7188b..0b531561ca 100644 --- a/Content.Shared/Cloning/CloningSettingsPrototype.cs +++ b/Content.Shared/Cloning/CloningSettingsPrototype.cs @@ -50,6 +50,12 @@ public sealed partial class CloningSettingsPrototype : IPrototype, IInheritingPr [DataField] public bool CopyImplants = true; + /// + /// Should infinite status effects applied to an entity be copied or not? + /// + [DataField] + public bool CopyStatusEffects = true; + /// /// Whitelist for the equipment allowed to be copied. /// diff --git a/Content.Shared/Roles/JobSpecial.cs b/Content.Shared/Roles/JobSpecial.cs index 468e939836..8ebeb69a6d 100644 --- a/Content.Shared/Roles/JobSpecial.cs +++ b/Content.Shared/Roles/JobSpecial.cs @@ -1,7 +1,9 @@ namespace Content.Shared.Roles { /// - /// Provides special hooks for when jobs get spawned in/equipped. + /// Provides special hooks for when jobs get spawned in/equipped. + /// TODO: This is being/should be utilized by more than jobs, and is really just a way to assign components/implants/status effects upon spawning. Rename this class and its derivatives in the future! + /// TODO: Move derivatives from Server to Shared, probably. /// [ImplicitDataDefinitionForInheritors] public abstract partial class JobSpecial diff --git a/Content.Shared/StatusEffectNew/StatusEffectSystem.API.cs b/Content.Shared/StatusEffectNew/StatusEffectSystem.API.cs index ab6362746c..a65d4fe063 100644 --- a/Content.Shared/StatusEffectNew/StatusEffectSystem.API.cs +++ b/Content.Shared/StatusEffectNew/StatusEffectSystem.API.cs @@ -353,6 +353,7 @@ public sealed partial class StatusEffectsSystem /// /// Returns all status effects that have the specified component. /// + /// Returns true if any entity with the specified component is found. public bool TryEffectsWithComp(EntityUid? target, [NotNullWhen(true)] out HashSet>? effects) where T : IComponent { effects = null; diff --git a/Content.Shared/StatusEffectNew/StatusEffectSystem.Relay.cs b/Content.Shared/StatusEffectNew/StatusEffectSystem.Relay.cs index 3644bed45e..9b16aadff0 100644 --- a/Content.Shared/StatusEffectNew/StatusEffectSystem.Relay.cs +++ b/Content.Shared/StatusEffectNew/StatusEffectSystem.Relay.cs @@ -1,3 +1,5 @@ +using Content.Shared.Damage.Events; +using Content.Shared.Mobs.Events; using Content.Shared.Movement.Events; using Content.Shared.Movement.Systems; using Content.Shared.Rejuvenate; @@ -25,6 +27,9 @@ public sealed partial class StatusEffectsSystem SubscribeLocalEvent(RefRelayStatusEffectEvent); SubscribeLocalEvent(RefRelayStatusEffectEvent); + SubscribeLocalEvent(RelayStatusEffectEvent); + SubscribeLocalEvent(RelayStatusEffectEvent); + SubscribeLocalEvent(RelayStatusEffectEvent); } diff --git a/Content.Shared/Traits/Assorted/PainNumbnessComponent.cs b/Content.Shared/Traits/Assorted/PainNumbnessComponent.cs deleted file mode 100644 index 9ae72c6286..0000000000 --- a/Content.Shared/Traits/Assorted/PainNumbnessComponent.cs +++ /dev/null @@ -1,16 +0,0 @@ -using Content.Shared.Dataset; -using Robust.Shared.GameStates; -using Robust.Shared.Prototypes; - -namespace Content.Shared.Traits.Assorted; - -[RegisterComponent, NetworkedComponent] -public sealed partial class PainNumbnessComponent : Component -{ - /// - /// The fluent string prefix to use when picking a random suffix - /// This is only active for those who have the pain numbness component - /// - [DataField] - public ProtoId ForceSayNumbDataset = "ForceSayNumbDataset"; -} diff --git a/Content.Shared/Traits/Assorted/PainNumbnessStatusEffectComponent.cs b/Content.Shared/Traits/Assorted/PainNumbnessStatusEffectComponent.cs new file mode 100644 index 0000000000..c5c340fd10 --- /dev/null +++ b/Content.Shared/Traits/Assorted/PainNumbnessStatusEffectComponent.cs @@ -0,0 +1,20 @@ +using Content.Shared.Dataset; +using Robust.Shared.GameStates; +using Robust.Shared.Prototypes; + +namespace Content.Shared.Traits.Assorted; + +/// +/// Hides the damage overlay and displays the health alert for the client controlling the entity as full. +/// Has to be applied as a status effect. +/// +[RegisterComponent, NetworkedComponent] +public sealed partial class PainNumbnessStatusEffectComponent : Component +{ + /// + /// The fluent string prefix to use when picking a random suffix upon taking damage. + /// This is only active for those who have the pain numbness status effect. Set to null to prevent changing. + /// + [DataField] + public ProtoId? ForceSayNumbDataset = "ForceSayNumbDataset"; +} diff --git a/Content.Shared/Traits/Assorted/PainNumbnessSystem.cs b/Content.Shared/Traits/Assorted/PainNumbnessSystem.cs index 3ded13300d..688354c161 100644 --- a/Content.Shared/Traits/Assorted/PainNumbnessSystem.cs +++ b/Content.Shared/Traits/Assorted/PainNumbnessSystem.cs @@ -2,6 +2,7 @@ using Content.Shared.Damage.Events; using Content.Shared.Mobs.Components; using Content.Shared.Mobs.Events; using Content.Shared.Mobs.Systems; +using Content.Shared.StatusEffectNew; namespace Content.Shared.Traits.Assorted; @@ -11,36 +12,37 @@ public sealed class PainNumbnessSystem : EntitySystem public override void Initialize() { - SubscribeLocalEvent(OnComponentInit); - SubscribeLocalEvent(OnComponentRemove); - SubscribeLocalEvent(OnChangeForceSay); - SubscribeLocalEvent(OnAlertSeverityCheck); + SubscribeLocalEvent(OnEffectApplied); + SubscribeLocalEvent(OnEffectRemoved); + SubscribeLocalEvent>(OnChangeForceSay); + SubscribeLocalEvent>(OnAlertSeverityCheck); } - private void OnComponentRemove(EntityUid uid, PainNumbnessComponent component, ComponentRemove args) + private void OnEffectApplied(Entity ent, ref StatusEffectAppliedEvent args) { - if (!HasComp(uid)) + if (!HasComp(args.Target)) return; - _mobThresholdSystem.VerifyThresholds(uid); + _mobThresholdSystem.VerifyThresholds(args.Target); } - private void OnComponentInit(EntityUid uid, PainNumbnessComponent component, ComponentInit args) + private void OnEffectRemoved(Entity ent, ref StatusEffectRemovedEvent args) { - if (!HasComp(uid)) + if (!HasComp(args.Target)) return; - _mobThresholdSystem.VerifyThresholds(uid); + _mobThresholdSystem.VerifyThresholds(args.Target); } - private void OnChangeForceSay(Entity ent, ref BeforeForceSayEvent args) + private void OnChangeForceSay(Entity ent, ref StatusEffectRelayedEvent args) { - args.Prefix = ent.Comp.ForceSayNumbDataset; + if (ent.Comp.ForceSayNumbDataset != null) + args.Args.Prefix = ent.Comp.ForceSayNumbDataset.Value; } - private void OnAlertSeverityCheck(Entity ent, ref BeforeAlertSeverityCheckEvent args) + private void OnAlertSeverityCheck(Entity ent, ref StatusEffectRelayedEvent args) { - if (args.CurrentAlert == "HumanHealth") - args.CancelUpdate = true; + if (args.Args.CurrentAlert == "HumanHealth") + args.Args.CancelUpdate = true; } } diff --git a/Content.Shared/Traits/TraitPrototype.cs b/Content.Shared/Traits/TraitPrototype.cs index caacaaff4a..91fcfccc8a 100644 --- a/Content.Shared/Traits/TraitPrototype.cs +++ b/Content.Shared/Traits/TraitPrototype.cs @@ -1,3 +1,4 @@ +// using Content.Shared.Roles; // using Content.Shared.Whitelist; // DeltaV - Traits rework // using Robust.Shared.Prototypes; // using Content.Shared.Humanoid.Prototypes; // DeltaV - Trait species hiding @@ -40,11 +41,19 @@ // // /// // /// The components that get added to the player, when they pick this trait. +// /// NOTE: When implementing a new trait, it's preferable to add it as a status effect instead if possible. // /// // [DataField] +// [Obsolete("Use JobSpecial instead.")] // public ComponentRegistry Components { get; private set; } = default!; // // /// +// /// Special effects applied to the player who takes this Trait. +// /// +// [DataField(serverOnly: true)] +// public List Specials { get; private set; } = new(); +// +// /// // /// DeltaV - Components that get added to the player, overriding any existing instances of the component if they exist. // /// // [DataField] diff --git a/Resources/Prototypes/Entities/Mobs/Player/clone.yml b/Resources/Prototypes/Entities/Mobs/Player/clone.yml index 7a3f9d99cf..6b0af7e86b 100644 --- a/Resources/Prototypes/Entities/Mobs/Player/clone.yml +++ b/Resources/Prototypes/Entities/Mobs/Player/clone.yml @@ -23,7 +23,6 @@ - Muted - Narcolepsy - Pacified - - PainNumbness - Paracusia - PermanentBlindness - Snoring diff --git a/Resources/Prototypes/Entities/StatusEffects/body.yml b/Resources/Prototypes/Entities/StatusEffects/body.yml index 3765ebefd4..4c94804884 100644 --- a/Resources/Prototypes/Entities/StatusEffects/body.yml +++ b/Resources/Prototypes/Entities/StatusEffects/body.yml @@ -3,16 +3,27 @@ id: BloodstreamStatusEffectBase abstract: true components: - - type: StatusEffect - whitelist: - components: - - Bloodstream + - type: StatusEffect + whitelist: + components: + - Bloodstream - type: entity parent: [ BloodstreamStatusEffectBase ] id: StatusEffectBloodloss name: bloodloss components: - - type: StutteringAccent - - type: DrunkStatusEffect - - type: RejuvenateRemovedStatusEffect + - type: StutteringAccent + - type: DrunkStatusEffect + - type: RejuvenateRemovedStatusEffect + +- type: entity + parent: MobStatusEffectBase + id: PainNumbnessTraitStatusEffect + components: + - type: StatusEffect + whitelist: + components: + - MobState + - MobThresholds + - type: PainNumbnessStatusEffect diff --git a/Resources/Prototypes/Traits/disabilities.yml b/Resources/Prototypes/Traits/disabilities.yml index 488fdd7d8c..b9a8e1fd54 100644 --- a/Resources/Prototypes/Traits/disabilities.yml +++ b/Resources/Prototypes/Traits/disabilities.yml @@ -87,8 +87,10 @@ # name: trait-painnumbness-name # description: trait-painnumbness-desc # category: Disabilities -# components: -# - type: PainNumbness +# specials: +# - !type:ApplyStatusEffectSpecial +# statusEffects: +# - PainNumbnessTraitStatusEffect # #- type: trait # id: ImpairedMobility From 7f2b7500d2234e04904f22a47aaf120217c006c9 Mon Sep 17 00:00:00 2001 From: BarryNorfolk Date: Thu, 22 Jan 2026 19:57:30 +0100 Subject: [PATCH 010/360] Downstream fix for painnumbness status effect --- Content.Server/_Shitmed/Medical/Surgery/SurgerySystem.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Content.Server/_Shitmed/Medical/Surgery/SurgerySystem.cs b/Content.Server/_Shitmed/Medical/Surgery/SurgerySystem.cs index e44aedb99c..2bce1959c4 100644 --- a/Content.Server/_Shitmed/Medical/Surgery/SurgerySystem.cs +++ b/Content.Server/_Shitmed/Medical/Surgery/SurgerySystem.cs @@ -21,6 +21,7 @@ using Robust.Shared.Prototypes; using Robust.Shared.Utility; using Content.Shared.Verbs; using Content.Shared._Goobstation.CCVar; +using Content.Shared.StatusEffectNew; namespace Content.Server._Shitmed.Medical.Surgery; @@ -35,6 +36,7 @@ public sealed class SurgerySystem : SharedSurgerySystem [Dependency] private readonly SurgeryCleanSystem _clean = default!; // DeltaV [Dependency] private readonly UserInterfaceSystem _ui = default!; [Dependency] private readonly InventorySystem _inventory = default!; // DeltaV - surgery cross contamination + [Dependency] private readonly StatusEffectsSystem _statusEffects = default!; private readonly HashSet _dirtyDnas = new(); // DeltaV @@ -251,7 +253,7 @@ public sealed class SurgerySystem : SharedSurgerySystem { if (HasComp(args.Body)) // DeltaV return; - if (HasComp(args.Body)) // DeltaV + if (_statusEffects.HasEffectComp(ent)) return; _chat.TryEmoteWithChat(args.Body, ent.Comp.Emote); From b24ec257b7e551027bc49a7df8bbe56a703557f0 Mon Sep 17 00:00:00 2001 From: BarryNorfolk Date: Fri, 23 Jan 2026 08:38:17 +0100 Subject: [PATCH 011/360] Extend DV trait system to handle status effects --- .../Tests/_DV/TraitSystemTest.cs | 3 +++ Content.Server/_DV/Traits/TraitSystem.cs | 4 ++++ .../Traits/Conditions/BaseTraitCondition.cs | 2 ++ .../_DV/Traits/Effects/ApplyStatusEffect.cs | 23 +++++++++++++++++++ .../_DV/Traits/Effects/BaseTraitEffect.cs | 2 ++ .../Prototypes/_DV/Traits/disabilities.yml | 6 ++--- 6 files changed, 37 insertions(+), 3 deletions(-) create mode 100644 Content.Shared/_DV/Traits/Effects/ApplyStatusEffect.cs diff --git a/Content.IntegrationTests/Tests/_DV/TraitSystemTest.cs b/Content.IntegrationTests/Tests/_DV/TraitSystemTest.cs index 5daf838b25..670b443de2 100644 --- a/Content.IntegrationTests/Tests/_DV/TraitSystemTest.cs +++ b/Content.IntegrationTests/Tests/_DV/TraitSystemTest.cs @@ -7,6 +7,7 @@ using Content.Shared._DV.Traits.Effects; using Content.Shared.Hands.Components; using Content.Shared.Hands.EntitySystems; using Content.Shared.Nutrition.Components; +using Content.Shared.StatusEffectNew; using Robust.Shared.GameObjects; using Robust.Shared.IoC; using Robust.Shared.Log; @@ -773,6 +774,7 @@ public sealed partial class TraitSystemTest LogMan = IoCManager.Resolve(), JobId = jobId, SpeciesId = speciesId, + StatusEffects = IoCManager.Resolve(), }; } @@ -790,6 +792,7 @@ public sealed partial class TraitSystemTest CompFactory = factory, LogMan = IoCManager.Resolve(), Transform = entMan.GetComponent(player), + StatusEffects = IoCManager.Resolve(), }; } diff --git a/Content.Server/_DV/Traits/TraitSystem.cs b/Content.Server/_DV/Traits/TraitSystem.cs index f3d67e2571..d43cfe1f2e 100644 --- a/Content.Server/_DV/Traits/TraitSystem.cs +++ b/Content.Server/_DV/Traits/TraitSystem.cs @@ -9,6 +9,7 @@ using Content.Shared.Humanoid; using Content.Shared.Humanoid.Prototypes; using Content.Shared.Preferences; using Content.Shared.Roles; +using Content.Shared.StatusEffectNew; using Robust.Shared.Configuration; using Robust.Shared.Player; using Robust.Shared.Prototypes; @@ -25,6 +26,7 @@ public sealed class TraitSystem : EntitySystem [Dependency] private readonly ILogManager _log = default!; [Dependency] private readonly IPrototypeManager _prototype = default!; [Dependency] private readonly SharedHandsSystem _hands = default!; + [Dependency] private readonly StatusEffectsSystem _statusEffects = default!; private int _maxTraitCount; private int _maxTraitPoints; @@ -104,6 +106,7 @@ public sealed class TraitSystem : EntitySystem JobId = jobId, SpeciesId = speciesId, Profile = profile, + StatusEffects = _statusEffects }; foreach (var traitId in selectedTraits) @@ -272,6 +275,7 @@ public sealed class TraitSystem : EntitySystem CompFactory = _factory, LogMan = _log, Transform = transform, + StatusEffects = _statusEffects, }; foreach (var effect in trait.Effects) diff --git a/Content.Shared/_DV/Traits/Conditions/BaseTraitCondition.cs b/Content.Shared/_DV/Traits/Conditions/BaseTraitCondition.cs index 293dceeb7e..68781af5d2 100644 --- a/Content.Shared/_DV/Traits/Conditions/BaseTraitCondition.cs +++ b/Content.Shared/_DV/Traits/Conditions/BaseTraitCondition.cs @@ -1,4 +1,5 @@ using Content.Shared.Preferences; +using Content.Shared.StatusEffectNew; using JetBrains.Annotations; using Robust.Shared.Player; using Robust.Shared.Prototypes; @@ -48,6 +49,7 @@ public sealed class TraitConditionContext public required IPrototypeManager Proto { get; init; } public required IComponentFactory CompFactory { get; init; } public required ILogManager LogMan { get; init; } + public required StatusEffectsSystem StatusEffects { get; init; } /// /// The job ID of the player, if available. diff --git a/Content.Shared/_DV/Traits/Effects/ApplyStatusEffect.cs b/Content.Shared/_DV/Traits/Effects/ApplyStatusEffect.cs new file mode 100644 index 0000000000..712d628825 --- /dev/null +++ b/Content.Shared/_DV/Traits/Effects/ApplyStatusEffect.cs @@ -0,0 +1,23 @@ +using Robust.Shared.Prototypes; + +namespace Content.Shared._DV.Traits.Effects; + +/// +/// Effect that adds status effects to the player entity. +/// +public sealed partial class ApplyStatusEffect : BaseTraitEffect +{ + /// + /// The status effects to add to the entity. + /// + [DataField(required: true)] + public HashSet StatusEffects = new(); + + public override void Apply(TraitEffectContext ctx) + { + foreach (var effect in StatusEffects) + { + ctx.StatusEffects.TrySetStatusEffectDuration(ctx.Player, effect); + } + } +} diff --git a/Content.Shared/_DV/Traits/Effects/BaseTraitEffect.cs b/Content.Shared/_DV/Traits/Effects/BaseTraitEffect.cs index a901e626d1..8e3118258e 100644 --- a/Content.Shared/_DV/Traits/Effects/BaseTraitEffect.cs +++ b/Content.Shared/_DV/Traits/Effects/BaseTraitEffect.cs @@ -1,3 +1,4 @@ +using Content.Shared.StatusEffectNew; using JetBrains.Annotations; using Robust.Shared.Prototypes; @@ -28,4 +29,5 @@ public sealed class TraitEffectContext public required IComponentFactory CompFactory { get; init; } public required ILogManager LogMan { get; init; } public required TransformComponent Transform { get; init; } + public required StatusEffectsSystem StatusEffects { get; init; } } diff --git a/Resources/Prototypes/_DV/Traits/disabilities.yml b/Resources/Prototypes/_DV/Traits/disabilities.yml index a8f6635fc1..b021d5c9ca 100644 --- a/Resources/Prototypes/_DV/Traits/disabilities.yml +++ b/Resources/Prototypes/_DV/Traits/disabilities.yml @@ -117,9 +117,9 @@ description: trait-painnumbness-desc category: Disabilities effects: - - !type:AddCompsEffect - components: - - type: PainNumbness + - !type:ApplyStatusEffect + statusEffects: + - PainNumbnessTraitStatusEffect - type: trait id: Hemophilia From 538a1b18394c49bfbe0d652c4ddce40a5f1d46b3 Mon Sep 17 00:00:00 2001 From: BarryNorfolk Date: Fri, 23 Jan 2026 09:14:02 +0100 Subject: [PATCH 012/360] Downstream devil fix to Painnumbness status effect --- .../Devil/Contract/DevilContractSystem.cs | 14 ++++++++++++++ .../Devil/Contract/DevilClausePrototype.cs | 3 +++ .../Prototypes/_Goobstation/Devil/clauses.yml | 5 ++++- 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/Content.Server/_Goobstation/Devil/Contract/DevilContractSystem.cs b/Content.Server/_Goobstation/Devil/Contract/DevilContractSystem.cs index 702a93205a..305d5ff864 100644 --- a/Content.Server/_Goobstation/Devil/Contract/DevilContractSystem.cs +++ b/Content.Server/_Goobstation/Devil/Contract/DevilContractSystem.cs @@ -35,6 +35,7 @@ using Robust.Shared.Prototypes; using Robust.Shared.Random; using Robust.Shared.Utility; using Content.Shared._EE.Silicon.Components; +using Content.Shared.StatusEffectNew; // DeltaV - Clause status effects namespace Content.Server._Goobstation.Devil.Contract; @@ -51,6 +52,7 @@ public sealed partial class DevilContractSystem : EntitySystem [Dependency] private readonly PolymorphSystem _polymorph = null!; [Dependency] private readonly ExplosionSystem _explosion = null!; [Dependency] private readonly MindSystem _mind = null!; + [Dependency] private readonly StatusEffectsSystem _statusEffects = null!; // DeltaV - Clause status effects public override void Initialize() { @@ -363,6 +365,8 @@ public sealed partial class DevilContractSystem : EntitySystem OverrideComponents(target, clause); // DeltaV - Fix component modifications + ApplyStatusEffect(target, clause); // DeltaV - Clause status effects + ChangeDamageModifier(target, clause); AddImplants(target, clause); @@ -414,6 +418,16 @@ public sealed partial class DevilContractSystem : EntitySystem } // End DeltaV Addition + // Begin DeltaV Addition - Devil clause status effects + private void ApplyStatusEffect(EntityUid target, DevilClausePrototype clause) + { + foreach (var effect in clause.StatusEffects) + { + _statusEffects.TrySetStatusEffectDuration(target, effect); + } + } + // End DeltaV Addition - Devil clause status effects + private void SpawnItems(EntityUid target, DevilClausePrototype clause) { if (clause.SpawnedItems == null) diff --git a/Content.Shared/_Goobstation/Devil/Contract/DevilClausePrototype.cs b/Content.Shared/_Goobstation/Devil/Contract/DevilClausePrototype.cs index 6f72df57f0..5b0d28cc15 100644 --- a/Content.Shared/_Goobstation/Devil/Contract/DevilClausePrototype.cs +++ b/Content.Shared/_Goobstation/Devil/Contract/DevilClausePrototype.cs @@ -27,6 +27,9 @@ public sealed class DevilClausePrototype : IPrototype [DataField] public ComponentRegistry? OverriddenComponents; // DeltaV - Added overridden components + [DataField] + public HashSet StatusEffects = new(); // DeltaV - Add status effects to clauses + [DataField] public string? DamageModifierSet; diff --git a/Resources/Prototypes/_Goobstation/Devil/clauses.yml b/Resources/Prototypes/_Goobstation/Devil/clauses.yml index f03a562f04..fe9db9627c 100644 --- a/Resources/Prototypes/_Goobstation/Devil/clauses.yml +++ b/Resources/Prototypes/_Goobstation/Devil/clauses.yml @@ -117,11 +117,14 @@ id: pain clauseWeight: -5 addedComponents: - - type: PainNumbness - type: SlowOnDamage speedModifierThresholds: 60: 1 80: 1 + # Begin DeltaV Additions - Clause status effects + statusEffects: + - PainNumbnessTraitStatusEffect + # End DeltaV Additions - Clause status effects - type: clause id: chance From 9dd9f5cd921cc233b7c0c27ea4b40d93ecf69fe5 Mon Sep 17 00:00:00 2001 From: Pieter-Jan Briers Date: Wed, 3 Dec 2025 16:52:25 +0100 Subject: [PATCH 013/360] Reduce explosion airtight cache memory usage (#40912) * Reduce explosion airtight cache memory usage This means you can happily add explosion prototypes again New approach has the tolerance value data in a shared storage with reference counting. * Oops fix index removal * Remove debug code and fix merge conflicts * Also address my other review * Oh it's in two places lmao --------- Co-authored-by: Princess Cheeseballs <66055347+Pronana@users.noreply.github.com> --- .../ExplosionAirtightGridComponent.cs | 100 +++++++++ .../EntitySystems/ExplosionGridTileFlood.cs | 19 +- .../EntitySystems/ExplosionSystem.Airtight.cs | 209 +++++++++++++----- .../EntitySystems/ExplosionSystem.GridMap.cs | 2 +- .../EntitySystems/ExplosionSystem.TileFill.cs | 19 +- .../EntitySystems/ExplosionSystem.cs | 3 + Resources/Prototypes/explosion.yml | 12 - 7 files changed, 282 insertions(+), 82 deletions(-) create mode 100644 Content.Server/Explosion/Components/ExplosionAirtightGridComponent.cs diff --git a/Content.Server/Explosion/Components/ExplosionAirtightGridComponent.cs b/Content.Server/Explosion/Components/ExplosionAirtightGridComponent.cs new file mode 100644 index 0000000000..68f576dcb9 --- /dev/null +++ b/Content.Server/Explosion/Components/ExplosionAirtightGridComponent.cs @@ -0,0 +1,100 @@ +using Content.Server.Explosion.EntitySystems; +using Content.Shared.Atmos; +using Content.Shared.FixedPoint; +using Robust.Shared.Map.Components; +using Robust.Shared.Utility; + +namespace Content.Server.Explosion.Components; + +/// +/// Stores data for airtight explosion traversal on a entity. +/// +/// +[RegisterComponent] +[Access(typeof(ExplosionSystem), Other = AccessPermissions.None)] +public sealed partial class ExplosionAirtightGridComponent : Component +{ + /// + /// Data for every tile on the current grid. + /// + /// + /// Intentionally not saved. + /// + [ViewVariables] + public readonly Dictionary Tiles = new(); + + /// + /// Data struct that describes the explosion-blocking airtight entities on a tile. + /// + public struct TileData + { + /// + /// Which index into the tolerance cache of this tile is using. + /// + public required int ToleranceCacheIndex; + + /// + /// Which directions this tile is blocking explosions in. Bitflag field. + /// + public required AtmosDirection BlockedDirections; + } + + /// + /// A set of tolerance values + /// + public struct ToleranceValues : IEquatable + { + /// + /// Special value that indicates the entity is "invulnerable" against a specific explosion type. + /// + /// + /// Here to deal with the limited range of over typical floats. + /// + public static readonly FixedPoint2 Invulnerable = FixedPoint2.MaxValue; + + /// + /// The intensities at which explosions of each type can instantly break through an entity. + /// + /// + /// + /// This is an array, with the index of each value corresponding to the "explosion type ID" cached by + /// . + /// + /// + /// Values are stored as to avoid possible precision issues resulting in + /// different-but-almost-identical tolerance values wasting memory. + /// + /// + /// If a value is , that indicates the tile is invulnerable. + /// + /// + public required FixedPoint2[] Values; + + public bool Equals(ToleranceValues other) + { + return Values.AsSpan().SequenceEqual(other.Values); + } + + public override bool Equals(object? obj) + { + return obj is ToleranceValues other && Equals(other); + } + + public override int GetHashCode() + { + var hc = new HashCode(); + hc.AddArray(Values); + return hc.ToHashCode(); + } + + public static bool operator ==(ToleranceValues left, ToleranceValues right) + { + return left.Equals(right); + } + + public static bool operator !=(ToleranceValues left, ToleranceValues right) + { + return !left.Equals(right); + } + } +} diff --git a/Content.Server/Explosion/EntitySystems/ExplosionGridTileFlood.cs b/Content.Server/Explosion/EntitySystems/ExplosionGridTileFlood.cs index da3ce635af..0274979c55 100644 --- a/Content.Server/Explosion/EntitySystems/ExplosionGridTileFlood.cs +++ b/Content.Server/Explosion/EntitySystems/ExplosionGridTileFlood.cs @@ -1,7 +1,8 @@ using System.Numerics; using Content.Shared.Atmos; -using Robust.Shared.Map; +using Content.Shared.FixedPoint; using Robust.Shared.Map.Components; +using static Content.Server.Explosion.Components.ExplosionAirtightGridComponent; using static Content.Server.Explosion.EntitySystems.ExplosionSystem; namespace Content.Server.Explosion.EntitySystems; @@ -11,6 +12,8 @@ namespace Content.Server.Explosion.EntitySystems; /// public sealed class ExplosionGridTileFlood : ExplosionTileFlood { + private readonly ExplosionSystem _explosionSystem; + public Entity Grid; private bool _needToTransform = false; @@ -45,7 +48,8 @@ public sealed class ExplosionGridTileFlood : ExplosionTileFlood Dictionary edgeTiles, EntityUid? referenceGrid, Matrix3x2 spaceMatrix, - Angle spaceAngle) + Angle spaceAngle, + ExplosionSystem explosionSystem) { Grid = grid; _airtightMap = airtightMap; @@ -53,6 +57,7 @@ public sealed class ExplosionGridTileFlood : ExplosionTileFlood _intensityStepSize = intensityStepSize; _typeIndex = typeIndex; _edgeTiles = edgeTiles; + _explosionSystem = explosionSystem; // initialise SpaceTiles foreach (var (tile, spaceNeighbors) in _edgeTiles) @@ -193,11 +198,11 @@ public sealed class ExplosionGridTileFlood : ExplosionTileFlood NewBlockedTiles.Add(tile); // At what explosion iteration would this blocker be destroyed? - var required = tileData.ExplosionTolerance[_typeIndex]; + var required = _explosionSystem.GetToleranceValues(tileData.ToleranceCacheIndex).Values[_typeIndex]; if (required > _maxIntensity) return; // blocker is never destroyed. - var clearIteration = iteration + (int) MathF.Ceiling(required / _intensityStepSize); + var clearIteration = iteration + (int) MathF.Ceiling((float)required / _intensityStepSize); if (FreedTileLists.TryGetValue(clearIteration, out var list)) list.Add(tile); else @@ -261,13 +266,13 @@ public sealed class ExplosionGridTileFlood : ExplosionTileFlood foreach (var tile in tiles) { var blockedDirections = AtmosDirection.Invalid; - float sealIntegrity = 0; + FixedPoint2 sealIntegrity = 0; // Note that if (grid, tile) is not a valid key, then airtight.BlockedDirections will default to 0 (no blocked directions) if (_airtightMap.TryGetValue(tile, out var tileData)) { blockedDirections = tileData.BlockedDirections; - sealIntegrity = tileData.ExplosionTolerance[_typeIndex]; + sealIntegrity = _explosionSystem.GetToleranceValues(tileData.ToleranceCacheIndex).Values[_typeIndex]; } // First, yield any neighboring tiles that are not blocked by airtight entities on this tile @@ -290,7 +295,7 @@ public sealed class ExplosionGridTileFlood : ExplosionTileFlood continue; // At what explosion iteration would this blocker be destroyed? - var clearIteration = iteration + (int) MathF.Ceiling(sealIntegrity / _intensityStepSize); + var clearIteration = iteration + (int) MathF.Ceiling((float) sealIntegrity / _intensityStepSize); // Get the delayed neighbours list if (!_delayedNeighbors.TryGetValue(clearIteration, out var list)) diff --git a/Content.Server/Explosion/EntitySystems/ExplosionSystem.Airtight.cs b/Content.Server/Explosion/EntitySystems/ExplosionSystem.Airtight.cs index 303c4e8cab..da2a571900 100644 --- a/Content.Server/Explosion/EntitySystems/ExplosionSystem.Airtight.cs +++ b/Content.Server/Explosion/EntitySystems/ExplosionSystem.Airtight.cs @@ -1,44 +1,59 @@ +using System.Linq; +using System.Runtime.InteropServices; using Content.Server.Atmos.Components; +using Content.Server.Explosion.Components; using Content.Shared.Atmos; using Content.Shared.Damage.Systems; using Content.Shared.Explosion; using Content.Shared.FixedPoint; +using Robust.Shared.Collections; using Robust.Shared.Map.Components; +using Robust.Shared.Prototypes; +using Robust.Shared.Utility; +using static Content.Server.Explosion.Components.ExplosionAirtightGridComponent; namespace Content.Server.Explosion.EntitySystems; public sealed partial class ExplosionSystem { - private readonly Dictionary _explosionTypes = new(); + // We keep track of which tiles are airtight, and how much damage from explosions those airtight blockers can take. + // This is quite complicated, as the data effectively needs to be tracked *per tile*, *per explosion type*. + // To avoid wasting significant memory, we calculate the values and share the actual backing storage of it. + // Stored values are reference counted so they can be evicted when no longer needed. + // At the time of writing, this compacts the storage for Box Station from ~5500 tolerance value sets to 13, + // at round start. + + // Use integers instead of prototype IDs for storage of explosion data. + // This allows us to replace a Dictionary with just a FixedPoint2[]. + private readonly Dictionary, int> _explosionTypes = new(); + // Index to look up if we already have an existing set of tolerance values stored, so the data can be shared. + private readonly Dictionary _toleranceIndex = new(); + // Storage for tolerance values. Entries form a free linked list when not occupied by a set of real values. + private ValueList _toleranceData; + // First free position in _toleranceData. + // -1 indicates there are no free slots left and the storage must be expanded. + private int _freeListHead = -1; private void InitAirtightMap() { - // Currently explosion prototype hot-reload isn't supported, as it would involve completely re-computing the - // airtight map. Could be done, just not yet implemented. + _explosionTypes.Clear(); - // for storing airtight entity damage thresholds for all anchored airtight entities, we will use integers in - // place of id-strings. This initializes the string <--> id association. - // This allows us to replace a Dictionary with just a float[]. int index = 0; foreach (var prototype in _prototypeManager.EnumeratePrototypes()) { - // TODO EXPLOSION - // just make this a field on the prototype _explosionTypes.Add(prototype.ID, index); index++; } } - // The explosion intensity required to break an entity depends on the explosion type. So it is stored in a - // Dictionary - // - // Hence, each tile has a tuple (Dictionary, AtmosDirection). This specifies what directions are - // blocked, and how intense a given explosion type needs to be in order to destroy ALL airtight entities on that - // tile. This is the TileData struct. - // - // We then need this data for every tile on a grid. So this mess of a variable maps the Grid ID and Vector2i grid - // indices to this tile-data struct. - private Dictionary> _airtightMap = new(); + private void ReloadExplosionPrototypes(PrototypesReloadedEventArgs prototypesReloadedEventArgs) + { + if (!prototypesReloadedEventArgs.Modified.Contains(typeof(ExplosionPrototype))) + return; + + InitAirtightMap(); + ReloadMap(); + } public void UpdateAirtightMap(EntityUid gridId, Vector2i tile, MapGridComponent? grid = null) { @@ -46,6 +61,12 @@ public sealed partial class ExplosionSystem UpdateAirtightMap(gridId, grid, tile); } + [Access(typeof(ExplosionGridTileFlood))] + public ToleranceValues GetToleranceValues(int idx) + { + return _toleranceData[idx].Values; + } + /// /// Update the map of explosion blockers. /// @@ -58,11 +79,12 @@ public sealed partial class ExplosionSystem /// public void UpdateAirtightMap(EntityUid gridId, MapGridComponent grid, Vector2i tile) { - var tolerance = new float[_explosionTypes.Count]; - var blockedDirections = AtmosDirection.Invalid; + var airtightGrid = EnsureComp(gridId); - if (!_airtightMap.ContainsKey(gridId)) - _airtightMap[gridId] = new(); + // Calculate tile new airtight state. + + var tolerance = new FixedPoint2[_explosionTypes.Count]; + var blockedDirections = AtmosDirection.Invalid; var anchoredEnumerator = _map.GetAnchoredEntitiesEnumerator(gridId, grid, tile); @@ -72,17 +94,97 @@ public sealed partial class ExplosionSystem continue; blockedDirections |= airtight.AirBlockedDirection; - var entityTolerances = GetExplosionTolerance(uid.Value); - for (var i = 0; i < tolerance.Length; i++) - { - tolerance[i] = Math.Max(tolerance[i], entityTolerances[i]); - } + GetExplosionTolerance(uid.Value, tolerance); } - if (blockedDirections != AtmosDirection.Invalid) - _airtightMap[gridId][tile] = new(tolerance, blockedDirections); + // Log.Info($"UPDATE {gridId}/{tile}: {blockedDirections}"); + + if (blockedDirections == AtmosDirection.Invalid) + { + // No longer airtight + + if (!airtightGrid.Tiles.Remove(tile, out var tileData)) + { + // Did not have this tile before and after, nothing to do. + return; + } + + // Removing tile data. + DecrementRefCount(tileData.ToleranceCacheIndex); + return; + } + + ref var tileEntry = ref CollectionsMarshal.GetValueRefOrAddDefault(airtightGrid.Tiles, tile, out var existed); + var cacheKey = new ToleranceValues { Values = tolerance }; + + // Remove previous tolerance reference if necessary. + if (existed) + { + ref var prevEntry = ref _toleranceData[tileEntry.ToleranceCacheIndex]; + if (prevEntry.Values == cacheKey) + { + // No change. + return; + } + + DecrementRefCount(tileEntry.ToleranceCacheIndex); + } + + ref var newCacheIndex = ref CollectionsMarshal.GetValueRefOrAddDefault(_toleranceIndex, cacheKey, out existed); + if (existed) + { + _toleranceData[newCacheIndex].RefCount += 1; + } else - _airtightMap[gridId].Remove(tile); + { + if (_freeListHead < 0) + ExpandCache(); + + newCacheIndex = _freeListHead; + ref var newCacheEntry = ref _toleranceData[newCacheIndex]; + _freeListHead = newCacheEntry.RefCount; + + newCacheEntry.Values = cacheKey; + newCacheEntry.RefCount = 1; + } + + tileEntry = new TileData + { + BlockedDirections = blockedDirections, + ToleranceCacheIndex = newCacheIndex, + }; + } + + private void ExpandCache() + { + var newCacheSize = Math.Max(8, _toleranceData.Count * 2); + var curSize = _toleranceData.Count; + + _toleranceData.EnsureLength(newCacheSize); + for (var i = curSize; i < newCacheSize; i++) + { + _toleranceData[i].RefCount = _freeListHead; + _freeListHead = i; + } + } + + private void DecrementRefCount(int index) + { + ref var cacheEntry = ref _toleranceData[index]; + + DebugTools.Assert(cacheEntry.RefCount > 0); + cacheEntry.RefCount -= 1; + + if (cacheEntry.RefCount == 0) + { + var prevValue = cacheEntry.Values; + cacheEntry.Values = default; + cacheEntry.RefCount = _freeListHead; + _freeListHead = index; + + var result = _toleranceIndex.Remove(prevValue); + DebugTools.Assert(result, "Failed to removed 0 refcounted index!"); + } } /// @@ -106,7 +208,7 @@ public sealed partial class ExplosionSystem /// /// Return a dictionary that specifies how intense a given explosion type needs to be in order to destroy an entity. /// - public float[] GetExplosionTolerance(EntityUid uid) + private void GetExplosionTolerance(EntityUid uid, Span explosionTolerance) { // How much total damage is needed to destroy this entity? This also includes "break" behaviors. This ASSUMES // that this will result in a non-airtight entity.Entities that ONLY break via construction graph node changes @@ -117,14 +219,14 @@ public sealed partial class ExplosionSystem totalDamageTarget = _destructibleSystem.DestroyedAt(uid, destructible); } - var explosionTolerance = new float[_explosionTypes.Count]; if (totalDamageTarget == FixedPoint2.MaxValue || !_damageableQuery.TryGetComponent(uid, out var damageable)) { for (var i = 0; i < explosionTolerance.Length; i++) { - explosionTolerance[i] = float.MaxValue; + explosionTolerance[i] = ToleranceValues.Invulnerable; } - return explosionTolerance; + + return; } // What multiple of each explosion type damage set will result in the damage exceeding the required amount? This @@ -157,38 +259,43 @@ public sealed partial class ExplosionSystem damagePerIntensity += value * mod * Math.Max(0, ev.DamageCoefficient); } - explosionTolerance[index] = damagePerIntensity > 0 + var toleranceValue = damagePerIntensity > 0 ? (float) ((totalDamageTarget - damageable.TotalDamage) / damagePerIntensity) - : float.MaxValue; - } + : ToleranceValues.Invulnerable; - return explosionTolerance; + explosionTolerance[index] = toleranceValue; + } } - /// - /// Data struct that describes the explosion-blocking airtight entities on a tile. - /// - public struct TileData + private void OnAirtightGridRemoved(EntityUid entity) { - public TileData(float[] explosionTolerance, AtmosDirection blockedDirections) + if (!TryComp(entity, out ExplosionAirtightGridComponent? airtightGrid)) + return; + + foreach (var tile in airtightGrid.Tiles.Values) { - ExplosionTolerance = explosionTolerance; - BlockedDirections = blockedDirections; + DecrementRefCount(tile.ToleranceCacheIndex); } - public float[] ExplosionTolerance; - public AtmosDirection BlockedDirections = AtmosDirection.Invalid; + RemComp(entity); } public override void ReloadMap() { - foreach (var(grid, dict) in _airtightMap) + var enumerator = EntityQueryEnumerator(); + while (enumerator.MoveNext(out var uid, out var airtightComp, out var mapGrid)) { - var comp = Comp(grid); - foreach (var index in dict.Keys) + foreach (var pos in airtightComp.Tiles.Keys) { - UpdateAirtightMap(grid, comp, index); + UpdateAirtightMap(uid, pos, mapGrid); } } } + + private struct CacheEntry + { + public ToleranceValues Values; + public int RefCount; // Doubles as freelist chain + } + } diff --git a/Content.Server/Explosion/EntitySystems/ExplosionSystem.GridMap.cs b/Content.Server/Explosion/EntitySystems/ExplosionSystem.GridMap.cs index 5c032d5c82..3767d0c238 100644 --- a/Content.Server/Explosion/EntitySystems/ExplosionSystem.GridMap.cs +++ b/Content.Server/Explosion/EntitySystems/ExplosionSystem.GridMap.cs @@ -38,7 +38,7 @@ public sealed partial class ExplosionSystem private void OnGridRemoved(GridRemovalEvent ev) { - _airtightMap.Remove(ev.EntityUid); + OnAirtightGridRemoved(ev.EntityUid); _gridEdges.Remove(ev.EntityUid); // this should be a small enough set that iterating all of them is fine diff --git a/Content.Server/Explosion/EntitySystems/ExplosionSystem.TileFill.cs b/Content.Server/Explosion/EntitySystems/ExplosionSystem.TileFill.cs index ac539da213..a274fa8660 100644 --- a/Content.Server/Explosion/EntitySystems/ExplosionSystem.TileFill.cs +++ b/Content.Server/Explosion/EntitySystems/ExplosionSystem.TileFill.cs @@ -1,5 +1,6 @@ using System.Linq; using System.Numerics; +using Content.Server.Explosion.Components; using Content.Shared.Administration; using Content.Shared.Explosion.Components; using Robust.Shared.Map; @@ -40,11 +41,7 @@ public sealed partial class ExplosionSystem if (totalIntensity <= 0 || slope <= 0) return null; - if (!_explosionTypes.TryGetValue(typeID, out var typeIndex)) - { - Log.Error("Attempted to spawn explosion using a prototype that was not defined during initialization. Explosion prototype hot-reload is not currently supported."); - return null; - } + var typeIndex = _explosionTypes[typeID]; Vector2i initialTile; EntityUid? epicentreGrid = null; @@ -103,8 +100,7 @@ public sealed partial class ExplosionSystem // set up the initial `gridData` instance encounteredGrids.Add(epicentreGrid.Value); - if (!_airtightMap.TryGetValue(epicentreGrid.Value, out var airtightMap)) - airtightMap = new(); + var airtightMap = CompOrNull(epicentreGrid)?.Tiles ?? new(); var initialGridData = new ExplosionGridTileFlood( (epicentreGrid.Value, Comp(epicentreGrid.Value)), @@ -115,7 +111,8 @@ public sealed partial class ExplosionSystem _gridEdges[epicentreGrid.Value], referenceGrid, spaceMatrix, - spaceAngle); + spaceAngle, + this); gridData[epicentreGrid.Value] = initialGridData; @@ -192,8 +189,7 @@ public sealed partial class ExplosionSystem // is this a new grid, for which we must create a new explosion data set if (!gridData.TryGetValue(grid, out var data)) { - if (!_airtightMap.TryGetValue(grid, out var airtightMap)) - airtightMap = new(); + var airtightMap = CompOrNull(grid)?.Tiles ?? new(); data = new ExplosionGridTileFlood( (grid, Comp(grid)), @@ -204,7 +200,8 @@ public sealed partial class ExplosionSystem _gridEdges[grid], referenceGrid, spaceMatrix, - spaceAngle); + spaceAngle, + this); gridData[grid] = data; } diff --git a/Content.Server/Explosion/EntitySystems/ExplosionSystem.cs b/Content.Server/Explosion/EntitySystems/ExplosionSystem.cs index 934e4b40c6..223d1dbd01 100644 --- a/Content.Server/Explosion/EntitySystems/ExplosionSystem.cs +++ b/Content.Server/Explosion/EntitySystems/ExplosionSystem.cs @@ -106,6 +106,8 @@ public sealed partial class ExplosionSystem : SharedExplosionSystem _destructibleQuery = GetEntityQuery(); _damageableQuery = GetEntityQuery(); _airtightQuery = GetEntityQuery(); + + _prototypeManager.PrototypesReloaded += ReloadExplosionPrototypes; } private void OnReset(RoundRestartCleanupEvent ev) @@ -124,6 +126,7 @@ public sealed partial class ExplosionSystem : SharedExplosionSystem base.Shutdown(); _nodeGroupSystem.PauseUpdating = false; _pathfindingSystem.PauseUpdating = false; + _prototypeManager.PrototypesReloaded -= ReloadExplosionPrototypes; } private void RelayedResistance(EntityUid uid, ExplosionResistanceComponent component, diff --git a/Resources/Prototypes/explosion.yml b/Resources/Prototypes/explosion.yml index ad00333892..4d3febeda7 100644 --- a/Resources/Prototypes/explosion.yml +++ b/Resources/Prototypes/explosion.yml @@ -1,11 +1,3 @@ -# Does not currently support prototype hot-reloading. See comments in c# file. - -# Note that for every explosion type you define, explosions & nukes will start performing worse -# You should only define a new explopsion type if you really need to -# -# If you just want to modify properties other than `damagePerIntensity`, it'd be better to -# split off explosion damage & explosion visuals/effects into their own separate prototypes. - - type: explosion id: Default damagePerIntensity: @@ -135,7 +127,3 @@ texturePath: /Textures/Effects/fire.rsi fireStates: 3 fireStacks: 2 - -# STOP -# BEFORE YOU ADD MORE EXPLOSION TYPES CONSIDER IF AN EXISTING ONE IS SUITABLE -# ADDING NEW ONES IS PROHIBITIVELY EXPENSIVE From 2ac36dcbffd7b0ffd04719f7989b590edcb6319d Mon Sep 17 00:00:00 2001 From: Hitlinemoss <209321380+Hitlinemoss@users.noreply.github.com> Date: Wed, 3 Dec 2025 12:39:18 -0500 Subject: [PATCH 014/360] Minor cleanup of hypospray.yml + clearer medipen descriptions (#41682) * Minor cleanup of hypospray.yml * SyndiHypo is only used by corpsmen (it's not in the uplink) so the description should reflect that * Small and large shots --- .../Objects/Specific/Medical/hypospray.yml | 61 +++++++++---------- 1 file changed, 30 insertions(+), 31 deletions(-) diff --git a/Resources/Prototypes/Entities/Objects/Specific/Medical/hypospray.yml b/Resources/Prototypes/Entities/Objects/Specific/Medical/hypospray.yml index 1cdcee68b3..fc6f4dc8e3 100644 --- a/Resources/Prototypes/Entities/Objects/Specific/Medical/hypospray.yml +++ b/Resources/Prototypes/Entities/Objects/Specific/Medical/hypospray.yml @@ -60,7 +60,7 @@ parent: [BaseHypospray, BaseSyndicateContraband] id: SyndiHypo name: gorlex hypospray - description: Using reverse engineered designs from NT, Cybersun produced these in limited quantities for Gorlex Marauder operatives. + description: A sterile injector for rapid administration of drugs. Reverse-engineered from Nanotrasen designs, Cybersun produces these in limited quantities for Gorlex Marauders' corpsmen. components: - type: Sprite sprite: Objects/Specific/Medical/syndihypo.rsi @@ -85,7 +85,7 @@ parent: BaseHypospray id: BorgHypo name: borghypo - description: A sterile injector for rapid administration of drugs to patients. A cheaper and more specialised version for medical borgs. + description: A sterile injector for rapid administration of drugs to patients. This integrated model is specialized for use by medical borgs. components: - type: Sprite sprite: Objects/Specific/Medical/hypospray.rsi @@ -137,7 +137,7 @@ - JetInjectorDynamicMode - JetInjectorInjectMode - type: Tag - tags: + tags: - JetInjector - type: entity @@ -186,7 +186,7 @@ parent: BaseHypospray id: ChemicalMedipen name: chemical medipen - description: A sterile injector for rapid administration of drugs to patients. This one can't be refilled. + description: A single-dose, non-refillable medipen. components: - type: Sprite sprite: Objects/Specific/Medical/medipen.rsi @@ -241,10 +241,10 @@ - ChemicalMedipen - type: entity - name: emergency medipen parent: ChemicalMedipen id: EmergencyMedipen - description: A rapid and safe way to stabilize patients in critical condition for personnel without advanced medical knowledge. Beware, as it's easy to overdose on epinephrine and tranexamic acid. + name: emergency medipen + description: A single-dose, non-refillable medipen containing epinephrine and tranexamic acid, used to temporarily stabilize patients in critical condition and buy time for them to recieve proper medical treatment. Beware of overdose. components: - type: Sprite sprite: Objects/Specific/Medical/medipen.rsi @@ -266,10 +266,10 @@ Quantity: 3 - type: entity - name: poison auto-injector parent: ChemicalMedipen id: AntiPoisonMedipen - description: A rapid dose of anti-poison. Contains ultravasculine and epinephrine. + name: poison auto-injector + description: A single-dose, non-refillable medipen containing ultravasculine and epinephrine, used to quickly and easily treat toxin poisoning. components: - type: Item inhandVisuals: @@ -303,10 +303,10 @@ Quantity: 5 - type: entity - name: brute auto-injector parent: ChemicalMedipen id: BruteAutoInjector - description: A rapid dose of bicaridine and tranexamic acid, intended for combat applications. + name: brute auto-injector + description: A single-dose, non-refillable medipen containing bicaridine and tranexamic acid, used to quickly and easily treat simple physical injuries. Commonly used as a combat medicine. components: - type: Item inhandVisuals: @@ -340,10 +340,10 @@ Quantity: 5 - type: entity - name: burn auto-injector parent: ChemicalMedipen id: BurnAutoInjector - description: A rapid dose of dermaline and leporazine, intended for combat applications. + name: burn auto-injector + description: A single-dose, non-refillable medipen containing dermaline and leporazine, used to quickly and easily treat non-chemical burns. Commonly used as a combat medicine. components: - type: Item inhandVisuals: @@ -377,10 +377,10 @@ Quantity: 10 - type: entity - name: rad auto-injector parent: ChemicalMedipen id: RadAutoInjector - description: A rapid dose of anti-radiation. Contains arithrazine and bicaridine. + name: rad auto-injector + description: A single-dose, non-refillable medipen containing arithrazine and bicaridine, used to quickly and easily treat radiation poisoning. components: - type: Item inhandVisuals: @@ -414,10 +414,10 @@ Quantity: 5 - type: entity - name: puncturase auto-injector parent: ChemicalMedipen id: PunctAutoInjector - description: A rapid dose of puncturase and tranexamic acid, intended for combat applications. + name: puncturase auto-injector + description: A single-dose, non-refillable medipen containing puncturase and tranexamic acid, used to quickly and easily treat puncture wounds. Commonly used as a combat medicine. components: - type: Item inhandVisuals: @@ -451,10 +451,10 @@ Quantity: 5 - type: entity - name: pyrazine auto-injector parent: ChemicalMedipen id: PyraAutoInjector - description: A rapid dose of pyrazine and dermaline, intended for combat applications. + name: pyrazine auto-injector + description: A single-dose, non-refillable medipen containing pyrazine and dermaline, used to quickly and easily treat thermal burns. Commonly used as a combat medicine. components: - type: Item inhandVisuals: @@ -488,10 +488,9 @@ Quantity: 10 - type: entity - name: airloss auto-injector parent: ChemicalMedipen id: AirlossAutoInjector - description: A rapid dose of saline and salbutamol, intended to get someone up quickly. # Funkychem - dex+ -> salbutamol + description: A single-dose, non-refillable medipen containing saline and dexalin plus, used to quickly and easily treat blood loss and asphyxiation. components: - type: Item inhandVisuals: @@ -527,10 +526,10 @@ tags: [] - type: entity - name: space medipen parent: ChemicalMedipen id: SpaceMedipen - description: Contains a mix of chemicals that protect you from the deadly effects of space. + name: space medipen + description: A single-dose, non-refillable medipen containing barozine and leporazine, used to protect exposed flesh from the deadly effects of space. components: - type: Item inhandVisuals: @@ -565,10 +564,10 @@ Quantity: 20 - type: entity - name: hyperzine injector parent: [ChemicalMedipen, BaseSyndicateContraband] id: Stimpack - description: Contains enough hyperzine for you to have the chemical's effect for 30 seconds. Use it when you're sure you're ready to throw down. + name: hyperzine injector + description: A chemical injector containing a large shot of pure hyperzine. For when it's time to throw down. Effects last for about 30 seconds. components: - type: Item inhandVisuals: @@ -604,10 +603,10 @@ price: 1500 - type: entity - name: hyperzine microinjector parent: [ChemicalMedipen, BaseSyndicateContraband] id: StimpackMini - description: A microinjector of hyperzine that give you about 15 seconds of the chemical's effects. + name: hyperzine microinjector + description: A chemical microinjector containing a small shot of pure hyperzine. Effects last for about 15 seconds. components: - type: Item inhandVisuals: @@ -643,10 +642,10 @@ price: 583 # 3500 for 6 as a freaky fraction - type: entity - name: combat medipen parent: [ChemicalMedipen, BaseSyndicateContraband] id: CombatMedipen - description: A single-use medipen containing chemicals that regenerate most types of damage. + name: combat medipen + description: A single-dose, non-refillable medipen containing a chemical cocktail that treats most forms of damage. components: - type: Item inhandVisuals: @@ -682,9 +681,9 @@ price: 1500 - type: entity - suffix: Hypopen parent: Pen # It is just like normal pen, isn't it? id: Hypopen + suffix: Hypopen components: - type: SolutionContainerManager solutions: @@ -729,10 +728,10 @@ path: /Audio/Effects/unwrap.ogg - type: entity - name: weh auto-injector parent: ChemicalMedipen id: WehMedipen - description: A rapid dose of Weh. Contains juice that makes you Weh. + name: weh auto-injector + description: A non-refillable medipen containing multiple doses of weh. components: - type: Sprite sprite: Objects/Specific/Medical/medipen.rsi From 1052426b3ec1a0de34837b0945d25d6cdd3e67de Mon Sep 17 00:00:00 2001 From: BarryNorfolk Date: Fri, 23 Jan 2026 08:27:45 +0100 Subject: [PATCH 015/360] Downstream fix for hypospray description updates --- .../prototypes/entities/objects/specific/medical/hypospray.ftl | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 Resources/Locale/en-US/_DV/prototypes/entities/objects/specific/medical/hypospray.ftl diff --git a/Resources/Locale/en-US/_DV/prototypes/entities/objects/specific/medical/hypospray.ftl b/Resources/Locale/en-US/_DV/prototypes/entities/objects/specific/medical/hypospray.ftl new file mode 100644 index 0000000000..d8ddcf0d04 --- /dev/null +++ b/Resources/Locale/en-US/_DV/prototypes/entities/objects/specific/medical/hypospray.ftl @@ -0,0 +1,3 @@ +# Funkychem - dex+ -> salbutamol +ent-AirlossAutoInjector = airloss auto injector + .desc = A single-dose, non-refillable medipen containing saline and salbutamol, used to quickly and easily treat blood loss and asphyxiation. From e21a29ddf822c715f34a51b1ba801614fbd4dbab Mon Sep 17 00:00:00 2001 From: Pok <113675512+Pok27@users.noreply.github.com> Date: Wed, 3 Dec 2025 21:44:17 +0200 Subject: [PATCH 016/360] Predict BedSystem (#41686) * BedSystem-move-to-shared * dependency * dirty!!! --- Content.Client/Bed/BedSystem.cs | 8 --- Content.Server/Bed/BedSystem.cs | 57 ------------------- .../Bed/{SharedBedSystem.cs => BedSystem.cs} | 54 ++++++++++++++++-- .../Components/StasisBedBuckledComponent.cs | 2 +- .../Bed/Components/StasisBedComponent.cs | 2 +- 5 files changed, 50 insertions(+), 73 deletions(-) delete mode 100644 Content.Client/Bed/BedSystem.cs delete mode 100644 Content.Server/Bed/BedSystem.cs rename Content.Shared/Bed/{SharedBedSystem.cs => BedSystem.cs} (70%) diff --git a/Content.Client/Bed/BedSystem.cs b/Content.Client/Bed/BedSystem.cs deleted file mode 100644 index 9c6f28290f..0000000000 --- a/Content.Client/Bed/BedSystem.cs +++ /dev/null @@ -1,8 +0,0 @@ -using Content.Shared.Bed; - -namespace Content.Client.Bed; - -public sealed class BedSystem : SharedBedSystem -{ - -} diff --git a/Content.Server/Bed/BedSystem.cs b/Content.Server/Bed/BedSystem.cs deleted file mode 100644 index c56838c032..0000000000 --- a/Content.Server/Bed/BedSystem.cs +++ /dev/null @@ -1,57 +0,0 @@ -using Content.Shared.Bed; -using Content.Shared.Bed.Components; -using Content.Shared.Bed.Sleep; -using Content.Shared.Buckle.Components; -using Content.Shared.Damage.Systems; -using Content.Shared.Mobs.Systems; -using Content.Shared.Power; -using Content.Shared._EE.Silicon.Components; // Goobstation - -namespace Content.Server.Bed -{ - public sealed class BedSystem : SharedBedSystem - { - [Dependency] private readonly DamageableSystem _damageableSystem = default!; - [Dependency] private readonly MobStateSystem _mobStateSystem = default!; - - private EntityQuery _sleepingQuery; - - public override void Initialize() - { - base.Initialize(); - - _sleepingQuery = GetEntityQuery(); - } - - public override void Update(float frameTime) - { - base.Update(frameTime); - - var query = EntityQueryEnumerator(); - while (query.MoveNext(out var uid, out _, out var bedComponent, out var strapComponent)) - { - if (Timing.CurTime < bedComponent.NextHealTime) - continue; - - bedComponent.NextHealTime += TimeSpan.FromSeconds(bedComponent.HealTime); - - if (strapComponent.BuckledEntities.Count == 0) - continue; - - foreach (var healedEntity in strapComponent.BuckledEntities) - { - if (_mobStateSystem.IsDead(healedEntity) - || HasComp(healedEntity)) // Goobstation - continue; - - var damage = bedComponent.Damage; - - if (_sleepingQuery.HasComp(healedEntity)) - damage *= bedComponent.SleepMultiplier; - - _damageableSystem.TryChangeDamage(healedEntity, damage, true, origin: uid); - } - } - } - } -} diff --git a/Content.Shared/Bed/SharedBedSystem.cs b/Content.Shared/Bed/BedSystem.cs similarity index 70% rename from Content.Shared/Bed/SharedBedSystem.cs rename to Content.Shared/Bed/BedSystem.cs index 0518f05fdf..c1b149c218 100644 --- a/Content.Shared/Bed/SharedBedSystem.cs +++ b/Content.Shared/Bed/BedSystem.cs @@ -1,10 +1,13 @@ +using Content.Shared._EE.Silicon.Components; // Goobstation using Content.Shared.Actions; using Content.Shared.Bed.Components; using Content.Shared.Bed.Sleep; using Content.Shared.Body.Events; using Content.Shared.Body.Systems; using Content.Shared.Buckle.Components; +using Content.Shared.Damage.Systems; using Content.Shared.Emag.Systems; +using Content.Shared.Mobs.Systems; using Content.Shared.Power; using Content.Shared.Power.EntitySystems; using Robust.Shared.Timing; @@ -12,16 +15,20 @@ using Robust.Shared.Utility; namespace Content.Shared.Bed; -public abstract class SharedBedSystem : EntitySystem +public sealed class BedSystem : EntitySystem { - [Dependency] protected readonly IGameTiming Timing = default!; [Dependency] private readonly ActionContainerSystem _actConts = default!; - [Dependency] private readonly SharedActionsSystem _actionsSystem = default!; + [Dependency] private readonly DamageableSystem _damageableSystem = default!; [Dependency] private readonly EmagSystem _emag = default!; + [Dependency] private readonly IGameTiming _timing = default!; + [Dependency] private readonly MobStateSystem _mobStateSystem = default!; + [Dependency] private readonly SharedActionsSystem _actionsSystem = default!; [Dependency] private readonly SharedMetabolizerSystem _metabolizer = default!; [Dependency] private readonly SharedPowerReceiverSystem _powerReceiver = default!; [Dependency] private readonly SleepingSystem _sleepingSystem = default!; + private EntityQuery _sleepingQuery; + public override void Initialize() { base.Initialize(); @@ -35,6 +42,8 @@ public abstract class SharedBedSystem : EntitySystem SubscribeLocalEvent(OnStasisEmagged); SubscribeLocalEvent(OnPowerChanged); SubscribeLocalEvent(OnStasisGetMetabolicMultiplier); + + _sleepingQuery = GetEntityQuery(); } private void OnHealMapInit(Entity ent, ref MapInitEvent args) @@ -46,7 +55,7 @@ public abstract class SharedBedSystem : EntitySystem private void OnStrapped(Entity bed, ref StrappedEvent args) { EnsureComp(bed); - bed.Comp.NextHealTime = Timing.CurTime + TimeSpan.FromSeconds(bed.Comp.HealTime); + bed.Comp.NextHealTime = _timing.CurTime + TimeSpan.FromSeconds(bed.Comp.HealTime); _actionsSystem.AddAction(args.Buckle, ref bed.Comp.SleepAction, SleepingSystem.SleepActionId, bed); Dirty(bed); @@ -62,7 +71,7 @@ public abstract class SharedBedSystem : EntitySystem _actionsSystem.RemoveAction(args.Buckle.Owner, bed.Comp.SleepAction); _sleepingSystem.TryWaking(args.Buckle.Owner); } - + RemComp(bed); } @@ -112,7 +121,7 @@ public abstract class SharedBedSystem : EntitySystem args.Multiplier *= stasis.Multiplier; } - protected void UpdateMetabolisms(Entity ent) + private void UpdateMetabolisms(Entity ent) { if (!Resolve(ent, ref ent.Comp, false)) return; @@ -122,4 +131,37 @@ public abstract class SharedBedSystem : EntitySystem _metabolizer.UpdateMetabolicMultiplier(buckledEntity); } } + + public override void Update(float frameTime) + { + base.Update(frameTime); + + var query = EntityQueryEnumerator(); + while (query.MoveNext(out var uid, out _, out var bedComponent, out var strapComponent)) + { + if (_timing.CurTime < bedComponent.NextHealTime) + continue; + + bedComponent.NextHealTime += TimeSpan.FromSeconds(bedComponent.HealTime); + + Dirty(uid, bedComponent); + + if (strapComponent.BuckledEntities.Count == 0) + continue; + + foreach (var healedEntity in strapComponent.BuckledEntities) + { + if (_mobStateSystem.IsDead(healedEntity) + || HasComp(healedEntity)) // Goobstation) + continue; + + var damage = bedComponent.Damage; + + if (_sleepingQuery.HasComp(healedEntity)) + damage *= bedComponent.SleepMultiplier; + + _damageableSystem.TryChangeDamage(healedEntity, damage, true, origin: uid); + } + } + } } diff --git a/Content.Shared/Bed/Components/StasisBedBuckledComponent.cs b/Content.Shared/Bed/Components/StasisBedBuckledComponent.cs index 3a1c991b1e..09759f71ef 100644 --- a/Content.Shared/Bed/Components/StasisBedBuckledComponent.cs +++ b/Content.Shared/Bed/Components/StasisBedBuckledComponent.cs @@ -6,5 +6,5 @@ namespace Content.Shared.Bed.Components; /// Tracking component added to entities buckled to stasis beds. /// [RegisterComponent, NetworkedComponent] -[Access(typeof(SharedBedSystem))] +[Access(typeof(BedSystem))] public sealed partial class StasisBedBuckledComponent : Component; diff --git a/Content.Shared/Bed/Components/StasisBedComponent.cs b/Content.Shared/Bed/Components/StasisBedComponent.cs index 97936261d6..fdc720c34f 100644 --- a/Content.Shared/Bed/Components/StasisBedComponent.cs +++ b/Content.Shared/Bed/Components/StasisBedComponent.cs @@ -7,7 +7,7 @@ namespace Content.Shared.Bed.Components; /// A that modifies a strapped entity's metabolic rate by the given multiplier /// [RegisterComponent, NetworkedComponent, AutoGenerateComponentState] -[Access(typeof(SharedBedSystem))] +[Access(typeof(BedSystem))] public sealed partial class StasisBedComponent : Component { /// From 1104f5d06610028d3bfe4a513d69917ebc9ee51d Mon Sep 17 00:00:00 2001 From: SlamBamActionman <83650252+SlamBamActionman@users.noreply.github.com> Date: Wed, 3 Dec 2025 22:55:04 +0100 Subject: [PATCH 017/360] Change stamina slowdown to use a percentage-based threshold (#41691) Change stamina to use a percentage based slowdown --- Content.Shared/Damage/Components/StaminaComponent.cs | 4 ++-- Content.Shared/Damage/Systems/SharedStaminaSystem.cs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Content.Shared/Damage/Components/StaminaComponent.cs b/Content.Shared/Damage/Components/StaminaComponent.cs index b343b24403..9875d31349 100644 --- a/Content.Shared/Damage/Components/StaminaComponent.cs +++ b/Content.Shared/Damage/Components/StaminaComponent.cs @@ -85,10 +85,10 @@ public sealed partial class StaminaComponent : Component public SoundSpecifier ForceStandSuccessSound = new SoundPathSpecifier("/Audio/Effects/thudswoosh.ogg"); /// - /// Thresholds that determine an entity's slowdown as a function of stamina damage. + /// Thresholds that determine an entity's slowdown as a function of stamina damage, in percentages. /// [DataField] - public Dictionary StunModifierThresholds = new() { {0, 1f }, { 60, 0.7f }, { 80, 0.5f } }; + public Dictionary StunModifierThresholds = new() { {0, 1f }, { 0.6, 0.7f }, { 0.8, 0.5f } }; #region Animation Data diff --git a/Content.Shared/Damage/Systems/SharedStaminaSystem.cs b/Content.Shared/Damage/Systems/SharedStaminaSystem.cs index be89c12470..79028962ed 100644 --- a/Content.Shared/Damage/Systems/SharedStaminaSystem.cs +++ b/Content.Shared/Damage/Systems/SharedStaminaSystem.cs @@ -465,7 +465,7 @@ public abstract partial class SharedStaminaSystem : EntitySystem { var key = thres.Key.Float(); - if (ent.Comp.StaminaDamage >= key && key > closest && closest < ent.Comp.CritThreshold) + if ((ent.Comp.StaminaDamage / ent.Comp.CritThreshold) >= key && key > closest && closest < 1f) closest = thres.Key; } From 0150cb5ed1faf8574fb4a24793377ff7e06a9f2c Mon Sep 17 00:00:00 2001 From: JackspajfMain <105893899+JackspajfMain@users.noreply.github.com> Date: Wed, 3 Dec 2025 20:06:54 -0500 Subject: [PATCH 018/360] Change to fix wording of Pun Pun's jacket (#41695) Slightly fixes wording on Pun Pun's jacket --- Resources/Prototypes/Entities/Clothing/Uniforms/jumpsuits.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Resources/Prototypes/Entities/Clothing/Uniforms/jumpsuits.yml b/Resources/Prototypes/Entities/Clothing/Uniforms/jumpsuits.yml index 2cab388fc5..4cef2dbec5 100644 --- a/Resources/Prototypes/Entities/Clothing/Uniforms/jumpsuits.yml +++ b/Resources/Prototypes/Entities/Clothing/Uniforms/jumpsuits.yml @@ -34,7 +34,7 @@ - type: entity parent: ClothingUniformBase id: ClothingUniformJumpsuitJacketMonkey - name: bartender's jacket monkey + name: bartender's monkey jacket description: A decent jacket, for a decent monkey. components: - type: Sprite From a4c5cff209652790fb7d54101db2ad4a32946494 Mon Sep 17 00:00:00 2001 From: Hitlinemoss <209321380+Hitlinemoss@users.noreply.github.com> Date: Tue, 3 Jun 2025 12:01:07 -0400 Subject: [PATCH 019/360] Cargo food crate adjustments (#38006) * Adjusted cargo food prices; removed large pizza/softdrinks crates * Adjusted salvage_rewards.yml and cargo_gifts.yml around the removal of large pizza/soda crates --- Resources/Migrations/migration.yml | 8 ++-- .../Prototypes/Catalog/Cargo/cargo_food.yml | 32 +++------------ .../Prototypes/Catalog/Fills/Crates/food.yml | 39 ------------------- .../Prototypes/GameRules/cargo_gifts.yml | 4 +- .../Prototypes/Procedural/salvage_rewards.yml | 2 +- 5 files changed, 13 insertions(+), 72 deletions(-) diff --git a/Resources/Migrations/migration.yml b/Resources/Migrations/migration.yml index 9cdbac19ca..a7804f0be7 100644 --- a/Resources/Migrations/migration.yml +++ b/Resources/Migrations/migration.yml @@ -618,9 +618,9 @@ WeaponEnergyTurretStationMachineCircuitboard: WeaponEnergyTurretSecurityMachineC # 2025-05-30 SpawnHonkBot: SpawnMobHonkBot -# 2025-06-01 - DeltaV: https://github.com/space-wizards/space-station-14/pull/38006 was never merged -#CrateFoodPizzaLarge: CrateFoodPizza -#CrateFoodSoftdrinksLarge: CrateFoodSoftdrinks +# 2025-06-01 +CrateFoodPizzaLarge: CrateFoodPizza +CrateFoodSoftdrinksLarge: CrateFoodSoftdrinks # 2025-06-03 FloorTileItemGCircuit4: FloorTileItemGCircuit @@ -691,4 +691,4 @@ ToyOwlman: ToyFigurineOwlman ToySkeleton: ToyFigurineSkeleton # 2025-10-28 -DrinkKiraSpecial: DrinkOrangeLimeSodaGlass \ No newline at end of file +DrinkKiraSpecial: DrinkOrangeLimeSodaGlass diff --git a/Resources/Prototypes/Catalog/Cargo/cargo_food.yml b/Resources/Prototypes/Catalog/Cargo/cargo_food.yml index e5847179c9..eec2516a8e 100644 --- a/Resources/Prototypes/Catalog/Cargo/cargo_food.yml +++ b/Resources/Prototypes/Catalog/Cargo/cargo_food.yml @@ -4,27 +4,17 @@ sprite: Objects/Consumable/Food/Baked/pizza.rsi state: margherita-slice product: CrateFoodPizza - cost: 1000 # DeltaV - raised from 450 + cost: 1000 # DeltaV - Lowered from 1600 category: cargoproduct-category-name-food group: market -#- type: cargoProduct # DeltaV - Removed to not invalidate chef -# id: FoodPizzaLarge -# icon: -# sprite: Objects/Consumable/Food/Baked/pizza.rsi -# state: margherita -# product: CrateFoodPizzaLarge -# cost: 1800 -# category: cargoproduct-category-name-food -# group: market - - type: cargoProduct id: FoodMRE icon: sprite: Objects/Consumable/Food/snacks.rsi state: nutribrick product: CrateFoodMRE - cost: 1000 + cost: 1400 category: cargoproduct-category-name-food group: market @@ -64,17 +54,7 @@ sprite: Objects/Consumable/Drinks/cola.rsi state: icon product: CrateFoodSoftdrinks - cost: 1200 - category: cargoproduct-category-name-food - group: market - -- type: cargoProduct - id: FoodSoftdrinksLarge - icon: - sprite: Objects/Consumable/Drinks/colabottle.rsi - state: icon - product: CrateFoodSoftdrinksLarge - cost: 2400 + cost: 1500 category: cargoproduct-category-name-food group: market @@ -94,7 +74,7 @@ sprite: Objects/Consumable/Food/burger.rsi state: bigbite product: CrateFoodHappyHonkBigBite - cost: 1500 + cost: 2800 category: cargoproduct-category-name-food group: market @@ -104,7 +84,7 @@ sprite: Objects/Consumable/Food/frozen.rsi state: sandwich product: CrateFoodIceCream - cost: 1200 + cost: 2000 category: cargoproduct-category-name-food group: market @@ -114,6 +94,6 @@ sprite: Objects/Consumable/Food/frozen.rsi state: cone product: CrateFoodSnowcone - cost: 1100 + cost: 2000 category: cargoproduct-category-name-food group: market diff --git a/Resources/Prototypes/Catalog/Fills/Crates/food.yml b/Resources/Prototypes/Catalog/Fills/Crates/food.yml index 150d70e508..cb263ee735 100644 --- a/Resources/Prototypes/Catalog/Fills/Crates/food.yml +++ b/Resources/Prototypes/Catalog/Fills/Crates/food.yml @@ -14,20 +14,6 @@ - id: LidSalami prob: 0.01 -- type: entity - id: CrateFoodPizzaLarge - parent: CratePlastic - name: disaster pizza delivery - description: In the ultimate event that all else has failed, Find comfort in that more pizza solves everything. Includes 16 pizzas. - components: - - type: StorageFill - contents: - - id: FoodBoxPizzaFilled - amount: 15 - - id: FoodBoxPizzaCotton - - id: LidSalami - prob: 0.04 - - type: entity id: CrateFoodMRE parent: CratePlastic @@ -155,31 +141,6 @@ - id: DrinkFourteenLokoCan amount: 2 -- type: entity - id: CrateFoodSoftdrinksLarge - parent: CrateFreezer - name: softdrinks bulk crate - description: Lots of sodas taken straight out of Centcomm's own vending machines, because you just can't leave your department. Includes 32 sodas. - components: - - type: EntityStorage - capacity: 32 # Slightly over-sized CrateFreezer to accomodate over 30 drink cans at once. - - type: StorageFill - contents: - - id: DrinkColaCan - amount: 8 - - id: DrinkGrapeCan - amount: 4 - - id: DrinkRootBeerCan - amount: 4 - - id: DrinkIcedTeaCan - amount: 4 - - id: DrinkLemonLimeCan - amount: 4 - - id: DrinkLemonLimeCranberryCan - amount: 4 - - id: DrinkFourteenLokoCan - amount: 4 - - type: entity id: CrateFoodGetMore parent: CrateFreezer diff --git a/Resources/Prototypes/GameRules/cargo_gifts.yml b/Resources/Prototypes/GameRules/cargo_gifts.yml index 486280a1af..a881bc29b6 100644 --- a/Resources/Prototypes/GameRules/cargo_gifts.yml +++ b/Resources/Prototypes/GameRules/cargo_gifts.yml @@ -65,9 +65,9 @@ description: cargo-gift-pizza-large dest: cargo-gift-dest-bar gifts: - FoodPizza: 2 # DeltaV - Changed to 2 small pizza crates, 8 pizzas total + FoodPizza: 2 # DeltaV - Changed to 2 small pizza crates, 8 pizzas total (Was 16) FoodBarSupply: 1 - FoodSoftdrinksLarge: 1 + FoodSoftdrinks: 2 # 32 sodas - type: entity id: GiftsEngineering diff --git a/Resources/Prototypes/Procedural/salvage_rewards.yml b/Resources/Prototypes/Procedural/salvage_rewards.yml index 2f24a32d1d..a54ac8fbb0 100644 --- a/Resources/Prototypes/Procedural/salvage_rewards.yml +++ b/Resources/Prototypes/Procedural/salvage_rewards.yml @@ -8,7 +8,7 @@ CrateMaterialSteel: 1.0 # things the station might want CrateEngineeringAMEJar: 0.25 - CrateFoodPizzaLarge: 0.25 + CrateFoodPizza: 0.25 CrateFoodSoftdrinks: 0.25 CrateFunInstrumentsVariety: 0.25 CrateSalvageEquipment: 0.25 From 514d6b5b395087eff9b3bd1da408ddc1e656f394 Mon Sep 17 00:00:00 2001 From: Hitlinemoss <209321380+Hitlinemoss@users.noreply.github.com> Date: Thu, 4 Dec 2025 02:55:35 -0500 Subject: [PATCH 020/360] Cleanup of prototypes in Resources/Prototypes/Catalog/Fills/Crates/ + fixed light crate descriptions (#41697) * Fix prototype string order * Fix replacement lights crate description * Clearer light descriptions in general * Suffix fix * Updated internals crate descriptions --- .../Prototypes/Catalog/Fills/Crates/antag.yml | 4 +- .../Catalog/Fills/Crates/armory.yml | 14 ++-- .../Catalog/Fills/Crates/botany.yml | 10 +-- .../Prototypes/Catalog/Fills/Crates/cargo.yml | 6 +- .../Catalog/Fills/Crates/chemistry.yml | 8 +-- .../Catalog/Fills/Crates/emergency.yml | 22 +++--- .../Catalog/Fills/Crates/engineering.yml | 40 +++++------ .../Catalog/Fills/Crates/engines.yml | 30 ++++---- .../Prototypes/Catalog/Fills/Crates/food.yml | 20 +++--- .../Prototypes/Catalog/Fills/Crates/fun.yml | 55 ++++++++------- .../Catalog/Fills/Crates/materials.yml | 34 +++++----- .../Catalog/Fills/Crates/medical.yml | 28 ++++---- .../Prototypes/Catalog/Fills/Crates/npc.yml | 48 ++++++------- .../Catalog/Fills/Crates/permaescape.yml | 56 +++++++-------- .../Catalog/Fills/Crates/salvage.yml | 10 +-- .../Catalog/Fills/Crates/science.yml | 6 +- .../Catalog/Fills/Crates/security.yml | 14 ++-- .../Catalog/Fills/Crates/service.yml | 68 +++++++++---------- .../Catalog/Fills/Crates/syndicate.yml | 8 +-- .../Catalog/Fills/Crates/vending.yml | 53 +++++++-------- 20 files changed, 266 insertions(+), 268 deletions(-) diff --git a/Resources/Prototypes/Catalog/Fills/Crates/antag.yml b/Resources/Prototypes/Catalog/Fills/Crates/antag.yml index 352b33a3d0..8b397bd31c 100644 --- a/Resources/Prototypes/Catalog/Fills/Crates/antag.yml +++ b/Resources/Prototypes/Catalog/Fills/Crates/antag.yml @@ -1,8 +1,8 @@ - type: entity + parent: CratePirate id: CratePirateChestCaptain name: captains pirate chest suffix: Filled - parent: CratePirate components: - type: EntityTableContainerFill containers: @@ -13,10 +13,10 @@ - id: MicroBombImplanter - type: entity + parent: CratePirate id: CratePirateChest name: crews pirate chest suffix: Filled - parent: CratePirate components: - type: EntityTableContainerFill containers: diff --git a/Resources/Prototypes/Catalog/Fills/Crates/armory.yml b/Resources/Prototypes/Catalog/Fills/Crates/armory.yml index 6a172a8a6f..9e01feb50e 100644 --- a/Resources/Prototypes/Catalog/Fills/Crates/armory.yml +++ b/Resources/Prototypes/Catalog/Fills/Crates/armory.yml @@ -1,6 +1,6 @@ - type: entity - id: CrateArmorySMG parent: [ CrateWeaponSecure, BaseSecurityContraband ] + id: CrateArmorySMG name: SMG crate description: Contains two SMGs with four mags. Requires Armory access to open. components: @@ -14,8 +14,8 @@ amount: 4 - type: entity - id: CrateArmoryShotgun parent: [ CrateWeaponSecure, BaseSecurityContraband ] + id: CrateArmoryShotgun name: shotgun crate description: For when the enemy absolutely needs to be replaced with lead. Contains two Enforcer Combat Shotguns, and some standard shotgun shells. Requires Armory access to open. components: @@ -29,8 +29,8 @@ amount: 4 - type: entity - id: CrateTrackingImplants parent: [ CrateWeaponSecure, BaseSecurityContraband ] + id: CrateTrackingImplants name: tracking implants description: Contains a handful of tracking implanters. Good for prisoners you'd like to release but still keep track of. components: @@ -53,8 +53,8 @@ amount: 3 - type: entity - id: CrateArmoryLaser parent: [ CrateWeaponSecure, BaseSecurityContraband ] + id: CrateArmoryLaser name: lasers crate description: Contains three standard-issue laser rifles. Requires Armory access to open. components: @@ -65,8 +65,8 @@ amount: 3 - type: entity - id: CrateArmoryPistols parent: [ CrateWeaponSecure, BaseSecurityContraband ] + id: CrateArmoryPistols name: pistols crate description: Contains two standard NT pistols with four mags. Requires Armory access to open. components: @@ -80,8 +80,8 @@ amount: 4 - type: entity - id: CrateSecurityRiot parent: [ CrateWeaponSecure, BaseSecurityContraband ] + id: CrateSecurityRiot name: swat crate description: Contains two sets of riot armor, helmets, shields, and enforcers loaded with beanbags. Extra ammo is included. Requires Armory access to open. components: @@ -101,8 +101,8 @@ amount: 2 - type: entity - id: CrateArmoryRifle parent: [ CrateWeaponSecure, BaseSecurityContraband ] + id: CrateArmoryRifle name: rifle crate description: Contains two high-powered assault rifles with four mags. Requires Armory access to open. components: diff --git a/Resources/Prototypes/Catalog/Fills/Crates/botany.yml b/Resources/Prototypes/Catalog/Fills/Crates/botany.yml index 7f95f57d73..99702bc018 100644 --- a/Resources/Prototypes/Catalog/Fills/Crates/botany.yml +++ b/Resources/Prototypes/Catalog/Fills/Crates/botany.yml @@ -1,6 +1,6 @@ - type: entity - id: CrateHydroponicsSeedsExotic parent: CrateHydroSecure + id: CrateHydroponicsSeedsExotic name: exotic seeds crate description: Any entrepreneuring botanist's dream. Contains many different exotic seeds. Requires Hydroponics access to open. components: @@ -24,8 +24,8 @@ amount: 2 - type: entity - id: CrateHydroponicsSeedsMedicinal parent: CrateHydroSecure + id: CrateHydroponicsSeedsMedicinal name: medicinal seeds crate description: The wannabe chemist's dream. The power of medicine is at your fingertips! Requires Hydroponics access to open. components: @@ -45,8 +45,8 @@ amount: 3 - type: entity - id: CrateHydroponicsTools parent: CrateHydroponics + id: CrateHydroponicsTools name: hydroponics equipment crate description: Supplies for growing a great garden! Contains some spray bottles of plant chemicals, a hatchet, a mini-hoe, scythe, as well as a pair of leather gloves and a botanist's apron. components: @@ -68,8 +68,8 @@ amount: 2 - type: entity - id: CrateHydroponicsSeeds parent: CrateHydroponics + id: CrateHydroponicsSeeds name: seeds crate description: Big things have small beginnings. Contains twenty-four different seeds. components: @@ -103,8 +103,8 @@ - id: CottonSeeds - type: entity - id: CrateHydroponicsTray parent: CrateHydroponics + id: CrateHydroponicsTray name: hydroponics tray crate description: Contains a hydroponics tray flatpack. components: diff --git a/Resources/Prototypes/Catalog/Fills/Crates/cargo.yml b/Resources/Prototypes/Catalog/Fills/Crates/cargo.yml index 6cc4b70b7a..35e1c426c8 100644 --- a/Resources/Prototypes/Catalog/Fills/Crates/cargo.yml +++ b/Resources/Prototypes/Catalog/Fills/Crates/cargo.yml @@ -1,6 +1,6 @@ - type: entity - id: CrateCargoLuxuryHardsuit parent: CratePirate + id: CrateCargoLuxuryHardsuit name: luxury mining hardsuit crate # DeltaV - Logistics Department - Replace Quartermaster with Logistics Officer description: Finally, a hardsuit the Logistics Officer could call their own. Centcomm has heard you, now stop asking. @@ -12,8 +12,8 @@ id: ClothingOuterHardsuitLuxury - type: entity - id: CrateCargoParcelWrap parent: CrateGenericSteel + id: CrateCargoParcelWrap name: parcel wrap crate description: All your parcel wrapping needs in one crate, containing three rolls of parcel wrap. components: @@ -24,10 +24,10 @@ amount: 3 - type: entity + parent: CratePrivateSecure id: CrateCargoGambling name: the grand lottery $$$ description: A box containing treasure beyond your greatest imaginations! - parent: CratePrivateSecure components: - type: EntityTableContainerFill containers: diff --git a/Resources/Prototypes/Catalog/Fills/Crates/chemistry.yml b/Resources/Prototypes/Catalog/Fills/Crates/chemistry.yml index 45fb81f1b5..01d05cd359 100644 --- a/Resources/Prototypes/Catalog/Fills/Crates/chemistry.yml +++ b/Resources/Prototypes/Catalog/Fills/Crates/chemistry.yml @@ -1,6 +1,6 @@ - type: entity - id: CrateChemistryP parent: CrateChemistrySecure + id: CrateChemistryP name: chemicals crate (P) description: Contains chemicals from the P-Block of elements. Requires Chemistry access to open. components: @@ -20,8 +20,8 @@ - id: JugNitrogen - type: entity - id: CrateChemistryS parent: CrateChemistrySecure + id: CrateChemistryS name: chemicals crate (S) description: Contains chemicals from the S-Block of elements. Requires Chemistry access to open. components: @@ -36,8 +36,8 @@ - id: JugRadium - type: entity - id: CrateChemistryD parent: CrateChemistrySecure + id: CrateChemistryD name: chemicals crate (D) description: Contains chemicals from the D-Block of elements. Requires Chemistry access to open. components: @@ -52,8 +52,8 @@ - id: JugSilver - type: entity - id: CratePlantBGone parent: CrateGenericSteel + id: CratePlantBGone name: bulk Plant-B-Gone crate description: From Monstano. "Unwanted Weeds, Meet Your Celestial Roundup!" components: diff --git a/Resources/Prototypes/Catalog/Fills/Crates/emergency.yml b/Resources/Prototypes/Catalog/Fills/Crates/emergency.yml index bf47d3f271..dd82c2208f 100644 --- a/Resources/Prototypes/Catalog/Fills/Crates/emergency.yml +++ b/Resources/Prototypes/Catalog/Fills/Crates/emergency.yml @@ -1,6 +1,6 @@ - type: entity - id: CrateEmergencyExplosive parent: CrateSecgear + id: CrateEmergencyExplosive name: bomb suit crate description: Science gone bonkers? Beeping behind the airlock? Buy now and be the hero the station des... I mean needs! (time not included) components: @@ -16,8 +16,8 @@ - id: ClothingOuterSuitBomb - type: entity - id: CrateEmergencyFire parent: CrateGenericSteel + id: CrateEmergencyFire name: firefighting crate description: Only you can prevent station fires. Partner up with two firefighter suits, gas masks, flashlights, large oxygen tanks, extinguishers, and hardhats! components: @@ -39,10 +39,10 @@ amount: 2 - type: entity + parent: CrateInternals id: CrateEmergencyInternals - parent: CrateInternals name: internals crate - description: Master your life energy and control your breathing with 3 breath masks, emergency suits and large air tanks. + description: Master your life energy and control your breathing with three breath masks, three gas masks, three emergency EVA suits, three oxygen tanks, and three nitrogen tanks. components: - type: EntityTableContainerFill containers: @@ -60,10 +60,10 @@ amount: 3 - type: entity + parent: CrateInternals id: CrateEmergencyInternalsLarge - parent: CrateInternals name: internals crate (large) - description: Master your life energy and control your breathing with 6 breath masks, emergency suits and large air tanks. + description: Master your life energy and control your breathing with six breath masks, six gas masks, six emergency EVA suits, six oxygen tanks, and six nitrogen tanks. components: - type: EntityTableContainerFill containers: @@ -81,10 +81,10 @@ amount: 6 - type: entity - id: CrateNitrogenInternals parent: CrateInternals + id: CrateNitrogenInternals name: internals crate (nitrogen) - description: Contains four breath masks and four large nitrogen tanks. Intended for Slimepeople and Vox. + description: Contains two breath masks, two gas masks, and four nitrogen tanks. Intended for nitrogen-breathing species. components: - type: EntityTableContainerFill containers: @@ -98,8 +98,8 @@ amount: 4 - type: entity - id: CrateEmergencyRadiation parent: CrateRadiation + id: CrateEmergencyRadiation name: radiation protection crate description: Survive the Nuclear Apocalypse and Supermatter Engine alike with two sets of Radiation suits. Each set contains a helmet, suit, and Geiger counter. We'll even throw in a bottle of vodka and some glasses too, considering the life-expectancy of people who order this. components: @@ -116,8 +116,8 @@ amount: 2 - type: entity - id: CrateEmergencyInflatablewall parent: CratePlastic + id: CrateEmergencyInflatablewall name: inflatable wall crate description: Three stacks of inflatable walls for when the stations metal walls don't want to hold atmosphere anymore. components: @@ -127,8 +127,8 @@ id: BoxInflatable - type: entity - id: CrateGenericBiosuit parent: CratePlastic + id: CrateGenericBiosuit name: emergency bio suit crate description: Contains 2 biohazard suits to ensure that no disease will distract you from what you're doing there. components: diff --git a/Resources/Prototypes/Catalog/Fills/Crates/engineering.yml b/Resources/Prototypes/Catalog/Fills/Crates/engineering.yml index bcf73a2c4d..27ade67868 100644 --- a/Resources/Prototypes/Catalog/Fills/Crates/engineering.yml +++ b/Resources/Prototypes/Catalog/Fills/Crates/engineering.yml @@ -1,6 +1,6 @@ - type: entity - id: CrateEngineeringGear parent: CrateEngineering + id: CrateEngineeringGear name: engineering gear crate description: Various engineering gear parts. components: @@ -22,8 +22,8 @@ amount: 2 - type: entity - id: CrateEngineeringToolbox parent: CrateEngineering + id: CrateEngineeringToolbox name: toolbox crate description: Two mechanical and two electrical toolboxes. components: @@ -37,8 +37,8 @@ amount: 2 #- type: entity -# id: CrateEngineeringPowercell # parent: CrateElectrical +# id: CrateEngineeringPowercell # name: AME crate # description: Three microcreactor powercells. # components: @@ -49,8 +49,8 @@ # amount: 3 - type: entity - id: CrateEngineeringCableLV parent: CrateElectrical + id: CrateEngineeringCableLV name: LV cable crate description: 3 coils of LV cables. components: @@ -61,8 +61,8 @@ amount: 3 - type: entity - id: CrateEngineeringCableMV parent: CrateElectrical + id: CrateEngineeringCableMV name: MV cable crate description: 3 coils of MV cables. components: @@ -73,8 +73,8 @@ amount: 3 - type: entity - id: CrateEngineeringCableHV parent: CrateElectrical + id: CrateEngineeringCableHV name: HV cable crate description: 3 coils of HV cables. components: @@ -85,8 +85,8 @@ amount: 3 - type: entity - id: CrateEngineeringFoamGrenade parent: CrateEngineeringSecure + id: CrateEngineeringFoamGrenade name: sealant grenade crate description: 5 metal foam sealant grenades. components: @@ -97,8 +97,8 @@ amount: 5 - type: entity - id: CrateEngineeringCableBulk parent: CrateElectrical + id: CrateEngineeringCableBulk name: bulk cable crate description: 2 coils each for every cable type. components: @@ -114,8 +114,8 @@ amount: 2 - type: entity - id: CrateEngineeringElectricalSupplies parent: CrateElectrical + id: CrateEngineeringElectricalSupplies name: electrical supplies crate description: NT is not responsible for any workplace infighting relating to the insulated gloves included within these crates. components: @@ -129,8 +129,8 @@ amount: 2 - type: entity - id: CrateEngineeringStationBeaconBundle parent: CratePlastic + id: CrateEngineeringStationBeaconBundle name: station beacon bundle description: A crate containing 5 station beacon assemblies for modifying the station map. components: @@ -141,8 +141,8 @@ amount: 5 - type: entity - id: CrateEngineeringJetpack parent: CrateGenericSteel + id: CrateEngineeringJetpack name: jetpack crate description: Two jetpacks for those who don't know how to use fire extinguishers. components: @@ -153,8 +153,8 @@ amount: 2 - type: entity - id: CrateEngineeringMiniJetpack parent: CrateGenericSteel + id: CrateEngineeringMiniJetpack name: mini jetpack crate description: Two mini jetpacks for those who want an extra challenge. components: @@ -165,8 +165,8 @@ amount: 2 - type: entity - id: CrateAirlockKit parent: CrateEngineering + id: CrateAirlockKit name: airlock kit description: A kit for building 6 airlocks, doesn't include tools. components: @@ -180,8 +180,8 @@ amount: 6 - type: entity - id: CrateEvaKit parent: CrateCommandSecure + id: CrateEvaKit name: EVA kit description: A set consisting of two prestigious EVA suits and helmets. components: @@ -195,8 +195,8 @@ amount: 2 - type: entity - id: CrateRCDAmmo parent: CrateEngineering + id: CrateRCDAmmo name: compressed matter crate description: Contains three compressed matter cartridges. components: @@ -207,8 +207,8 @@ amount: 3 - type: entity - id: CrateRCD parent: CrateEngineeringSecure + id: CrateRCD name: RCD crate description: A crate containing a single rapid construction device. components: @@ -218,8 +218,8 @@ id: RCD - type: entity - id: CrateParticleDecelerators parent: CrateEngineeringSecure + id: CrateParticleDecelerators name: particle decelerators crate description: A crate containing 3 Particle Decelerators. components: @@ -230,8 +230,8 @@ amount: 3 - type: entity - id: CrateEngineeringSpaceHeater parent: CrateEngineering + id: CrateEngineeringSpaceHeater name: space heater crate description: Contains a space heater for climate control. components: @@ -258,8 +258,8 @@ - id: BlockGameArcadeComputerCircuitboard - type: entity - id: CrateTechBoardRandom parent: ToteBase + id: CrateTechBoardRandom name: surplus boards description: Surplus boards from somewhere. components: @@ -271,8 +271,8 @@ range: 6, 8 - type: entity - id: CrateAirGrenade parent: CrateEngineering + id: CrateAirGrenade name: air grenade crate description: A crate containing 3 air grenades. components: diff --git a/Resources/Prototypes/Catalog/Fills/Crates/engines.yml b/Resources/Prototypes/Catalog/Fills/Crates/engines.yml index e81b6135ec..92a3eabe08 100644 --- a/Resources/Prototypes/Catalog/Fills/Crates/engines.yml +++ b/Resources/Prototypes/Catalog/Fills/Crates/engines.yml @@ -1,8 +1,8 @@ # AME - type: entity - id: CrateEngineeringAMEShielding parent: CrateEngineeringSecure + id: CrateEngineeringAMEShielding name: packaged antimatter reactor crate description: 9 parts for the main body of an antimatter reactor, or for expanding an existing one. components: @@ -13,8 +13,8 @@ amount: 9 - type: entity - id: CrateEngineeringAMEJar parent: CrateEngineeringSecure + id: CrateEngineeringAMEJar name: antimatter containment jar crate description: 3 antimatter jars, for fuelling an antimatter reactor. components: @@ -25,8 +25,8 @@ amount: 3 - type: entity - id: CrateEngineeringAMEControl parent: CrateEngineeringSecure + id: CrateEngineeringAMEControl name: antimatter control unit crate description: The control unit of an antimatter reactor. components: @@ -38,8 +38,8 @@ # Singularity - type: entity - id: CrateEngineeringSingularityEmitter parent: CrateEngineeringSecure + id: CrateEngineeringSingularityEmitter name: emitter crate description: An emitter, best used for singularity engines. components: @@ -49,8 +49,8 @@ id: EmitterFlatpack - type: entity - id: CrateEngineeringSingularityCollector parent: CrateEngineeringSecure + id: CrateEngineeringSingularityCollector name: radiation collector crate description: A radiation collector, best used for singularity engines. Plasma is included. components: @@ -62,8 +62,8 @@ - id: PlasmaTankFilled - type: entity - id: CrateEngineeringSingularityContainment parent: CrateEngineeringSecure + id: CrateEngineeringSingularityContainment name: containment field generator crate description: A containment field generator, keeps the singulo in submission. components: @@ -73,8 +73,8 @@ id: ContainmentFieldGeneratorFlatpack - type: entity - id: CrateEngineeringSingularityGenerator parent: CrateEngineeringSecure + id: CrateEngineeringSingularityGenerator name: singularity generator crate description: A singularity generator, the mother of the beast. components: @@ -86,8 +86,8 @@ # Particle Accelerator - type: entity - id: CrateEngineeringParticleAccelerator parent: CrateEngineeringSecure + id: CrateEngineeringParticleAccelerator name: PA board crate description: Complex to setup, but rewarding as fuck. Contains boards for all particle accelerator components. components: @@ -106,10 +106,10 @@ # Non-functional for some reason #- type: entity +# parent: CrateEngineeringSecure # id: CrateEngineeringSingularity # name: singularity crate # description: "Prank the station!" -# parent: CrateEngineeringSecure # components: # - type: EntityTableContainerFill # containers: @@ -117,8 +117,8 @@ # id: Singularity - type: entity - id: CrateEngineeringGenerator parent: CrateEngineering + id: CrateEngineeringGenerator name: generator crate suffix: DEBUG components: @@ -128,8 +128,8 @@ id: DebugGenerator # TODO change to flatpack - type: entity - id: CrateEngineeringSolar parent: CrateEngineering + id: CrateEngineeringSolar name: solar assembly crate description: A kit with solar flatpacks and glass to construct ten solar panels. components: @@ -143,8 +143,8 @@ amount: 2 - type: entity - id: CrateEngineeringShuttle parent: CrateEngineeringSecure + id: CrateEngineeringShuttle name: shuttle powering crate description: A crate containing all needs for shuttle powering. components: @@ -158,8 +158,8 @@ - id: InflatableDoorStack1 - type: entity - id: CrateEngineeringTeslaGenerator parent: CrateEngineeringSecure + id: CrateEngineeringTeslaGenerator name: tesla generator crate description: A tesla generator. God save you. components: @@ -169,8 +169,8 @@ id: TeslaGeneratorFlatpack - type: entity - id: CrateEngineeringTeslaCoil parent: CrateEngineeringSecure + id: CrateEngineeringTeslaCoil name: tesla coil crate description: Tesla coil. Attracts lightning and generates energy from it. components: @@ -180,8 +180,8 @@ id: TeslaCoilFlatpack - type: entity - id: CrateEngineeringTeslaGroundingRod parent: CrateEngineeringSecure + id: CrateEngineeringTeslaGroundingRod name: tesla grounding rod crate description: Grounding rod, best for lightning protection. components: diff --git a/Resources/Prototypes/Catalog/Fills/Crates/food.yml b/Resources/Prototypes/Catalog/Fills/Crates/food.yml index cb263ee735..29203f32d0 100644 --- a/Resources/Prototypes/Catalog/Fills/Crates/food.yml +++ b/Resources/Prototypes/Catalog/Fills/Crates/food.yml @@ -1,6 +1,6 @@ - type: entity - id: CrateFoodPizza parent: CratePlastic + id: CrateFoodPizza name: emergency pizza delivery description: Help do your part to end station hunger by distributing pizza to underfunded departments! Includes 4 pizzas. components: @@ -15,8 +15,8 @@ prob: 0.01 - type: entity - id: CrateFoodMRE parent: CratePlastic + id: CrateFoodMRE name: MRE crate description: A military style meal fit to feed a whole department. components: @@ -27,8 +27,8 @@ amount: 6 - type: entity - id: CrateFoodCooking parent: CrateFreezer + id: CrateFoodCooking name: kitchen supplies crate description: Extra kitchen supplies, in case the botanists are absent. components: @@ -61,8 +61,8 @@ amount: 2 - type: entity - id: CrateFoodDinnerware parent: CratePlastic + id: CrateFoodDinnerware name: kitchen dinnerware crate description: Extra kitchen supplies, in case the clown was allowed in the cafeteria unsupervised. components: @@ -88,8 +88,8 @@ - id: BoxUtensil - type: entity - id: CrateFoodBarSupply parent: CrateFreezer + id: CrateFoodBarSupply name: bartending supplies crate description: Extra Bar supplies, in case the clown was allowed in the bar unsupervised. components: @@ -117,8 +117,8 @@ amount: 2 - type: entity - id: CrateFoodSoftdrinks parent: CrateFreezer + id: CrateFoodSoftdrinks name: softdrinks crate description: A variety of sodas to complement a small party, without having to empty the soda machines. Includes 14 sodas. components: @@ -142,8 +142,8 @@ amount: 2 - type: entity - id: CrateFoodGetMore parent: CrateFreezer + id: CrateFoodGetMore name: Getmore Bakemore crate description: Getmore branded snacks and baking supplies for the creative chef, all without the need of emptying your station's Getmore machines! components: @@ -170,8 +170,8 @@ - id: FoodBoxCloth - type: entity - id: CrateFoodIceCream parent: CrateFreezer + id: CrateFoodIceCream name: ice cream delivery description: An assortment of ice cream delights for any occasion! Includes 16 frozen treats. components: @@ -195,8 +195,8 @@ amount: 2 - type: entity - id: CrateFoodSnowcone parent: CrateFreezer + id: CrateFoodSnowcone name: snowcone delivery description: A freezer packed with refreshing snowcones for a hard working crew, or even a lazy one! Includes 16 snowcones. components: @@ -218,8 +218,8 @@ amount: 2 - type: entity - id: CrateFoodHappyHonkBigBite parent: CratePlastic + id: CrateFoodHappyHonkBigBite name: Happy Honk meal delivery description: Two fully loaded Happy Honk Big Bite burger meals, complete with cheesy fries, a bottle of Space Cola, a slice of apple pie and a toy! components: diff --git a/Resources/Prototypes/Catalog/Fills/Crates/fun.yml b/Resources/Prototypes/Catalog/Fills/Crates/fun.yml index a32fae9fef..cb40b508f7 100644 --- a/Resources/Prototypes/Catalog/Fills/Crates/fun.yml +++ b/Resources/Prototypes/Catalog/Fills/Crates/fun.yml @@ -156,8 +156,8 @@ - id: PottedPlant26 - type: entity - id: CratePlants parent: CrateGenericSteel + id: CratePlants name: plant crate description: A variety pack of potted plants to spruce up your station! components: @@ -169,8 +169,8 @@ value: 5 - type: entity - id: CrateFunPlushie parent: CrateGenericSteel + id: CrateFunPlushie name: plushie crate description: A buncha soft plushies. Throw them around and then wonder how you're gonna explain this purchase to NT. components: @@ -182,8 +182,8 @@ value: 10 - type: entity - id: CrateFunLizardPlushieBulk parent: CrateGenericSteel + id: CrateFunLizardPlushieBulk name: bulk lizard plushie crate description: A buncha soft lizard plushies. Throw them around and then wonder how you're gonna explain this purchase to NT. components: @@ -195,8 +195,8 @@ value: 6 - type: entity - id: CrateFunSharkPlushieBulk parent: CrateGenericSteel + id: CrateFunSharkPlushieBulk name: bulk soft toy shark crate description: A crate filled with a variety of everyone's favorite finned friend. Rawr! components: @@ -215,8 +215,8 @@ value: 2 - type: entity - id: CrateFunInstrumentsVariety parent: CrateGenericSteel + id: CrateFunInstrumentsVariety name: variety instrument collection description: Get your sad station movin' and groovin' with this catch-all variety pack! Contains seven different instruments. components: @@ -233,8 +233,8 @@ - id: GlockenspielInstrument - type: entity - id: CrateFunInstrumentsBrass parent: CrateGenericSteel + id: CrateFunInstrumentsBrass name: brass instrument ensemble crate description: Bring some jazz to the station with the brass ensemble. Contains a variety of brass instruments for the whole station to play. components: @@ -252,8 +252,8 @@ - id: TubaInstrument - type: entity - id: CrateFunInstrumentsString parent: CrateGenericSteel + id: CrateFunInstrumentsString name: string instrument ensemble crate description: Pluck or pick, slap or shred! Play a smooth melody or melt peoples' faces with this package of stringed instruments. components: @@ -272,8 +272,8 @@ - id: HarpInstrument - type: entity - id: CrateFunInstrumentsWoodwind parent: CrateGenericSteel + id: CrateFunInstrumentsWoodwind name: woodwind instrument ensemble crate description: If atmos is good at their job, use air to play music with these woodwind instruments! Real wood not guaranteed with every item. components: @@ -294,8 +294,8 @@ - id: PanFluteInstrument - type: entity - id: CrateFunInstrumentsKeyedPercussion parent: CrateGenericSteel + id: CrateFunInstrumentsKeyedPercussion name: keyed/percussion instrument ensemble crate description: Hit some keys with some sticks or your hands, with this Keyed and Percussion instrument ensemble crate. components: @@ -315,8 +315,8 @@ - id: VibraphoneInstrument - type: entity - id: CrateFunInstrumentsSpecial parent: CrateGenericSteel + id: CrateFunInstrumentsSpecial name: special instrument collector's crate description: Create some noise with this special collection of arguably-instruments! Centcomm is not responsible for any trauma caused by the contents. components: @@ -336,8 +336,8 @@ - id: ReverseCymbalsInstrument - type: entity - id: CrateFunInstrumentsRandom parent: CrateGenericSteel + id: CrateFunInstrumentsRandom name: random instrument collection description: A box containing several randomly curated instruments, hand picked by Centcomm's top musicians! components: @@ -360,8 +360,8 @@ rolls: 2 - type: entity - id: CrateFunArtSupplies parent: CrateGenericSteel + id: CrateFunArtSupplies name: art supplies description: Make some happy little accidents with lots of crayons! components: @@ -371,8 +371,8 @@ id: CrayonBox - type: entity - id: CrateFunBoardGames parent: CrateGenericSteel + id: CrateFunBoardGames name: board game crate description: Game nights have been proven to either decrease boredom or increase murderous rage depending on the game. components: @@ -395,8 +395,8 @@ amount: 6 - type: entity - id: CrateFunSadTromboneImplants parent: CrateGenericSteel + id: CrateFunSadTromboneImplants name: sad trombone implants description: Death's never been so fun before! Implant these to make dying a bit more happy. components: @@ -407,8 +407,8 @@ amount: 3 - type: entity - id: CrateFunLightImplants parent: CrateGenericSteel + id: CrateFunLightImplants name: light implants description: Light up your skin with these implants! components: @@ -419,8 +419,8 @@ amount: 3 - type: entity - id: CrateFunParty parent: CrateGenericSteel + id: CrateFunParty name: party crate description: An entire party just waiting for you to open it. Includes party favors, party beverages, and even a cake. components: @@ -452,8 +452,8 @@ amount: 2 - type: entity - id: CrateFunWaterGuns parent: CratePlastic + id: CrateFunWaterGuns name: water gun crate description: A summer special with a variety of brightly colored water guns. Water not included. components: @@ -467,8 +467,8 @@ amount: 4 - type: entity - id: CrateFunFoamGuns parent: CratePlastic + id: CrateFunFoamGuns name: Foam Force crate description: Contains four Foam Force rifles, some grenades, and extra ammo. It's [REDACTED] or nothing! components: @@ -484,8 +484,8 @@ amount: 4 - type: entity - id: CrateFunBoxing parent: CrateGenericSteel + id: CrateFunBoxing name: boxing crate description: Want to set up an underground fight club or host a tournament amongst station crew? This crate is for you! components: @@ -503,8 +503,8 @@ amount: 3 - type: entity - id: CrateFunPirate parent: CratePirate + id: CrateFunPirate suffix: Filled components: - type: EntityTableContainerFill @@ -522,8 +522,8 @@ amount: 2 - type: entity - id: CrateFunToyBox parent: CrateToyBox + id: CrateFunToyBox suffix: Filled components: - type: EntityTableContainerFill @@ -551,8 +551,8 @@ - id: RubberChicken - type: entity - id: CrateFunBikeHornImplants parent: CrateGenericSteel + id: CrateFunBikeHornImplants name: bike horn implants description: A thousand honks a day keeps security officers away! components: @@ -563,8 +563,8 @@ amount: 3 - type: entity - id: CrateFunMysteryFigurines parent: CratePlastic + id: CrateFunMysteryFigurines name: mystery figure crate description: A collection of 10 Mystery Figurine boxes. Duplicates non refundable. components: @@ -579,10 +579,10 @@ prob: 0.05 - type: entity + parent: CratePlastic + id: CrateFunDartsSet name: dartboard box set description: A box with everything you need for a fun game of darts. - id: CrateFunDartsSet - parent: CratePlastic components: - type: EntityTableContainerFill containers: @@ -595,10 +595,10 @@ prob: 0.05 - type: entity + parent: CrateLivestock + id: CrateFunScurret name: hydrated scurret description: Wait, what? - id: CrateFunScurret - parent: CrateLivestock components: - type: EntityTableContainerFill containers: @@ -614,4 +614,3 @@ - id: ClothingHeadHatHardhatYellow - id: ClothingNeckMantleQM - id: ClothingHeadsetCargo - diff --git a/Resources/Prototypes/Catalog/Fills/Crates/materials.yml b/Resources/Prototypes/Catalog/Fills/Crates/materials.yml index cb8a690f2b..ebf1a4a584 100644 --- a/Resources/Prototypes/Catalog/Fills/Crates/materials.yml +++ b/Resources/Prototypes/Catalog/Fills/Crates/materials.yml @@ -1,6 +1,6 @@ - type: entity - id: CrateMaterialGlass parent: CrateGenericSteel + id: CrateMaterialGlass name: glass sheet crate description: 90 sheets of glass, packed with care. components: @@ -11,8 +11,8 @@ amount: 3 - type: entity - id: CrateMaterialSteel parent: CrateGenericSteel + id: CrateMaterialSteel name: steel sheet crate description: 90 sheets of steel. components: @@ -23,8 +23,8 @@ amount: 3 - type: entity - id: CrateMaterialTextiles parent: CrateGenericSteel + id: CrateMaterialTextiles name: textiles crate description: 60 pieces of cloth and 30 pieces of durathread. components: @@ -37,8 +37,8 @@ - id: MaterialDurathread - type: entity - id: CrateMaterialPlastic parent: CrateGenericSteel + id: CrateMaterialPlastic name: plastic sheet crate description: 90 sheets of plastic. components: @@ -49,8 +49,8 @@ amount: 3 - type: entity - id: CrateMaterialWood parent: CrateGenericSteel + id: CrateMaterialWood name: wood crate description: Bunch of wood planks. components: @@ -60,8 +60,8 @@ id: MaterialWoodPlank - type: entity - id: CrateMaterialBrass parent: CrateGenericSteel + id: CrateMaterialBrass name: brass crate description: 90 sheets of brass. components: @@ -72,8 +72,8 @@ amount: 3 - type: entity - id: CrateMaterialPlasteel parent: CrateGenericSteel + id: CrateMaterialPlasteel name: plasteel crate description: 30 sheets of plasteel. components: @@ -83,8 +83,8 @@ id: SheetPlasteel - type: entity - id: CrateMaterialPlasma parent: CratePlasma + id: CrateMaterialPlasma name: solid plasma crate description: 30 sheets of plasma. components: @@ -94,8 +94,8 @@ id: SheetPlasma - type: entity - id: CrateMaterialGold parent: CrateGenericSteel + id: CrateMaterialGold name: gold crate description: 30 bars of gold. components: @@ -105,8 +105,8 @@ id: IngotGold - type: entity - id: CrateMaterialSilver parent: CrateGenericSteel + id: CrateMaterialSilver name: silver crate description: 30 bars of silver. components: @@ -116,8 +116,8 @@ id: IngotSilver - type: entity - id: CrateMaterialCardboard parent: CrateGenericSteel + id: CrateMaterialCardboard name: cardboard crate description: 90 pieces of cardboard. components: @@ -128,8 +128,8 @@ amount: 3 - type: entity - id: CrateMaterialPaper parent: CrateGenericSteel + id: CrateMaterialPaper name: paper crate description: 90 sheets of paper. components: @@ -171,8 +171,8 @@ - id: IngotSilver1 - type: entity - id: CrateMaterialRandom parent: CrateGenericSteel + id: CrateMaterialRandom name: surplus materials description: Surplus materials from somewhere. components: @@ -184,8 +184,8 @@ range: 2, 4 - type: entity - id: CrateMaterialSilo parent: CrateGenericSteel + id: CrateMaterialSilo name: material silo crate description: A package including all the materials to create a material silo. components: @@ -202,8 +202,8 @@ amount: 2 - type: entity - id: CrateMaterialBasicResource parent: CrateGenericSteel + id: CrateMaterialBasicResource name: basic sheet crate description: 30 sheets of steel, glass, and plastic. components: @@ -216,9 +216,9 @@ - id: SheetPlastic #- type: entity +# parent: CrateGenericSteel # id: CrateMaterialHFuelTank # name: fueltank crate -# parent: CrateGenericSteel # components: # - type: EntityTableContainerFill # containers: @@ -226,9 +226,9 @@ # id: WeldingFuelTank #- type: entity +# parent: CrateGenericSteel # id: CrateMaterialHWaterTank # name: watertank crate -# parent: CrateGenericSteel # components: # - type: EntityTableContainerFill # containers: diff --git a/Resources/Prototypes/Catalog/Fills/Crates/medical.yml b/Resources/Prototypes/Catalog/Fills/Crates/medical.yml index f14dffc6c5..7c904ff325 100644 --- a/Resources/Prototypes/Catalog/Fills/Crates/medical.yml +++ b/Resources/Prototypes/Catalog/Fills/Crates/medical.yml @@ -1,6 +1,6 @@ - type: entity - id: CrateMedicalSupplies parent: CrateMedical + id: CrateMedicalSupplies name: medical supplies crate description: Basic medical supplies. components: @@ -19,8 +19,8 @@ - id: BoxMouthSwab - type: entity - id: CrateChemistrySupplies parent: CrateMedical + id: CrateChemistrySupplies name: chemistry supplies crate description: Basic chemistry supplies. components: @@ -39,8 +39,8 @@ amount: 2 - type: entity - id: CrateChemistryVials parent: CrateMedical + id: CrateChemistryVials name: vial supply crate description: Crate filled with a box of vials. components: @@ -50,8 +50,8 @@ id: BoxVial - type: entity - id: CrateMindShieldImplants parent: CrateMedical + id: CrateMindShieldImplants name: MindShield implant crate description: Crate filled with 3 MindShield implants. components: @@ -62,8 +62,8 @@ amount: 3 - type: entity - id: CrateMedicalSurgery parent: CrateSurgery + id: CrateMedicalSurgery name: surgical supplies crate description: Surgical instruments. components: @@ -84,8 +84,8 @@ - id: BoxSterileMask - type: entity - id: CrateMedicalScrubs parent: CrateMedical + id: CrateMedicalScrubs name: medical scrubs crate description: Medical clothings. components: @@ -116,8 +116,8 @@ amount: 1 - type: entity - id: CrateEmergencyBurnKit parent: CrateMedical + id: CrateEmergencyBurnKit name: emergency burn kit description: Crate filled with a burn treatment kit. components: @@ -127,8 +127,8 @@ id: MedkitBurnFilled - type: entity - id: CrateEmergencyToxinKit parent: CrateMedical + id: CrateEmergencyToxinKit name: emergency toxin kit description: Crate filled with a toxin treatment kit. components: @@ -138,8 +138,8 @@ id: MedkitToxinFilled - type: entity - id: CrateEmergencyO2Kit parent: CrateMedical + id: CrateEmergencyO2Kit name: emergency O2 kit description: Crate filled with an O2 treatment kit. components: @@ -149,8 +149,8 @@ id: MedkitOxygenFilled - type: entity - id: CrateEmergencyBruteKit parent: CrateMedical + id: CrateEmergencyBruteKit name: emergency brute kit description: Crate filled with a brute treatment kit. components: @@ -160,8 +160,8 @@ id: MedkitBruteFilled - type: entity - id: CrateEmergencyAdvancedKit parent: CrateMedical + id: CrateEmergencyAdvancedKit name: emergency advanced kit description: Crate filled with an advanced treatment kit. components: @@ -171,8 +171,8 @@ id: MedkitAdvancedFilled - type: entity - id: CrateEmergencyRadiationKit parent: CrateMedical + id: CrateEmergencyRadiationKit name: emergency radiation kit description: Crate filled with a radiation treatment kit. components: @@ -182,8 +182,8 @@ id: MedkitRadiationFilled - type: entity - id: CrateBodyBags parent: CrateMedical + id: CrateBodyBags name: body bags crate description: Contains ten body bags. components: @@ -194,8 +194,8 @@ amount: 2 - type: entity - id: CrateVirologyBiosuit parent: CrateMedicalSecure + id: CrateVirologyBiosuit name: virology bio suit crate description: Contains 2 biohazard suits to ensure that no disease will distract you from treating the crew. Requires Medical access to open. components: diff --git a/Resources/Prototypes/Catalog/Fills/Crates/npc.yml b/Resources/Prototypes/Catalog/Fills/Crates/npc.yml index 625a890d8b..84a58e67ce 100644 --- a/Resources/Prototypes/Catalog/Fills/Crates/npc.yml +++ b/Resources/Prototypes/Catalog/Fills/Crates/npc.yml @@ -1,6 +1,6 @@ - type: entity - id: CrateNPCBee parent: CrateLivestock + id: CrateNPCBee name: crate of bees description: A crate containing a swarm of eight bees. components: @@ -11,8 +11,8 @@ amount: 8 - type: entity - id: CrateNPCButterflies parent: CrateLivestock + id: CrateNPCButterflies name: crate of butterflies description: A crate containing five butterflies. components: @@ -23,8 +23,8 @@ amount: 5 - type: entity - id: CrateNPCCat parent: CrateLivestock + id: CrateNPCCat name: cat crate description: A crate containing a single cat. components: @@ -42,8 +42,8 @@ weight: 0.005 - type: entity - id: CrateNPCChicken parent: CrateLivestock + id: CrateNPCChicken name: chicken crate description: A crate containing four fully grown chickens. components: @@ -54,8 +54,8 @@ amount: 4 - type: entity - id: CrateNPCCrab parent: CrateLivestock + id: CrateNPCCrab name: crab crate description: A crate containing three huge crabs. components: @@ -66,8 +66,8 @@ amount: 3 - type: entity - id: CrateNPCDuck parent: CrateLivestock + id: CrateNPCDuck name: duck crate description: A crate containing six fully grown ducks. components: @@ -81,8 +81,8 @@ amount: 2 - type: entity - id: CrateNPCCorgi parent: CrateLivestock + id: CrateNPCCorgi name: corgi crate description: A crate containing a single corgi. components: @@ -92,8 +92,8 @@ id: MobCorgi - type: entity - id: CrateNPCPuppyCorgi parent: CrateLivestock + id: CrateNPCPuppyCorgi name: puppy corgi crate description: A crate containing a single puppy corgi. Awww. components: @@ -103,8 +103,8 @@ id: MobCorgiPuppy - type: entity - id: CrateNPCCow parent: CrateLivestock + id: CrateNPCCow name: cow crate description: A crate containing a single cow. components: @@ -114,8 +114,8 @@ id: MobCow - type: entity - id: CrateNPCGoat parent: CrateLivestock + id: CrateNPCGoat name: goat crate description: A crate containing a single goat. components: @@ -125,8 +125,8 @@ id: MobGoat - type: entity - id: CrateNPCGoose parent: CrateLivestock + id: CrateNPCGoose name: goose crate description: A crate containing two geese. components: @@ -137,8 +137,8 @@ amount: 2 - type: entity - id: CrateNPCGorilla parent: CrateLivestock + id: CrateNPCGorilla name: gorilla crate description: A crate containing a single gorilla. components: @@ -148,8 +148,8 @@ id: MobGorilla - type: entity - id: CrateNPCMonkeyCube parent: CrateGenericSteel + id: CrateNPCMonkeyCube name: monkey cube crate description: A crate containing single box of monkey cubes. components: @@ -159,8 +159,8 @@ id: MonkeyCubeBox - type: entity - id: CrateNPCKoboldCube parent: CrateGenericSteel + id: CrateNPCKoboldCube name: kobold cube crate description: A crate containing single box of kobold cubes. components: @@ -170,8 +170,8 @@ id: KoboldCubeBox - type: entity - id: CrateNPCMouse parent: CrateLivestock + id: CrateNPCMouse name: mice crate description: A crate containing five mice. components: @@ -182,8 +182,8 @@ amount: 5 - type: entity - id: CrateNPCParrot parent: CrateLivestock + id: CrateNPCParrot name: parrot crate description: A crate containing three parrots. components: @@ -194,8 +194,8 @@ amount: 3 - type: entity - id: CrateNPCPenguin parent: CrateLivestock + id: CrateNPCPenguin name: penguin crate description: A crate containing two penguins. components: @@ -206,8 +206,8 @@ amount: 2 - type: entity - id: CrateNPCPig parent: CrateLivestock + id: CrateNPCPig name: pig crate description: A crate containing a single pig. components: @@ -217,8 +217,8 @@ id: MobPig - type: entity - id: CrateNPCSnake parent: CrateLivestock + id: CrateNPCSnake name: snake crate description: A crate containing three snakes. components: @@ -229,8 +229,8 @@ amount: 3 - type: entity - id: CrateNPCHamster parent: CrateRodentCage + id: CrateNPCHamster suffix: Filled components: - type: EntityTableContainerFill @@ -239,8 +239,8 @@ id: MobHamster - type: entity - id: CrateNPCHamlet parent: CrateRodentCage + id: CrateNPCHamlet suffix: Hamlet components: - type: EntityTableContainerFill @@ -252,8 +252,8 @@ weight: 0.001 - type: entity - id: CrateNPCLizard parent: CrateLivestock + id: CrateNPCLizard name: lizard crate description: A crate containing a lizard. components: @@ -263,8 +263,8 @@ id: MobLizard - type: entity - id: CrateNPCKangaroo parent: CrateLivestock + id: CrateNPCKangaroo name: kangaroo crate description: A crate containing a kangaroo. components: @@ -274,8 +274,8 @@ id: MobKangaroo - type: entity - id: CrateNPCMothroach parent: CrateLivestock + id: CrateNPCMothroach name: crate of mothroaches description: A crate containing four mothroaches. components: diff --git a/Resources/Prototypes/Catalog/Fills/Crates/permaescape.yml b/Resources/Prototypes/Catalog/Fills/Crates/permaescape.yml index e81d340bb0..3cf7e72eb0 100644 --- a/Resources/Prototypes/Catalog/Fills/Crates/permaescape.yml +++ b/Resources/Prototypes/Catalog/Fills/Crates/permaescape.yml @@ -1,31 +1,31 @@ - type: entity - name: Perma Escape Crate Spawner - id: CratePermaEscapeSpawner parent: CrateEmptySpawner + id: CratePermaEscapeSpawner + name: Perma Escape Crate Spawner components: - type: RandomSpawner prototypes: # Please note any duplicates & alphabetize <3 + - ClosetMaintenanceFilledRandom # x3 + - ClosetMaintenanceFilledRandom + - ClosetMaintenanceFilledRandom - CrateEngineeringMiniJetpack - CratePermaEscapeBureaucracy - - CratePermaEscapeEVA - - CratePermaEscapeGiftsFromSyndicate - - CratePermaEscapeGun - - CratePermaEscapeLights - - CratePermaEscapeMerc - - CrateServiceCustomSmokable - - CrateTrashCartFilled - CratePermaEscapeComs # x2 - CratePermaEscapeComs - CratePermaEscapeDigging # x2 - CratePermaEscapeDigging + - CratePermaEscapeEVA + - CratePermaEscapeGiftsFromSyndicate + - CratePermaEscapeGun + - CratePermaEscapeLights - CratePermaEscapeMats #x2 - CratePermaEscapeMats + - CratePermaEscapeMerc - CratePermaEscapeTowercap # x2 - CratePermaEscapeTowercap - - ClosetMaintenanceFilledRandom # x3 - - ClosetMaintenanceFilledRandom - - ClosetMaintenanceFilledRandom + - CrateTrashCartFilled + - CrateServiceCustomSmokable rarePrototypes: - MobTick # These need to be killable by one dude with a shovel. rareChance: .30 @@ -33,8 +33,8 @@ offset: 0.0 - type: entity - id: CratePermaEscapeDigging parent: CrateGenericSteel + id: CratePermaEscapeDigging suffix: Digging components: - type: EntityTableContainerFill @@ -58,9 +58,9 @@ prob: 0.05 - type: entity - id: CratePermaEscapeEVA parent: CrateGenericSteel - suffix: EVAs + id: CratePermaEscapeEVA + suffix: EVA components: - type: EntityTableContainerFill containers: @@ -88,8 +88,8 @@ prob: 0.05 - type: entity - id: CratePermaEscapeGun parent: CrateGenericSteel + id: CratePermaEscapeGun suffix: Gun components: - type: EntityTableContainerFill @@ -112,9 +112,9 @@ weight: 2 - type: entity - id: CratePermaEscapeBureaucracy parent: CrateGenericSteel - suffix: Writing + id: CratePermaEscapeBureaucracy + suffix: Bureaucracy components: - type: EntityTableContainerFill containers: @@ -145,8 +145,8 @@ - id: PersonalAI - type: entity - id: CratePermaEscapeLights parent: CrateGenericSteel + id: CratePermaEscapeLights suffix: Glowsticks components: - type: EntityTableContainerFill @@ -185,9 +185,9 @@ prob: 0.05 - type: entity - id: CratePermaEscapeMats parent: CrateGenericSteel - suffix: Mats + id: CratePermaEscapeMats + suffix: Materials components: - type: EntityTableContainerFill containers: @@ -198,9 +198,9 @@ - id: PartRodMetal - type: entity - id: CratePermaEscapeGiftsFromSyndicate parent: CrateGenericSteel - suffix: Syndi Gifts + id: CratePermaEscapeGiftsFromSyndicate + suffix: Syndicate gifts components: - type: EntityTableContainerFill containers: @@ -240,9 +240,9 @@ prob: 0.005 - type: entity - id: CratePermaEscapeMerc parent: CrateGenericSteel - suffix: Merc + id: CratePermaEscapeMerc + suffix: Mercenary components: - type: EntityTableContainerFill containers: @@ -273,9 +273,9 @@ prob: 0.05 - type: entity - id: CratePermaEscapeComs parent: CrateGenericSteel - suffix: Coms + id: CratePermaEscapeComs + suffix: Comms components: - type: EntityTableContainerFill containers: @@ -305,8 +305,8 @@ prob: 0.01 - type: entity - id: CratePermaEscapeTowercap parent: CrateGenericSteel + id: CratePermaEscapeTowercap suffix: Towercap components: - type: EntityTableContainerFill diff --git a/Resources/Prototypes/Catalog/Fills/Crates/salvage.yml b/Resources/Prototypes/Catalog/Fills/Crates/salvage.yml index 8c8e0e02cb..0580d1f46f 100644 --- a/Resources/Prototypes/Catalog/Fills/Crates/salvage.yml +++ b/Resources/Prototypes/Catalog/Fills/Crates/salvage.yml @@ -1,9 +1,9 @@ - type: entity + parent: CrateGenericSteel id: CrateSalvageEquipment name: "salvage equipment crate" - description: For the daring. suffix: Filled - parent: CrateGenericSteel + description: For the daring. components: - type: EntityTableContainerFill containers: @@ -28,10 +28,10 @@ prob: 0.8 - type: entity - id: CrateSalvageAssortedGoodies - suffix: Filled, Salvage Random - categories: [ HideSpawnMenu ] # You should use SalvageMaterialCrateSpawner instead parent: CrateGenericSteel + id: CrateSalvageAssortedGoodies + categories: [ HideSpawnMenu ] # You should use SalvageMaterialCrateSpawner instead + suffix: Filled, Salvage Random components: - type: EntityTableContainerFill containers: diff --git a/Resources/Prototypes/Catalog/Fills/Crates/science.yml b/Resources/Prototypes/Catalog/Fills/Crates/science.yml index 1a5bd028ad..ab8cdc90e8 100644 --- a/Resources/Prototypes/Catalog/Fills/Crates/science.yml +++ b/Resources/Prototypes/Catalog/Fills/Crates/science.yml @@ -1,6 +1,6 @@ - type: entity - id: CrateScienceBiosuit parent: CrateScienceSecure + id: CrateScienceBiosuit name: scientist bio suit crate description: Contains 2 biohazard suits to ensure that no disease will distract you from doing science. Requires Science access to open. components: @@ -15,8 +15,8 @@ amount: 2 - type: entity - id: CrateCrewMonitoring parent: CrateScienceSecure + id: CrateCrewMonitoring name: crew monitoring crate description: Contains a flatpack of a crew monitoring server and a few crew monitoring computers. Requires Science access to open. components: @@ -29,8 +29,8 @@ amount: 3 - type: entity - id: CrateStationAiCore parent: CrateScienceSecure + id: CrateStationAiCore name: station AI core crate description: Contains the components for constructing a station AI core. Positronic brain not included. Requires Science access to open. components: diff --git a/Resources/Prototypes/Catalog/Fills/Crates/security.yml b/Resources/Prototypes/Catalog/Fills/Crates/security.yml index 2727cd8799..9c3b695a5d 100644 --- a/Resources/Prototypes/Catalog/Fills/Crates/security.yml +++ b/Resources/Prototypes/Catalog/Fills/Crates/security.yml @@ -1,6 +1,6 @@ - type: entity - id: CrateSecurityArmor parent: CrateSecgear + id: CrateSecurityArmor name: armor crate description: Contains three bulletproof vests. Requires Security access to open. components: @@ -11,8 +11,8 @@ amount: 3 - type: entity - id: CrateSecurityHelmet parent: CrateSecgear + id: CrateSecurityHelmet name: helmet crate description: Contains three standard-issue brain buckets. Requires Security access to open. components: @@ -23,8 +23,8 @@ amount: 3 - type: entity - id: CrateSecurityNonlethal parent: CrateSecgear + id: CrateSecurityNonlethal name: nonlethals crate description: Contains a mix of disablers, stun batons, and flashes. Requires Security access to open. components: @@ -43,8 +43,8 @@ # - GrenadeTeargas - type: entity - id: CrateSecuritySupplies parent: CrateSecgear + id: CrateSecuritySupplies name: security supplies crate description: Contains various supplies for the station's Security team. Requires Security access to open. components: @@ -59,8 +59,8 @@ # - SpacelawBook - type: entity - id: CrateRestraints parent: CrateSecgear + id: CrateRestraints name: restraints crate description: Contains two boxes each of handcuffs and zipties. Requires Security access to open. components: @@ -74,8 +74,8 @@ amount: 2 - type: entity - id: CrateSecurityBiosuit parent: CrateSecgear + id: CrateSecurityBiosuit name: security bio suit crate description: Contains 2 biohazard suits to ensure that no disease will distract you from your duties. Requires Security access to open. components: @@ -90,10 +90,10 @@ amount: 2 - type: entity + parent: CrateSecgear id: CrateSecurityTrackingMindshieldImplants name: implanter crate description: Contains 4 MindShield implants and 4 tracking implant. Requires Security access to open. - parent: CrateSecgear components: - type: EntityTableContainerFill containers: diff --git a/Resources/Prototypes/Catalog/Fills/Crates/service.yml b/Resources/Prototypes/Catalog/Fills/Crates/service.yml index 8a4f04894b..528db232e9 100644 --- a/Resources/Prototypes/Catalog/Fills/Crates/service.yml +++ b/Resources/Prototypes/Catalog/Fills/Crates/service.yml @@ -1,6 +1,6 @@ - type: entity - id: CrateServiceJanitorialSupplies parent: CratePlastic + id: CrateServiceJanitorialSupplies name: janitorial supplies crate description: Fight back against dirt and grime with Nanotrasen's Janitorial Essentials(tm)! Contains three buckets, caution signs, and cleaner grenades. Also has a single mop, broom, spray cleaner, wire brush, rag, and trash bag. components: @@ -26,8 +26,8 @@ amount: 2 - type: entity - id: CrateServiceCleanerGrenades parent: CratePlastic + id: CrateServiceCleanerGrenades name: bulk cleanades crate description: Contains two boxes of cleaner grenades, for those deeply-entrenched stains. components: @@ -38,10 +38,10 @@ amount: 2 - type: entity - id: CrateServiceReplacementLights parent: CrateGenericSteel + id: CrateServiceReplacementLights name: replacement lights crate - description: May the light of Aether shine upon this station! Or at least, the light of forty two light tubes and twenty one light bulbs. + description: May the light of Aether shine upon this station! Or at least, the light of twelve fluorescent light tubes and twelve incandescent light bulbs. components: - type: EntityTableContainerFill containers: @@ -51,10 +51,23 @@ - id: BoxLightbulb - type: entity - id: CrateServiceHolidayLights parent: CrateGenericSteel + id: CrateServiceColorfulLights + name: colorful lights crate + description: It's not a party until it's hard to see, a little disorienting, and your ears hurt. Contains twelve light tubes and twelve light bulbs in a variety of colors. + components: + - type: EntityTableContainerFill + containers: + entity_storage: !type:AllSelector + children: + - id: BoxLightbulbColorfulMixed + - id: BoxLighttubeColorfulMixed + +- type: entity + parent: CrateGenericSteel + id: CrateServiceHolidayLights name: holiday lights crate - description: Deck the halls with these festive holiday lights! + description: Deck the halls with these festive holiday lights! Contains twelve red light tubes and twelve green light tubes. components: - type: EntityTableContainerFill containers: @@ -63,8 +76,8 @@ amount: 2 - type: entity - id: CrateMousetrapBoxes parent: CrateGenericSteel + id: CrateMousetrapBoxes name: mousetraps crate description: Mousetraps, for when all of service is being haunted by an entire horde of rats. Use sparingly... or not. components: @@ -74,8 +87,8 @@ id: BoxMousetrap - type: entity - id: CrateServiceSmokeables parent: CrateGenericSteel + id: CrateServiceSmokeables name: smokeables crate description: Tired of a quick death on the station? Order this crate and chain-smoke your way to a coughy demise! components: @@ -109,8 +122,8 @@ amount: 2 - type: entity - id: CrateServiceTheatre parent: CrateGenericSteel + id: CrateServiceTheatre name: theatrical performances crate description: Contains a moth cloak, barber scissors, maid uniform, clown and mime attributes, and other performance charms. components: @@ -138,8 +151,8 @@ - id: ClothingBeltSuspendersBlack - type: entity - id: CrateServiceCustomSmokable parent: CrateGenericSteel + id: CrateServiceCustomSmokable name: DIY smokeables crate description: Want to get a little creative with what you use to destroy your lungs? Then this crate is for you! Has everything you need to roll your own cigarettes. components: @@ -156,8 +169,8 @@ - id: Matchbox - type: entity - id: CrateServiceBureaucracy parent: CrateGenericSteel + id: CrateServiceBureaucracy name: bureaucracy crate description: Several stacks of paper, a few pens and an office toy. What more could you ask for? components: @@ -207,8 +220,8 @@ # End DeltaV - More folders & colored paper reams in the bureaucracy crate + denied/approved stamp, low chance of paperwork hater stamp - type: entity - id: CrateServiceFaxMachine parent: CrateGenericSteel + id: CrateServiceFaxMachine name: fax machine crate description: A fax machine and a screwdriver to set the name with. components: @@ -220,8 +233,8 @@ - id: FaxMachineFlatpack - type: entity - id: CrateServicePersonnel parent: CrateCommandSecure + id: CrateServicePersonnel name: personnel crate description: Contains a box of blank ID cards and PDAs. components: @@ -233,8 +246,8 @@ - id: BoxID - type: entity - id: CrateServiceBooks parent: CrateGenericSteel + id: CrateServiceBooks name: books crate description: Contains 10 empty books of random appearance. components: @@ -245,8 +258,8 @@ amount: 10 - type: entity - id: CrateServiceGuidebooks parent: CrateGenericSteel + id: CrateServiceGuidebooks name: guidebooks crate description: Contains guidebooks. components: @@ -270,8 +283,8 @@ - id: BookSpaceLaw - type: entity - id: CrateServiceSodaDispenser parent: CrateFreezer + id: CrateServiceSodaDispenser name: soda dispenser refill crate description: Contains refills for soda dispensers. components: @@ -299,8 +312,8 @@ - id: DrinkWaterMelonJuiceJug - type: entity - id: CrateServiceBoozeDispenser parent: CrateFreezer + id: CrateServiceBoozeDispenser name: booze dispenser refill crate description: Contains refills for booze dispensers. components: @@ -323,8 +336,8 @@ - id: DrinkJaegermisterBottleFull # Den - Jaegerminster - type: entity - id: CrateServiceBox parent: CratePlastic + id: CrateServiceBox name: boxes crate description: Contains 6 empty multipurpose boxes. components: @@ -335,8 +348,8 @@ amount: 6 - type: entity - id: CrateJanitorBiosuit parent: CratePlastic + id: CrateJanitorBiosuit name: janitor bio suit crate description: Contains 2 biohazard suits to ensure that no disease will distract you from cleaning. components: @@ -351,9 +364,9 @@ amount: 2 - type: entity + parent: CrateTrashCart id: CrateTrashCartFilled suffix: Filled - parent: CrateTrashCart components: - type: EntityTableContainerFill containers: @@ -428,8 +441,8 @@ prob: 0.1 - type: entity - id: CrateCandles parent: CrateGenericSteel + id: CrateCandles name: candles crate description: Contains 4 boxes of candles, 2 large and 2 small. For atmosphere or something. components: @@ -441,16 +454,3 @@ amount: 2 - id: BoxCandleSmall amount: 2 - -- type: entity - parent: CrateGenericSteel - id: CrateServiceColorfulLights - name: colorful lights crate - description: It's not a party until it's hard to see, a little disorienting, and your ears hurt. - components: - - type: EntityTableContainerFill - containers: - entity_storage: !type:AllSelector - children: - - id: BoxLightbulbColorfulMixed - - id: BoxLighttubeColorfulMixed diff --git a/Resources/Prototypes/Catalog/Fills/Crates/syndicate.yml b/Resources/Prototypes/Catalog/Fills/Crates/syndicate.yml index b51db18fc4..6e4418778a 100644 --- a/Resources/Prototypes/Catalog/Fills/Crates/syndicate.yml +++ b/Resources/Prototypes/Catalog/Fills/Crates/syndicate.yml @@ -1,6 +1,6 @@ - type: entity - id: CrateSyndicateSurplusBundle parent: [ CrateSyndicate, StorePresetUplink, BaseSyndicateContraband ] + id: CrateSyndicateSurplusBundle name: Syndicate surplus crate description: Contains 50 telecrystals worth of completely random Syndicate items. It can be useless junk or really good. components: @@ -11,10 +11,10 @@ - Syndicate - type: entity - id: CrateCybersunJuggernautBundle - suffix: Filled parent: CrateSyndicate + id: CrateCybersunJuggernautBundle name: Cybersun juggernaut bundle + suffix: Filled description: Contains everything except a big gun to go postal. components: - type: EntityTableContainerFill @@ -29,8 +29,8 @@ - Syndicate - type: entity - id: CrateSyndicateSuperSurplusBundle parent: [ CrateSyndicate, StorePresetUplink, BaseSyndicateContraband ] + id: CrateSyndicateSuperSurplusBundle name: Syndicate super surplus crate description: Contains 125 telecrystals worth of completely random Syndicate items. components: diff --git a/Resources/Prototypes/Catalog/Fills/Crates/vending.yml b/Resources/Prototypes/Catalog/Fills/Crates/vending.yml index 0a68481bbd..047ae5c36f 100644 --- a/Resources/Prototypes/Catalog/Fills/Crates/vending.yml +++ b/Resources/Prototypes/Catalog/Fills/Crates/vending.yml @@ -1,6 +1,6 @@ - type: entity - id: CrateVendingMachineRestockBoozeFilled parent: CratePlastic + id: CrateVendingMachineRestockBoozeFilled name: Booze-O-Mat restock crate description: Contains a restock box for the Booze-O-Mat. components: @@ -10,8 +10,8 @@ id: VendingMachineRestockBooze - type: entity - id: CrateVendingMachineRestockChefvendFilled parent: CratePlastic + id: CrateVendingMachineRestockChefvendFilled name: ChefVend restock crate description: Contains a restock box for the ChefVend. components: @@ -21,8 +21,8 @@ id: VendingMachineRestockChefvend - type: entity - id: CrateVendingMachineRestockClothesFilled parent: CratePlastic + id: CrateVendingMachineRestockClothesFilled name: clothing restock crate description: Contains a restock box for the clothes vending machines. components: @@ -32,8 +32,8 @@ id: VendingMachineRestockClothes - type: entity - id: CrateVendingMachineRestockAutoDrobeFilled parent: CratePlastic + id: CrateVendingMachineRestockAutoDrobeFilled name: AutoDrobe restock crate description: Contains a restock box for the AutoDrobe. components: @@ -43,8 +43,8 @@ id: VendingMachineRestockCostumes - type: entity - id: CrateVendingMachineRestockCondimentStationFilled parent: CratePlastic + id: CrateVendingMachineRestockCondimentStationFilled name: condiment station restock crate description: Contains a restock box for the condiment station. components: @@ -54,8 +54,8 @@ id: VendingMachineRestockCondimentStation - type: entity - id: CrateVendingMachineRestockDinnerwareFilled parent: CratePlastic + id: CrateVendingMachineRestockDinnerwareFilled name: Plasteel Chef restock crate description: Contains a restock box for the Plasteel Chef vending machine. components: @@ -65,8 +65,8 @@ id: VendingMachineRestockDinnerware - type: entity - id: CrateVendingMachineRestockEngineeringFilled parent: CrateEngineeringSecure + id: CrateVendingMachineRestockEngineeringFilled name: EngiVend restock crate description: Contains a restock box for the EngiVend. Also supports the YouTool. components: @@ -76,8 +76,8 @@ id: VendingMachineRestockEngineering - type: entity - id: CrateVendingMachineRestockGamesFilled parent: CratePlastic + id: CrateVendingMachineRestockGamesFilled name: Good Clean Fun restock crate description: Contains a restock box for the Good Clean Fun vending machine. components: @@ -87,8 +87,8 @@ id: VendingMachineRestockGames - type: entity - id: CrateVendingMachineRestockHotDrinksFilled parent: CratePlastic + id: CrateVendingMachineRestockHotDrinksFilled name: Solar's Best restock crate description: Contains two restock boxes for Solar's Best Hot Drinks vending machine. components: @@ -99,8 +99,8 @@ amount: 2 - type: entity - id: CrateVendingMachineRestockMedicalFilled parent: CrateMedicalSecure + id: CrateVendingMachineRestockMedicalFilled name: NanoMed restock crate description: Contains a restock box, compatible with the NanoMed and NanoMedPlus. components: @@ -110,8 +110,8 @@ id: VendingMachineRestockMedical - type: entity - id: CrateVendingMachineRestockChemVendFilled parent: CrateMedicalSecure + id: CrateVendingMachineRestockChemVendFilled name: ChemVend restock crate description: Contains a restock box for the ChemVend. components: @@ -121,8 +121,8 @@ id: VendingMachineRestockChemVend - type: entity - id: CrateVendingMachineRestockNutriMaxFilled parent: CrateHydroSecure + id: CrateVendingMachineRestockNutriMaxFilled name: NutriMax restock crate description: Contains a restock box for the NutriMax vending machine. components: @@ -132,8 +132,8 @@ id: VendingMachineRestockNutriMax - type: entity - id: CrateVendingMachineRestockPTechFilled parent: CratePlastic + id: CrateVendingMachineRestockPTechFilled name: PTech restock crate description: Contains a restock box for the PTech bureaucracy dispenser. components: @@ -143,8 +143,8 @@ id: VendingMachineRestockPTech - type: entity - id: CrateVendingMachineRestockRobustSoftdrinksFilled parent: CratePlastic + id: CrateVendingMachineRestockRobustSoftdrinksFilled name: beverage vendor restock crate description: Contains restock boxes for beverage vending machines. components: @@ -154,11 +154,10 @@ id: VendingMachineRestockRobustSoftdrinks amount: 2 - #- type: entity # DeltaV: Salvage vendor doesn't have stock anymore #- type: entity -# id: CrateVendingMachineRestockSalvageEquipmentFilled # parent: CrateGenericSteel +# id: CrateVendingMachineRestockSalvageEquipmentFilled # name: Salvage restock crate # description: Contains a restock box for the salvage vendor. # components: @@ -168,8 +167,8 @@ # id: VendingMachineRestockSalvageEquipment - type: entity - id: CrateVendingMachineRestockSecTechFilled parent: CrateSecgear + id: CrateVendingMachineRestockSecTechFilled name: SecTech restock crate description: Contains a restock box for the SecTech vending machine. components: @@ -179,8 +178,8 @@ id: VendingMachineRestockSecTech - type: entity - id: CrateVendingMachineRestockSeedsFilled parent: CrateHydroSecure + id: CrateVendingMachineRestockSeedsFilled name: MegaSeed restock crate description: Contains a restock box for the MegaSeed vending machine. components: @@ -190,8 +189,8 @@ id: VendingMachineRestockSeeds - type: entity - id: CrateVendingMachineRestockSmokesFilled parent: CratePlastic + id: CrateVendingMachineRestockSmokesFilled name: ShadyCigs restock crate description: Contains two restock boxes for the ShadyCigs vending machine. components: @@ -202,8 +201,8 @@ amount: 2 - type: entity - id: CrateVendingMachineRestockVendomatFilled parent: CratePlastic + id: CrateVendingMachineRestockVendomatFilled name: Vendomat restock crate description: Contains a restock box for a Vendomat vending machine. components: @@ -213,8 +212,8 @@ id: VendingMachineRestockVendomat - type: entity - id: CrateVendingMachineRestockRoboticsFilled parent: CrateScienceSecure + id: CrateVendingMachineRestockRoboticsFilled name: Robotech Deluxe restock crate description: Contains a restock box for a Robotech Deluxe vending machine. components: @@ -224,8 +223,8 @@ id: VendingMachineRestockRobotics - type: entity - id: CrateVendingMachineRestockTankDispenserFilled parent: CratePlastic + id: CrateVendingMachineRestockTankDispenserFilled name: tank dispenser restock crate description: Contains a restock box for an Engineering or Atmospherics tank dispenser. components: @@ -235,8 +234,8 @@ id: VendingMachineRestockTankDispenser - type: entity - id: CrateVendingMachineRestockHappyHonkFilled parent: CratePlastic + id: CrateVendingMachineRestockHappyHonkFilled name: Happy Honk restock crate description: Contains a restock box for a happy honk dispenser. components: @@ -247,8 +246,8 @@ amount: 2 - type: entity - id: CrateVendingMachineRestockGetmoreChocolateCorpFilled parent: CratePlastic + id: CrateVendingMachineRestockGetmoreChocolateCorpFilled name: Getmore Chocolate Corp restock crate description: Contains a restock box for a Getmore Chocolate Corp dispenser. components: @@ -259,8 +258,8 @@ amount: 2 - type: entity - id: CrateVendingMachineRestockChangFilled parent: CratePlastic + id: CrateVendingMachineRestockChangFilled name: Chang restock crate description: Contains a restock box for a Mr. Chang dispenser. components: @@ -271,8 +270,8 @@ amount: 2 - type: entity - id: CrateVendingMachineRestockDiscountDansFilled parent: CratePlastic + id: CrateVendingMachineRestockDiscountDansFilled name: Discount Dans restock crate description: Contains a restock box for a Discount Dan's dispenser. components: @@ -283,8 +282,8 @@ amount: 2 - type: entity - id: CrateVendingMachineRestockDonutFilled parent: CratePlastic + id: CrateVendingMachineRestockDonutFilled name: Donut restock crate description: Contains a restock box for a Monkin' Donuts dispenser. components: From 5bbfd796fd3f4401dc37e89ea118a493ab3aebd0 Mon Sep 17 00:00:00 2001 From: Hitlinemoss <209321380+Hitlinemoss@users.noreply.github.com> Date: Thu, 4 Dec 2025 03:06:27 -0500 Subject: [PATCH 021/360] figurines.ftl is now sorted by department (#41701) * figurines.ftl is now sorted by department * Nukie order fix * Greytider order fix * Tweaks to existing lines * still tweaking --- Resources/Locale/en-US/datasets/figurines.ftl | 494 +++++++++--------- 1 file changed, 259 insertions(+), 235 deletions(-) diff --git a/Resources/Locale/en-US/datasets/figurines.ftl b/Resources/Locale/en-US/datasets/figurines.ftl index 2c5d073864..b6428c0560 100644 --- a/Resources/Locale/en-US/datasets/figurines.ftl +++ b/Resources/Locale/en-US/datasets/figurines.ftl @@ -1,59 +1,4 @@ -figurines-hop-1 = Papers, please. -figurines-hop-2 = You are fired. -figurines-hop-3 = BRB. -figurines-hop-4 = You can get AA if you fill out the form. -figurines-hop-5 = I was gone for two seconds... - -figurines-passenger-1 = Insuls please. -figurines-passenger-2 = Call evac. -figurines-passenger-3 = HELP MAINTS!! -figurines-passenger-4 = I'm no tider. -figurines-passenger-5 = How much for a toolbelt? - -figurines-greytider-1 = Man, this party stinks. I fucking hate these people. -figurines-greytider-2 = Uh-oh, who's lost their stunbaton? -figurines-greytider-3 = Robust. -figurines-greytider-4 = I'm not me without a toolbox. -figurines-greytider-5 = Grey tide station wide! -figurines-greytider-6 = Viva la revolution. - -figurines-clown-1 = Honk! -figurines-clown-2 = Banana! -figurines-clown-3 = Soap! -figurines-clown-4 = HoP has one clown, HoS has the whole department. -figurines-clown-5 = Do I annoy you? -figurines-clown-6 = Can I have AA? Please? -figurines-clown-7 = I'm a clown, but you're the whole circus! - -figurines-holoclown-1 = I'm helping my older brother. -figurines-holoclown-2 = Hello, officer! -figurines-holoclown-3 = Who are you calling blue? -figurines-holoclown-4 = Bleeding on the ground is a good look for you. -figurines-holoclown-5 = Pathetic. -figurines-holoclown-6 = It's not them you need to worry about; it's me. -figurines-holoclown-7 = What's so funny? - -figurines-mime-1 = ... -figurines-mime-2 = ... -figurines-mime-3 = .... -figurines-mime-4 = ....... -figurines-mime-5 = ................ -figurines-mime-6 = ...........? -figurines-mime-7 = !!! -figurines-mime-8 = ....! -figurines-mime-9 = ??? - -figurines-musician-1 = Never gonna give you up! -figurines-musician-2 = Never gonna let you down! -figurines-musician-3 = Music is an art. -figurines-musician-4 = Thank you, I'll be here all night. -figurines-musician-5 = I'm a one man band. - -figurines-boxer-1 = The first rule of Fight Club is... -figurines-boxer-2 = We settle this in the ring, alright? -figurines-boxer-3 = I. AM. THE. CHAMPION!! -figurines-boxer-4 = Don't look at me; he was shot, not punched. -figurines-boxer-5 = 1v1 me, captain. +# Command figurines-captain-1 = Glory to NT! figurines-captain-2 = How did I get hired? Yes. @@ -64,19 +9,108 @@ figurines-captain-6 = The disk was in my bag last I checked. figurines-captain-7 = The chain of command starts and ends with me. figurines-captain-8 = It's hard being at the top. +# Cargo + +figurines-qm-1 = Who stole the shuttle? +figurines-qm-2 = Wait, where did my digi-board go? +figurines-qm-3 = I didn't approve that shipment of guns! +figurines-qm-4 = One toy box for my fellow clown! +figurines-qm-5 = Time to gamble! +figurines-qm-6 = Viva la Cargonia! +figurines-qm-7 = Fill out the form. +figurines-qm-8 = Where'd all our money go? +figurines-qm-9 = 99% of gamblers quit right before they hit it big! + +figurines-cargotech-1 = DRAGON ON ATS! +figurines-cargotech-2 = I sold the station! +figurines-cargotech-3 = Brain bounty? I don't have a brain. +figurines-cargotech-4 = You're worth 3000 spesos. Congrats. +figurines-cargotech-5 = Vegetable bounty? Nobody eats those anyways. +figurines-cargotech-6 = WE ARE SECEDING!! ALL HAIL CARGONIA!! + +figurines-salvage-1 = Megafauna? It was mega easy. +figurines-salvage-2 = We're lost. Anyone bring a GPS? +figurines-salvage-3 = Anyone have oxygen? +figurines-salvage-4 = I found a blood-red and e-sword! +figurines-salvage-5 = There's bears in space? +figurines-salvage-6 = Crusher? I barely know her! + +# Engineering + +figurines-ce-1 = Everyone to the briefing! +figurines-ce-2 = Wire the solars! +figurines-ce-3 = How to setup the TEG? +figurines-ce-4 = SINGULOOSE! +figurines-ce-5 = TESLOOSE! +figurines-ce-6 = Power's out again. + +figurines-atmostech-1 = I put plasma in distro. +figurines-atmostech-2 = I will burn you in a burn chamber. +figurines-atmostech-3 = Frezon... +figurines-atmostech-4 = Tritium... +figurines-atmostech-5 = Glory to Atmosia! +figurines-atmostech-6 = Distro? That's short for disposal. +figurines-atmostech-7 = TEG: Thermal Energy? Gone! + +figurines-engineer-1 = SINGULOOSE! +figurines-engineer-2 = TESLOOSE! +figurines-engineer-3 = Did anyone remember to turn the AME on? +figurines-engineer-4 = Free insuls at Engineering! +figurines-engineer-5 = Where'd the power go? +figurines-engineer-6 = Someone bombed the medbay... again... +figurines-engineer-7 = Well, why don't you come and fix it? + +# Medical + +figurines-cmo-1 = Suit sensors! +figurines-cmo-2 = Why do we have meth? +figurines-cmo-3 = Who drank all the chems? +figurines-cmo-4 = Desoxyephedrine? Sounds healthy. +figurines-cmo-5 = No, you're not getting my hypospray. + +figurines-chemist-1 = Get your pills! +figurines-chemist-2 = We need to cook. +figurines-chemist-3 = I am the one who knocks! +figurines-chemist-4 = Say my name. +figurines-chemist-5 = 99.8% purity. +figurines-chemist-6 = Epinephrine? Didn't you say methamphetamine? + +figurines-doctor-1 = The patient is already dead! +figurines-doctor-2 = CLEAR! +figurines-doctor-3 = Saw makes BRRR. +figurines-doctor-4 = Just a week away... +figurines-doctor-5 = I knew it... + +figurines-paramedic-1 = Insuls and tools! +figurines-paramedic-2 = I need AA for saving people! +figurines-paramedic-3 = SUIT SENSORS!! +figurines-paramedic-4 = I need the hypospray for saving people! +figurines-paramedic-5 = 14 dead in the clown's room. + +# Science + +figurines-rd-1 = Blowing up all of the borgs! +figurines-rd-2 = Tier 3 Arsenal? No way. +figurines-rd-3 = Now where did I leave my hardsuit...? +figurines-rd-4 = Now you're thinking with portals! +figurines-rd-5 = The cake is a lie! +figurines-rd-6 = The trait I look for in a scientist is expendability. + +figurines-scientist-1 = Someone else must have made those bombs! +figurines-scientist-2 = He asked to be borged! +figurines-scientist-3 = Carp at sci! +figurines-scientist-4 = Explosion at sci! +figurines-scientist-5 = Anyone seen an anomaly? +figurines-scientist-6 = The anomaly exploded! + +# Security + figurines-hos-1 = Space law? What? figurines-hos-2 = Shoot the clown. figurines-hos-3 = Yes, I shot the clown. No, I don't regret it. figurines-hos-4 = Clown is now KOS. figurines-hos-5 = Armory is now open to the public! -figurines-warden-1 = Execute him for breaking in! -figurines-warden-2 = Perma the fucker for insulting me! -figurines-warden-3 = We totally treat everyone fairly and do NOT mistreat our prisoners. -figurines-warden-4 = Brig is my home. My home is brig. My brig is home. Stop, what? -figurines-warden-5 = Soap is now contraband. -figurines-warden-6 = You're going away for a long time, buddy. - figurines-detective-1 = The butler did it. figurines-detective-2 = I need some whiskey after this. figurines-detective-3 = Chameleon fibers? How did a chameleon get in here? @@ -94,98 +128,86 @@ figurines-security-8 = I love donuts. figurines-security-9 = Greytide this, motherfucker. figurines-security-10 = Do not resist. +figurines-warden-1 = Execute him for breaking in! +figurines-warden-2 = Perma the fucker for insulting me! +figurines-warden-3 = We totally treat everyone fairly and do NOT mistreat our prisoners. +figurines-warden-4 = Brig is my home. My home is brig. My brig is home. Stop, what? +figurines-warden-5 = Soap is now contraband. +figurines-warden-6 = You're going away for a long time, buddy. + +# Service + +figurines-hop-1 = Papers, please. +figurines-hop-2 = You are fired. +figurines-hop-3 = BRB. +figurines-hop-4 = You can get AA if you fill out the form. +figurines-hop-5 = I was gone for two seconds... + +figurines-bartender-1 = Where's my monkey? +figurines-bartender-2 = Sec won't drink. +figurines-bartender-3 = I mixed a little something in there... +figurines-bartender-4 = The recipe? Plasma and vomit. Why? +figurines-bartender-5 = I need those toxins for my drinks, officer! +figurines-bartender-6 = Read the room. +figurines-bartender-7 = I've got a shotgun. + +figurines-botanist-1 = I don't have any weed, officer! +figurines-botanist-2 = Dude, I see colors... +figurines-botanist-3 = Is it just me, or is that weed glowing? +figurines-botanist-4 = 50 more units of mutagen. That should be enough. +figurines-botanist-5 = More bananas for my favorite clown! + +figurines-boxer-1 = The first rule of Fight Club is... +figurines-boxer-2 = We settle this in the ring, alright? +figurines-boxer-3 = I. AM. THE. CHAMPION!! +figurines-boxer-4 = Don't look at me; he was shot, not punched. +figurines-boxer-5 = 1v1 me, captain. + +figurines-chaplain-1 = Would you like to join my cul- I mean religion. +figurines-chaplain-2 = Gods, please make me a killing machine! +figurines-chaplain-3 = God exists! +figurines-chaplain-4 = Those aren't blood runes, I drew them in crayon. +figurines-chaplain-5 = Anyone want to be sacrificed? +figurines-chaplain-6 = Vampires aren't real. + +figurines-chef-1 = I swear it's not human meat. +figurines-chef-2 = More banana cream pies? +figurines-chef-3 = How does rotary sushi sound? +figurines-chef-4 = That'll be 1,000 spesos. +figurines-chef-5 = For here or to go? +figurines-chef-6 = Where'd Pun Pun go? No idea... + +figurines-clown-1 = Honk! +figurines-clown-2 = Banana! +figurines-clown-3 = Soap! +figurines-clown-4 = HoP has one clown, HoS has the whole department. +figurines-clown-5 = Do I annoy you? +figurines-clown-6 = Can I have AA? Please? +figurines-clown-7 = I'm a clown, but you're the whole circus! + +figurines-greytider-1 = Man, this party stinks. I fucking hate these people. +figurines-greytider-2 = Uh-oh, who's lost their stunbaton? +figurines-greytider-3 = Robust. +figurines-greytider-4 = I'm not me without a toolbox. +figurines-greytider-5 = Grey tide station wide! +figurines-greytider-6 = Viva la revolution. + +figurines-janitor-1 = Clown stole my soap. Again. +figurines-janitor-2 = Look at the signs, you idiot. +figurines-janitor-3 = I've never seen this much lube in my life. +figurines-janitor-4 = Another day, another spill. +figurines-janitor-5 = I'm not even paid for this. +figurines-janitor-6 = This blood wasn't evidence, right? +figurines-janitor-7 = My only friend is my mop. +figurines-janitor-8 = That better not be what I think it is... +figurines-janitor-9 = Another day, another body. + figurines-lawyer-1 = Better Call Saul! figurines-lawyer-2 = Objection! figurines-lawyer-3 = Did you know that you have rights? figurines-lawyer-4 = Space law says! figurines-lawyer-5 = Sign the contract first. -figurines-cargotech-1 = DRAGON ON ATS! -figurines-cargotech-2 = I sold the station! -figurines-cargotech-3 = Brain bounty? I don't have a brain. -figurines-cargotech-4 = You're worth 3000 spesos. Congrats. -figurines-cargotech-5 = Vegetable bounty? Nobody eats those anyways. -figurines-cargotech-6 = WE ARE SECEDING!! ALL HAIL CARGONIA!! - -figurines-salvage-1 = Megafauna? It was mega easy. -figurines-salvage-2 = We're lost. Anyone bring a GPS? -figurines-salvage-3 = Anyone have oxygen? -figurines-salvage-4 = I found a blood-red and e-sword! -figurines-salvage-5 = There's bears in space? -figurines-salvage-6 = Crusher? I barely know her! - -figurines-qm-1 = Who stole the shuttle? -figurines-qm-2 = I won't approve the guns. -figurines-qm-3 = I didn't buy those guns! -figurines-qm-4 = One toys crate for ma fellow clown! -figurines-qm-5 = Time to spent all money on gambling. -figurines-qm-6 = Viva La Cargonia! -figurines-qm-7 = Fill the form. -figurines-qm-8 = Where'd all our money go? -figurines-qm-9 = 99% of gamblers quit right before they hit it big! - -figurines-ce-1 = Everyone to the briefing! -figurines-ce-2 = Wire the solars! -figurines-ce-3 = How to setup the TEG? -figurines-ce-4 = SINGULOOSE! -figurines-ce-5 = TESLOOSE! -figurines-ce-6 = Power's out again. - -figurines-engineer-1 = SINGULOOSE! -figurines-engineer-2 = TESLOOSE! -figurines-engineer-3 = What is AME? -figurines-engineer-4 = Free insuls at Engineering! -figurines-engineer-5 = Where'd the power go? -figurines-engineer-6 = Someone bombed the medbay... again... -figurines-engineer-7 = Well, why don't you come and fix it? - -figurines-atmostech-1 = I put plasma in distro. -figurines-atmostech-2 = I will burn you in a burn chamber. -figurines-atmostech-3 = Frezon... -figurines-atmostech-4 = Tritium... -figurines-atmostech-5 = Glory to Atmosia! -figurines-atmostech-6 = Distro? That's short for disposal. -figurines-atmostech-7 = TEG: Thermal Energy? Gone! - -figurines-rd-1 = Blowing up all of the borgs! -figurines-rd-2 = Tier 3 Arsenal? No way. -figurines-rd-3 = Now where did I leave my hardsuit...? -figurines-rd-4 = Now you're thinking with portals! -figurines-rd-5 = The cake is a lie! -figurines-rd-6 = The trait I look for in a scientist is expendability. - -figurines-scientist-1 = Someone else must have made those bombs! -figurines-scientist-2 = He asked to be borged! -figurines-scientist-3 = Carp at sci! -figurines-scientist-4 = Explosion at sci! -figurines-scientist-5 = Anyone seen an anomaly? -figurines-scientist-6 = The anomaly exploded! - -figurines-cmo-1 = Suit sensors! -figurines-cmo-2 = Why do we have meth? -figurines-cmo-3 = Who drank all the chems? -figurines-cmo-4 = Desoxyephedrine? Sounds healthy. -figurines-cmo-5 = No, you're not getting my hypospray. - -figurines-chemist-1 = Get your pills! -figurines-chemist-2 = We need to cook. -figurines-chemist-3 = I am the one who knocks! -figurines-chemist-4 = Say my name. -figurines-chemist-5 = 99.8% purity. -figurines-chemist-6 = Epinephrine? Didn't you say methamphetamine? - -figurines-paramedic-1 = Insuls and tools! -figurines-paramedic-2 = I need AA for saving people! -figurines-paramedic-3 = SUIT SENSORS!! -figurines-paramedic-4 = I need the hypospray for saving people! -figurines-paramedic-5 = 14 dead in the clown's room. - -figurines-doctor-1 = The patient is already dead! -figurines-doctor-2 = CLEAR! -figurines-doctor-3 = Saw makes BRRR. -figurines-doctor-4 = Just a week away... -figurines-doctor-5 = I knew it... - figurines-librarian-1 = Silence! figurines-librarian-2 = One day while... figurines-librarian-3 = Once upon a time... @@ -201,62 +223,33 @@ figurines-librarian-12 = Gather round... figurines-librarian-13 = ...It's a tale as old as time... figurines-librarian-14 = ...That's all she wrote. -figurines-chaplain-1 = Would you like to join my cul- I mean religion. -figurines-chaplain-2 = Gods make me a killing machine please! -figurines-chaplain-3 = God exists! -figurines-chaplain-4 = Those aren't blood runes, I drew them in crayon. -figurines-chaplain-5 = Anyone want to be sacrificed? -figurines-chaplain-6 = Vampires aren't real. +figurines-mime-1 = ... +figurines-mime-2 = ... +figurines-mime-3 = .... +figurines-mime-4 = ....... +figurines-mime-5 = ................ +figurines-mime-6 = ...........? +figurines-mime-7 = !!! +figurines-mime-8 = ....! +figurines-mime-9 = ??? -figurines-chef-1 = I swear it's not human meat. -figurines-chef-2 = More banana cream pies? -figurines-chef-3 = How does rotary sushi sound? -figurines-chef-4 = That'll be 1000 spesos -figurines-chef-5 = For here or to go? -figurines-chef-6 = Where'd Pun Pun go? No idea... +figurines-musician-1 = Never gonna give you up! +figurines-musician-2 = Never gonna let you down! +figurines-musician-3 = Music is an art. +figurines-musician-4 = Thank you, I'll be here all night. +figurines-musician-5 = I'm a one man band. -figurines-bartender-1 = Where's my monkey? -figurines-bartender-2 = Sec won't drink. -figurines-bartender-3 = I mixed a little something in there... -figurines-bartender-4 = The recipe? Plasma and vomit. Why? -figurines-bartender-5 = I need those toxins for my drinks, officer! -figurines-bartender-6 = Read the room. -figurines-bartender-7 = I've got a shotgun. +figurines-passenger-1 = Insuls please. +figurines-passenger-2 = Call evac. +figurines-passenger-3 = HELP MAINTS!! +figurines-passenger-4 = I'm no tider. +figurines-passenger-5 = How much for a toolbelt? -figurines-botanist-1 = I don't have any weed, officer! -figurines-botanist-2 = Dude, I see colors... -figurines-botanist-3 = Is it just me, or is that weed glowing? -figurines-botanist-4 = 50 more units of mutagen. That should be enough. -figurines-botanist-5 = More bananas for my favorite clown! +# Silicon -figurines-janitor-1 = Clown stole my soap. Again. -figurines-janitor-2 = Look at the signs, you idiot. -figurines-janitor-3 = I've never seen this much lube in my life. -figurines-janitor-4 = Another day, another spill. -figurines-janitor-5 = I'm not even paid for this. -figurines-janitor-6 = This blood wasn't evidence, right? -figurines-janitor-7 = My only friend is my mop. -figurines-janitor-8 = That better not be what I think it is... -figurines-janitor-9 = Another day, another body. +# ...no voiced silicon figures at the moment. -figurines-nukie-1 = I got the disk! -figurines-nukie-2 = Whiskey, Echo, Whiskey. -figurines-nukie-3 = The nuke makes boom. -figurines-nukie-4 = What's the code? -figurines-nukie-5 = Commander...? ...That's a balloon... - -figurines-nukie-elite-1 = Not a word in Nanotrasen. -figurines-nukie-elite-2 = THAT'S A KEG! -figurines-nukie-elite-3 = Guys, are you alive? -figurines-nukie-elite-4 = Breach and clear! -figurines-nukie-elite-5 = Leave no survivors. -figurines-nukie-elite-6 = Good work, team. - -figurines-nukie-commander-1 = GET DAT FUKKEN DISK! -figurines-nukie-commander-2 = Fuckin' flukies. -figurines-nukie-commander-3 = The Syndicate sends its regards. -figurines-nukie-commander-4 = Failure is not an option. -figurines-nukie-commander-5 = Whoops. +# Antagonists figurines-footsoldier-1 = I'm an evil boy. Less boy every day, more evil every day. figurines-footsoldier-2 = Who will you choose? Them or us? Us or them? @@ -264,16 +257,32 @@ figurines-footsoldier-3 = Glory to the Syndicate! figurines-footsoldier-4 = Down with Nanotrasen! figurines-footsoldier-5 = I'd rather die than join Nanotrasen. -figurines-wizard-1 = Ei Nath!! -figurines-wizard-2 = Real wizards support trans rights. -figurines-wizard-3 = Skidaddle skadoodle! -figurines-wizard-4 = FIREBALL! +figurines-holoclown-1 = I'm helping my older brother. +figurines-holoclown-2 = Hello, officer! +figurines-holoclown-3 = Who are you calling blue? +figurines-holoclown-4 = Bleeding on the ground is a good look for you. +figurines-holoclown-5 = Pathetic. +figurines-holoclown-6 = It's not them you need to worry about; it's me. +figurines-holoclown-7 = What's so funny? -figurines-space-dragon-1 = Fish will consume the station. -figurines-space-dragon-2 = Dragon de- Actually, nevermind. -figurines-space-dragon-3 = Crew is delicious. -figurines-space-dragon-4 = Don't you dare make sushi. -figurines-space-dragon-5 = This station ain't big enough for the two of us. +figurines-nukie-1 = I got the disk! +figurines-nukie-2 = Whiskey, Echo, Whiskey. +figurines-nukie-3 = The nuke makes boom. +figurines-nukie-4 = What's the code? +figurines-nukie-5 = Commander...? ...That's a balloon... + +figurines-nukie-commander-1 = GET DAT FUKKEN DISK! +figurines-nukie-commander-2 = Fuckin' flukies. +figurines-nukie-commander-3 = The Syndicate sends its regards. +figurines-nukie-commander-4 = Failure is not an option. +figurines-nukie-commander-5 = Whoops. + +figurines-nukie-elite-1 = Not a word in Nanotrasen. +figurines-nukie-elite-2 = THAT'S A KEG! +figurines-nukie-elite-3 = Guys, are you alive? +figurines-nukie-elite-4 = Breach and clear! +figurines-nukie-elite-5 = Leave no survivors. +figurines-nukie-elite-6 = Good work, team. figurines-queen-1 = Our domain must grow. figurines-queen-2 = The hive hungers. @@ -295,6 +304,40 @@ figurines-rat-servant-3 = The boss wants a word with youse. figurines-rat-servant-4 = Ay, I'm walkin' here! figurines-rat-servant-5 = You get the chedda', then we talk. +figurines-space-dragon-1 = Fish will consume the station. +figurines-space-dragon-2 = Dragon de- Actually, nevermind. +figurines-space-dragon-3 = Crew is delicious. +figurines-space-dragon-4 = Don't you dare make sushi. +figurines-space-dragon-5 = This station ain't big enough for the two of us. + +figurines-skeleton-1 = ACK ACK! +figurines-skeleton-2 = Ugh, that locker was cramped! +figurines-skeleton-3 = You're going to have a bad time. +figurines-skeleton-4 = Got any milk? +figurines-skeleton-5 = I have a bone to pick with you! + +figurines-thief-1 = You don't have a warrant! +figurines-thief-2 = This is just a normal beacon! +figurines-thief-3 = Theres nothing suspicious about this satchel at all, officer. +figurines-thief-4 = I have NO idea where your pet is... +figurines-thief-5 = Huh, I didn't know that wall could open up... + +figurines-wizard-1 = Ei Nath!! +figurines-wizard-2 = Real wizards support trans rights. +figurines-wizard-3 = Skidaddle skadoodle! +figurines-wizard-4 = FIREBALL! + +# Animals + +figurines-hamlet-1 = Piep! +figurines-hamlet-2 = Squeak! +figurines-hamlet-3 = Chuu! +figurines-hamlet-4 = Eeee! +figurines-hamlet-5 = Pip! +figurines-hamlet-6 = Fwiep! +figurines-hamlet-7 = Heep! +figurines-hamlet-8 = NOT THE MICROWAVE! + figurines-mouse-1 = Piep! figurines-mouse-2 = Squeak! figurines-mouse-3 = Chuu! @@ -308,35 +351,16 @@ figurines-slime-2 = Blimpuf? figurines-slime-3 = Blump! figurines-slime-4 = Squish! -figurines-hamlet-1 = Piep! -figurines-hamlet-2 = Squeak! -figurines-hamlet-3 = Chuu! -figurines-hamlet-4 = Eeee! -figurines-hamlet-5 = Pip! -figurines-hamlet-6 = Fwiep! -figurines-hamlet-7 = Heep! -figurines-hamlet-8 = NOT THE MICROWAVE! - -figurines-thief-1 = You don't have a warrant! -figurines-thief-2 = This is just a normal beacon! -figurines-thief-3 = Theres nothing suspicious about this satchel at all, officer. -figurines-thief-4 = I have NO idea where your pet is... -figurines-thief-5 = Huh, I didn't know that wall could open up... - -figurines-skeleton-1 = ACK ACK! -figurines-skeleton-2 = Ugh, that locker was cramped! -figurines-skeleton-3 = You're going to have a bad time. -figurines-skeleton-4 = Got any milk? -figurines-skeleton-5 = I have a bone to pick with you! - -figurines-owlman-1 = No need to fear, Owlman is here! -figurines-owlman-2 = Owl be seeing you later! -figurines-owlman-3 = HOOT!! -figurines-owlman-4 = What do you call an owl magician, HOO-DINI! -figurines-owlman-5 = Don't worry citizen, I'll save the day! +# Other figurines-griffin-1 = MUHAHAHAHA, I am so evil!! figurines-griffin-2 = The second I see Owlman, they are so dead!! figurines-griffin-3 = How do us Griffins deal with stress? We wing it! figurines-griffin-4 = My name isn't Gilda!! figurines-griffin-5 = Being a criminal mastermind, isn't easy. + +figurines-owlman-1 = No need to fear, Owlman is here! +figurines-owlman-2 = Owl be seeing you later! +figurines-owlman-3 = HOOT!! +figurines-owlman-4 = What do you call an owl magician, HOO-DINI! +figurines-owlman-5 = Don't worry citizen, I'll save the day! From 0c4c101cb512ff59138ac2063265feac2f6f75a2 Mon Sep 17 00:00:00 2001 From: Minerva <218184747+mnva0@users.noreply.github.com> Date: Thu, 4 Dec 2025 11:55:03 -0500 Subject: [PATCH 022/360] Allows spesos to fit in envelopes (#41700) Co-authored-by: ScarKy0 --- Resources/Prototypes/Entities/Objects/Misc/paper.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Resources/Prototypes/Entities/Objects/Misc/paper.yml b/Resources/Prototypes/Entities/Objects/Misc/paper.yml index 89deedf812..890642ad0d 100644 --- a/Resources/Prototypes/Entities/Objects/Misc/paper.yml +++ b/Resources/Prototypes/Entities/Objects/Misc/paper.yml @@ -421,6 +421,8 @@ insertSound: /Audio/Effects/packetrip.ogg ejectSound: /Audio/Effects/packetrip.ogg whitelist: + components: + - Cash tags: - Paper - type: ActivatableUI From 5d496b92d92d86b0e29c988025244de10ef0a123 Mon Sep 17 00:00:00 2001 From: SlamBamActionman <83650252+SlamBamActionman@users.noreply.github.com> Date: Thu, 4 Dec 2025 18:52:56 +0100 Subject: [PATCH 023/360] Change Ephedrine, Desoxyephedrine and Hyperzine properties (#41693) * merff (no numbness) * I can't feel a thing * Update self-damage and OD values * Missed a 5 --- .../Locale/en-US/store/uplink-catalog.ftl | 4 +- .../Entities/StatusEffects/body.yml | 4 + Resources/Prototypes/Reagents/narcotics.yml | 172 ++++++++++-------- 3 files changed, 106 insertions(+), 74 deletions(-) diff --git a/Resources/Locale/en-US/store/uplink-catalog.ftl b/Resources/Locale/en-US/store/uplink-catalog.ftl index a3a68132f2..736e1e21f3 100644 --- a/Resources/Locale/en-US/store/uplink-catalog.ftl +++ b/Resources/Locale/en-US/store/uplink-catalog.ftl @@ -405,10 +405,10 @@ uplink-nocturine-chemistry-bottle-name = Nocturine Bottle uplink-nocturine-chemistry-bottle-desc = A chemical that puts your target straight to sleep. uplink-stimpack-name = Hyperzine Injector -uplink-stimpack-desc = The legendary chemical produced by Donk Co. for the Syndicate. Injecting yourself with this will increase your run speed and let you recover from stuns faster for 30 seconds. +uplink-stimpack-desc = The legendary chemical produced by Donk Co. for the Syndicate. Injecting yourself with this will increase your run speed and let you recover from stuns faster for 60 seconds. uplink-stimkit-name = Hyperzine Injector Kit -uplink-stimkit-desc = A medkit containing 6 hyperzine microinjectors, which each inject you with enough hyperzine to last for 15 seconds. +uplink-stimkit-desc = A medkit containing 6 hyperzine microinjectors, which each inject you with enough hyperzine to last for 30 seconds. uplink-syndicate-segway-crate-name = Syndicate Segway uplink-syndicate-segway-crate-desc = Be an enemy of the corporation, in style! diff --git a/Resources/Prototypes/Entities/StatusEffects/body.yml b/Resources/Prototypes/Entities/StatusEffects/body.yml index 4c94804884..6b6f704a2c 100644 --- a/Resources/Prototypes/Entities/StatusEffects/body.yml +++ b/Resources/Prototypes/Entities/StatusEffects/body.yml @@ -27,3 +27,7 @@ - MobState - MobThresholds - type: PainNumbnessStatusEffect + +- type: entity + parent: PainNumbnessTraitStatusEffect + id: StatusEffectPainNumbness diff --git a/Resources/Prototypes/Reagents/narcotics.yml b/Resources/Prototypes/Reagents/narcotics.yml index c290ac0a24..bb025f4c24 100644 --- a/Resources/Prototypes/Reagents/narcotics.yml +++ b/Resources/Prototypes/Reagents/narcotics.yml @@ -4,44 +4,54 @@ group: Narcotics desc: reagent-desc-desoxyephedrine physicalDesc: reagent-physical-desc-translucent - contrabandSeverity: Major + contrabandSeverity: Minor flavor: bitter color: "#FAFAFA" boilingPoint: 212.0 # Dexosyephedrine vape when? meltingPoint: 170.0 metabolisms: Poison: + # Main effects effects: - !type:HealthChange damage: types: - Poison: 0.75 + Poison: 0.55 + Blunt: 0.5 Cellular: 1 # DeltaV - meth rots you just like in real life :D + # OD - !type:HealthChange conditions: - !type:ReagentCondition reagent: Desoxyephedrine - min: 30 + min: 16 damage: types: - Poison: 2 # this is added to the base damage of the meth. + Poison: 3 # this is added to the base damage of the meth. Asphyxiation: 2 Narcotic: effects: + # Main effects - !type:MovementSpeedModifier - walkSpeedModifier: 1.35 - sprintSpeedModifier: 1.35 + walkSpeedModifier: 1.20 + sprintSpeedModifier: 1.20 + - !type:GenericStatusEffect + key: StaminaModifier # You are on meth. You keep going. + component: StaminaModifier + time: 3 + - !type:GenericStatusEffect + key: Adrenaline + component: IgnoreSlowOnDamage + time: 3 + # Side effects + - !type:Jitter - !type:GenericStatusEffect key: Stutter component: StutteringAccent - - !type:Jitter - !type:ModifyStatusEffect - effectProto: StatusEffectStunned - time: 3 - type: Remove - - !type:ModifyKnockdown - time: 3 - type: Remove + effectProto: StatusEffectPainNumbness + time: 2 + # Interactions - !type:ModifyStatusEffect conditions: - !type:ReagentCondition @@ -59,11 +69,12 @@ - !type:SuppressAddiction Medicine: effects: + # Side effects - !type:ResetNarcolepsy conditions: - !type:ReagentCondition reagent: Desoxyephedrine - min: 20 + min: 5 - type: reagent id: Ephedrine @@ -71,7 +82,6 @@ group: Narcotics desc: reagent-desc-ephedrine physicalDesc: reagent-physical-desc-powdery - contrabandSeverity: Minor flavor: bitter color: "#D2FFFA" boilingPoint: 255.0 @@ -79,19 +89,10 @@ metabolisms: Narcotic: effects: + # Main effects - !type:MovementSpeedModifier - walkSpeedModifier: 1.25 - sprintSpeedModifier: 1.25 - - !type:HealthChange - conditions: - - !type:ReagentCondition - reagent: Ephedrine - min: 20 - damage: - types: - Poison: 2 # this is added to the base damage of the meth. - Asphyxiation: 2 - - !type:Jitter + walkSpeedModifier: 1.15 + sprintSpeedModifier: 1.15 - !type:ModifyStatusEffect effectProto: StatusEffectStunned time: 1 @@ -99,6 +100,24 @@ - !type:ModifyKnockdown time: 1 type: Remove + # Side effects + - !type:Jitter + - !type:PopupMessage + visualType: Medium + messages: ["ephedrine-effect-tight-pain", "ephedrine-effect-heart-pounds"] + type: Local + probability: 0.05 + # OD + - !type:HealthChange + conditions: + - !type:ReagentCondition + reagent: Ephedrine + min: 20 + damage: + types: + Poison: 2 + Asphyxiation: 2 + # Interactions - !type:ModifyStatusEffect conditions: - !type:ReagentCondition @@ -107,18 +126,14 @@ effectProto: StatusEffectDrowsiness time: 10 type: Remove - - !type:PopupMessage - visualType: Medium - messages: ["ephedrine-effect-tight-pain", "ephedrine-effect-heart-pounds"] - type: Local - probability: 0.05 Medicine: effects: + # Side effects - !type:ResetNarcolepsy conditions: - !type:ReagentCondition reagent: Ephedrine - min: 30 + min: 15 - type: reagent id: Stimulants @@ -133,41 +148,38 @@ meltingPoint: 170.0 metabolisms: Narcotic: - metabolismRate: 1.0 effects: + # Main effects - !type:MovementSpeedModifier - walkSpeedModifier: 1.3 - sprintSpeedModifier: 1.3 - - !type:HealthChange - conditions: - - !type:ReagentCondition - reagent: Stimulants - min: 80 #please wait 3 minutes before using another stimpack - damage: - types: - Poison: 1 - - !type:AdjustReagent - conditions: - - !type:ReagentCondition - reagent: ChloralHydrate - min: 1 - reagent: ChloralHydrate - amount: -10 + walkSpeedModifier: 1.25 + sprintSpeedModifier: 1.25 - !type:ModifyStatusEffect effectProto: StatusEffectStunned - time: 3 + time: 3.5 type: Remove - !type:ModifyKnockdown - time: 3 + time: 3.5 type: Remove - - !type:GenericStatusEffect - key: StaminaModifier - component: StaminaModifier - time: 3 - !type:ModifyStatusEffect effectProto: StatusEffectForcedSleeping time: 3 type: Remove + - !type:GenericStatusEffect + key: Adrenaline + component: IgnoreSlowOnDamage + time: 3 + # Side effects + - !type:Jitter + # OD + - !type:HealthChange + conditions: + - !type:ReagentCondition + reagent: Stimulants + min: 50 + damage: + types: + Poison: 1 + # Interactions - !type:ModifyStatusEffect conditions: - !type:ReagentCondition @@ -176,22 +188,38 @@ effectProto: StatusEffectDrowsiness time: 10 type: Remove + - !type:AdjustReagent + conditions: + - !type:ReagentCondition + reagent: ChloralHydrate + min: 1 + reagent: ChloralHydrate + amount: -10 Medicine: - metabolismRate: 1.0 effects: - - !type:ResetNarcolepsy - - !type:SatiateHunger - factor: 1 - - !type:SatiateThirst - factor: 1 - - !type:HealthChange - conditions: - - !type:TotalDamageCondition - min: 70 # only heals when you're more dead than alive - damage: # heals at the same rate as tricordrazine, doesn't heal poison because if you OD'd I'm not giving you a safety net - groups: - Burn: -1 - Brute: -1 + # Main effects + - !type:ModifyBleed + amount: -1.5 + - !type:EvenHealthChange + conditions: + - !type:TotalDamageCondition + min: 70 # only heals when you're more dead than alive + damage: # Doesn't heal poison because if you OD'd I'm not giving you a safety net + Burn: -0.5 + Brute: -0.5 + - !type:HealthChange + conditions: + - !type:TotalDamageCondition + min: 95 # Just to bring you back from the brink of death + damage: + types: + Asphyxiation: -2 + # Side effects + - !type:ResetNarcolepsy + - !type:SatiateHunger + factor: 1 + - !type:SatiateThirst + factor: 1 - type: reagent id: THC @@ -215,7 +243,7 @@ time: 16 type: Add # Delta-V - Addictive - - !type:Addicting + - !type:Addicting probability: 0.4 # Chance of Addiction rising per tick conditions: - !type:ReagentCondition From 376d1cdafc7cb30a67886668fb20acf793f7d625 Mon Sep 17 00:00:00 2001 From: ScarKy0 <106310278+ScarKy0@users.noreply.github.com> Date: Fri, 5 Dec 2025 01:42:03 +0100 Subject: [PATCH 024/360] Warfarin and Hemorrhinol, Hemophilia turned into a StatusEffect (#41685) * init * yeah * move folders * comments * i hate cloning sometimes * review * review squred * fix stuff --- .../StatusEffectSystem.Relay.cs | 3 ++ .../Traits/Assorted/HemophiliaComponent.cs | 16 -------- .../HemophiliaStatusEffectComponent.cs | 22 +++++++++++ .../Traits/Assorted/HemophiliaSystem.cs | 10 +++-- .../Locale/en-US/reagents/meta/medicine.ftl | 3 ++ .../Locale/en-US/reagents/meta/toxins.ftl | 3 ++ .../Prototypes/Entities/Mobs/Player/clone.yml | 1 - .../Entities/StatusEffects/body.yml | 37 +++++++++++++++++-- Resources/Prototypes/Reagents/medicine.yml | 24 ++++++++++++ Resources/Prototypes/Reagents/toxins.yml | 19 ++++++++++ .../Prototypes/Recipes/Reactions/medicine.yml | 26 ++++++++++++- Resources/Prototypes/Traits/disabilities.yml | 19 ++++++---- 12 files changed, 151 insertions(+), 32 deletions(-) delete mode 100644 Content.Shared/Traits/Assorted/HemophiliaComponent.cs create mode 100644 Content.Shared/Traits/Assorted/HemophiliaStatusEffectComponent.cs diff --git a/Content.Shared/StatusEffectNew/StatusEffectSystem.Relay.cs b/Content.Shared/StatusEffectNew/StatusEffectSystem.Relay.cs index 9b16aadff0..30c5d9f67e 100644 --- a/Content.Shared/StatusEffectNew/StatusEffectSystem.Relay.cs +++ b/Content.Shared/StatusEffectNew/StatusEffectSystem.Relay.cs @@ -1,3 +1,4 @@ +using Content.Shared.Body.Events; using Content.Shared.Damage.Events; using Content.Shared.Mobs.Events; using Content.Shared.Movement.Events; @@ -31,6 +32,8 @@ public sealed partial class StatusEffectsSystem SubscribeLocalEvent(RelayStatusEffectEvent); SubscribeLocalEvent(RelayStatusEffectEvent); + + SubscribeLocalEvent(RefRelayStatusEffectEvent); } private void RefRelayStatusEffectEvent(EntityUid uid, StatusEffectContainerComponent component, ref T args) where T : struct diff --git a/Content.Shared/Traits/Assorted/HemophiliaComponent.cs b/Content.Shared/Traits/Assorted/HemophiliaComponent.cs deleted file mode 100644 index 208883f11c..0000000000 --- a/Content.Shared/Traits/Assorted/HemophiliaComponent.cs +++ /dev/null @@ -1,16 +0,0 @@ -using Robust.Shared.GameStates; - -namespace Content.Shared.Traits.Assorted; - -/// -/// This component is used for the Hemophilia Trait, it reduces the passive bleed stack reduction amount so entities with it bleed for longer. -/// -[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] -public sealed partial class HemophiliaComponent : Component -{ - /// - /// What multiplier should be applied to the BleedReduction when an entity bleeds? - /// - [DataField, AutoNetworkedField] - public float HemophiliaBleedReductionMultiplier = 0.33f; -} diff --git a/Content.Shared/Traits/Assorted/HemophiliaStatusEffectComponent.cs b/Content.Shared/Traits/Assorted/HemophiliaStatusEffectComponent.cs new file mode 100644 index 0000000000..3216052257 --- /dev/null +++ b/Content.Shared/Traits/Assorted/HemophiliaStatusEffectComponent.cs @@ -0,0 +1,22 @@ +using Robust.Shared.GameStates; + +namespace Content.Shared.Traits.Assorted; + +/// +/// This component is used for the Hemophilia Trait, it reduces the passive bleed stack reduction amount so entities with it bleed for longer. +/// +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +public sealed partial class HemophiliaStatusEffectComponent : Component +{ + /// + /// Multiplier to use for the amount of bloodloss reduction during a bleed tick. + /// + [DataField, AutoNetworkedField] + public float BleedReductionMultiplier = 0.33f; + + /// + /// Multiplier to use for the amount of blood lost during a bleed tick. + /// + [DataField, AutoNetworkedField] + public float BleedAmountMultiplier = 1f; +} diff --git a/Content.Shared/Traits/Assorted/HemophiliaSystem.cs b/Content.Shared/Traits/Assorted/HemophiliaSystem.cs index 53f6609575..4544007ac7 100644 --- a/Content.Shared/Traits/Assorted/HemophiliaSystem.cs +++ b/Content.Shared/Traits/Assorted/HemophiliaSystem.cs @@ -1,4 +1,5 @@ using Content.Shared.Body.Events; +using Content.Shared.StatusEffectNew; namespace Content.Shared.Traits.Assorted; @@ -6,11 +7,14 @@ public sealed class HemophiliaSystem : EntitySystem { public override void Initialize() { - SubscribeLocalEvent(OnBleedModifier); + SubscribeLocalEvent>(OnBleedModifier); } - private void OnBleedModifier(Entity ent, ref BleedModifierEvent args) + private void OnBleedModifier(Entity ent, ref StatusEffectRelayedEvent args) { - args.BleedReductionAmount *= ent.Comp.HemophiliaBleedReductionMultiplier; + var ev = args.Args; + ev.BleedReductionAmount *= ent.Comp.BleedReductionMultiplier; + ev.BleedAmount *= ent.Comp.BleedAmountMultiplier; + args.Args = ev; } } diff --git a/Resources/Locale/en-US/reagents/meta/medicine.ftl b/Resources/Locale/en-US/reagents/meta/medicine.ftl index 7d71b43c1d..3a675dc3f4 100644 --- a/Resources/Locale/en-US/reagents/meta/medicine.ftl +++ b/Resources/Locale/en-US/reagents/meta/medicine.ftl @@ -156,3 +156,6 @@ reagent-desc-haloperidol = Removes most stimulating and hallucinogenic drugs. Re reagent-name-stelloxadone = stelloxadone reagent-desc-stelloxadone = A cryogenics chemical. Used to aggressively dissolve toxins from the body. Works regardless of the patient being alive or dead. + +reagent-name-warfarin = warfarin +reagent-desc-warfarin = Commonly used as an anticoagulant medication. Causes blood to have difficulty forming clots. Can cause internal bleeding when overdosed. diff --git a/Resources/Locale/en-US/reagents/meta/toxins.ftl b/Resources/Locale/en-US/reagents/meta/toxins.ftl index c0cf06fe26..5c4657d34b 100644 --- a/Resources/Locale/en-US/reagents/meta/toxins.ftl +++ b/Resources/Locale/en-US/reagents/meta/toxins.ftl @@ -84,3 +84,6 @@ reagent-desc-mechanotoxin = A neurotoxin used as venom by some species of spider reagent-name-toxintrash = reprocessed material reagent-desc-toxintrash = An awful-smelling slurry efficiently refined from discarded matter. It represents a perfect, zero-waste conversion of salvage into Vox sustenance, though it is a violent poison to others. + +reagent-name-hemorrhinol = hemorrhinol +reagent-desc-hemorrhinol = A toxin that causes severe damage to blood vessels, causing rapid bleeding. diff --git a/Resources/Prototypes/Entities/Mobs/Player/clone.yml b/Resources/Prototypes/Entities/Mobs/Player/clone.yml index 6b0af7e86b..b5572e53d7 100644 --- a/Resources/Prototypes/Entities/Mobs/Player/clone.yml +++ b/Resources/Prototypes/Entities/Mobs/Player/clone.yml @@ -16,7 +16,6 @@ # traits - BlackAndWhiteOverlay - Clumsy - - Hemophilia - ImpairedMobility # - LegsParalyzed (you get healed) - LightweightDrunk diff --git a/Resources/Prototypes/Entities/StatusEffects/body.yml b/Resources/Prototypes/Entities/StatusEffects/body.yml index 6b6f704a2c..739c9c3b22 100644 --- a/Resources/Prototypes/Entities/StatusEffects/body.yml +++ b/Resources/Prototypes/Entities/StatusEffects/body.yml @@ -9,13 +9,19 @@ - Bloodstream - type: entity - parent: [ BloodstreamStatusEffectBase ] + parent: BloodstreamStatusEffectBase + id: BloodstreamStatusEffectDebuff + abstract: true + components: + - type: RejuvenateRemovedStatusEffect + +- type: entity + parent: BloodstreamStatusEffectDebuff id: StatusEffectBloodloss name: bloodloss components: - type: StutteringAccent - type: DrunkStatusEffect - - type: RejuvenateRemovedStatusEffect - type: entity parent: MobStatusEffectBase @@ -29,5 +35,30 @@ - type: PainNumbnessStatusEffect - type: entity - parent: PainNumbnessTraitStatusEffect + parent: BloodstreamStatusEffectBase + id: StatusEffectHemophiliaTrait + components: + - type: HemophiliaStatusEffect + +- type: entity + parent: BloodstreamStatusEffectDebuff + id: StatusEffectAnticoagulant # Decreases the amount of blood coagulation when bleeding. + name: thin blood + components: + - type: HemophiliaStatusEffect + bleedReductionMultiplier: 0.33 + bleedAmountMultiplier: 1 + +- type: entity + parent: BloodstreamStatusEffectDebuff + id: StatusEffectHemorrhage # Increases the amount of blood lost when bleeding. + name: hemorrhage + components: + - type: HemophiliaStatusEffect + bleedReductionMultiplier: 1 # We don't want it to also reduce coagulation, it would stack with Anticoagulant. + bleedAmountMultiplier: 1.33 + +- type: entity + parent: [ PainNumbnessTraitStatusEffect, MobStatusEffectDebuff ] id: StatusEffectPainNumbness + name: pain numbness diff --git a/Resources/Prototypes/Reagents/medicine.yml b/Resources/Prototypes/Reagents/medicine.yml index 4a51ebd26e..bda7d27e07 100644 --- a/Resources/Prototypes/Reagents/medicine.yml +++ b/Resources/Prototypes/Reagents/medicine.yml @@ -1558,3 +1558,27 @@ - !type:AdjustReagent reagent: MindbreakerToxin amount: -3.0 + +- type: reagent + id: Warfarin + name: reagent-name-warfarin + group: Medicine + desc: reagent-desc-warfarin + physicalDesc: reagent-physical-desc-thin + allowedDepartments: + - Medical + flavor: medicine + color: "#d0e21b" + metabolisms: + Medicine: + effects: # One day this could be useful for treating blood clots, if we get those + - !type:ModifyStatusEffect + effectProto: StatusEffectAnticoagulant + time: 30 # 10 bleed ticks, you bleed every 3 seconds by default. + type: Update + - !type:ModifyBleed + conditions: + - !type:ReagentCondition + reagent: Warfarin + min: 15 + amount: 0.25 diff --git a/Resources/Prototypes/Reagents/toxins.yml b/Resources/Prototypes/Reagents/toxins.yml index a582b28561..daf0d9554f 100644 --- a/Resources/Prototypes/Reagents/toxins.yml +++ b/Resources/Prototypes/Reagents/toxins.yml @@ -776,3 +776,22 @@ conditions: - !type:MetabolizerTypeCondition type: [Vox] + +- type: reagent + id: Hemorrhinol + name: reagent-name-hemorrhinol + group: Toxins + desc: reagent-desc-hemorrhinol + physicalDesc: reagent-physical-desc-thin + contrabandSeverity: Major + flavor: sharp + color: "#96424f" + metabolisms: + Poison: + effects: + - !type:ModifyStatusEffect + effectProto: StatusEffectHemorrhage + time: 21 # 7 bleed ticks, you bleed every 3 seconds by default. + type: Update + - !type:ModifyBleed + amount: 0.5 diff --git a/Resources/Prototypes/Recipes/Reactions/medicine.yml b/Resources/Prototypes/Recipes/Reactions/medicine.yml index 5b8af49e20..46289b6b4c 100644 --- a/Resources/Prototypes/Recipes/Reactions/medicine.yml +++ b/Resources/Prototypes/Recipes/Reactions/medicine.yml @@ -691,7 +691,7 @@ amount: 1 products: Traumoxadone: 3 - + - type: reaction id: Stelloxadone impact: Medium @@ -706,3 +706,27 @@ Stelloxadone: 5 Water: 3 Fiber: 2 + +- type: reaction + id: Warfarin + reactants: + SulfuricAcid: + amount: 1 + Nitrogen: + amount: 1 + Sodium: + amount: 1 + products: + Warfarin: 2 + +- type: reaction + id: Hemorrhinol + reactants: + Warfarin: + amount: 2 + Razorium: + amount: 2 + Plasma: + amount: 1 + products: + Hemorrhinol: 2 diff --git a/Resources/Prototypes/Traits/disabilities.yml b/Resources/Prototypes/Traits/disabilities.yml index b9a8e1fd54..3ff8529607 100644 --- a/Resources/Prototypes/Traits/disabilities.yml +++ b/Resources/Prototypes/Traits/disabilities.yml @@ -93,18 +93,21 @@ # - PainNumbnessTraitStatusEffect # #- type: trait +# id: Hemophilia +# name: trait-hemophilia-name +# description: trait-hemophilia-desc +# category: Disabilities +# specials: +# - !type:ApplyStatusEffectSpecial +# statusEffects: +# - StatusEffectHemophiliaTrait +# +#- type: trait # id: ImpairedMobility # name: trait-impaired-mobility-name # description: trait-impaired-mobility-desc # traitGear: OffsetCane # category: Disabilities # components: -# - type: ImpairedMobility +# - type: ImpairedMobility # -#- type: trait -# id: Hemophilia -# name: trait-hemophilia-name -# description: trait-hemophilia-desc -# category: Disabilities -# components: -# - type: Hemophilia From b671ea6b1005bfd5b5664643c203bb367215d6f3 Mon Sep 17 00:00:00 2001 From: BarryNorfolk Date: Sat, 24 Jan 2026 16:35:56 +0100 Subject: [PATCH 025/360] Downstream fix for Hemophilia status effect change --- Resources/Prototypes/_DV/Traits/disabilities.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Resources/Prototypes/_DV/Traits/disabilities.yml b/Resources/Prototypes/_DV/Traits/disabilities.yml index b021d5c9ca..1c2762b152 100644 --- a/Resources/Prototypes/_DV/Traits/disabilities.yml +++ b/Resources/Prototypes/_DV/Traits/disabilities.yml @@ -127,6 +127,6 @@ description: trait-hemophilia-desc category: Disabilities effects: - - !type:AddCompsEffect - components: - - type: Hemophilia + - !type:ApplyStatusEffect + statusEffects: + - StatusEffectHemophiliaTrait From 37b0a845f30f53391f452dd3c12e86dc26cbc903 Mon Sep 17 00:00:00 2001 From: BarryNorfolk Date: Sat, 24 Jan 2026 11:21:57 +0100 Subject: [PATCH 026/360] Move Stelloxadone ftl and reaction to _Floof namespace --- .../en-US/_Floof/reagents/meta/medicine.ftl | 2 ++ Resources/Locale/en-US/reagents/meta/medicine.ftl | 3 --- .../Prototypes/Recipes/Reactions/medicine.yml | 15 --------------- .../_Floof/Recipes/Reactions/medicine.yml | 14 ++++++++++++++ 4 files changed, 16 insertions(+), 18 deletions(-) create mode 100644 Resources/Locale/en-US/_Floof/reagents/meta/medicine.ftl create mode 100644 Resources/Prototypes/_Floof/Recipes/Reactions/medicine.yml diff --git a/Resources/Locale/en-US/_Floof/reagents/meta/medicine.ftl b/Resources/Locale/en-US/_Floof/reagents/meta/medicine.ftl new file mode 100644 index 0000000000..90d167b28e --- /dev/null +++ b/Resources/Locale/en-US/_Floof/reagents/meta/medicine.ftl @@ -0,0 +1,2 @@ +reagent-name-stelloxadone = stelloxadone +reagent-desc-stelloxadone = A cryogenics chemical. Used to aggressively dissolve toxins from the body. Works regardless of the patient being alive or dead. diff --git a/Resources/Locale/en-US/reagents/meta/medicine.ftl b/Resources/Locale/en-US/reagents/meta/medicine.ftl index 3a675dc3f4..b6240170da 100644 --- a/Resources/Locale/en-US/reagents/meta/medicine.ftl +++ b/Resources/Locale/en-US/reagents/meta/medicine.ftl @@ -154,8 +154,5 @@ reagent-desc-potassium-iodide = Will reduce the damaging effects of radiation by reagent-name-haloperidol = haloperidol reagent-desc-haloperidol = Removes most stimulating and hallucinogenic drugs. Reduces druggy effects and jitteriness. Causes drowsiness. -reagent-name-stelloxadone = stelloxadone -reagent-desc-stelloxadone = A cryogenics chemical. Used to aggressively dissolve toxins from the body. Works regardless of the patient being alive or dead. - reagent-name-warfarin = warfarin reagent-desc-warfarin = Commonly used as an anticoagulant medication. Causes blood to have difficulty forming clots. Can cause internal bleeding when overdosed. diff --git a/Resources/Prototypes/Recipes/Reactions/medicine.yml b/Resources/Prototypes/Recipes/Reactions/medicine.yml index 46289b6b4c..b98accf093 100644 --- a/Resources/Prototypes/Recipes/Reactions/medicine.yml +++ b/Resources/Prototypes/Recipes/Reactions/medicine.yml @@ -692,21 +692,6 @@ products: Traumoxadone: 3 -- type: reaction - id: Stelloxadone - impact: Medium - reactants: - Stellibinin: - amount: 5 - Cryoxadone: - amount: 3 - Arithrazine: - amount: 2 - products: - Stelloxadone: 5 - Water: 3 - Fiber: 2 - - type: reaction id: Warfarin reactants: diff --git a/Resources/Prototypes/_Floof/Recipes/Reactions/medicine.yml b/Resources/Prototypes/_Floof/Recipes/Reactions/medicine.yml new file mode 100644 index 0000000000..0b067204a5 --- /dev/null +++ b/Resources/Prototypes/_Floof/Recipes/Reactions/medicine.yml @@ -0,0 +1,14 @@ +- type: reaction + id: Stelloxadone + impact: Medium + reactants: + Stellibinin: + amount: 5 + Cryoxadone: + amount: 3 + Arithrazine: + amount: 2 + products: + Stelloxadone: 5 + Water: 3 + Fiber: 2 From c9627733c13a1aabfc6504cb0bab9a5a555753f8 Mon Sep 17 00:00:00 2001 From: MissKay1994 <15877268+MissKay1994@users.noreply.github.com> Date: Fri, 5 Dec 2025 05:34:00 -0500 Subject: [PATCH 027/360] Add missing vox unequipped sprite for explorer mask (#41405) Mask on face --- .../Clothing/Mask/gasexplorer.rsi/meta.json | 6 +++++- .../Mask/gasexplorer.rsi/up-equipped-MASK-vox.png | Bin 0 -> 947 bytes 2 files changed, 5 insertions(+), 1 deletion(-) create mode 100644 Resources/Textures/Clothing/Mask/gasexplorer.rsi/up-equipped-MASK-vox.png diff --git a/Resources/Textures/Clothing/Mask/gasexplorer.rsi/meta.json b/Resources/Textures/Clothing/Mask/gasexplorer.rsi/meta.json index baaca1f25f..976c85ed20 100644 --- a/Resources/Textures/Clothing/Mask/gasexplorer.rsi/meta.json +++ b/Resources/Textures/Clothing/Mask/gasexplorer.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e. Reptilian edit by Nairod(Github). Vox state by Flareguy for SS14 | vulpkanin version edited by Floofers. Feroxi sprites made by @Stxcking", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e. Reptilian edit by Nairod(Github). Vox state by Flareguy for SS14 | vulpkanin version edited by Floofers. Feroxi sprites made by @Stxcking | Vox unequipped by MissKay1994(Github)", "size": { "x": 32, "y": 32 @@ -39,6 +39,10 @@ { "name": "equipped-MASK-reptilian", "directions": 4 + }, + { + "name": "up-equipped-MASK-vox", + "directions": 4 } ] } diff --git a/Resources/Textures/Clothing/Mask/gasexplorer.rsi/up-equipped-MASK-vox.png b/Resources/Textures/Clothing/Mask/gasexplorer.rsi/up-equipped-MASK-vox.png new file mode 100644 index 0000000000000000000000000000000000000000..bbf58361038b1c6c2398bb4e63f744a08ebbdd33 GIT binary patch literal 947 zcmV;k15EshP)Px&ZAnByRCt{2nomd+Q5?s=BZ3GrJ0e1kJGt&2TrngpG^xW9brMPh2~95^VqtGf z2tjy=z>9bjqJt+<#LE(R2nsx8h|!)JcRMK7$|x++>|7)eejVg3JKLf=f81C3KBqVT ze((4D&ilPL%=-ZX!KFs3_Qs8k4cl=t5hvE3UwBou9lw~G7%%p}xU^jCKNgEQvQy`# z^JF4Uirj=~BnU-rvWZbklz{BnhGPMei8xtZEoh$}OC9A+v`>$vtge=ti?Fz~ESUw% z_V(T2NB|c6;N(b3*E2AOuBUW8gTcv>nut(3>;d4>(Css?S3|uUM|3@N+F1E8jIleZ z;_(He1Z2FPe@Ot)(bfzAc)PMd-wuBkuj9aQWYduVX2HU(lOVR!nPK_s52W?1)VBh% zx?0eG(ul2s<*0L~m<0>j-GhpgZZZ)k(?$PPr@++2I4J=cTj?G2pEM$^XC(kg>shJ) zq!C-`9fUO1)i87d>$lQ*H$hfd&aAtN+3TY}T&Af|C%hKNvyc-0B?iyb%KMc7QiR0NxJpMhL*$0p47C0bKtQ^9!ec zasB4fj{qTnR|CmJoYg$P8Y1^w^*98*gBolFpMuGre!ujP3g4V(oy}eL^BaL~AEj zhp=6LjE=TuL?c1mxYkWxgNI)!z=B`P8@AekkfwTeFr=xrI)t^nQ53@8M&=-?Z6xi{}&w2USu6GFI0&0RW?| zDh7Hx|G3ZV2hTunr!9CTAR`=9`K17Z)diG_0Kk{GQ)+8BY0BR6gYWgosd@t`V)BLYj*AA3sTctONpqKp+qZ1OkCTAP@)y0)gQ2@Egq| VXtvYfgDn66002ovPDHLkV1iEyuo?gW literal 0 HcmV?d00001 From 371968842922dd39d9692be0a88a9927579c1864 Mon Sep 17 00:00:00 2001 From: alexalexmax <149889301+alexalexmax@users.noreply.github.com> Date: Fri, 5 Dec 2025 02:42:23 -0800 Subject: [PATCH 028/360] Fix recharging spray painters (#41725) change one line --- Content.Shared/SprayPainter/SharedSprayPainterSystem.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Content.Shared/SprayPainter/SharedSprayPainterSystem.cs b/Content.Shared/SprayPainter/SharedSprayPainterSystem.cs index a1316e3565..d1f19d0c25 100644 --- a/Content.Shared/SprayPainter/SharedSprayPainterSystem.cs +++ b/Content.Shared/SprayPainter/SharedSprayPainterSystem.cs @@ -188,7 +188,7 @@ public abstract class SharedSprayPainterSystem : EntitySystem args.Handled = true; if (TryComp(args.Used, out var charges) - && charges.LastCharges < targetGroup.Cost) + && Charges.GetCurrentCharges((args.Used, charges)) < targetGroup.Cost) { var msg = Loc.GetString("spray-painter-interact-no-charges"); _popup.PopupClient(msg, args.User, args.User); From 8cfc9e71842f4ae7eea15d6ff9959501f6f9a38c Mon Sep 17 00:00:00 2001 From: Hitlinemoss <209321380+Hitlinemoss@users.noreply.github.com> Date: Fri, 5 Dec 2025 07:24:22 -0500 Subject: [PATCH 029/360] New figurine voicelines (#41723) --- Resources/Locale/en-US/datasets/figurines.ftl | 50 ++++++++++++++----- Resources/Prototypes/Datasets/figurines.yml | 20 ++++---- 2 files changed, 48 insertions(+), 22 deletions(-) diff --git a/Resources/Locale/en-US/datasets/figurines.ftl b/Resources/Locale/en-US/datasets/figurines.ftl index b6428c0560..9a27dbc584 100644 --- a/Resources/Locale/en-US/datasets/figurines.ftl +++ b/Resources/Locale/en-US/datasets/figurines.ftl @@ -17,9 +17,8 @@ figurines-qm-3 = I didn't approve that shipment of guns! figurines-qm-4 = One toy box for my fellow clown! figurines-qm-5 = Time to gamble! figurines-qm-6 = Viva la Cargonia! -figurines-qm-7 = Fill out the form. -figurines-qm-8 = Where'd all our money go? -figurines-qm-9 = 99% of gamblers quit right before they hit it big! +figurines-qm-7 = Where'd all our money go? +figurines-qm-8 = 99% of gamblers quit right before they hit it big! figurines-cargotech-1 = DRAGON ON ATS! figurines-cargotech-2 = I sold the station! @@ -27,6 +26,11 @@ figurines-cargotech-3 = Brain bounty? I don't have a brain. figurines-cargotech-4 = You're worth 3000 spesos. Congrats. figurines-cargotech-5 = Vegetable bounty? Nobody eats those anyways. figurines-cargotech-6 = WE ARE SECEDING!! ALL HAIL CARGONIA!! +figurines-cargotech-7 = Pizza party at cargo! +figurines-cargotech-8 = The mail never stops... +figurines-cargotech-9 = Nothing stops the mail! +figurines-cargotech-10 = Clown mask bounty? Alright, let me just find a weapon... +figurines-cargotech-11 = Laser bounty? Nobody will notice if we ship practice lasers instead, right? figurines-salvage-1 = Megafauna? It was mega easy. figurines-salvage-2 = We're lost. Anyone bring a GPS? @@ -34,6 +38,9 @@ figurines-salvage-3 = Anyone have oxygen? figurines-salvage-4 = I found a blood-red and e-sword! figurines-salvage-5 = There's bears in space? figurines-salvage-6 = Crusher? I barely know her! +figurines-salvage-7 = Can someone come pick me up? +figurines-salvage-8 = I found that contraband on a wreck! It's not mine! +figurines-salvage-9 = Can we borrow the cargo shuttle? Please? # Engineering @@ -51,6 +58,8 @@ figurines-atmostech-4 = Tritium... figurines-atmostech-5 = Glory to Atmosia! figurines-atmostech-6 = Distro? That's short for disposal. figurines-atmostech-7 = TEG: Thermal Energy? Gone! +figurines-atmostech-8 = Does anyone else hear glass cracking? +figurines-atmostech-9 = I promise this burn chamber is totally safe and will NOT explode. figurines-engineer-1 = SINGULOOSE! figurines-engineer-2 = TESLOOSE! @@ -74,12 +83,15 @@ figurines-chemist-3 = I am the one who knocks! figurines-chemist-4 = Say my name. figurines-chemist-5 = 99.8% purity. figurines-chemist-6 = Epinephrine? Didn't you say methamphetamine? +figurines-chemist-7 = Pills here! +figurines-chemist-8 = Legally speaking, it's not actually a bomb until you mix both beakers together. figurines-doctor-1 = The patient is already dead! figurines-doctor-2 = CLEAR! figurines-doctor-3 = Saw makes BRRR. figurines-doctor-4 = Just a week away... figurines-doctor-5 = I knew it... +figurines-doctor-6 = Well, at least we have body bags. figurines-paramedic-1 = Insuls and tools! figurines-paramedic-2 = I need AA for saving people! @@ -140,8 +152,10 @@ figurines-warden-6 = You're going away for a long time, buddy. figurines-hop-1 = Papers, please. figurines-hop-2 = You are fired. figurines-hop-3 = BRB. -figurines-hop-4 = You can get AA if you fill out the form. +figurines-hop-4 = Fill out the form. figurines-hop-5 = I was gone for two seconds... +figurines-hop-6 = Go get this form stamped. +figurines-hop-7 = Has anyone seen Ian? figurines-bartender-1 = Where's my monkey? figurines-bartender-2 = Sec won't drink. @@ -179,11 +193,12 @@ figurines-chef-6 = Where'd Pun Pun go? No idea... figurines-clown-1 = Honk! figurines-clown-2 = Banana! -figurines-clown-3 = Soap! -figurines-clown-4 = HoP has one clown, HoS has the whole department. -figurines-clown-5 = Do I annoy you? -figurines-clown-6 = Can I have AA? Please? -figurines-clown-7 = I'm a clown, but you're the whole circus! +figurines-clown-3 = Pie! +figurines-clown-4 = Soap! +figurines-clown-5 = Service has one clown, but Security has a whole department of them. +figurines-clown-6 = Do I annoy you? +figurines-clown-7 = Can I have AA? Please? +figurines-clown-8 = I'm a clown, but you're the whole circus! figurines-greytider-1 = Man, this party stinks. I fucking hate these people. figurines-greytider-2 = Uh-oh, who's lost their stunbaton? @@ -207,6 +222,13 @@ figurines-lawyer-2 = Objection! figurines-lawyer-3 = Did you know that you have rights? figurines-lawyer-4 = Space law says! figurines-lawyer-5 = Sign the contract first. +figurines-lawyer-6 = My client is innocent! +figurines-lawyer-7 = I'm suing. +figurines-lawyer-8 = You may be entitled to financial compensation! +figurines-lawyer-9 = Come back with a warrant! +figurines-lawyer-10 = See you in court! +figurines-lawyer-11 = Guilty! +figurines-lawyer-12 = Not guilty! figurines-librarian-1 = Silence! figurines-librarian-2 = One day while... @@ -322,10 +344,14 @@ figurines-thief-3 = Theres nothing suspicious about this satchel at all, officer figurines-thief-4 = I have NO idea where your pet is... figurines-thief-5 = Huh, I didn't know that wall could open up... -figurines-wizard-1 = Ei Nath!! -figurines-wizard-2 = Real wizards support trans rights. +figurines-wizard-1 = EI NATH!! +figurines-wizard-2 = ONI'SOMA!! figurines-wizard-3 = Skidaddle skadoodle! -figurines-wizard-4 = FIREBALL! +figurines-wizard-4 = Real wizards support trans rights. +figurines-wizard-5 = Which one of you NERDS is ready to be shoved in a locker? +figurines-wizard-6 = I'm not the wizard! I'm the captain! I got mind-swapped! +figurines-wizard-7 = Now you see me, now you don't! +figurines-wizard-8 = Guns are for losers who can't explode people with their mind. # Animals diff --git a/Resources/Prototypes/Datasets/figurines.yml b/Resources/Prototypes/Datasets/figurines.yml index 53ba40da64..8d1a256b53 100644 --- a/Resources/Prototypes/Datasets/figurines.yml +++ b/Resources/Prototypes/Datasets/figurines.yml @@ -2,7 +2,7 @@ id: FigurinesHoP values: prefix: figurines-hop- - count: 5 + count: 7 - type: localizedDataset id: FigurinesPassenger @@ -20,7 +20,7 @@ id: FigurinesClown values: prefix: figurines-clown- - count: 7 + count: 8 - type: localizedDataset id: FigurinesHoloClown @@ -80,25 +80,25 @@ id: FigurinesLawyer values: prefix: figurines-lawyer- - count: 5 + count: 12 - type: localizedDataset id: FigurinesCargoTech values: prefix: figurines-cargotech- - count: 6 + count: 11 - type: localizedDataset id: FigurinesSalvage values: prefix: figurines-salvage- - count: 6 + count: 9 - type: localizedDataset id: FigurinesQM values: prefix: figurines-qm- - count: 9 + count: 8 - type: localizedDataset id: FigurinesCE @@ -116,7 +116,7 @@ id: FigurinesAtmosTech values: prefix: figurines-atmostech- - count: 7 + count: 9 - type: localizedDataset id: FigurinesRD @@ -140,7 +140,7 @@ id: FigurinesChemist values: prefix: figurines-chemist- - count: 6 + count: 8 - type: localizedDataset id: FigurinesParamedic @@ -152,7 +152,7 @@ id: FigurinesDoctor values: prefix: figurines-doctor- - count: 5 + count: 6 - type: localizedDataset id: FigurinesLibrarian @@ -218,7 +218,7 @@ id: FigurinesWizard values: prefix: figurines-wizard- - count: 4 + count: 8 - type: localizedDataset id: FigurinesSpaceDragon From 4dc0ff5c6a59b12525ff75373ef687fb5bba263b Mon Sep 17 00:00:00 2001 From: Pieter-Jan Briers Date: Fri, 5 Dec 2025 13:37:02 +0100 Subject: [PATCH 030/360] C# 14 fixes (#41708) Necessary for the move to .NET 10 & C# 14. Actual PR to change SS14 to C# 14 will be separate. --- Content.Client/Parallax/Managers/ParallaxManager.cs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/Content.Client/Parallax/Managers/ParallaxManager.cs b/Content.Client/Parallax/Managers/ParallaxManager.cs index bc7d7d60d6..bd46288ebf 100644 --- a/Content.Client/Parallax/Managers/ParallaxManager.cs +++ b/Content.Client/Parallax/Managers/ParallaxManager.cs @@ -98,10 +98,13 @@ public sealed class ParallaxManager : IParallaxManager } else { - layers = await Task.WhenAll( + // Explicitly allocate params array to avoid sandbox violation since C# 14. + var tasks = new[] + { LoadParallaxLayers(parallaxPrototype.Layers, loadedLayers, cancel), - LoadParallaxLayers(parallaxPrototype.LayersLQ, loadedLayers, cancel) - ); + LoadParallaxLayers(parallaxPrototype.LayersLQ, loadedLayers, cancel), + }; + layers = await Task.WhenAll(tasks); } cancel.ThrowIfCancellationRequested(); From dc3eeb917cba3452545111fb9927be885cef1b3e Mon Sep 17 00:00:00 2001 From: Pieter-Jan Briers Date: Fri, 5 Dec 2025 15:53:35 +0100 Subject: [PATCH 031/360] Fix shuttle FTL with UI scale (#40933) Fixed click inputs being broken Fixed rendering of background parallax. --- Content.Client/Shuttles/UI/ShuttleMapControl.xaml.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Content.Client/Shuttles/UI/ShuttleMapControl.xaml.cs b/Content.Client/Shuttles/UI/ShuttleMapControl.xaml.cs index 70ac02bda9..daf2622d81 100644 --- a/Content.Client/Shuttles/UI/ShuttleMapControl.xaml.cs +++ b/Content.Client/Shuttles/UI/ShuttleMapControl.xaml.cs @@ -124,7 +124,7 @@ public sealed partial class ShuttleMapControl : BaseShuttleControl else { // We'll send the "adjusted" position and server will adjust it back when relevant. - var mapCoords = new MapCoordinates(InverseMapPosition(args.RelativePosition), ViewingMap); + var mapCoords = new MapCoordinates(InverseMapPosition(args.RelativePixelPosition), ViewingMap); RequestFTL?.Invoke(mapCoords, _ftlAngle); } } @@ -180,7 +180,7 @@ public sealed partial class ShuttleMapControl : BaseShuttleControl // Remove offset so we can floor. var botLeft = new Vector2(0f, 0f); - var topRight = botLeft + Size; + var topRight = botLeft + PixelSize; var flooredBL = botLeft - originBL; From 6a2537f5117c24b44a08b7a753c13084e617007e Mon Sep 17 00:00:00 2001 From: B_Kirill <153602297+B-Kirill@users.noreply.github.com> Date: Sat, 6 Dec 2025 01:51:48 +1000 Subject: [PATCH 032/360] Remove static IoC from Replay and Shared EntryPoint (#41707) --- Content.Replay/EntryPoint.cs | 4 ++-- Content.Shared/Entry/EntryPoint.cs | 15 ++++++++------- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/Content.Replay/EntryPoint.cs b/Content.Replay/EntryPoint.cs index ed6460a7e7..6a6658f5ef 100644 --- a/Content.Replay/EntryPoint.cs +++ b/Content.Replay/EntryPoint.cs @@ -19,8 +19,8 @@ public sealed class EntryPoint : GameClient public override void Init() { base.Init(); - IoCManager.BuildGraph(); - IoCManager.InjectDependencies(this); + Dependencies.BuildGraph(); + Dependencies.InjectDependencies(this); } public override void PostInit() diff --git a/Content.Shared/Entry/EntryPoint.cs b/Content.Shared/Entry/EntryPoint.cs index db8d6a6abd..1b5755dd66 100644 --- a/Content.Shared/Entry/EntryPoint.cs +++ b/Content.Shared/Entry/EntryPoint.cs @@ -2,7 +2,6 @@ using System.Diagnostics.CodeAnalysis; using System.IO; using System.Linq; using Content.Shared.Humanoid.Markings; -using Content.Shared.IoC; using Content.Shared.Maps; using Robust.Shared; using Robust.Shared.Configuration; @@ -21,12 +20,15 @@ namespace Content.Shared.Entry [Dependency] private readonly IPrototypeManager _prototypeManager = default!; [Dependency] private readonly ITileDefinitionManager _tileDefinitionManager = default!; [Dependency] private readonly IResourceManager _resMan = default!; +#if DEBUG + [Dependency] private readonly IConfigurationManager _configurationManager = default!; +#endif private readonly ResPath _ignoreFileDirectory = new("/IgnoredPrototypes/"); public override void PreInit() { - IoCManager.InjectDependencies(this); + Dependencies.InjectDependencies(this); } public override void Shutdown() @@ -44,13 +46,12 @@ namespace Content.Shared.Entry base.PostInit(); InitTileDefinitions(); - IoCManager.Resolve().Initialize(); + Dependencies.Resolve().Initialize(); #if DEBUG - var configMan = IoCManager.Resolve(); - configMan.OverrideDefault(CVars.NetFakeLagMin, 0.075f); - configMan.OverrideDefault(CVars.NetFakeLoss, 0.005f); - configMan.OverrideDefault(CVars.NetFakeDuplicates, 0.005f); + _configurationManager.OverrideDefault(CVars.NetFakeLagMin, 0.075f); + _configurationManager.OverrideDefault(CVars.NetFakeLoss, 0.005f); + _configurationManager.OverrideDefault(CVars.NetFakeDuplicates, 0.005f); #endif } From 29ca8f78ffeab21b19e8677fff59f4808cf85df0 Mon Sep 17 00:00:00 2001 From: beck-thompson <107373427+beck-thompson@users.noreply.github.com> Date: Sun, 22 Jun 2025 12:28:21 -0700 Subject: [PATCH 033/360] Allow admins to export round logs to CSV files (#38206) --- .../UI/Logs/AdminLogsControl.xaml | 1 + .../Administration/UI/Logs/AdminLogsEui.cs | 69 +++++++++++++++++++ .../en-US/administration/ui/admin-logs.ftl | 1 + 3 files changed, 71 insertions(+) diff --git a/Content.Client/Administration/UI/Logs/AdminLogsControl.xaml b/Content.Client/Administration/UI/Logs/AdminLogsControl.xaml index 9b5da77801..86b72d9392 100644 --- a/Content.Client/Administration/UI/Logs/AdminLogsControl.xaml +++ b/Content.Client/Administration/UI/Logs/AdminLogsControl.xaml @@ -55,6 +55,7 @@ private List RawAdminLogs { get; set; } = new(); - private bool RenderRichText { get; set; } - private bool RemoveMarkup { get; set; } public HashSet SelectedTypes { get; } = new(); public HashSet SelectedPlayers { get; } = new(); @@ -132,19 +123,6 @@ public sealed partial class AdminLogsControl : Control private void LogSearchChanged(LineEditEventArgs args) { - // This exception is thrown if the regex is invalid, which happens often, so we ignore it. - try - { - LogSearchRegex = new Regex( - "(" + LogSearch.Text + ")", - RegexOptions.IgnoreCase, - TimeSpan.FromSeconds(1)); - } - catch (ArgumentException) - { - return; - } - UpdateLogs(); } @@ -226,26 +204,6 @@ public sealed partial class AdminLogsControl : Control UpdateLogs(); } - private void RenderRichTextChanged(ButtonEventArgs args) - { - RenderRichText = args.Button.Pressed; - - RemoveMarkup = RemoveMarkup && !RenderRichText; - RemoveMarkupButton.Pressed = RemoveMarkup; - - UpdateLogs(); - } - - private void RemoveMarkupChanged(ButtonEventArgs args) - { - RemoveMarkup = args.Button.Pressed; - - RenderRichText = !RemoveMarkup && RenderRichText; - RenderRichTextButton.Pressed = RenderRichText; - - UpdateLogs(); - } - public void SetTypesSelection(HashSet selectedTypes, bool invert = false) { SelectedTypes.Clear(); @@ -304,15 +262,16 @@ public sealed partial class AdminLogsControl : Control foreach (var child in LogsContainer.Children) { - if (child is not AdminLogEntry log) + if (child is not AdminLogLabel log) + { continue; + } child.Visible = ShouldShowLog(log); - if (!child.Visible) - continue; - - log.RenderResults(LogSearchRegex, RenderRichText, RemoveMarkup); - ShownLogs++; + if (child.Visible) + { + ShownLogs++; + } } UpdateCount(); @@ -330,30 +289,30 @@ public sealed partial class AdminLogsControl : Control button.Text.Contains(PlayerSearch.Text, StringComparison.OrdinalIgnoreCase); } - private bool LogMatchesPlayerFilter(AdminLogEntry entry) + private bool LogMatchesPlayerFilter(AdminLogLabel label) { - if (entry.Log.Players.Length == 0) + if (label.Log.Players.Length == 0) return SelectedPlayers.Count == 0 || IncludeNonPlayerLogs; - return SelectedPlayers.Overlaps(entry.Log.Players); + return SelectedPlayers.Overlaps(label.Log.Players); } - private bool ShouldShowLog(AdminLogEntry entry) + private bool ShouldShowLog(AdminLogLabel label) { // Check log type - if (!SelectedTypes.Contains(entry.Log.Type)) + if (!SelectedTypes.Contains(label.Log.Type)) return false; // Check players - if (!LogMatchesPlayerFilter(entry)) + if (!LogMatchesPlayerFilter(label)) return false; // Check impact - if (!SelectedImpacts.Contains(entry.Log.Impact)) + if (!SelectedImpacts.Contains(label.Log.Impact)) return false; // Check search - if (!LogSearchRegex.IsMatch(entry.Log.Message)) + if (!label.Log.Message.Contains(LogSearch.Text, StringComparison.OrdinalIgnoreCase)) return false; return true; @@ -427,16 +386,15 @@ public sealed partial class AdminLogsControl : Control { var log = tempLogs[i]; ref var logRef = ref log; // It didn't like me doing this as one line lmao - var entry = new AdminLogEntry(ref log); - //var label = new AdminLogLabel(ref logRef, separator); - //label.Visible = ShouldShowLog(label); + var separator = new HSeparator(); + var label = new AdminLogLabel(ref logRef, separator); + label.Visible = ShouldShowLog(label); - TotalLogs++; - //if (label.Visible) ShownLogs++; + if (label.Visible) ShownLogs++; - //LogsContainer.AddChild(label); - LogsContainer.AddChild(entry); + LogsContainer.AddChild(label); + LogsContainer.AddChild(separator); } UpdateLogs(); } @@ -636,7 +594,6 @@ public sealed partial class AdminLogsControl : Control SelectAllTypesButton.OnPressed -= SelectAllTypes; SelectNoTypesButton.OnPressed -= SelectNoTypes; - IncludeNonPlayersButton.OnPressed -= IncludeNonPlayers; IncludeNonPlayersButton.OnPressed -= IncludeNonPlayers; SelectAllPlayersButton.OnPressed -= SelectAllPlayers; SelectNoPlayersButton.OnPressed -= SelectNoPlayers; diff --git a/Content.Client/Administration/UI/Logs/AdminLogsEui.cs b/Content.Client/Administration/UI/Logs/AdminLogsEui.cs index 52364111c0..28aca23f75 100644 --- a/Content.Client/Administration/UI/Logs/AdminLogsEui.cs +++ b/Content.Client/Administration/UI/Logs/AdminLogsEui.cs @@ -1,6 +1,6 @@ using System.IO; using System.Linq; -using Content.Client.Administration.UI.Logs.Entries; +using Content.Client.Administration.UI.CustomControls; using Content.Client.Eui; using Content.Shared.Administration.Logs; using Content.Shared.Eui; diff --git a/Content.Client/Administration/UI/Logs/Entries/AdminLogEntry.xaml b/Content.Client/Administration/UI/Logs/Entries/AdminLogEntry.xaml deleted file mode 100644 index 7733c2b1cb..0000000000 --- a/Content.Client/Administration/UI/Logs/Entries/AdminLogEntry.xaml +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - - - - diff --git a/Content.Client/Administration/UI/Logs/Entries/AdminLogEntry.xaml.cs b/Content.Client/Administration/UI/Logs/Entries/AdminLogEntry.xaml.cs deleted file mode 100644 index fc9f960b66..0000000000 --- a/Content.Client/Administration/UI/Logs/Entries/AdminLogEntry.xaml.cs +++ /dev/null @@ -1,79 +0,0 @@ -using System.Text.RegularExpressions; -using Content.Client.Message; -using Content.Shared.Administration.Logs; -using Content.Shared.CCVar; -using Robust.Client.AutoGenerated; -using Robust.Client.UserInterface.Controls; -using Robust.Client.UserInterface.XAML; -using Robust.Shared.Configuration; -using Robust.Shared.Utility; - -namespace Content.Client.Administration.UI.Logs.Entries; - -[GenerateTypedNameReferences] -public sealed partial class AdminLogEntry : BoxContainer -{ - private readonly IConfigurationManager _cfgManager; - - public SharedAdminLog Log { get; } - - private readonly string _rawMessage; - - public AdminLogEntry(ref SharedAdminLog log) - { - _cfgManager = IoCManager.Resolve(); - - RobustXamlLoader.Load(this); - - Log = log; - - _rawMessage = $"{log.Date:HH:mm:ss}: {log.Message}"; - Message.SetMessage(_rawMessage); - - DetailsHeading.OnToggled += DetailsToggled; - } - - /// - /// Sets text to be highlighted from a search result, and renders rich text, or removes all rich text markup. - /// - public void RenderResults(Regex highlightRegex, bool renderRichText, bool removeMarkup) - { - var color = _cfgManager.GetCVar(CCVars.AdminLogsHighlightColor); - var formattedMessage = renderRichText - ? _rawMessage - : removeMarkup - ? FormattedMessage.RemoveMarkupPermissive(_rawMessage) - : FormattedMessage.EscapeText(_rawMessage); - - // Want to avoid highlighting smaller strings - if (highlightRegex.ToString().Length > 4) - { - try - { - formattedMessage = highlightRegex.Replace(formattedMessage, $"[color={color}]$1[/color]", 3); - } - catch (RegexMatchTimeoutException) - { - // if we time out then don't bother highlighting results - } - } - - if (!FormattedMessage.TryFromMarkup(formattedMessage, out var outputMessage)) - return; - - Message.SetMessage(outputMessage); - } - - /// - /// We perform some extra calculations in the dropdown, so we want to render that only when - /// the dropdown is actually opened. - /// This also removes itself from the event listener so it doesn't trigger again. - /// - private void DetailsToggled(BaseButton.ButtonToggledEventArgs args) - { - if (!args.Pressed || DetailsBody.ChildCount > 0) - return; - DetailsBody.AddChild(new AdminLogEntryDetails(Log)); - DetailsHeading.OnToggled -= DetailsToggled; - } -} diff --git a/Content.Client/Administration/UI/Logs/Entries/AdminLogEntryDetails.xaml b/Content.Client/Administration/UI/Logs/Entries/AdminLogEntryDetails.xaml deleted file mode 100644 index 23391046b9..0000000000 --- a/Content.Client/Administration/UI/Logs/Entries/AdminLogEntryDetails.xaml +++ /dev/null @@ -1,44 +0,0 @@ - - - - - - - - - - - - - - - diff --git a/Content.Client/Administration/UI/Logs/Entries/AdminLogEntryDetails.xaml.cs b/Content.Client/Administration/UI/Logs/Entries/AdminLogEntryDetails.xaml.cs deleted file mode 100644 index 611626e544..0000000000 --- a/Content.Client/Administration/UI/Logs/Entries/AdminLogEntryDetails.xaml.cs +++ /dev/null @@ -1,98 +0,0 @@ -using System.Linq; -using Content.Client.Administration.Systems; -using Content.Client.Administration.UI.CustomControls; -using Content.Client.UserInterface.Controls; -using Content.Client.Verbs.UI; -using Content.Shared.Administration.Logs; -using Robust.Client.AutoGenerated; -using Robust.Client.UserInterface; -using Robust.Client.UserInterface.Controls; -using Robust.Client.UserInterface.XAML; -using Robust.Shared.Input; -using Robust.Shared.Network; - -namespace Content.Client.Administration.UI.Logs.Entries; - -[GenerateTypedNameReferences] -public sealed partial class AdminLogEntryDetails : BoxContainer -{ - private readonly AdminSystem _adminSystem; - private readonly IUserInterfaceManager _uiManager; - private readonly IEntityManager _entManager; - - public AdminLogEntryDetails(SharedAdminLog log) - { - RobustXamlLoader.Load(this); - _entManager = IoCManager.Resolve(); - _uiManager = IoCManager.Resolve(); - _adminSystem = _entManager.System(); - - Type.Text = log.Type.ToString(); - Impact.Text = log.Impact.ToString(); - - LocalTime.Text = $"{log.Date.ToLocalTime():HH:mm:ss}"; - UTCTime.Text = $"{log.Date:HH:mm:ss}"; - // TimeSpan and DateTime use different formatting string conventions for some completely logical reason - // that mere mortals such as myself will never be able to understand. - CurTime.Text = new TimeSpan(log.CurTime).ToString(@"hh\:mm\:ss"); - - PlayerListContainer.ItemKeyBindDown += PlayerListItemKeyBindDown; - PlayerListContainer.GenerateItem += GenerateButton; - PopulateList(log.Players); - } - - private void PopulateList(Guid[] players) - { - if (players.Length == 0) - return; - - if (_adminSystem.PlayerList is not { } allPlayers || allPlayers.Count == 0) - return; - - var listData = new List(); - foreach (var playerGuid in players) - { - var netUserId = new NetUserId(playerGuid); - - // Linq here is fine since this runs in response to admin input in the UI and - // this loop only tends to go through 1-4 iterations. - if (allPlayers.FirstOrDefault(player => player.SessionId == netUserId) is not { } playerInfo) - continue; - - listData.Add(new PlayerListData(playerInfo)); - } - - if (listData.Count == 0) - return; - - PlayerListContainer.PopulateList(listData); - } - - private void PlayerListItemKeyBindDown(GUIBoundKeyEventArgs? args, ListData? data) - { - if (args == null || data is not PlayerListData { Info: var selectedPlayer }) - return; - - if (!(args.Function == EngineKeyFunctions.UIRightClick - || args.Function == EngineKeyFunctions.UIClick) - || selectedPlayer.NetEntity == null) - return; - - _uiManager.GetUIController().OpenVerbMenu(selectedPlayer.NetEntity.Value, true); - args.Handle(); - } - - private void GenerateButton(ListData data, ListContainerButton button) - { - if (data is not PlayerListData { Info: var info }) - return; - - var entryLabel = new Label(); - entryLabel.Text = $"{info.CharacterName} ({info.Username})"; - var entry = new BoxContainer(); - entry.AddChild(entryLabel); - - button.AddChild(entry); - button.AddStyleClass(ListContainer.StyleClassListContainerButton); - } -} diff --git a/Content.Client/Administration/UI/Tabs/PlayerTab/PlayerTab.xaml.cs b/Content.Client/Administration/UI/Tabs/PlayerTab/PlayerTab.xaml.cs index 371b9952e4..d999df6d98 100644 --- a/Content.Client/Administration/UI/Tabs/PlayerTab/PlayerTab.xaml.cs +++ b/Content.Client/Administration/UI/Tabs/PlayerTab/PlayerTab.xaml.cs @@ -56,6 +56,7 @@ public sealed partial class PlayerTab : Control _config.OnValueChanged(CCVars.AdminPlayerTabMarkGhosted, MarkGhostedChanged, true); // DeltaV _config.OnValueChanged(CCVars.AdminPlayerTabMarkWatchlisted, MarkWatchlistedChanged, true); // DeltaV + OverlayButton.OnPressed += OverlayButtonPressed; ShowDisconnectedButton.OnPressed += ShowDisconnectedPressed; @@ -68,6 +69,7 @@ public sealed partial class PlayerTab : Control SearchList.ItemKeyBindDown += (args, data) => OnEntryKeyBindDown?.Invoke(args, data); RefreshPlayerList(_adminSystem.PlayerList); + } // DeltaV - mark ghosted, watchlisted START diff --git a/Content.Client/Options/UI/Tabs/AdminOptionsTab.xaml b/Content.Client/Options/UI/Tabs/AdminOptionsTab.xaml index 53e6e29cee..dfa9a89b77 100644 --- a/Content.Client/Options/UI/Tabs/AdminOptionsTab.xaml +++ b/Content.Client/Options/UI/Tabs/AdminOptionsTab.xaml @@ -11,9 +11,6 @@ -