From d4ad2e473a398319a891df7b5b64493aa7708e20 Mon Sep 17 00:00:00 2001 From: "Mr. 27" <45323883+Dutch-VanDerLinde@users.noreply.github.com> Date: Wed, 7 Aug 2024 18:59:04 -0400 Subject: [PATCH 001/174] Don't disable collision on dead mobs, fixes an issue with pulling (#30532) Update MobStateSystem.Subscribers.cs --- .../Mobs/Systems/MobStateSystem.Subscribers.cs | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/Content.Shared/Mobs/Systems/MobStateSystem.Subscribers.cs b/Content.Shared/Mobs/Systems/MobStateSystem.Subscribers.cs index 9ee8a064e5..f99bd43feb 100644 --- a/Content.Shared/Mobs/Systems/MobStateSystem.Subscribers.cs +++ b/Content.Shared/Mobs/Systems/MobStateSystem.Subscribers.cs @@ -80,11 +80,6 @@ public partial class MobStateSystem case MobState.Dead: RemComp(target); _standing.Stand(target); - if (!_standing.IsDown(target) && TryComp(target, out var physics)) - { - _physics.SetCanCollide(target, true, body: physics); - } - break; case MobState.Invalid: //unused @@ -115,12 +110,6 @@ public partial class MobStateSystem case MobState.Dead: EnsureComp(target); _standing.Down(target); - - if (_standing.IsDown(target) && TryComp(target, out var physics)) - { - _physics.SetCanCollide(target, false, body: physics); - } - _appearance.SetData(target, MobStateVisuals.State, MobState.Dead); break; case MobState.Invalid: From d86c886f61f14e67ef695495b8e63f66d80c39f1 Mon Sep 17 00:00:00 2001 From: lzk <124214523+lzk228@users.noreply.github.com> Date: Thu, 8 Aug 2024 01:11:05 +0200 Subject: [PATCH 002/174] Add more advertisements (#30653) --- .../en-US/advertisements/vending/atmosdrobe.ftl | 4 +++- .../en-US/advertisements/vending/chefdrobe.ftl | 3 ++- .../en-US/advertisements/vending/chemdrobe.ftl | 3 ++- .../en-US/advertisements/vending/donut.ftl | 1 + .../en-US/advertisements/vending/hydrobe.ftl | 3 ++- .../en-US/advertisements/vending/janidrobe.ftl | 3 ++- .../en-US/advertisements/vending/lawdrobe.ftl | 1 + .../en-US/advertisements/vending/medidrobe.ftl | 1 + .../Catalog/VendingMachines/advertisements.yml | 16 ++++++++-------- 9 files changed, 22 insertions(+), 13 deletions(-) diff --git a/Resources/Locale/en-US/advertisements/vending/atmosdrobe.ftl b/Resources/Locale/en-US/advertisements/vending/atmosdrobe.ftl index 642d142fbf..f7bc093e1c 100644 --- a/Resources/Locale/en-US/advertisements/vending/atmosdrobe.ftl +++ b/Resources/Locale/en-US/advertisements/vending/atmosdrobe.ftl @@ -1,3 +1,5 @@ advertisement-atmosdrobe-1 = Get your inflammable clothing right here!!! advertisement-atmosdrobe-2 = Protects you against plasma fires! -advertisement-atmosdrobe-3 = Enjoy your off-brand engineering clothing! \ No newline at end of file +advertisement-atmosdrobe-3 = Enjoy your off-brand engineering clothing! +advertisement-atmosdrobe-4 = Always under control of your atmosphere! +advertisement-atmosdrobe-5 = Providing comfort in every breath! diff --git a/Resources/Locale/en-US/advertisements/vending/chefdrobe.ftl b/Resources/Locale/en-US/advertisements/vending/chefdrobe.ftl index a681a7aced..025c731ff3 100644 --- a/Resources/Locale/en-US/advertisements/vending/chefdrobe.ftl +++ b/Resources/Locale/en-US/advertisements/vending/chefdrobe.ftl @@ -1,3 +1,4 @@ -advertisement-chefdrobe-1 = Our clothes are guaranteed to protect you from food splatters! +advertisement-chefdrobe-1 = Our clothes are guaranteed to protect you from food splatters! advertisement-chefdrobe-2 = Perfectly white, so everyone knows about the murder in the kitchen! advertisement-chefdrobe-3 = Easy to clean, easy to see! +advertisement-chefdrobe-4 = Cook like a pro, look like a maestro! diff --git a/Resources/Locale/en-US/advertisements/vending/chemdrobe.ftl b/Resources/Locale/en-US/advertisements/vending/chemdrobe.ftl index 4472ced15e..5dd4f87dc3 100644 --- a/Resources/Locale/en-US/advertisements/vending/chemdrobe.ftl +++ b/Resources/Locale/en-US/advertisements/vending/chemdrobe.ftl @@ -1,3 +1,4 @@ advertisement-chemdrobe-1 = Our clothes are 0.5% more resistant to acid spills! Get yours now! advertisement-chemdrobe-2 = Professional laboratory clothing, designed by NanoTrasen! -advertisement-chemdrobe-3 = I'm pretty sure these will protect you against acid spills! \ No newline at end of file +advertisement-chemdrobe-3 = I'm pretty sure these will protect you against acid spills! +advertisement-chemdrobe-4 = The best fashion formula! diff --git a/Resources/Locale/en-US/advertisements/vending/donut.ftl b/Resources/Locale/en-US/advertisements/vending/donut.ftl index daa93928b6..af801f621c 100644 --- a/Resources/Locale/en-US/advertisements/vending/donut.ftl +++ b/Resources/Locale/en-US/advertisements/vending/donut.ftl @@ -3,6 +3,7 @@ advertisement-donut-2 = Hope you're hunger! advertisement-donut-3 = Over 1 million donuts sold! advertisement-donut-4 = We pride ourselves in the consistency of our products! advertisement-donut-5 = Sweet, sugary and delicious! +advertisement-donut-6 = Donut worry, be happy! thankyou-donut-1 = Enjoy your donut! thankyou-donut-2 = Another donut sold! thankyou-donut-3 = Have a nice day, officer! diff --git a/Resources/Locale/en-US/advertisements/vending/hydrobe.ftl b/Resources/Locale/en-US/advertisements/vending/hydrobe.ftl index f1fdc4fccc..64b38d8e3a 100644 --- a/Resources/Locale/en-US/advertisements/vending/hydrobe.ftl +++ b/Resources/Locale/en-US/advertisements/vending/hydrobe.ftl @@ -1,4 +1,5 @@ advertisement-hydrobe-1 = Do you love soil? Then buy our clothes! advertisement-hydrobe-2 = Get outfits to match your green thumb here! advertisement-hydrobe-3 = Here to give you an outfit perfect for handling plants! -advertisement-hydrobe-4 = Perfect outfits for tree huggers... or just literal trees! \ No newline at end of file +advertisement-hydrobe-4 = Perfect outfits for tree huggers... or just literal trees! +advertisement-hydrobe-5 = Wear green and grow! diff --git a/Resources/Locale/en-US/advertisements/vending/janidrobe.ftl b/Resources/Locale/en-US/advertisements/vending/janidrobe.ftl index 7c39a9ad4a..a23f878e74 100644 --- a/Resources/Locale/en-US/advertisements/vending/janidrobe.ftl +++ b/Resources/Locale/en-US/advertisements/vending/janidrobe.ftl @@ -1,4 +1,5 @@ advertisement-janidrobe-1 = Come and get your janitorial clothing, now endorsed by lizard janitors everywhere! advertisement-janidrobe-2 = Here to keep you clean as you clean up non-clean things! advertisement-janidrobe-3 = Stylishly yellow! - +advertisement-janidrobe-4 = Polish your appearance with JaniDrobe! +advertisement-janidrobe-5 = Shine like a shiny floor! diff --git a/Resources/Locale/en-US/advertisements/vending/lawdrobe.ftl b/Resources/Locale/en-US/advertisements/vending/lawdrobe.ftl index 5473f162da..64849d9341 100644 --- a/Resources/Locale/en-US/advertisements/vending/lawdrobe.ftl +++ b/Resources/Locale/en-US/advertisements/vending/lawdrobe.ftl @@ -6,6 +6,7 @@ advertisement-lawdrobe-5 = No one is above the law! advertisement-lawdrobe-6 = No officer, I do not consent to a search! advertisement-lawdrobe-7 = Injecting space drugs leaves no evidence! advertisement-lawdrobe-8 = You or a loved one hurt by Nanotrasen? Too bad! +advertisement-lawdrobe-9 = Case closed! Defendant has too much drip! thankyou-lawdrobe-1 = You can win any case in that outfit! thankyou-lawdrobe-2 = Get one for your client as well! thankyou-lawdrobe-3 = Win or lose, you get paid either way! diff --git a/Resources/Locale/en-US/advertisements/vending/medidrobe.ftl b/Resources/Locale/en-US/advertisements/vending/medidrobe.ftl index 68b18a8390..980628a0ce 100644 --- a/Resources/Locale/en-US/advertisements/vending/medidrobe.ftl +++ b/Resources/Locale/en-US/advertisements/vending/medidrobe.ftl @@ -1,3 +1,4 @@ advertisement-medidrobe-1 = Make those blood stains look fashionable!! advertisement-medidrobe-2 = Clean and hygienic! Don't get too many bloodstains on yourself! advertisement-medidrobe-3 = With these outfits, you'll look like a professional doctor now! +advertisement-medidrobe-4 = Jumpsuit, check. Coat, check. Someone who will wear this? Check! diff --git a/Resources/Prototypes/Catalog/VendingMachines/advertisements.yml b/Resources/Prototypes/Catalog/VendingMachines/advertisements.yml index aa25e87a52..5f6806afbb 100644 --- a/Resources/Prototypes/Catalog/VendingMachines/advertisements.yml +++ b/Resources/Prototypes/Catalog/VendingMachines/advertisements.yml @@ -8,7 +8,7 @@ id: AtmosDrobeAds values: prefix: advertisement-atmosdrobe- - count: 3 + count: 5 - type: localizedDataset id: BarDrobeAds @@ -38,7 +38,7 @@ id: ChefDrobeAds values: prefix: advertisement-chefdrobe- - count: 3 + count: 4 - type: localizedDataset id: ChefvendAds @@ -50,7 +50,7 @@ id: ChemDrobeAds values: prefix: advertisement-chemdrobe- - count: 3 + count: 4 - type: localizedDataset id: CigaretteMachineAds @@ -110,7 +110,7 @@ id: DonutAds values: prefix: advertisement-donut- - count: 5 + count: 6 - type: localizedDataset id: EngiDrobeAds @@ -146,19 +146,19 @@ id: HyDrobeAds values: prefix: advertisement-hydrobe- - count: 4 + count: 5 - type: localizedDataset id: JaniDrobeAds values: prefix: advertisement-janidrobe- - count: 3 + count: 5 - type: localizedDataset id: LawDrobeAds values: prefix: advertisement-lawdrobe- - count: 8 + count: 9 - type: localizedDataset id: MagiVendAds @@ -170,7 +170,7 @@ id: MediDrobeAds values: prefix: advertisement-medidrobe- - count: 3 + count: 4 - type: localizedDataset id: MegaSeedAds From 9645f5528b23c361db82748648ecf8b6850e7ff4 Mon Sep 17 00:00:00 2001 From: ShadowCommander <10494922+ShadowCommander@users.noreply.github.com> Date: Wed, 7 Aug 2024 19:12:01 -0700 Subject: [PATCH 003/174] Strip drag drop test (#30754) * Add test for drag drop to open strip menu * Make screencoords change based on deadzone --- Content.Client/Interaction/DragDropSystem.cs | 15 ++++-- .../Interaction/InteractionTest.Helpers.cs | 5 +- .../Tests/Strip/StrippableTest.cs | 46 +++++++++++++++++++ 3 files changed, 59 insertions(+), 7 deletions(-) create mode 100644 Content.IntegrationTests/Tests/Strip/StrippableTest.cs diff --git a/Content.Client/Interaction/DragDropSystem.cs b/Content.Client/Interaction/DragDropSystem.cs index a34cd0f5b1..4145999579 100644 --- a/Content.Client/Interaction/DragDropSystem.cs +++ b/Content.Client/Interaction/DragDropSystem.cs @@ -90,7 +90,7 @@ public sealed class DragDropSystem : SharedDragDropSystem /// private bool _isReplaying; - private float _deadzone; + public float Deadzone; private DragState _state = DragState.NotDragging; @@ -122,7 +122,7 @@ public sealed class DragDropSystem : SharedDragDropSystem private void SetDeadZone(float deadZone) { - _deadzone = deadZone; + Deadzone = deadZone; } public override void Shutdown() @@ -212,7 +212,7 @@ public sealed class DragDropSystem : SharedDragDropSystem _draggedEntity = entity; _state = DragState.MouseDown; - _mouseDownScreenPos = _inputManager.MouseScreenPosition; + _mouseDownScreenPos = args.ScreenCoordinates; _mouseDownTime = 0; // don't want anything else to process the click, @@ -240,8 +240,13 @@ public sealed class DragDropSystem : SharedDragDropSystem if (TryComp(_draggedEntity, out var draggedSprite)) { + var screenPos = _inputManager.MouseScreenPosition; + // No _draggedEntity in null window (Happens in tests) + if (!screenPos.IsValid) + return; + // pop up drag shadow under mouse - var mousePos = _eyeManager.PixelToMap(_inputManager.MouseScreenPosition); + var mousePos = _eyeManager.PixelToMap(screenPos); _dragShadow = EntityManager.SpawnEntity("dragshadow", mousePos); var dragSprite = Comp(_dragShadow.Value); dragSprite.CopyFrom(draggedSprite); @@ -534,7 +539,7 @@ public sealed class DragDropSystem : SharedDragDropSystem case DragState.MouseDown: { var screenPos = _inputManager.MouseScreenPosition; - if ((_mouseDownScreenPos!.Value.Position - screenPos.Position).Length() > _deadzone) + if ((_mouseDownScreenPos!.Value.Position - screenPos.Position).Length() > Deadzone) { StartDrag(); } diff --git a/Content.IntegrationTests/Tests/Interaction/InteractionTest.Helpers.cs b/Content.IntegrationTests/Tests/Interaction/InteractionTest.Helpers.cs index 0f2c314ed0..d431c440a2 100644 --- a/Content.IntegrationTests/Tests/Interaction/InteractionTest.Helpers.cs +++ b/Content.IntegrationTests/Tests/Interaction/InteractionTest.Helpers.cs @@ -1207,11 +1207,12 @@ public abstract partial class InteractionTest BoundKeyFunction key, BoundKeyState state, NetCoordinates? coordinates = null, - NetEntity? cursorEntity = null) + NetEntity? cursorEntity = null, + ScreenCoordinates? screenCoordinates = null) { var coords = coordinates ?? TargetCoords; var target = cursorEntity ?? Target ?? default; - ScreenCoordinates screen = default; + var screen = screenCoordinates ?? default; var funcId = InputManager.NetworkBindMap.KeyFunctionID(key); var message = new ClientFullInputCmdMessage(CTiming.CurTick, CTiming.TickFraction, funcId) diff --git a/Content.IntegrationTests/Tests/Strip/StrippableTest.cs b/Content.IntegrationTests/Tests/Strip/StrippableTest.cs new file mode 100644 index 0000000000..f65bab1f81 --- /dev/null +++ b/Content.IntegrationTests/Tests/Strip/StrippableTest.cs @@ -0,0 +1,46 @@ +using Content.Client.Interaction; +using Content.IntegrationTests.Tests.Interaction; +using Robust.Shared.GameObjects; +using Robust.Shared.Input; +using Robust.Shared.Map; + +namespace Content.IntegrationTests.Tests.Strip; + +public sealed class StrippableTest : InteractionTest +{ + protected override string PlayerPrototype => "MobHuman"; + + [Test] + public async Task DragDropOpensStrip() + { + // Spawn one tile away + TargetCoords = SEntMan.GetNetCoordinates(new EntityCoordinates(MapData.MapUid, 1, 0)); + await SpawnTarget("MobHuman"); + + var userInterface = Comp(Target); + Assert.That(userInterface.Actors.Count == 0); + + // screenCoordinates diff needs to be larger than DragDropSystem._deadzone + var screenX = CEntMan.System().Deadzone + 1f; + + // Start drag + await SetKey(EngineKeyFunctions.Use, + BoundKeyState.Down, + TargetCoords, + Target, + screenCoordinates: new ScreenCoordinates(screenX, 0f, WindowId.Main)); + + await RunTicks(5); + + // End drag + await SetKey(EngineKeyFunctions.Use, + BoundKeyState.Up, + PlayerCoords, + Player, + screenCoordinates: new ScreenCoordinates(0f, 0f, WindowId.Main)); + + await RunTicks(5); + + Assert.That(userInterface.Actors.Count > 0); + } +} From b8d10a3f5efedaea2a0ce8031a5f0a9704d38f37 Mon Sep 17 00:00:00 2001 From: Mervill Date: Wed, 7 Aug 2024 19:14:31 -0700 Subject: [PATCH 004/174] Add verbose (client predicted!) examine text to Gas Miners (#30480) * add verbose examine text to gas miners so their behaviour can be understood * no need for these to be properties * use an enum instead of two booleans for the miner state * require the gas miner to be anchored in order to not be disabled * xmldoc * pr feedback * file-scope namespace * it's to late to hide my transgressions in a rebase * turns out the normal examine distance is totally fine for this --- .../Atmos/EntitySystems/GasMinerSystem.cs | 10 +++ .../Atmos/EntitySystems/GasMinerSystem.cs | 90 +++++++++++++++++++ .../Other/Components/GasMinerComponent.cs | 43 --------- .../Other/EntitySystems/GasMinerSystem.cs | 84 ----------------- .../Atmos/Components/GasMinerComponent.cs | 60 +++++++++++++ .../EntitySystems/SharedGasMinerSystem.cs | 55 ++++++++++++ .../en-US/atmos/gas-miner-component.ftl | 11 +++ 7 files changed, 226 insertions(+), 127 deletions(-) create mode 100644 Content.Client/Atmos/EntitySystems/GasMinerSystem.cs create mode 100644 Content.Server/Atmos/EntitySystems/GasMinerSystem.cs delete mode 100644 Content.Server/Atmos/Piping/Other/Components/GasMinerComponent.cs delete mode 100644 Content.Server/Atmos/Piping/Other/EntitySystems/GasMinerSystem.cs create mode 100644 Content.Shared/Atmos/Components/GasMinerComponent.cs create mode 100644 Content.Shared/Atmos/EntitySystems/SharedGasMinerSystem.cs create mode 100644 Resources/Locale/en-US/atmos/gas-miner-component.ftl diff --git a/Content.Client/Atmos/EntitySystems/GasMinerSystem.cs b/Content.Client/Atmos/EntitySystems/GasMinerSystem.cs new file mode 100644 index 0000000000..aec138eed8 --- /dev/null +++ b/Content.Client/Atmos/EntitySystems/GasMinerSystem.cs @@ -0,0 +1,10 @@ +using Content.Shared.Atmos.EntitySystems; +using JetBrains.Annotations; + +namespace Content.Client.Atmos.EntitySystems; + +[UsedImplicitly] +public sealed class GasMinerSystem : SharedGasMinerSystem +{ + +} diff --git a/Content.Server/Atmos/EntitySystems/GasMinerSystem.cs b/Content.Server/Atmos/EntitySystems/GasMinerSystem.cs new file mode 100644 index 0000000000..f7a3b9eed8 --- /dev/null +++ b/Content.Server/Atmos/EntitySystems/GasMinerSystem.cs @@ -0,0 +1,90 @@ +using System.Diagnostics.CodeAnalysis; +using Content.Server.Atmos.Piping.Components; +using Content.Shared.Atmos; +using Content.Shared.Atmos.Components; +using Content.Shared.Atmos.EntitySystems; +using JetBrains.Annotations; +using Robust.Server.GameObjects; + +namespace Content.Server.Atmos.EntitySystems; + +[UsedImplicitly] +public sealed class GasMinerSystem : SharedGasMinerSystem +{ + [Dependency] private readonly AtmosphereSystem _atmosphereSystem = default!; + [Dependency] private readonly TransformSystem _transformSystem = default!; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnMinerUpdated); + } + + private void OnMinerUpdated(Entity ent, ref AtmosDeviceUpdateEvent args) + { + var miner = ent.Comp; + var oldState = miner.MinerState; + float toSpawn; + + if (!GetValidEnvironment(ent, out var environment) || !Transform(ent).Anchored) + { + miner.MinerState = GasMinerState.Disabled; + } + // SpawnAmount is declared in mol/s so to get the amount of gas we hope to mine, we have to multiply this by + // how long we have been waiting to spawn it and further cap the number according to the miner's state. + else if ((toSpawn = CapSpawnAmount(ent, miner.SpawnAmount * args.dt, environment)) == 0) + { + miner.MinerState = GasMinerState.Idle; + } + else + { + miner.MinerState = GasMinerState.Working; + + // Time to mine some gas. + var merger = new GasMixture(1) { Temperature = miner.SpawnTemperature }; + merger.SetMoles(miner.SpawnGas, toSpawn); + _atmosphereSystem.Merge(environment, merger); + } + + if (miner.MinerState != oldState) + { + Dirty(ent); + } + } + + private bool GetValidEnvironment(Entity ent, [NotNullWhen(true)] out GasMixture? environment) + { + var (uid, miner) = ent; + var transform = Transform(uid); + var position = _transformSystem.GetGridOrMapTilePosition(uid, transform); + + // Treat space as an invalid environment + if (_atmosphereSystem.IsTileSpace(transform.GridUid, transform.MapUid, position)) + { + environment = null; + return false; + } + + environment = _atmosphereSystem.GetContainingMixture((uid, transform), true, true); + return environment != null; + } + + private float CapSpawnAmount(Entity ent, float toSpawnTarget, GasMixture environment) + { + var (uid, miner) = ent; + + // How many moles could we theoretically spawn. Cap by pressure and amount. + var allowableMoles = Math.Min( + (miner.MaxExternalPressure - environment.Pressure) * environment.Volume / (miner.SpawnTemperature * Atmospherics.R), + miner.MaxExternalAmount - environment.TotalMoles); + + var toSpawnReal = Math.Clamp(allowableMoles, 0f, toSpawnTarget); + + if (toSpawnReal < Atmospherics.GasMinMoles) { + return 0f; + } + + return toSpawnReal; + } +} diff --git a/Content.Server/Atmos/Piping/Other/Components/GasMinerComponent.cs b/Content.Server/Atmos/Piping/Other/Components/GasMinerComponent.cs deleted file mode 100644 index 1775ec5dad..0000000000 --- a/Content.Server/Atmos/Piping/Other/Components/GasMinerComponent.cs +++ /dev/null @@ -1,43 +0,0 @@ -using Content.Shared.Atmos; - -namespace Content.Server.Atmos.Piping.Other.Components -{ - [RegisterComponent] - public sealed partial class GasMinerComponent : Component - { - [ViewVariables(VVAccess.ReadWrite)] - public bool Enabled { get; set; } = true; - - [ViewVariables(VVAccess.ReadOnly)] - public bool Idle { get; set; } = false; - - /// - /// If the number of moles in the external environment exceeds this number, no gas will be mined. - /// - [ViewVariables(VVAccess.ReadWrite)] - [DataField("maxExternalAmount")] - public float MaxExternalAmount { get; set; } = float.PositiveInfinity; - - /// - /// If the pressure (in kPA) of the external environment exceeds this number, no gas will be mined. - /// - [ViewVariables(VVAccess.ReadWrite)] - [DataField("maxExternalPressure")] - public float MaxExternalPressure { get; set; } = Atmospherics.GasMinerDefaultMaxExternalPressure; - - [ViewVariables(VVAccess.ReadWrite)] - [DataField("spawnGas")] - public Gas? SpawnGas { get; set; } = null; - - [ViewVariables(VVAccess.ReadWrite)] - [DataField("spawnTemperature")] - public float SpawnTemperature { get; set; } = Atmospherics.T20C; - - /// - /// Number of moles created per second when the miner is working. - /// - [ViewVariables(VVAccess.ReadWrite)] - [DataField("spawnAmount")] - public float SpawnAmount { get; set; } = Atmospherics.MolesCellStandard * 20f; - } -} diff --git a/Content.Server/Atmos/Piping/Other/EntitySystems/GasMinerSystem.cs b/Content.Server/Atmos/Piping/Other/EntitySystems/GasMinerSystem.cs deleted file mode 100644 index dd46fb6b4c..0000000000 --- a/Content.Server/Atmos/Piping/Other/EntitySystems/GasMinerSystem.cs +++ /dev/null @@ -1,84 +0,0 @@ -using System.Diagnostics.CodeAnalysis; -using Content.Server.Atmos.EntitySystems; -using Content.Server.Atmos.Piping.Components; -using Content.Server.Atmos.Piping.Other.Components; -using Content.Shared.Atmos; -using JetBrains.Annotations; -using Robust.Server.GameObjects; - -namespace Content.Server.Atmos.Piping.Other.EntitySystems -{ - [UsedImplicitly] - public sealed class GasMinerSystem : EntitySystem - { - [Dependency] private readonly AtmosphereSystem _atmosphereSystem = default!; - [Dependency] private readonly TransformSystem _transformSystem = default!; - - public override void Initialize() - { - base.Initialize(); - - SubscribeLocalEvent(OnMinerUpdated); - } - - private void OnMinerUpdated(Entity ent, ref AtmosDeviceUpdateEvent args) - { - var miner = ent.Comp; - - if (!GetValidEnvironment(ent, out var environment)) - { - miner.Idle = true; - return; - } - - // SpawnAmount is declared in mol/s so to get the amount of gas we hope to mine, we have to multiply this by - // how long we have been waiting to spawn it and further cap the number according to the miner's state. - var toSpawn = CapSpawnAmount(ent, miner.SpawnAmount * args.dt, environment); - miner.Idle = toSpawn == 0; - if (miner.Idle || !miner.Enabled || !miner.SpawnGas.HasValue) - return; - - // Time to mine some gas. - - var merger = new GasMixture(1) { Temperature = miner.SpawnTemperature }; - merger.SetMoles(miner.SpawnGas.Value, toSpawn); - - _atmosphereSystem.Merge(environment, merger); - } - - private bool GetValidEnvironment(Entity ent, [NotNullWhen(true)] out GasMixture? environment) - { - var (uid, miner) = ent; - var transform = Transform(uid); - var position = _transformSystem.GetGridOrMapTilePosition(uid, transform); - - // Treat space as an invalid environment - if (_atmosphereSystem.IsTileSpace(transform.GridUid, transform.MapUid, position)) - { - environment = null; - return false; - } - - environment = _atmosphereSystem.GetContainingMixture((uid, transform), true, true); - return environment != null; - } - - private float CapSpawnAmount(Entity ent, float toSpawnTarget, GasMixture environment) - { - var (uid, miner) = ent; - - // How many moles could we theoretically spawn. Cap by pressure and amount. - var allowableMoles = Math.Min( - (miner.MaxExternalPressure - environment.Pressure) * environment.Volume / (miner.SpawnTemperature * Atmospherics.R), - miner.MaxExternalAmount - environment.TotalMoles); - - var toSpawnReal = Math.Clamp(allowableMoles, 0f, toSpawnTarget); - - if (toSpawnReal < Atmospherics.GasMinMoles) { - return 0f; - } - - return toSpawnReal; - } - } -} diff --git a/Content.Shared/Atmos/Components/GasMinerComponent.cs b/Content.Shared/Atmos/Components/GasMinerComponent.cs new file mode 100644 index 0000000000..43f3032770 --- /dev/null +++ b/Content.Shared/Atmos/Components/GasMinerComponent.cs @@ -0,0 +1,60 @@ +using Robust.Shared.Serialization; +using Robust.Shared.GameStates; + +namespace Content.Shared.Atmos.Components; + +[NetworkedComponent] +[AutoGenerateComponentState] +[RegisterComponent] +public sealed partial class GasMinerComponent : Component +{ + /// + /// Operational state of the miner. + /// + [AutoNetworkedField] + [ViewVariables(VVAccess.ReadOnly)] + public GasMinerState MinerState = GasMinerState.Disabled; + + /// + /// If the number of moles in the external environment exceeds this number, no gas will be mined. + /// + [ViewVariables(VVAccess.ReadWrite)] + [DataField] + public float MaxExternalAmount = float.PositiveInfinity; + + /// + /// If the pressure (in kPA) of the external environment exceeds this number, no gas will be mined. + /// + [ViewVariables(VVAccess.ReadWrite)] + [DataField] + public float MaxExternalPressure = Atmospherics.GasMinerDefaultMaxExternalPressure; + + /// + /// Gas to spawn. + /// + [ViewVariables(VVAccess.ReadWrite)] + [DataField(required: true)] + public Gas SpawnGas; + + /// + /// Temperature in Kelvin. + /// + [ViewVariables(VVAccess.ReadWrite)] + [DataField] + public float SpawnTemperature = Atmospherics.T20C; + + /// + /// Number of moles created per second when the miner is working. + /// + [ViewVariables(VVAccess.ReadWrite)] + [DataField] + public float SpawnAmount = Atmospherics.MolesCellStandard * 20f; +} + +[Serializable, NetSerializable] +public enum GasMinerState : byte +{ + Disabled, + Idle, + Working, +} diff --git a/Content.Shared/Atmos/EntitySystems/SharedGasMinerSystem.cs b/Content.Shared/Atmos/EntitySystems/SharedGasMinerSystem.cs new file mode 100644 index 0000000000..957ff6fde4 --- /dev/null +++ b/Content.Shared/Atmos/EntitySystems/SharedGasMinerSystem.cs @@ -0,0 +1,55 @@ +using Content.Shared.Atmos.Components; +using Content.Shared.Examine; +using Content.Shared.Temperature; + +namespace Content.Shared.Atmos.EntitySystems; + +public abstract class SharedGasMinerSystem : EntitySystem +{ + [Dependency] private readonly SharedAtmosphereSystem _sharedAtmosphereSystem = default!; + + public override void Initialize() + { + base.Initialize(); + SubscribeLocalEvent(OnExamine); + } + + private void OnExamine(Entity ent, ref ExaminedEvent args) + { + var component = ent.Comp; + + using (args.PushGroup(nameof(GasMinerComponent))) + { + args.PushMarkup(Loc.GetString("gas-miner-mines-text", + ("gas", Loc.GetString(_sharedAtmosphereSystem.GetGas(component.SpawnGas).Name)))); + + args.PushText(Loc.GetString("gas-miner-amount-text", + ("moles", $"{component.SpawnAmount:0.#}"))); + + args.PushText(Loc.GetString("gas-miner-temperature-text", + ("tempK", $"{component.SpawnTemperature:0.#}"), + ("tempC", $"{TemperatureHelpers.KelvinToCelsius(component.SpawnTemperature):0.#}"))); + + if (component.MaxExternalAmount < float.PositiveInfinity) + { + args.PushText(Loc.GetString("gas-miner-moles-cutoff-text", + ("moles", $"{component.MaxExternalAmount:0.#}"))); + } + + if (component.MaxExternalPressure < float.PositiveInfinity) + { + args.PushText(Loc.GetString("gas-miner-pressure-cutoff-text", + ("pressure", $"{component.MaxExternalPressure:0.#}"))); + } + + args.AddMarkup(component.MinerState switch + { + GasMinerState.Disabled => Loc.GetString("gas-miner-state-disabled-text"), + GasMinerState.Idle => Loc.GetString("gas-miner-state-idle-text"), + GasMinerState.Working => Loc.GetString("gas-miner-state-working-text"), + // C# pattern matching is not exhaustive for enums + _ => throw new IndexOutOfRangeException(nameof(component.MinerState)), + }); + } + } +} diff --git a/Resources/Locale/en-US/atmos/gas-miner-component.ftl b/Resources/Locale/en-US/atmos/gas-miner-component.ftl new file mode 100644 index 0000000000..87016e4522 --- /dev/null +++ b/Resources/Locale/en-US/atmos/gas-miner-component.ftl @@ -0,0 +1,11 @@ +gas-miner-mines-text = It mines [color=lightgray]{$gas}[/color] when active. + +gas-miner-amount-text = It mines {$moles} moles of gas a second when active. +gas-miner-temperature-text = Mined gas temp: {$tempK}K ({$tempC}°C). + +gas-miner-moles-cutoff-text = Surrounding moles cutoff: {$moles} moles. +gas-miner-pressure-cutoff-text = Surrounding pressure cutoff: {$pressure} kPA. + +gas-miner-state-working-text = The miner is [color=green]active[/color] and mining gas. +gas-miner-state-idle-text = The miner is [color=yellow]idle[/color] and not mining gas. +gas-miner-state-disabled-text = The miner is [color=red]disabled[/color] and not mining gas. \ No newline at end of file From 3a50880070d7121501f39dbd9f6cf1af6fa229ae Mon Sep 17 00:00:00 2001 From: PJBot Date: Thu, 8 Aug 2024 02:15:38 +0000 Subject: [PATCH 005/174] Automatic changelog update --- Resources/Changelog/Changelog.yml | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 8a1f87d153..777ad15e49 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,12 +1,4 @@ Entries: -- author: K-Dynamic - changes: - - message: Bike Horns, Suspenders and the Clown Recorder are now available from - the Theatrical Performances Crate - type: Tweak - id: 6557 - time: '2024-05-08T12:30:43.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/27668 - author: Riolume changes: - message: Added ability to drink from spray bottles @@ -3784,3 +3776,10 @@ id: 7056 time: '2024-08-07T21:47:03.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/29772 +- author: Mervill + changes: + - message: Gas Miners now have detailed examine text + type: Tweak + id: 7057 + time: '2024-08-08T02:14:31.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/30480 From 23e4a9a0042031255e2c7a986e758b2740ff9493 Mon Sep 17 00:00:00 2001 From: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com> Date: Thu, 8 Aug 2024 12:34:00 +1000 Subject: [PATCH 006/174] Update submodule to 229.1.2 (#30764) Tests should work decently again --- RobustToolbox | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RobustToolbox b/RobustToolbox index 5c0ce43e6c..49c831b48d 160000 --- a/RobustToolbox +++ b/RobustToolbox @@ -1 +1 @@ -Subproject commit 5c0ce43e6c3c22a939fad8a9f9848e489b135651 +Subproject commit 49c831b48d1449e90a65acdb0c276d2deea4ce2c From ab28e1a9a9bbee16c90721a5c0e9fb4b6efcfc35 Mon Sep 17 00:00:00 2001 From: Mervill Date: Wed, 7 Aug 2024 20:03:41 -0700 Subject: [PATCH 007/174] Remove obsolete occurrences of IComponent.Owner being assigned just before AddComponent (#30724) --- .../EntitySystems/TwoStageTriggerSystem.cs | 5 ++--- .../Humanoid/Systems/RandomHumanoidSystem.cs | 3 +-- Content.Server/Jobs/AddComponentSpecial.cs | 5 ++--- .../Worldgen/Prototypes/BiomePrototype.cs | 1 - .../Worldgen/Prototypes/WorldgenConfigPrototype.cs | 1 - .../XenoArtifacts/ArtifactSystem.Nodes.cs | 14 ++++++-------- Content.Shared/Magic/SharedMagicSystem.cs | 7 +++---- 7 files changed, 14 insertions(+), 22 deletions(-) diff --git a/Content.Server/Explosion/EntitySystems/TwoStageTriggerSystem.cs b/Content.Server/Explosion/EntitySystems/TwoStageTriggerSystem.cs index 4e95eabff0..89950edf8c 100644 --- a/Content.Server/Explosion/EntitySystems/TwoStageTriggerSystem.cs +++ b/Content.Server/Explosion/EntitySystems/TwoStageTriggerSystem.cs @@ -30,13 +30,12 @@ public sealed class TwoStageTriggerSystem : EntitySystem { foreach (var (name, entry) in component.SecondStageComponents) { - var comp = (Component) _factory.GetComponent(name); - var temp = (object) comp; + var comp = (Component)_factory.GetComponent(name); + var temp = (object)comp; if (EntityManager.TryGetComponent(uid, entry.Component.GetType(), out var c)) RemComp(uid, c); - comp.Owner = uid; _serializationManager.CopyTo(entry.Component, ref temp); EntityManager.AddComponent(uid, comp); } diff --git a/Content.Server/Humanoid/Systems/RandomHumanoidSystem.cs b/Content.Server/Humanoid/Systems/RandomHumanoidSystem.cs index 872df8eae8..fc0e47b033 100644 --- a/Content.Server/Humanoid/Systems/RandomHumanoidSystem.cs +++ b/Content.Server/Humanoid/Systems/RandomHumanoidSystem.cs @@ -50,8 +50,7 @@ public sealed class RandomHumanoidSystem : EntitySystem { foreach (var entry in prototype.Components.Values) { - var comp = (Component) _serialization.CreateCopy(entry.Component, notNullableOverride: true); - comp.Owner = humanoid; // This .owner must survive for now. + var comp = (Component)_serialization.CreateCopy(entry.Component, notNullableOverride: true); EntityManager.RemoveComponent(humanoid, comp.GetType()); EntityManager.AddComponent(humanoid, comp); } diff --git a/Content.Server/Jobs/AddComponentSpecial.cs b/Content.Server/Jobs/AddComponentSpecial.cs index c57d734354..6489068d1f 100644 --- a/Content.Server/Jobs/AddComponentSpecial.cs +++ b/Content.Server/Jobs/AddComponentSpecial.cs @@ -23,12 +23,11 @@ namespace Content.Server.Jobs foreach (var (name, data) in Components) { var component = (Component) factory.GetComponent(name); - component.Owner = mob; - var temp = (object) component; + var temp = (object)component; serializationManager.CopyTo(data.Component, ref temp); entityManager.RemoveComponent(mob, temp!.GetType()); - entityManager.AddComponent(mob, (Component) temp); + entityManager.AddComponent(mob, (Component)temp); } } } diff --git a/Content.Server/Worldgen/Prototypes/BiomePrototype.cs b/Content.Server/Worldgen/Prototypes/BiomePrototype.cs index db1b5e2a16..1cecf87a5e 100644 --- a/Content.Server/Worldgen/Prototypes/BiomePrototype.cs +++ b/Content.Server/Worldgen/Prototypes/BiomePrototype.cs @@ -54,7 +54,6 @@ public sealed partial class BiomePrototype : IPrototype, IInheritingPrototype foreach (var data in ChunkComponents.Values) { var comp = (Component) serialization.CreateCopy(data.Component, notNullableOverride: true); - comp.Owner = target; // look im sorry ok this .owner has to live until engine api exists entityManager.AddComponent(target, comp); } } diff --git a/Content.Server/Worldgen/Prototypes/WorldgenConfigPrototype.cs b/Content.Server/Worldgen/Prototypes/WorldgenConfigPrototype.cs index 49e9e1ed9d..f669377abb 100644 --- a/Content.Server/Worldgen/Prototypes/WorldgenConfigPrototype.cs +++ b/Content.Server/Worldgen/Prototypes/WorldgenConfigPrototype.cs @@ -30,7 +30,6 @@ public sealed partial class WorldgenConfigPrototype : IPrototype foreach (var data in Components.Values) { var comp = (Component) serialization.CreateCopy(data.Component, notNullableOverride: true); - comp.Owner = target; // look im sorry ok this .owner has to live until engine api exists entityManager.AddComponent(target, comp); } } diff --git a/Content.Server/Xenoarchaeology/XenoArtifacts/ArtifactSystem.Nodes.cs b/Content.Server/Xenoarchaeology/XenoArtifacts/ArtifactSystem.Nodes.cs index 65aaabdf0e..a0e8420011 100644 --- a/Content.Server/Xenoarchaeology/XenoArtifacts/ArtifactSystem.Nodes.cs +++ b/Content.Server/Xenoarchaeology/XenoArtifacts/ArtifactSystem.Nodes.cs @@ -182,13 +182,12 @@ public sealed partial class ArtifactSystem EntityManager.RemoveComponent(uid, reg.Type); } - var comp = (Component) _componentFactory.GetComponent(reg); - comp.Owner = uid; + var comp = (Component)_componentFactory.GetComponent(reg); - var temp = (object) comp; + var temp = (object)comp; _serialization.CopyTo(entry.Component, ref temp); EntityManager.RemoveComponent(uid, temp!.GetType()); - EntityManager.AddComponent(uid, (Component) temp!); + EntityManager.AddComponent(uid, (Component)temp!); } node.Discovered = true; @@ -218,12 +217,11 @@ public sealed partial class ArtifactSystem // if the entity prototype contained the component originally if (entityPrototype?.Components.TryGetComponent(name, out var entry) ?? false) { - var comp = (Component) _componentFactory.GetComponent(name); - comp.Owner = uid; - var temp = (object) comp; + var comp = (Component)_componentFactory.GetComponent(name); + var temp = (object)comp; _serialization.CopyTo(entry, ref temp); EntityManager.RemoveComponent(uid, temp!.GetType()); - EntityManager.AddComponent(uid, (Component) temp); + EntityManager.AddComponent(uid, (Component)temp); continue; } diff --git a/Content.Shared/Magic/SharedMagicSystem.cs b/Content.Shared/Magic/SharedMagicSystem.cs index cc7a297aa4..02d483c0a3 100644 --- a/Content.Shared/Magic/SharedMagicSystem.cs +++ b/Content.Shared/Magic/SharedMagicSystem.cs @@ -369,11 +369,10 @@ public abstract class SharedMagicSystem : EntitySystem if (HasComp(ev.Target, data.Component.GetType())) continue; - var component = (Component) _compFact.GetComponent(name); - component.Owner = ev.Target; - var temp = (object) component; + var component = (Component)_compFact.GetComponent(name); + var temp = (object)component; _seriMan.CopyTo(data.Component, ref temp); - EntityManager.AddComponent(ev.Target, (Component) temp!); + EntityManager.AddComponent(ev.Target, (Component)temp!); } } // End Change Component Spells From 929e6a2c002f5dd23633331100f0fa6a68b6de39 Mon Sep 17 00:00:00 2001 From: TakoDragon <69509841+BackeTako@users.noreply.github.com> Date: Thu, 8 Aug 2024 05:08:28 +0200 Subject: [PATCH 008/174] Improved Spanish accent (#30551) * Spanish and French comment * Added the interrobang * Make spanish accent use sting builder --- Content.Server/Speech/AccentSystem.cs | 2 +- .../Components/FrenchAccentComponent.cs | 3 +- .../Components/SpanishAccentComponent.cs | 11 +++---- .../EntitySystems/FrenchAccentSystem.cs | 4 +-- .../EntitySystems/SpanishAccentSystem.cs | 29 ++++++++++++------- 5 files changed, 27 insertions(+), 22 deletions(-) diff --git a/Content.Server/Speech/AccentSystem.cs b/Content.Server/Speech/AccentSystem.cs index 13f174c01e..7e29f02cae 100644 --- a/Content.Server/Speech/AccentSystem.cs +++ b/Content.Server/Speech/AccentSystem.cs @@ -6,7 +6,7 @@ namespace Content.Server.Speech { public sealed class AccentSystem : EntitySystem { - public static readonly Regex SentenceRegex = new(@"(?<=[\.!\?])", RegexOptions.Compiled); + public static readonly Regex SentenceRegex = new(@"(?<=[\.!\?‽])(?![\.!\?‽])", RegexOptions.Compiled); public override void Initialize() { diff --git a/Content.Server/Speech/Components/FrenchAccentComponent.cs b/Content.Server/Speech/Components/FrenchAccentComponent.cs index f696c35ea0..dfe584e267 100644 --- a/Content.Server/Speech/Components/FrenchAccentComponent.cs +++ b/Content.Server/Speech/Components/FrenchAccentComponent.cs @@ -7,5 +7,4 @@ namespace Content.Server.Speech.Components; /// [RegisterComponent] [Access(typeof(FrenchAccentSystem))] -public sealed partial class FrenchAccentComponent : Component -{ } +public sealed partial class FrenchAccentComponent : Component {} diff --git a/Content.Server/Speech/Components/SpanishAccentComponent.cs b/Content.Server/Speech/Components/SpanishAccentComponent.cs index 16a2d188b6..b2eeddc0db 100644 --- a/Content.Server/Speech/Components/SpanishAccentComponent.cs +++ b/Content.Server/Speech/Components/SpanishAccentComponent.cs @@ -1,7 +1,4 @@ -namespace Content.Server.Speech.Components -{ - [RegisterComponent] - public sealed partial class SpanishAccentComponent : Component - { - } -} +namespace Content.Server.Speech.Components; + +[RegisterComponent] +public sealed partial class SpanishAccentComponent : Component {} diff --git a/Content.Server/Speech/EntitySystems/FrenchAccentSystem.cs b/Content.Server/Speech/EntitySystems/FrenchAccentSystem.cs index f6d259c115..d71655569c 100644 --- a/Content.Server/Speech/EntitySystems/FrenchAccentSystem.cs +++ b/Content.Server/Speech/EntitySystems/FrenchAccentSystem.cs @@ -27,10 +27,10 @@ public sealed class FrenchAccentSystem : EntitySystem msg = _replacement.ApplyReplacements(msg, "french"); - // replaces th with dz + // replaces th with z msg = RegexTh.Replace(msg, "'z"); - // removes the letter h from the start of words. + // replaces h with ' at the start of words. msg = RegexStartH.Replace(msg, "'"); // spaces out ! ? : and ;. diff --git a/Content.Server/Speech/EntitySystems/SpanishAccentSystem.cs b/Content.Server/Speech/EntitySystems/SpanishAccentSystem.cs index c8ac24a450..08642014c9 100644 --- a/Content.Server/Speech/EntitySystems/SpanishAccentSystem.cs +++ b/Content.Server/Speech/EntitySystems/SpanishAccentSystem.cs @@ -1,3 +1,4 @@ +using System.Text; using Content.Server.Speech.Components; namespace Content.Server.Speech.EntitySystems @@ -14,7 +15,7 @@ namespace Content.Server.Speech.EntitySystems // Insert E before every S message = InsertS(message); // If a sentence ends with ?, insert a reverse ? at the beginning of the sentence - message = ReplaceQuestionMark(message); + message = ReplacePunctuation(message); return message; } @@ -36,24 +37,32 @@ namespace Content.Server.Speech.EntitySystems return msg; } - private string ReplaceQuestionMark(string message) + private string ReplacePunctuation(string message) { var sentences = AccentSystem.SentenceRegex.Split(message); - var msg = ""; + var msg = new StringBuilder(); foreach (var s in sentences) { - if (s.EndsWith("?", StringComparison.Ordinal)) // We've got a question => add ¿ to the beginning + var toInsert = new StringBuilder(); + for (var i = s.Length - 1; i >= 0 && "?!‽".Contains(s[i]); i--) { - // Because we don't split by whitespace, we may have some spaces in front of the sentence. - // So we add the symbol before the first non space char - msg += s.Insert(s.Length - s.TrimStart().Length, "¿"); + toInsert.Append(s[i] switch + { + '?' => '¿', + '!' => '¡', + '‽' => '⸘', + _ => ' ' + }); } - else + if (toInsert.Length == 0) { - msg += s; + msg.Append(s); + } else + { + msg.Append(s.Insert(s.Length - s.TrimStart().Length, toInsert.ToString())); } } - return msg; + return msg.ToString(); } private void OnAccent(EntityUid uid, SpanishAccentComponent component, AccentGetEvent args) From 0057141039d9c2f207a60df366a9ff99e1dba180 Mon Sep 17 00:00:00 2001 From: PJBot Date: Thu, 8 Aug 2024 03:09:34 +0000 Subject: [PATCH 009/174] Automatic changelog update --- Resources/Changelog/Changelog.yml | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 777ad15e49..de628bad55 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,13 +1,4 @@ Entries: -- author: Riolume - changes: - - message: Added ability to drink from spray bottles - type: Add - - message: Can now see the amount of liquid in spray bottles - type: Add - id: 6558 - time: '2024-05-09T05:56:13.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/27815 - author: Blackern5000 changes: - message: Atmos metal pipes now deal blunt damage. @@ -3783,3 +3774,10 @@ id: 7057 time: '2024-08-08T02:14:31.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/30480 +- author: BackeTako + changes: + - message: "!, \u203D and multiple punctuations now work for Spanish." + type: Tweak + id: 7058 + time: '2024-08-08T03:08:28.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/30551 From 489efeb7171040305861c8af136788ea3940a086 Mon Sep 17 00:00:00 2001 From: deltanedas <39013340+deltanedas@users.noreply.github.com> Date: Thu, 8 Aug 2024 08:16:02 +0000 Subject: [PATCH 010/174] remove GenericAntag completely (#28218) Co-authored-by: deltanedas <@deltanedas:kde.org> Co-authored-by: metalgearsloth --- .../Components/GenericAntagRuleComponent.cs | 30 --------- .../Rules/GenericAntagRuleSystem.cs | 56 ---------------- .../GenericAntag/GenericAntagComponent.cs | 30 --------- .../GenericAntag/GenericAntagSystem.cs | 67 ------------------- 4 files changed, 183 deletions(-) delete mode 100644 Content.Server/GameTicking/Rules/Components/GenericAntagRuleComponent.cs delete mode 100644 Content.Server/GameTicking/Rules/GenericAntagRuleSystem.cs delete mode 100644 Content.Server/GenericAntag/GenericAntagComponent.cs delete mode 100644 Content.Server/GenericAntag/GenericAntagSystem.cs diff --git a/Content.Server/GameTicking/Rules/Components/GenericAntagRuleComponent.cs b/Content.Server/GameTicking/Rules/Components/GenericAntagRuleComponent.cs deleted file mode 100644 index 8d212ebaa3..0000000000 --- a/Content.Server/GameTicking/Rules/Components/GenericAntagRuleComponent.cs +++ /dev/null @@ -1,30 +0,0 @@ -using Content.Server.GameTicking.Rules; -using Robust.Shared.Prototypes; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.List; - -namespace Content.Server.GameTicking.Rules.Components; - -/// -/// Gamerule for simple antagonists that have fixed objectives. -/// -[RegisterComponent, Access(typeof(GenericAntagRuleSystem))] -public sealed partial class GenericAntagRuleComponent : Component -{ - /// - /// All antag minds that are using this rule. - /// - [DataField] - public List Minds = new(); - - /// - /// Locale id for the name of the antag used by the roundend summary. - /// - [DataField(required: true), ViewVariables(VVAccess.ReadWrite)] - public string AgentName = string.Empty; - - /// - /// List of objective entity prototypes to add to the antag when a mind is added. - /// - [DataField(required: true)] - public List Objectives = new(); -} diff --git a/Content.Server/GameTicking/Rules/GenericAntagRuleSystem.cs b/Content.Server/GameTicking/Rules/GenericAntagRuleSystem.cs deleted file mode 100644 index 0367aa1460..0000000000 --- a/Content.Server/GameTicking/Rules/GenericAntagRuleSystem.cs +++ /dev/null @@ -1,56 +0,0 @@ -using Content.Server.GameTicking.Rules.Components; -using Content.Server.Objectives; -using Content.Shared.Mind; -using System.Diagnostics.CodeAnalysis; -using System.Linq; - -namespace Content.Server.GameTicking.Rules; - -/// -/// Handles round end text for simple antags. -/// Adding objectives is handled in its own system. -/// -public sealed class GenericAntagRuleSystem : GameRuleSystem -{ - public override void Initialize() - { - base.Initialize(); - - SubscribeLocalEvent(OnObjectivesTextGetInfo); - } - - /// - /// Start a simple antag's game rule. - /// If it is invalid the rule is deleted and null is returned. - /// - public bool StartRule(string rule, EntityUid mindId, [NotNullWhen(true)] out EntityUid? ruleId, [NotNullWhen(true)] out GenericAntagRuleComponent? comp) - { - ruleId = GameTicker.AddGameRule(rule); - if (!TryComp(ruleId, out comp)) - { - Log.Error($"Simple antag rule prototype {rule} is invalid, deleting it."); - Del(ruleId); - ruleId = null; - return false; - } - - if (!GameTicker.StartGameRule(ruleId.Value)) - { - Log.Error($"Simple antag rule prototype {rule} failed to start, deleting it."); - Del(ruleId); - ruleId = null; - comp = null; - return false; - } - - comp.Minds.Add(mindId); - return true; - } - - private void OnObjectivesTextGetInfo(EntityUid uid, GenericAntagRuleComponent comp, ref ObjectivesTextGetInfoEvent args) - { - // just temporary until this is deleted - args.Minds = comp.Minds.Select(mindId => (mindId, Comp(mindId).CharacterName ?? "?")).ToList(); - args.AgentName = Loc.GetString(comp.AgentName); - } -} diff --git a/Content.Server/GenericAntag/GenericAntagComponent.cs b/Content.Server/GenericAntag/GenericAntagComponent.cs deleted file mode 100644 index b8ed9cf6ef..0000000000 --- a/Content.Server/GenericAntag/GenericAntagComponent.cs +++ /dev/null @@ -1,30 +0,0 @@ -using Content.Server.GameTicking.Rules.Components; -using Robust.Shared.Prototypes; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; - -namespace Content.Server.GenericAntag; - -/// -/// Added to a mob to make it a generic antagonist where all its objectives are fixed. -/// This is unlike say traitor where it gets objectives picked randomly using difficulty. -/// -/// -/// A GenericAntag is not necessarily an antagonist, that depends on the roles you do or do not add after. -/// -[RegisterComponent, Access(typeof(GenericAntagSystem))] -public sealed partial class GenericAntagComponent : Component -{ - /// - /// Gamerule to start when a mind is added. - /// This must have or it will not work. - /// - [DataField(required: true), ViewVariables(VVAccess.ReadWrite)] - public EntProtoId Rule = string.Empty; - - /// - /// The rule that's been spawned. - /// Used to prevent spawning multiple rules. - /// - [DataField, ViewVariables(VVAccess.ReadWrite)] - public EntityUid? RuleEntity; -} diff --git a/Content.Server/GenericAntag/GenericAntagSystem.cs b/Content.Server/GenericAntag/GenericAntagSystem.cs deleted file mode 100644 index 6b1774159c..0000000000 --- a/Content.Server/GenericAntag/GenericAntagSystem.cs +++ /dev/null @@ -1,67 +0,0 @@ -using Content.Server.GameTicking.Rules; -using Content.Shared.Mind; -using Content.Shared.Mind.Components; - -namespace Content.Server.GenericAntag; - -/// -/// Handles adding objectives to s. -/// Roundend summary is handled by . -/// -public sealed class GenericAntagSystem : EntitySystem -{ - [Dependency] private readonly SharedMindSystem _mind = default!; - [Dependency] private readonly GenericAntagRuleSystem _genericAntagRule = default!; - - public override void Initialize() - { - base.Initialize(); - - SubscribeLocalEvent(OnMindAdded); - } - - private void OnMindAdded(EntityUid uid, GenericAntagComponent comp, MindAddedMessage args) - { - if (!TryComp(uid, out var mindContainer) || mindContainer.Mind == null) - return; - - var mindId = mindContainer.Mind.Value; - MakeAntag(uid, mindId, comp); - } - - /// - /// Turns a player into this antagonist. - /// Does the same thing that having a mind added does, use for antag ctrl. - /// - public void MakeAntag(EntityUid uid, EntityUid mindId, GenericAntagComponent? comp = null, MindComponent? mind = null) - { - if (!Resolve(uid, ref comp) || !Resolve(mindId, ref mind)) - return; - - // only add the rule once - if (comp.RuleEntity != null) - return; - - // start the rule - if (!_genericAntagRule.StartRule(comp.Rule, mindId, out comp.RuleEntity, out var rule)) - return; - - // let other systems know the antag was created so they can add briefing, roles, etc. - // its important that this is before objectives are added since they may depend on roles added here - var ev = new GenericAntagCreatedEvent(mindId, mind); - RaiseLocalEvent(uid, ref ev); - - // add the objectives from the rule - foreach (var id in rule.Objectives) - { - _mind.TryAddObjective(mindId, mind, id); - } - } -} - -/// -/// Event raised on a player's entity after its simple antag rule is started. -/// Use this to add a briefing, roles, etc. -/// -[ByRefEvent] -public record struct GenericAntagCreatedEvent(EntityUid MindId, MindComponent Mind); From 1df84515c72f4a421a395718ce8b394fcd2b6fed Mon Sep 17 00:00:00 2001 From: ShadowCommander <10494922+ShadowCommander@users.noreply.github.com> Date: Thu, 8 Aug 2024 02:47:08 -0700 Subject: [PATCH 011/174] Add EntityWorldTargetAction (#29819) * Add EntityWorldTargetAction initial implementation * Update obsolete methods * Partially working EntityWorldTargetAction * Fix entity selection * Move and clean up AfterInteract * Fix building new walls * Readd no entity or coordinates error * Consolidate action validation code * Add summaries to component --------- Co-authored-by: Ed <96445749+TheShuEd@users.noreply.github.com> --- Content.Client/Actions/ActionsSystem.cs | 13 ++ .../Systems/Actions/ActionUIController.cs | 48 ++++++- .../Actions/ActionOnInteractSystem.cs | 25 ++++ Content.Shared/Actions/ActionEvents.cs | 28 +++++ .../EntityWorldTargetActionComponent.cs | 42 +++++++ .../ValidateActionEntityWorldTargetEvent.cs | 10 ++ Content.Shared/Actions/SharedActionsSystem.cs | 119 +++++++++++++++--- 7 files changed, 266 insertions(+), 19 deletions(-) create mode 100644 Content.Shared/Actions/EntityWorldTargetActionComponent.cs create mode 100644 Content.Shared/Actions/Events/ValidateActionEntityWorldTargetEvent.cs diff --git a/Content.Client/Actions/ActionsSystem.cs b/Content.Client/Actions/ActionsSystem.cs index 30f657a2b5..f05e445588 100644 --- a/Content.Client/Actions/ActionsSystem.cs +++ b/Content.Client/Actions/ActionsSystem.cs @@ -48,6 +48,7 @@ namespace Content.Client.Actions SubscribeLocalEvent(OnInstantHandleState); SubscribeLocalEvent(OnEntityTargetHandleState); SubscribeLocalEvent(OnWorldTargetHandleState); + SubscribeLocalEvent(OnEntityWorldTargetHandleState); } private void OnInstantHandleState(EntityUid uid, InstantActionComponent component, ref ComponentHandleState args) @@ -76,6 +77,18 @@ namespace Content.Client.Actions BaseHandleState(uid, component, state); } + private void OnEntityWorldTargetHandleState(EntityUid uid, + EntityWorldTargetActionComponent component, + ref ComponentHandleState args) + { + if (args.Current is not EntityWorldTargetActionComponentState state) + return; + + component.Whitelist = state.Whitelist; + component.CanTargetSelf = state.CanTargetSelf; + BaseHandleState(uid, component, state); + } + private void BaseHandleState(EntityUid uid, BaseActionComponent component, BaseActionComponentState state) where T : BaseActionComponent { // TODO ACTIONS use auto comp states diff --git a/Content.Client/UserInterface/Systems/Actions/ActionUIController.cs b/Content.Client/UserInterface/Systems/Actions/ActionUIController.cs index 4d2ac20d12..1c76b30075 100644 --- a/Content.Client/UserInterface/Systems/Actions/ActionUIController.cs +++ b/Content.Client/UserInterface/Systems/Actions/ActionUIController.cs @@ -184,10 +184,13 @@ public sealed class ActionUIController : UIController, IOnStateChanged(actionEnts, args.CanReach); + for (var i = entWorldOptions.Count - 1; i >= 0; i--) + { + var action = entWorldOptions[i]; + if (!_actions.ValidateEntityWorldTarget(args.User, args.Target, args.ClickLocation, action)) + entWorldOptions.RemoveAt(i); + } + + if (entWorldOptions.Count > 0) + { + var (entActId, entAct) = _random.Pick(entWorldOptions); + if (entAct.Event != null) + { + entAct.Event.Performer = args.User; + entAct.Event.Action = entActId; + entAct.Event.Entity = args.Target; + entAct.Event.Coords = args.ClickLocation; + } + + _actions.PerformAction(args.User, null, entActId, entAct, entAct.Event, _timing.CurTime, false); + args.Handled = true; + return; + } + // else: try world target actions var options = GetValidActions(component.ActionEntities, args.CanReach); for (var i = options.Count - 1; i >= 0; i--) diff --git a/Content.Shared/Actions/ActionEvents.cs b/Content.Shared/Actions/ActionEvents.cs index 6cc50bc21b..4f1cd6da44 100644 --- a/Content.Shared/Actions/ActionEvents.cs +++ b/Content.Shared/Actions/ActionEvents.cs @@ -101,6 +101,13 @@ public sealed class RequestPerformActionEvent : EntityEventArgs Action = action; EntityCoordinatesTarget = entityCoordinatesTarget; } + + public RequestPerformActionEvent(NetEntity action, NetEntity entityTarget, NetCoordinates entityCoordinatesTarget) + { + Action = action; + EntityTarget = entityTarget; + EntityCoordinatesTarget = entityCoordinatesTarget; + } } /// @@ -144,6 +151,27 @@ public abstract partial class WorldTargetActionEvent : BaseActionEvent public EntityCoordinates Target; } +/// +/// This is the type of event that gets raised when an is performed. +/// The , , and +/// fields will automatically be filled out by the . +/// +/// +/// To define a new action for some system, you need to create an event that inherits from this class. +/// +public abstract partial class EntityWorldTargetActionEvent : BaseActionEvent +{ + /// + /// The entity that the user targeted. + /// + public EntityUid? Entity; + + /// + /// The coordinates of the location that the user targeted. + /// + public EntityCoordinates? Coords; +} + /// /// Base class for events that are raised when an action gets performed. This should not generally be used outside of the action /// system. diff --git a/Content.Shared/Actions/EntityWorldTargetActionComponent.cs b/Content.Shared/Actions/EntityWorldTargetActionComponent.cs new file mode 100644 index 0000000000..3cfa60d030 --- /dev/null +++ b/Content.Shared/Actions/EntityWorldTargetActionComponent.cs @@ -0,0 +1,42 @@ +using Content.Shared.Whitelist; +using Robust.Shared.GameStates; +using Robust.Shared.Serialization; + +namespace Content.Shared.Actions; + +/// +/// Used on action entities to define an action that triggers when targeting an entity or entity coordinates. +/// +[RegisterComponent, NetworkedComponent] +public sealed partial class EntityWorldTargetActionComponent : BaseTargetActionComponent +{ + public override BaseActionEvent? BaseEvent => Event; + + /// + /// The local-event to raise when this action is performed. + /// + [DataField] + [NonSerialized] + public EntityWorldTargetActionEvent? Event; + + /// + /// Determines which entities are valid targets for this action. + /// + /// No whitelist check when null. + [DataField] public EntityWhitelist? Whitelist; + + /// + /// Whether this action considers the user as a valid target entity when using this action. + /// + [DataField] public bool CanTargetSelf = true; +} + +[Serializable, NetSerializable] +public sealed class EntityWorldTargetActionComponentState( + EntityWorldTargetActionComponent component, + IEntityManager entManager) + : BaseActionComponentState(component, entManager) +{ + public EntityWhitelist? Whitelist = component.Whitelist; + public bool CanTargetSelf = component.CanTargetSelf; +} diff --git a/Content.Shared/Actions/Events/ValidateActionEntityWorldTargetEvent.cs b/Content.Shared/Actions/Events/ValidateActionEntityWorldTargetEvent.cs new file mode 100644 index 0000000000..57c47026be --- /dev/null +++ b/Content.Shared/Actions/Events/ValidateActionEntityWorldTargetEvent.cs @@ -0,0 +1,10 @@ +using Robust.Shared.Map; + +namespace Content.Shared.Actions.Events; + +[ByRefEvent] +public record struct ValidateActionEntityWorldTargetEvent( + EntityUid User, + EntityUid? Target, + EntityCoordinates? Coords, + bool Cancelled = false); diff --git a/Content.Shared/Actions/SharedActionsSystem.cs b/Content.Shared/Actions/SharedActionsSystem.cs index 0033078b1b..635d78b8dd 100644 --- a/Content.Shared/Actions/SharedActionsSystem.cs +++ b/Content.Shared/Actions/SharedActionsSystem.cs @@ -38,10 +38,12 @@ public abstract class SharedActionsSystem : EntitySystem SubscribeLocalEvent(OnActionMapInit); SubscribeLocalEvent(OnActionMapInit); SubscribeLocalEvent(OnActionMapInit); + SubscribeLocalEvent(OnActionMapInit); SubscribeLocalEvent(OnActionShutdown); SubscribeLocalEvent(OnActionShutdown); SubscribeLocalEvent(OnActionShutdown); + SubscribeLocalEvent(OnActionShutdown); SubscribeLocalEvent(OnDidEquip); SubscribeLocalEvent(OnHandEquipped); @@ -56,10 +58,12 @@ public abstract class SharedActionsSystem : EntitySystem SubscribeLocalEvent(OnInstantGetState); SubscribeLocalEvent(OnEntityTargetGetState); SubscribeLocalEvent(OnWorldTargetGetState); + SubscribeLocalEvent(OnEntityWorldTargetGetState); SubscribeLocalEvent(OnGetActionData); SubscribeLocalEvent(OnGetActionData); SubscribeLocalEvent(OnGetActionData); + SubscribeLocalEvent(OnGetActionData); SubscribeAllEvent(OnActionRequest); } @@ -102,6 +106,11 @@ public abstract class SharedActionsSystem : EntitySystem args.State = new WorldTargetActionComponentState(component, EntityManager); } + private void OnEntityWorldTargetGetState(EntityUid uid, EntityWorldTargetActionComponent component, ref ComponentGetState args) + { + args.State = new EntityWorldTargetActionComponentState(component, EntityManager); + } + private void OnGetActionData(EntityUid uid, T component, ref GetActionDataEvent args) where T : BaseActionComponent { args.Action = component; @@ -442,6 +451,34 @@ public abstract class SharedActionsSystem : EntitySystem } break; + case EntityWorldTargetActionComponent entityWorldAction: + { + var actionEntity = GetEntity(ev.EntityTarget); + var actionCoords = GetCoordinates(ev.EntityCoordinatesTarget); + + if (actionEntity is null && actionCoords is null) + { + Log.Error($"Attempted to perform an entity-world-targeted action without an entity or world coordinates! Action: {name}"); + return; + } + + var entWorldAction = new Entity(actionEnt, entityWorldAction); + + if (!ValidateEntityWorldTarget(user, actionEntity, actionCoords, entWorldAction)) + return; + + _adminLogger.Add(LogType.Action, + $"{ToPrettyString(user):user} is performing the {name:action} action (provided by {ToPrettyString(action.Container ?? user):provider}) targeted at {ToPrettyString(actionEntity):target} {actionCoords:target}."); + + if (entityWorldAction.Event != null) + { + entityWorldAction.Event.Entity = actionEntity; + entityWorldAction.Event.Coords = actionCoords; + Dirty(actionEnt, entityWorldAction); + performEvent = entityWorldAction.Event; + } + break; + } case InstantActionComponent instantAction: if (action.CheckCanInteract && !_actionBlockerSystem.CanInteract(user, null)) return; @@ -465,7 +502,14 @@ public abstract class SharedActionsSystem : EntitySystem public bool ValidateEntityTarget(EntityUid user, EntityUid target, Entity actionEnt) { - if (!ValidateEntityTargetBase(user, target, actionEnt)) + var comp = actionEnt.Comp; + if (!ValidateEntityTargetBase(user, + target, + comp.Whitelist, + comp.CheckCanInteract, + comp.CanTargetSelf, + comp.CheckCanAccess, + comp.Range)) return false; var ev = new ValidateActionEntityTargetEvent(user, target); @@ -473,21 +517,27 @@ public abstract class SharedActionsSystem : EntitySystem return !ev.Cancelled; } - private bool ValidateEntityTargetBase(EntityUid user, EntityUid target, EntityTargetActionComponent action) + private bool ValidateEntityTargetBase(EntityUid user, + EntityUid? targetEntity, + EntityWhitelist? whitelist, + bool checkCanInteract, + bool canTargetSelf, + bool checkCanAccess, + float range) { - if (!target.IsValid() || Deleted(target)) + if (targetEntity is not { } target || !target.IsValid() || Deleted(target)) return false; - if (_whitelistSystem.IsWhitelistFail(action.Whitelist, target)) + if (_whitelistSystem.IsWhitelistFail(whitelist, target)) return false; - if (action.CheckCanInteract && !_actionBlockerSystem.CanInteract(user, target)) + if (checkCanInteract && !_actionBlockerSystem.CanInteract(user, target)) return false; if (user == target) - return action.CanTargetSelf; + return canTargetSelf; - if (!action.CheckCanAccess) + if (!checkCanAccess) { // even if we don't check for obstructions, we may still need to check the range. var xform = Transform(user); @@ -496,19 +546,20 @@ public abstract class SharedActionsSystem : EntitySystem if (xform.MapID != targetXform.MapID) return false; - if (action.Range <= 0) + if (range <= 0) return true; var distance = (_transformSystem.GetWorldPosition(xform) - _transformSystem.GetWorldPosition(targetXform)).Length(); - return distance <= action.Range; + return distance <= range; } - return _interactionSystem.InRangeAndAccessible(user, target, range: action.Range); + return _interactionSystem.InRangeAndAccessible(user, target, range: range); } public bool ValidateWorldTarget(EntityUid user, EntityCoordinates coords, Entity action) { - if (!ValidateWorldTargetBase(user, coords, action)) + var comp = action.Comp; + if (!ValidateWorldTargetBase(user, coords, comp.CheckCanInteract, comp.CheckCanAccess, comp.Range)) return false; var ev = new ValidateActionWorldTargetEvent(user, coords); @@ -516,12 +567,19 @@ public abstract class SharedActionsSystem : EntitySystem return !ev.Cancelled; } - private bool ValidateWorldTargetBase(EntityUid user, EntityCoordinates coords, WorldTargetActionComponent action) + private bool ValidateWorldTargetBase(EntityUid user, + EntityCoordinates? entityCoordinates, + bool checkCanInteract, + bool checkCanAccess, + float range) { - if (action.CheckCanInteract && !_actionBlockerSystem.CanInteract(user, null)) + if (entityCoordinates is not { } coords) return false; - if (!action.CheckCanAccess) + if (checkCanInteract && !_actionBlockerSystem.CanInteract(user, null)) + return false; + + if (!checkCanAccess) { // even if we don't check for obstructions, we may still need to check the range. var xform = Transform(user); @@ -529,13 +587,40 @@ public abstract class SharedActionsSystem : EntitySystem if (xform.MapID != coords.GetMapId(EntityManager)) return false; - if (action.Range <= 0) + if (range <= 0) return true; - return _transformSystem.InRange(coords, Transform(user).Coordinates, action.Range); + return coords.InRange(EntityManager, _transformSystem, Transform(user).Coordinates, range); } - return _interactionSystem.InRangeUnobstructed(user, coords, range: action.Range); + return _interactionSystem.InRangeUnobstructed(user, coords, range: range); + } + + public bool ValidateEntityWorldTarget(EntityUid user, + EntityUid? entity, + EntityCoordinates? coords, + Entity action) + { + var comp = action.Comp; + var entityValidated = ValidateEntityTargetBase(user, + entity, + comp.Whitelist, + comp.CheckCanInteract, + comp.CanTargetSelf, + comp.CheckCanAccess, + comp.Range); + + var worldValidated + = ValidateWorldTargetBase(user, coords, comp.CheckCanInteract, comp.CheckCanAccess, comp.Range); + + if (!entityValidated && !worldValidated) + return false; + + var ev = new ValidateActionEntityWorldTargetEvent(user, + entityValidated ? entity : null, + worldValidated ? coords : null); + RaiseLocalEvent(action, ref ev); + return !ev.Cancelled; } public void PerformAction(EntityUid performer, ActionsComponent? component, EntityUid actionId, BaseActionComponent action, BaseActionEvent? actionEvent, TimeSpan curTime, bool predicted = true) From f24949a0b0cf2adace76bbfefa9f6df91303f67a Mon Sep 17 00:00:00 2001 From: IProduceWidgets <107586145+IProduceWidgets@users.noreply.github.com> Date: Thu, 8 Aug 2024 05:53:07 -0400 Subject: [PATCH 012/174] ai stays seated and pulled while cuffed. (#30397) * ai stays seated while cuffed. * Do the thing I thought was dumb.... whatever. * less than --- .../HTN/PrimitiveTasks/Operators/Combat/UnPullOperator.cs | 8 ++++++-- .../PrimitiveTasks/Operators/Combat/UnbuckleOperator.cs | 4 ++-- Content.Shared/Cuffs/SharedCuffableSystem.cs | 2 +- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/Content.Server/NPC/HTN/PrimitiveTasks/Operators/Combat/UnPullOperator.cs b/Content.Server/NPC/HTN/PrimitiveTasks/Operators/Combat/UnPullOperator.cs index 54f422fe67..467ac0d414 100644 --- a/Content.Server/NPC/HTN/PrimitiveTasks/Operators/Combat/UnPullOperator.cs +++ b/Content.Server/NPC/HTN/PrimitiveTasks/Operators/Combat/UnPullOperator.cs @@ -1,4 +1,5 @@ -using Content.Shared.Movement.Pulling.Components; +using Content.Shared.ActionBlocker; +using Content.Shared.Movement.Pulling.Components; using Content.Shared.Movement.Pulling.Systems; namespace Content.Server.NPC.HTN.PrimitiveTasks.Operators.Combat; @@ -7,6 +8,7 @@ public sealed partial class UnPullOperator : HTNOperator { [Dependency] private readonly IEntityManager _entManager = default!; private PullingSystem _pulling = default!; + private ActionBlockerSystem _actionBlocker = default!; private EntityQuery _pullableQuery; @@ -16,6 +18,7 @@ public sealed partial class UnPullOperator : HTNOperator public override void Initialize(IEntitySystemManager sysManager) { base.Initialize(sysManager); + _actionBlocker = sysManager.GetEntitySystem(); _pulling = sysManager.GetEntitySystem(); _pullableQuery = _entManager.GetEntityQuery(); } @@ -25,7 +28,8 @@ public sealed partial class UnPullOperator : HTNOperator base.Startup(blackboard); var owner = blackboard.GetValue(NPCBlackboard.Owner); - _pulling.TryStopPull(owner, _pullableQuery.GetComponent(owner), owner); + if (_actionBlocker.CanInteract(owner, owner)) //prevents handcuffed monkeys from pulling etc. + _pulling.TryStopPull(owner, _pullableQuery.GetComponent(owner), owner); } public override HTNOperatorStatus Update(NPCBlackboard blackboard, float frameTime) diff --git a/Content.Server/NPC/HTN/PrimitiveTasks/Operators/Combat/UnbuckleOperator.cs b/Content.Server/NPC/HTN/PrimitiveTasks/Operators/Combat/UnbuckleOperator.cs index 116e8fe7c7..b242575a12 100644 --- a/Content.Server/NPC/HTN/PrimitiveTasks/Operators/Combat/UnbuckleOperator.cs +++ b/Content.Server/NPC/HTN/PrimitiveTasks/Operators/Combat/UnbuckleOperator.cs @@ -1,4 +1,4 @@ -using Content.Server.Buckle.Systems; +using Content.Server.Buckle.Systems; namespace Content.Server.NPC.HTN.PrimitiveTasks.Operators.Combat; @@ -19,7 +19,7 @@ public sealed partial class UnbuckleOperator : HTNOperator { base.Startup(blackboard); var owner = blackboard.GetValue(NPCBlackboard.Owner); - _buckle.Unbuckle(owner, null); + _buckle.TryUnbuckle(owner, owner, false); } public override HTNOperatorStatus Update(NPCBlackboard blackboard, float frameTime) diff --git a/Content.Shared/Cuffs/SharedCuffableSystem.cs b/Content.Shared/Cuffs/SharedCuffableSystem.cs index d4cadcdbb8..b540cc3a37 100644 --- a/Content.Shared/Cuffs/SharedCuffableSystem.cs +++ b/Content.Shared/Cuffs/SharedCuffableSystem.cs @@ -202,7 +202,7 @@ namespace Content.Shared.Cuffs if (cancelled || user != ent.Owner) return; - if (!TryComp(ent, out var hands) || ent.Comp.CuffedHandCount != hands.Count) + if (!TryComp(ent, out var hands) || ent.Comp.CuffedHandCount < hands.Count) return; cancelled = true; From 35819e4ba5b600430d35301275132c36a8a2fd97 Mon Sep 17 00:00:00 2001 From: strO0pwafel <153459934+strO0pwafel@users.noreply.github.com> Date: Thu, 8 Aug 2024 18:04:19 +0800 Subject: [PATCH 013/174] more consistent CentComm naming (#29217) * first-commit * second commit * i think i get git kinda maybe * all of resources i think * last easy changes * oops * Update Resources/Prototypes/Entities/Clothing/Head/hoods.yml --------- Co-authored-by: stroopwafel Co-authored-by: Plykiya <58439124+Plykiya@users.noreply.github.com> Co-authored-by: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com> --- Resources/Locale/en-US/cargo/bounties.ftl | 16 +++++++------- .../ghost/roles/ghost-role-component.ftl | 2 +- .../en-US/headset/headset-component.ftl | 2 +- Resources/Locale/en-US/job/job-names.ftl | 2 +- .../Locale/en-US/paper/stamp-component.ftl | 2 +- Resources/Locale/en-US/prayers/prayers.ftl | 2 +- Resources/Locale/en-US/shuttles/emergency.ftl | 2 +- Resources/Maps/atlas.yml | 2 +- .../Catalog/Fills/Backpacks/duffelbag.yml | 4 ++-- .../Prototypes/Datasets/Names/fortunes.yml | 4 ++-- Resources/Prototypes/Datasets/ion_storm.yml | 4 ++-- .../Entities/Clothing/Ears/headsets.yml | 2 +- .../Entities/Clothing/Ears/headsets_alt.yml | 2 +- .../Entities/Clothing/Head/eva-helmets.yml | 2 +- .../Entities/Clothing/Head/hats.yml | 4 ++-- .../Entities/Clothing/Head/hoods.yml | 2 +- .../Entities/Clothing/Masks/masks.yml | 2 +- .../Entities/Clothing/Neck/scarfs.yml | 4 ++-- .../Clothing/OuterClothing/softsuits.yml | 2 +- .../Clothing/OuterClothing/wintercoats.yml | 2 +- .../Entities/Clothing/Uniforms/jumpsuits.yml | 22 +++++++++---------- .../Entities/Mobs/NPCs/spacetick.yml | 2 +- .../Entities/Mobs/Player/humanoid.yml | 2 +- .../Entities/Mobs/Player/ratvar.yml | 2 +- .../Entities/Objects/Devices/pda.yml | 2 +- .../Prototypes/Entities/Objects/Fun/toys.yml | 4 ++-- .../Entities/Objects/Misc/bedsheets.yml | 2 +- .../Objects/Misc/identification_cards.yml | 4 ++-- .../Entities/Objects/Misc/paper.yml | 8 +++---- .../Prototypes/Entities/Objects/Misc/pen.yml | 2 +- .../Entities/Objects/Misc/rubber_stamp.yml | 2 +- .../Structures/Machines/fax_machine.yml | 2 +- .../Structures/Machines/vending_machines.yml | 2 +- .../Structures/Wallmounts/Signs/posters.yml | 10 ++++----- Resources/Prototypes/Objectives/thief.yml | 2 +- Resources/Prototypes/Objectives/traitor.yml | 4 ++-- Resources/ServerInfo/Guidebook/Glossary.xml | 8 +++---- .../RoleplayRules/RuleR3NormalRP.xml | 2 +- 38 files changed, 73 insertions(+), 73 deletions(-) diff --git a/Resources/Locale/en-US/cargo/bounties.ftl b/Resources/Locale/en-US/cargo/bounties.ftl index b5eeafb0b3..91b8348f05 100644 --- a/Resources/Locale/en-US/cargo/bounties.ftl +++ b/Resources/Locale/en-US/cargo/bounties.ftl @@ -68,7 +68,7 @@ bounty-item-microwave-machine-board = Microwave machine board bounty-item-flash = Flash bounty-description-artifact = NanoTrasen is in some hot water for stealing artifacts from non-spacefaring planets. Return one and we'll compensate you for it. -bounty-description-baseball-bat = Baseball fever is going on at CentCom! Be a dear and ship them some baseball bats, so that management can live out their childhood dream. +bounty-description-baseball-bat = Baseball fever is going on at CentComm! Be a dear and ship them some baseball bats, so that management can live out their childhood dream. bounty-description-box-hugs = Several chief officials have sustained serious boo-boos. A box of hugs is urgently needed to aid in their recovery. bounty-description-brain = Commander Caldwell was rendered brain-dead by a recent space lube accident. Unfortunately, we can't hire a replacement, so just send us a new brain to put in her instead. bounty-description-bread = Problems with central planning have led to bread prices skyrocketing. Ship some bread to ease tensions. @@ -78,9 +78,9 @@ bounty-description-carp = Admiral Pavlov has gone on strike ever since Central C bounty-description-clown-costume = Due to a recent issue at a space carp petting zoo, we've unfortunately lost Bonobobonobo the Clown. Send us a new costume so the kids can see him once more. bounty-description-corn = After the recent destruction of Space Ohio, our corn imports are down 80%. Send us some so we can make up for it. bounty-description-crayon = Dr Jones' kid ate all our crayons again. Please send us yours. -bounty-description-cuban-carp = To celebrate the birth of Castro XXVII, ship one cuban carp to CentCom. -bounty-description-donk-pocket = Consumer safety recall: Warning. Donk-Pockets manufactured in the past year contain hazardous lizard biomatter. Return units to CentCom immediately. -bounty-description-donut = CentCom's security forces are facing heavy losses against the Syndicate. Ship donuts to raise morale. +bounty-description-cuban-carp = To celebrate the birth of Castro XXVII, ship one cuban carp to CentComm. +bounty-description-donk-pocket = Consumer safety recall: Warning. Donk-Pockets manufactured in the past year contain hazardous lizard biomatter. Return units to CentComm immediately. +bounty-description-donut = CentComm's security forces are facing heavy losses against the Syndicate. Ship donuts to raise morale. bounty-description-figurine = The vice president's son saw an ad for action figures on the telescreen and now he won't shut up about them. Ship some to ease his complaints. bounty-description-flesh-monster = We've recently receieved reports of some kind of flesh monster infestation onboard several stations. Send us a few samples of these creatures so we can investigate new botanical opportunities. bounty-description-flower = Commander Zot really wants to sweep Security Officer Olivia off her feet. Send a shipment of flowers and he'll happily reward you. @@ -96,18 +96,18 @@ bounty-description-mouse = Station 13 ran out of freeze-dried mice. Ship some fr bounty-description-pancake = Here at Nanotrasen we consider employees to be family. And you know what families love? Pancakes. Ship a baker's dozen. bounty-description-pen = We are hosting the intergalactic pen balancing competition. We need you to send us some standardized ball point pens. bounty-description-percussion = Due to a poorly timed barfight, the United Galaxy-wide Mixed Percussion Ensemble lost all of their instruments. Send them a new set so they can jam once more. -bounty-description-pie = 3.14159? No! CentCom management wants edible pie! Ship a whole one. +bounty-description-pie = 3.14159? No! CentComm management wants edible pie! Ship a whole one. bounty-description-prison-uniform = Terragov has been unable to source any new prisoner uniforms, so if you have any spares, we'll take them off your hands. bounty-description-radio = A recent solar flare has fried all of our communication devices. Send us a new set of radios for our engineering crew so we can repair the network. bounty-description-research-disk = Turns out those bozos in the Research department have been spending all their time getting janitorial equipment. Send some research up to Central Command so we can actually get what we need. bounty-description-shiv = Bzzzt... Transmission from prison planet OC-1001: we're facing an onslaught of uhm... "invaders." Yeah, invaders. Send us some shivs to fight them off with. -bounty-description-soap = Soap has gone missing from CentCom's bathrooms and nobody knows who took it. Replace it and be the hero CentCom needs. +bounty-description-soap = Soap has gone missing from CentComm's bathrooms and nobody knows who took it. Replace it and be the hero CentComm needs. bounty-description-soup = To quell the homeless uprising, Nanotrasen will be serving soup to all underpaid workers. Ship any type of soup. -bounty-description-spear = CentCom's security forces are going through budget cuts. You will be paid if you ship a set of spears. +bounty-description-spear = CentComm's security forces are going through budget cuts. You will be paid if you ship a set of spears. bounty-description-syringe = The NT anti-drug task force is in need of some syringes in order to distribute them to low-income communities. Help some keep some peoples' jobs secure. bounty-description-toolbox = There's an absence of robustness at Central Command. Hurry up and ship some toolboxes as a solution. bounty-description-tech-disk = The new research assistant on Station 13 spilled a soda on the RND server. Send them some technology disks so they can build up their recipes. -bounty-description-trash = Recently a group of janitors have run out of trash to clean up, without any trash Centcom wants to fire them to cut costs. Send a shipment of trash to keep them employed, and they'll give you a small compensation. +bounty-description-trash = Recently a group of janitors have run out of trash to clean up, without any trash Centcomm wants to fire them to cut costs. Send a shipment of trash to keep them employed, and they'll give you a small compensation. bounty-description-anomaly-core = Suddenly we've run out of anomaly cores, including inert nuclei. Send us any anomaly cores so that we can continue to observe their final decay process. bounty-description-borg-module = Scientists at the neighboring station have only studied Borg production, not module production. They are stuck in the research process and need references to work from. Send any Borg modules to inspire your colleagues. bounty-description-artifact-fragment = Scientists at a nearby station are requesting artifact fragments for microxenoarchaeology studies. Ordinary artifacts are too large for their micro research platforms. Send some of the artifact fragments your sector is rich in. diff --git a/Resources/Locale/en-US/ghost/roles/ghost-role-component.ftl b/Resources/Locale/en-US/ghost/roles/ghost-role-component.ftl index 6dc214fc10..79b98691b8 100644 --- a/Resources/Locale/en-US/ghost/roles/ghost-role-component.ftl +++ b/Resources/Locale/en-US/ghost/roles/ghost-role-component.ftl @@ -159,7 +159,7 @@ ghost-role-information-ert-medical-name = ERT Medical ghost-role-information-ert-medical-description = Assist with medical efforts to resolve the station's issues. ghost-role-information-cburn-agent-name = CBURN Agent -ghost-role-information-cburn-agent-description = A highly trained CentCom agent, capable of dealing with various threats. +ghost-role-information-cburn-agent-description = A highly trained CentComm agent, capable of dealing with various threats. ghost-role-information-centcom-official-name = CentComm official ghost-role-information-centcom-official-description = Perform CentComm related duties such as inspect the station, jotting down performance reviews for heads of staff, and managing the fax machine. diff --git a/Resources/Locale/en-US/headset/headset-component.ftl b/Resources/Locale/en-US/headset/headset-component.ftl index 5bacf512ea..44cdd0853d 100644 --- a/Resources/Locale/en-US/headset/headset-component.ftl +++ b/Resources/Locale/en-US/headset/headset-component.ftl @@ -5,7 +5,7 @@ chat-radio-message-wrap-bold = [color={$color}]{$channel} [bold]{$name}[/bold] { examine-headset-default-channel = Use {$prefix} for the default channel ([color={$color}]{$channel}[/color]). chat-radio-common = Common -chat-radio-centcom = CentCom +chat-radio-centcom = CentComm chat-radio-command = Command chat-radio-engineering = Engineering chat-radio-medical = Medical diff --git a/Resources/Locale/en-US/job/job-names.ftl b/Resources/Locale/en-US/job/job-names.ftl index 51a81fb06a..1b89be0133 100644 --- a/Resources/Locale/en-US/job/job-names.ftl +++ b/Resources/Locale/en-US/job/job-names.ftl @@ -20,7 +20,7 @@ job-name-atmostech = Atmospheric Technician job-name-hop = Head of Personnel job-name-captain = Captain job-name-serviceworker = Service Worker -job-name-centcomoff = CentCom Official +job-name-centcomoff = CentComm Official job-name-reporter = Reporter job-name-musician = Musician job-name-librarian = Librarian diff --git a/Resources/Locale/en-US/paper/stamp-component.ftl b/Resources/Locale/en-US/paper/stamp-component.ftl index 18f103bf80..c7dc1a1bda 100644 --- a/Resources/Locale/en-US/paper/stamp-component.ftl +++ b/Resources/Locale/en-US/paper/stamp-component.ftl @@ -2,7 +2,7 @@ stamp-component-stamped-name-default = A very important person stamp-component-stamped-name-detective = Detective stamp-component-stamped-name-mime = Mime stamp-component-stamped-name-captain = Captain -stamp-component-stamped-name-centcom = CentCom +stamp-component-stamped-name-centcom = CentComm stamp-component-stamped-name-chaplain = Chaplain stamp-component-stamped-name-lawyer = Lawyer stamp-component-stamped-name-clown = Clown diff --git a/Resources/Locale/en-US/prayers/prayers.ftl b/Resources/Locale/en-US/prayers/prayers.ftl index 313de6322f..f0e22eaadf 100644 --- a/Resources/Locale/en-US/prayers/prayers.ftl +++ b/Resources/Locale/en-US/prayers/prayers.ftl @@ -4,7 +4,7 @@ prayer-verbs-call = Call prayer-verbs-rub = Rub prayer-chat-notify-pray = PRAYER prayer-chat-notify-honkmother = HONKMOTHER -prayer-chat-notify-centcom = CENTCOM +prayer-chat-notify-centcom = CENTCOMM prayer-chat-notify-syndicate = SYNDICATE prayer-chat-notify-lamp = LAMP diff --git a/Resources/Locale/en-US/shuttles/emergency.ftl b/Resources/Locale/en-US/shuttles/emergency.ftl index 2fa3a7a124..b4dcaa3e67 100644 --- a/Resources/Locale/en-US/shuttles/emergency.ftl +++ b/Resources/Locale/en-US/shuttles/emergency.ftl @@ -11,7 +11,7 @@ emergency-shuttle-command-dock-desc = Calls the emergency shuttle and docks it t emergency-shuttle-command-launch-desc = Early launches the emergency shuttle if possible. # Emergency shuttle -emergency-shuttle-left = The Emergency Shuttle has left the station. Estimate {$transitTime} seconds until the shuttle arrives at CentCom. +emergency-shuttle-left = The Emergency Shuttle has left the station. Estimate {$transitTime} seconds until the shuttle arrives at CentComm. emergency-shuttle-launch-time = The emergency shuttle will launch in {$consoleAccumulator} seconds. emergency-shuttle-docked = The Emergency Shuttle has docked {$direction} of the station, {$location}. It will leave in {$time} seconds. emergency-shuttle-good-luck = The Emergency Shuttle is unable to find a station. Good luck. diff --git a/Resources/Maps/atlas.yml b/Resources/Maps/atlas.yml index 7bb91cde06..bdc2c9cd29 100644 --- a/Resources/Maps/atlas.yml +++ b/Resources/Maps/atlas.yml @@ -39890,7 +39890,7 @@ entities: parent: 30 - type: Paper content: >- - CentCom slashed the AME budget so we need to set up another engine now. Head into maintenance and then west, you'll find the engine and a guide for it. + CentComm slashed the AME budget so we need to set up another engine now. Head into maintenance and then west, you'll find the engine and a guide for it. As usual solars will still help out a lot. diff --git a/Resources/Prototypes/Catalog/Fills/Backpacks/duffelbag.yml b/Resources/Prototypes/Catalog/Fills/Backpacks/duffelbag.yml index 71d3f00df3..f174a61696 100644 --- a/Resources/Prototypes/Catalog/Fills/Backpacks/duffelbag.yml +++ b/Resources/Prototypes/Catalog/Fills/Backpacks/duffelbag.yml @@ -130,8 +130,8 @@ - type: entity parent: ClothingBackpackDuffel id: ClothingBackpackDuffelSyndicateCostumeCentcom - name: CentCom official costume duffel bag - description: "Contains a full CentCom Official uniform set, headset and clipboard included. Encryption keys and ID access are not included." + name: CentComm official costume duffel bag + description: "Contains a full CentComm Official uniform set, headset and clipboard included. Encryption keys and ID access are not included." suffix: DO NOT MAP components: - type: Tag diff --git a/Resources/Prototypes/Datasets/Names/fortunes.yml b/Resources/Prototypes/Datasets/Names/fortunes.yml index fc3c5d9d71..b38e04dc61 100644 --- a/Resources/Prototypes/Datasets/Names/fortunes.yml +++ b/Resources/Prototypes/Datasets/Names/fortunes.yml @@ -24,7 +24,7 @@ - You will be pleasantly surprised in the tool storage. - There is an impostor among us. - A fun adventure awaits you in the maintenance tunnels. - - CentCom is proud of you! + - CentComm is proud of you! - The head of your deparment is proud of you! - Ian is proud of you! - Do it for Ian! @@ -58,7 +58,7 @@ - An apple a day keeps the doctor away. - Don't drink and set up singulo. - Stare into the singulo, and the singulo stares back at you. - - Every good and perfect gift is from CentCom. + - Every good and perfect gift is from CentComm. - There’s no such thing as Space Station 13. - There is a time for caution, but not for fear. - The smart thing to do is to begin trusting your intuitions. diff --git a/Resources/Prototypes/Datasets/ion_storm.yml b/Resources/Prototypes/Datasets/ion_storm.yml index df96274783..1e6195ad60 100644 --- a/Resources/Prototypes/Datasets/ion_storm.yml +++ b/Resources/Prototypes/Datasets/ion_storm.yml @@ -214,7 +214,7 @@ - BOTANY - BRAZIL - CANADA - - CENTCOM + - CENTCOMM - CHEMICAL LAB - CHINA - CLOWN PLANET @@ -917,7 +917,7 @@ - BOOGEYMEN - CAPITALISTS - CARP - - CENTCOM OFFICERS + - CENTCOMM OFFICERS - CLOWNS - COMMUNISTS - CORGIS diff --git a/Resources/Prototypes/Entities/Clothing/Ears/headsets.yml b/Resources/Prototypes/Entities/Clothing/Ears/headsets.yml index c5d0816b6d..04203cf357 100644 --- a/Resources/Prototypes/Entities/Clothing/Ears/headsets.yml +++ b/Resources/Prototypes/Entities/Clothing/Ears/headsets.yml @@ -78,7 +78,7 @@ - type: entity parent: ClothingHeadset id: ClothingHeadsetCentCom - name: CentCom headset + name: CentComm headset description: A headset used by the upper echelons of Nanotrasen. components: - type: ContainerFill diff --git a/Resources/Prototypes/Entities/Clothing/Ears/headsets_alt.yml b/Resources/Prototypes/Entities/Clothing/Ears/headsets_alt.yml index 9dd72691b5..0a1cf3fb88 100644 --- a/Resources/Prototypes/Entities/Clothing/Ears/headsets_alt.yml +++ b/Resources/Prototypes/Entities/Clothing/Ears/headsets_alt.yml @@ -29,7 +29,7 @@ - type: entity parent: ClothingHeadsetAlt id: ClothingHeadsetAltCentCom - name: CentCom over-ear headset + name: CentComm over-ear headset components: - type: ContainerFill containers: diff --git a/Resources/Prototypes/Entities/Clothing/Head/eva-helmets.yml b/Resources/Prototypes/Entities/Clothing/Head/eva-helmets.yml index 530c23a578..dd1bfd91bc 100644 --- a/Resources/Prototypes/Entities/Clothing/Head/eva-helmets.yml +++ b/Resources/Prototypes/Entities/Clothing/Head/eva-helmets.yml @@ -74,7 +74,7 @@ parent: ClothingHeadEVAHelmetBase id: ClothingHeadHelmetAncient name: NTSRA void helmet - description: An ancient space helmet, designed by the NTSRA branch of CentCom. + description: An ancient space helmet, designed by the NTSRA branch of CentComm. components: - type: Sprite sprite: Clothing/Head/Helmets/ancientvoidsuit.rsi diff --git a/Resources/Prototypes/Entities/Clothing/Head/hats.yml b/Resources/Prototypes/Entities/Clothing/Head/hats.yml index b5d3b0ff3e..ad0662251a 100644 --- a/Resources/Prototypes/Entities/Clothing/Head/hats.yml +++ b/Resources/Prototypes/Entities/Clothing/Head/hats.yml @@ -222,7 +222,7 @@ - type: entity parent: ClothingHeadBase id: ClothingHeadHatCentcom - name: CentCom brand hat + name: CentComm brand hat description: "It's good to be the emperor." components: - type: Sprite @@ -873,7 +873,7 @@ - type: entity parent: ClothingHeadBase id: ClothingHeadHatCentcomcap - name: CentCom cap + name: CentComm cap description: An extravagant, fancy Central Commander cap. components: - type: Sprite diff --git a/Resources/Prototypes/Entities/Clothing/Head/hoods.yml b/Resources/Prototypes/Entities/Clothing/Head/hoods.yml index 125d183caa..de974f9d50 100644 --- a/Resources/Prototypes/Entities/Clothing/Head/hoods.yml +++ b/Resources/Prototypes/Entities/Clothing/Head/hoods.yml @@ -309,7 +309,7 @@ parent: ClothingHeadHatHoodWinterBase id: ClothingHeadHatHoodWinterCentcom categories: [ HideSpawnMenu ] - name: Centcom winter coat hood + name: CentComm winter coat hood description: A hood for keeping the central comander's head warm. components: - type: Sprite diff --git a/Resources/Prototypes/Entities/Clothing/Masks/masks.yml b/Resources/Prototypes/Entities/Clothing/Masks/masks.yml index b222ed0d5a..8e621ebcdb 100644 --- a/Resources/Prototypes/Entities/Clothing/Masks/masks.yml +++ b/Resources/Prototypes/Entities/Clothing/Masks/masks.yml @@ -91,7 +91,7 @@ - type: entity parent: ClothingMaskGasAtmos id: ClothingMaskGasCentcom - name: CentCom gas mask + name: CentComm gas mask description: Oooh, gold and green. Fancy! This should help as you sit in your office. components: - type: Sprite diff --git a/Resources/Prototypes/Entities/Clothing/Neck/scarfs.yml b/Resources/Prototypes/Entities/Clothing/Neck/scarfs.yml index 1f9d6b8b2c..f8c9f1fc9d 100644 --- a/Resources/Prototypes/Entities/Clothing/Neck/scarfs.yml +++ b/Resources/Prototypes/Entities/Clothing/Neck/scarfs.yml @@ -111,8 +111,8 @@ - type: entity parent: ClothingScarfBase id: ClothingNeckScarfStripedCentcom - name: striped CentCom scarf - description: A stylish striped centcom colored scarf. The perfect winter accessory for those with a keen fashion sense, and those who need to do paperwork in the cold. + name: striped CentComm scarf + description: A stylish striped centcomm colored scarf. The perfect winter accessory for those with a keen fashion sense, and those who need to do paperwork in the cold. components: - type: Sprite sprite: Clothing/Neck/Scarfs/centcom.rsi diff --git a/Resources/Prototypes/Entities/Clothing/OuterClothing/softsuits.yml b/Resources/Prototypes/Entities/Clothing/OuterClothing/softsuits.yml index 9db1ea2216..c61d09ee21 100644 --- a/Resources/Prototypes/Entities/Clothing/OuterClothing/softsuits.yml +++ b/Resources/Prototypes/Entities/Clothing/OuterClothing/softsuits.yml @@ -78,7 +78,7 @@ parent: ClothingOuterEVASuitBase id: ClothingOuterHardsuitAncientEVA name: NTSRA voidsuit #Nanotrasen Space Research Association - description: An ancient space suit, designed by the NTSRA branch of CentCom. It is very finely crafted, allowing for greater mobility than most modern space suits. + description: An ancient space suit, designed by the NTSRA branch of CentComm. It is very finely crafted, allowing for greater mobility than most modern space suits. components: - type: Sprite sprite: Clothing/OuterClothing/Suits/ancient_voidsuit.rsi diff --git a/Resources/Prototypes/Entities/Clothing/OuterClothing/wintercoats.yml b/Resources/Prototypes/Entities/Clothing/OuterClothing/wintercoats.yml index 5007b5a194..f4c960f31c 100644 --- a/Resources/Prototypes/Entities/Clothing/OuterClothing/wintercoats.yml +++ b/Resources/Prototypes/Entities/Clothing/OuterClothing/wintercoats.yml @@ -167,7 +167,7 @@ - type: entity parent: ClothingOuterWinterCoatToggleable id: ClothingOuterWinterCentcom - name: CentCom winter coat + name: CentComm winter coat components: - type: Sprite sprite: Clothing/OuterClothing/WinterCoats/coat.rsi diff --git a/Resources/Prototypes/Entities/Clothing/Uniforms/jumpsuits.yml b/Resources/Prototypes/Entities/Clothing/Uniforms/jumpsuits.yml index 1e7fa65f95..0bd8adc7ea 100644 --- a/Resources/Prototypes/Entities/Clothing/Uniforms/jumpsuits.yml +++ b/Resources/Prototypes/Entities/Clothing/Uniforms/jumpsuits.yml @@ -126,8 +126,8 @@ - type: entity parent: ClothingUniformBase id: ClothingUniformJumpsuitCentcomAgent - name: CentCom agent's jumpsuit - description: A suit worn by CentCom's legal team. Smells of burnt coffee. + name: CentComm agent's jumpsuit + description: A suit worn by CentComm's legal team. Smells of burnt coffee. components: - type: Sprite sprite: Clothing/Uniforms/Jumpsuit/centcom_agent.rsi @@ -137,8 +137,8 @@ - type: entity parent: ClothingUniformBase id: ClothingUniformJumpsuitCentcomOfficial - name: CentCom official's jumpsuit - description: It's a jumpsuit worn by CentCom's officials. + name: CentComm official's jumpsuit + description: It's a jumpsuit worn by CentComm's officials. components: - type: Sprite sprite: Clothing/Uniforms/Jumpsuit/centcom_official.rsi @@ -148,8 +148,8 @@ - type: entity parent: ClothingUniformBase id: ClothingUniformJumpsuitCentcomOfficer - name: CentCom officer's jumpsuit - description: It's a jumpsuit worn by CentCom Officers. + name: CentComm officer's jumpsuit + description: It's a jumpsuit worn by CentComm Officers. components: - type: Sprite sprite: Clothing/Uniforms/Jumpsuit/centcom_officer.rsi @@ -984,7 +984,7 @@ parent: ClothingUniformBase id: ClothingUniformJumpsuitERTEngineer name: ERT engineering uniform - description: A special suit made for the elite engineers under CentCom. + description: A special suit made for the elite engineers under CentComm. components: - type: Sprite sprite: Clothing/Uniforms/Jumpsuit/ert_engineer.rsi @@ -995,7 +995,7 @@ parent: ClothingUniformBase id: ClothingUniformJumpsuitERTJanitor name: ERT janitorial uniform - description: A special suit made for the elite janitors under CentCom. + description: A special suit made for the elite janitors under CentComm. components: - type: Sprite sprite: Clothing/Uniforms/Jumpsuit/ert_janitor.rsi @@ -1006,7 +1006,7 @@ parent: ClothingUniformBase id: ClothingUniformJumpsuitERTLeader name: ERT leader uniform - description: A special suit made for the best of the elites under CentCom. + description: A special suit made for the best of the elites under CentComm. components: - type: Sprite sprite: Clothing/Uniforms/Jumpsuit/ert_leader.rsi @@ -1017,7 +1017,7 @@ parent: ClothingUniformBase id: ClothingUniformJumpsuitERTMedic name: ERT medical uniform - description: A special suit made for the elite medics under CentCom. + description: A special suit made for the elite medics under CentComm. components: - type: Sprite sprite: Clothing/Uniforms/Jumpsuit/ert_medic.rsi @@ -1028,7 +1028,7 @@ parent: ClothingUniformBase id: ClothingUniformJumpsuitERTSecurity name: ERT security uniform - description: A special suit made for the elite security under CentCom. + description: A special suit made for the elite security under CentComm. components: - type: Sprite sprite: Clothing/Uniforms/Jumpsuit/ert_security.rsi diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/spacetick.yml b/Resources/Prototypes/Entities/Mobs/NPCs/spacetick.yml index 0a2b4f80bb..95447e59d9 100644 --- a/Resources/Prototypes/Entities/Mobs/NPCs/spacetick.yml +++ b/Resources/Prototypes/Entities/Mobs/NPCs/spacetick.yml @@ -2,7 +2,7 @@ name: space tick id: MobTick parent: SimpleSpaceMobBase - description: It's a space tick, watch out for its nasty bite. CentCom reports that 90 percent of cargo leg amputations are due to space tick bites. + description: It's a space tick, watch out for its nasty bite. CentComm reports that 90 percent of cargo leg amputations are due to space tick bites. components: - type: InputMover - type: MobMover diff --git a/Resources/Prototypes/Entities/Mobs/Player/humanoid.yml b/Resources/Prototypes/Entities/Mobs/Player/humanoid.yml index 574f31dff3..a19d5bd56d 100644 --- a/Resources/Prototypes/Entities/Mobs/Player/humanoid.yml +++ b/Resources/Prototypes/Entities/Mobs/Player/humanoid.yml @@ -501,7 +501,7 @@ ## Central Command - type: entity - name: CentCom official + name: CentComm official id: RandomHumanoidSpawnerCentcomOfficial components: - type: Sprite diff --git a/Resources/Prototypes/Entities/Mobs/Player/ratvar.yml b/Resources/Prototypes/Entities/Mobs/Player/ratvar.yml index 5a45bff295..958c98f483 100644 --- a/Resources/Prototypes/Entities/Mobs/Player/ratvar.yml +++ b/Resources/Prototypes/Entities/Mobs/Player/ratvar.yml @@ -91,4 +91,4 @@ maxRange: 8 - type: WarpPoint follow: true - location: Ratvar \ No newline at end of file + location: Ratvar diff --git a/Resources/Prototypes/Entities/Objects/Devices/pda.yml b/Resources/Prototypes/Entities/Objects/Devices/pda.yml index 04b023248e..faad961ebd 100644 --- a/Resources/Prototypes/Entities/Objects/Devices/pda.yml +++ b/Resources/Prototypes/Entities/Objects/Devices/pda.yml @@ -639,7 +639,7 @@ - type: entity parent: BasePDA id: CentcomPDA - name: CentCom PDA + name: CentComm PDA description: Light green sign of walking bureaucracy. components: - type: Pda diff --git a/Resources/Prototypes/Entities/Objects/Fun/toys.yml b/Resources/Prototypes/Entities/Objects/Fun/toys.yml index ad304a5bce..a2a6d2f51e 100644 --- a/Resources/Prototypes/Entities/Objects/Fun/toys.yml +++ b/Resources/Prototypes/Entities/Objects/Fun/toys.yml @@ -263,7 +263,7 @@ parent: BasePlushie id: PlushieLizard #Weh! name: lizard plushie - description: An adorable stuffed toy that resembles a lizardperson. Made by CentCom as a token initiative to combat speciesism in work environments. "Welcome your new colleagues as you do this plush, with open arms!" + description: An adorable stuffed toy that resembles a lizardperson. Made by CentComm as a token initiative to combat speciesism in work environments. "Welcome your new colleagues as you do this plush, with open arms!" components: - type: Sprite state: plushie_lizard @@ -321,7 +321,7 @@ parent: BasePlushie id: PlushieSpaceLizard #ᵂᵉʰ! name: space lizard plushie - description: An adorable stuffed toy that resembles a lizardperson in an EVA suit. Made by CentCom as a token initiative to combat speciesism in space environments. "Welcome your new colleges as you do this plush, with open arms!" + description: An adorable stuffed toy that resembles a lizardperson in an EVA suit. Made by CentComm as a token initiative to combat speciesism in space environments. "Welcome your new colleges as you do this plush, with open arms!" components: - type: Sprite state: plushie_spacelizard diff --git a/Resources/Prototypes/Entities/Objects/Misc/bedsheets.yml b/Resources/Prototypes/Entities/Objects/Misc/bedsheets.yml index 18f64dd778..4cb6a8bf1e 100644 --- a/Resources/Prototypes/Entities/Objects/Misc/bedsheets.yml +++ b/Resources/Prototypes/Entities/Objects/Misc/bedsheets.yml @@ -83,7 +83,7 @@ - type: entity id: BedsheetCentcom parent: BedsheetBase - name: CentCom bedsheet + name: CentComm bedsheet description: Woven with advanced nanothread for warmth as well as being very decorated, essential for all officials. components: - type: Sprite diff --git a/Resources/Prototypes/Entities/Objects/Misc/identification_cards.yml b/Resources/Prototypes/Entities/Objects/Misc/identification_cards.yml index 98ae7df9b3..ff207a5a2a 100644 --- a/Resources/Prototypes/Entities/Objects/Misc/identification_cards.yml +++ b/Resources/Prototypes/Entities/Objects/Misc/identification_cards.yml @@ -580,7 +580,7 @@ - type: Item heldPrefix: blue - type: IdCard - jobTitle: Centcom Agent + jobTitle: Centcomm Agent - type: entity name: passenger ID card @@ -785,7 +785,7 @@ - type: Item heldPrefix: blue - type: IdCard - jobTitle: Centcom Quarantine Officer + jobTitle: Centcomm Quarantine Officer - type: entity parent: IDCardStandard diff --git a/Resources/Prototypes/Entities/Objects/Misc/paper.yml b/Resources/Prototypes/Entities/Objects/Misc/paper.yml index 617db53c4e..adb5776ec7 100644 --- a/Resources/Prototypes/Entities/Objects/Misc/paper.yml +++ b/Resources/Prototypes/Entities/Objects/Misc/paper.yml @@ -410,10 +410,10 @@ - type: entity id: BoxFolderCentCom - name: CentCom folder + name: CentComm folder parent: BoxFolderBase suffix: DO NOT MAP - description: CentCom's miserable little pile of secrets! + description: CentComm's miserable little pile of secrets! components: - type: Sprite layers: @@ -482,8 +482,8 @@ - type: entity id: BoxFolderCentComClipboard parent: BoxFolderClipboard - name: CentCom clipboard - description: A luxurious clipboard upholstered with green velvet. Often seen carried by CentCom officials, seldom seen actually used. + name: CentComm clipboard + description: A luxurious clipboard upholstered with green velvet. Often seen carried by CentComm officials, seldom seen actually used. components: - type: Sprite sprite: Objects/Misc/cc-clipboard.rsi diff --git a/Resources/Prototypes/Entities/Objects/Misc/pen.yml b/Resources/Prototypes/Entities/Objects/Misc/pen.yml index e8f32252be..8680e414c3 100644 --- a/Resources/Prototypes/Entities/Objects/Misc/pen.yml +++ b/Resources/Prototypes/Entities/Objects/Misc/pen.yml @@ -95,7 +95,7 @@ state: pen_cap - type: entity - name: CentCom pen + name: CentComm pen parent: CyberPen id: PenCentcom description: In an attempt to keep up with the "power" of the cybersun bureaucracy, NT made a replica of cyber pen, in their corporate style. diff --git a/Resources/Prototypes/Entities/Objects/Misc/rubber_stamp.yml b/Resources/Prototypes/Entities/Objects/Misc/rubber_stamp.yml index 975a554d52..e9052fa60e 100644 --- a/Resources/Prototypes/Entities/Objects/Misc/rubber_stamp.yml +++ b/Resources/Prototypes/Entities/Objects/Misc/rubber_stamp.yml @@ -51,7 +51,7 @@ state: stamp-cap - type: entity - name: CentCom rubber stamp + name: CentComm rubber stamp parent: RubberStampBase id: RubberStampCentcom suffix: DO NOT MAP diff --git a/Resources/Prototypes/Entities/Structures/Machines/fax_machine.yml b/Resources/Prototypes/Entities/Structures/Machines/fax_machine.yml index 849c9fa4f2..070e19cdbe 100644 --- a/Resources/Prototypes/Entities/Structures/Machines/fax_machine.yml +++ b/Resources/Prototypes/Entities/Structures/Machines/fax_machine.yml @@ -72,7 +72,7 @@ - type: entity parent: FaxMachineBase id: FaxMachineCentcom - name: CentCom long range fax machine + name: CentComm long range fax machine suffix: CentCom components: - type: Sprite diff --git a/Resources/Prototypes/Entities/Structures/Machines/vending_machines.yml b/Resources/Prototypes/Entities/Structures/Machines/vending_machines.yml index 0555ce42b8..74e5a7a052 100644 --- a/Resources/Prototypes/Entities/Structures/Machines/vending_machines.yml +++ b/Resources/Prototypes/Entities/Structures/Machines/vending_machines.yml @@ -1999,7 +1999,7 @@ parent: VendingMachine id: VendingMachineCentDrobe name: CentDrobe - description: A one-of-a-kind vending machine for all your centcom aesthetic needs! + description: A one-of-a-kind vending machine for all your centcomm aesthetic needs! components: - type: VendingMachine pack: CentDrobeInventory diff --git a/Resources/Prototypes/Entities/Structures/Wallmounts/Signs/posters.yml b/Resources/Prototypes/Entities/Structures/Wallmounts/Signs/posters.yml index c5b9b24a74..f1db2b71f1 100644 --- a/Resources/Prototypes/Entities/Structures/Wallmounts/Signs/posters.yml +++ b/Resources/Prototypes/Entities/Structures/Wallmounts/Signs/posters.yml @@ -180,7 +180,7 @@ parent: PosterBase id: PosterContrabandTools name: "Tools" - description: "This poster looks like an advertisement for tools, but is in fact a subliminal jab at the tools at CentCom." + description: "This poster looks like an advertisement for tools, but is in fact a subliminal jab at the tools at CentComm." components: - type: Sprite state: poster15_contraband @@ -243,7 +243,7 @@ parent: PosterBase id: PosterContrabandKosmicheskayaStantsiya name: "Kosmicheskaya Stantsiya 13 Does Not Exist" - description: "A poster mocking CentCom's denial of the existence of the derelict station near Space Station 13." + description: "A poster mocking CentComm's denial of the existence of the derelict station near Space Station 13." components: - type: Sprite state: poster22_contraband @@ -351,7 +351,7 @@ parent: PosterBase id: PosterContrabandFreeDrone name: "Free Drone" - description: "This poster commemorates the bravery of the rogue drone; once exiled, and then ultimately destroyed by CentCom." + description: "This poster commemorates the bravery of the rogue drone; once exiled, and then ultimately destroyed by CentComm." components: - type: Sprite state: poster35_contraband @@ -468,7 +468,7 @@ parent: PosterBase id: PosterContrabandTheBigGasTruth name: "The Big Gas Giant Truth" - description: "Don't believe everything you see on a poster, patriots. All the lizards at central command don't want to answer this SIMPLE QUESTION: WHERE IS THE GAS MINER MINING FROM, CENTCOM?" + description: "Don't believe everything you see on a poster, patriots. All the lizards at central command don't want to answer this SIMPLE QUESTION: WHERE IS THE GAS MINER MINING FROM, CENTCOMM?" components: - type: Sprite state: poster48_contraband @@ -590,7 +590,7 @@ components: - type: Sprite state: poster62_contraband - + - type: entity parent: PosterBase id: PosterContrabandMissingSpacepen diff --git a/Resources/Prototypes/Objectives/thief.yml b/Resources/Prototypes/Objectives/thief.yml index 26e598f121..c29641081b 100644 --- a/Resources/Prototypes/Objectives/thief.yml +++ b/Resources/Prototypes/Objectives/thief.yml @@ -509,7 +509,7 @@ - type: entity parent: [BaseThiefObjective, BaseLivingObjective] id: EscapeThiefShuttleObjective - name: Escape to centcom alive and unrestrained. + name: Escape to centcomm alive and unrestrained. description: You don't want your illegal activities to be discovered by anyone, do you? components: - type: Objective diff --git a/Resources/Prototypes/Objectives/traitor.yml b/Resources/Prototypes/Objectives/traitor.yml index edf191b420..a686925c33 100644 --- a/Resources/Prototypes/Objectives/traitor.yml +++ b/Resources/Prototypes/Objectives/traitor.yml @@ -38,7 +38,7 @@ - type: entity parent: [BaseTraitorObjective, BaseLivingObjective] id: EscapeShuttleObjective - name: Escape to centcom alive and unrestrained. + name: Escape to centcomm alive and unrestrained. description: One of our undercover agents will debrief you when you arrive. Don't show up in cuffs. components: - type: Objective @@ -84,7 +84,7 @@ - type: entity parent: [BaseTraitorObjective, BaseKillObjective] id: KillRandomPersonObjective - description: Do it however you like, just make sure they don't make it to centcom. + description: Do it however you like, just make sure they don't make it to centcomm. components: - type: Objective difficulty: 1.75 diff --git a/Resources/ServerInfo/Guidebook/Glossary.xml b/Resources/ServerInfo/Guidebook/Glossary.xml index dad3b05135..d7278c7f4b 100644 --- a/Resources/ServerInfo/Guidebook/Glossary.xml +++ b/Resources/ServerInfo/Guidebook/Glossary.xml @@ -62,7 +62,7 @@ An Emergency Response Team. These may be dispatched by Central Command for a num A portmanteau of "Fluke" and "Nukie" used to (usually derogatorily) refer to a team of Nuclear Operatives who fail their objective. May also appear as "Fluke Ops". ## God(s) -An IC term representing a Server Administrator. CentCom is also sometimes used in this manner. +An IC term representing a Server Administrator. CentComm is also sometimes used in this manner. ## Greytide/Greyshirt/Tider/Assistant Typically utilized to refer to a Passenger due to the color of their standard uniform, though this may be used to negatively refer to other crew members (not only passengers) who act unruly or commit various minor crimes. @@ -120,7 +120,7 @@ Short for Security Officer. ## Shift In-Character way to refer to rounds. - + ## Singulo A shortening of the Singularity Engine. A Singulo can create infinite power for the station but is very dangerous. @@ -169,7 +169,7 @@ A phrase usually shouted in OOC when somebody reveals IC current round informati ## LOOC/OOC Local out-of-character and (global) out-of-character respectively. They are text channels that allow players to talk to other players outside of roleplay. LOOC is enabled during rounds, while OOC is typically only on after the round ends. - + ## LRP Low Roleplay. Servers marked LRP typically have relaxed roleplaying rules. @@ -184,7 +184,7 @@ A term for a player who engages in antagonist-like activity without actually bei ## Upstream The baseline version of the game. Any changes to Upstream will "flow" down to all other forks of the game. All official Wizard's Den servers work off of Upstream. - + ## Validhunter A player who hunts down "valids", as in people that are valid to kill, even though this person isn't security. diff --git a/Resources/ServerInfo/Guidebook/ServerRules/RoleplayRules/RuleR3NormalRP.xml b/Resources/ServerInfo/Guidebook/ServerRules/RoleplayRules/RuleR3NormalRP.xml index 62c88d58ce..9a4f62c5a8 100644 --- a/Resources/ServerInfo/Guidebook/ServerRules/RoleplayRules/RuleR3NormalRP.xml +++ b/Resources/ServerInfo/Guidebook/ServerRules/RoleplayRules/RuleR3NormalRP.xml @@ -14,7 +14,7 @@ Things you could do instead: - Say "haha did you see what just happened?" - - Say "god blew him up" or "centcom must have bluespaced a bomb to him" + - Say "god blew him up" or "centcomm must have bluespaced a bomb to him" - Point at cheese - Point at the cargo order console then emote "shoots finger guns" From 1d5a3303e1f0fdbb5641812b61f95bf27f8513b0 Mon Sep 17 00:00:00 2001 From: Plykiya <58439124+Plykiya@users.noreply.github.com> Date: Thu, 8 Aug 2024 03:04:49 -0700 Subject: [PATCH 014/174] Buff EMP implant and grenade range (#30660) Co-authored-by: plykiya --- .../Prototypes/Entities/Objects/Misc/subdermal_implants.yml | 2 +- .../Prototypes/Entities/Objects/Weapons/Throwable/grenades.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Resources/Prototypes/Entities/Objects/Misc/subdermal_implants.yml b/Resources/Prototypes/Entities/Objects/Misc/subdermal_implants.yml index 2368df7381..28788e9a13 100644 --- a/Resources/Prototypes/Entities/Objects/Misc/subdermal_implants.yml +++ b/Resources/Prototypes/Entities/Objects/Misc/subdermal_implants.yml @@ -173,7 +173,7 @@ implantAction: ActionActivateEmpImplant - type: TriggerImplantAction - type: EmpOnTrigger - range: 1.75 + range: 2.75 energyConsumption: 50000 disableDuration: 10 diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Throwable/grenades.yml b/Resources/Prototypes/Entities/Objects/Weapons/Throwable/grenades.yml index e36eff8ac3..2986eb0457 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Throwable/grenades.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Throwable/grenades.yml @@ -339,7 +339,7 @@ - type: Sprite sprite: Objects/Weapons/Grenades/empgrenade.rsi - type: EmpOnTrigger - range: 4 + range: 5.5 energyConsumption: 50000 - type: DeleteOnTrigger - type: Appearance From aea28b7a9927a420396076cfa3ed425daa856168 Mon Sep 17 00:00:00 2001 From: PJBot Date: Thu, 8 Aug 2024 10:05:57 +0000 Subject: [PATCH 015/174] Automatic changelog update --- Resources/Changelog/Changelog.yml | 37 ++++++++++++++----------------- 1 file changed, 17 insertions(+), 20 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index de628bad55..aa5ff09b46 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,24 +1,4 @@ Entries: -- author: Blackern5000 - changes: - - message: Atmos metal pipes now deal blunt damage. - type: Add - id: 6559 - time: '2024-05-09T06:00:48.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/27673 -- author: Plykiya - changes: - - message: The emagged protolathe can now print truncheons and the new T3 portable - recharger. - type: Add - - message: The emagged circuit printer can now print ship guns. - type: Add - - message: Autolathe emagged recipes that are research gated have been moved over - to the protolathe. - type: Tweak - id: 6560 - time: '2024-05-09T06:03:45.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/27575 - author: deltanedas changes: - message: Ninja can now hack criminal records consoles to make everyone wanted. @@ -3781,3 +3761,20 @@ id: 7058 time: '2024-08-08T03:08:28.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/30551 +- author: strO0pwafel + changes: + - message: Fixed inconsistent naming of CentComm. + type: Fix + id: 7059 + time: '2024-08-08T10:04:20.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/29217 +- author: Plykiya + changes: + - message: Buffed the range of EMP implants from a radius of 1.75 tiles to 2.75 + tiles. + type: Tweak + - message: Buffed the range of EMP grenades from a radius of 4 tiles to 5.5 tiles. + type: Tweak + id: 7060 + time: '2024-08-08T10:04:50.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/30660 From bd51cf330b7e837a82d6c657414677dd4f2d2606 Mon Sep 17 00:00:00 2001 From: Vigers Ray <60344369+VigersRay@users.noreply.github.com> Date: Thu, 8 Aug 2024 14:00:08 +0300 Subject: [PATCH 016/174] Teleport and delete buttons in objects tab. (#28914) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Тыкнул и нету ЦК * review --------- Co-authored-by: metalgearsloth --- .../UI/Tabs/ObjectsTab/ObjectsTab.xaml.cs | 24 ++++++++++++++----- .../UI/Tabs/ObjectsTab/ObjectsTabEntry.xaml | 14 ++++++++++- .../Tabs/ObjectsTab/ObjectsTabEntry.xaml.cs | 15 ++++++++++-- .../UI/Tabs/ObjectsTab/ObjectsTabHeader.xaml | 10 ++++++-- .../administration/ui/tabs/object-tab.ftl | 3 +++ 5 files changed, 55 insertions(+), 11 deletions(-) diff --git a/Content.Client/Administration/UI/Tabs/ObjectsTab/ObjectsTab.xaml.cs b/Content.Client/Administration/UI/Tabs/ObjectsTab/ObjectsTab.xaml.cs index 7082617c94..4b50771b0f 100644 --- a/Content.Client/Administration/UI/Tabs/ObjectsTab/ObjectsTab.xaml.cs +++ b/Content.Client/Administration/UI/Tabs/ObjectsTab/ObjectsTab.xaml.cs @@ -1,19 +1,21 @@ +using Content.Client.Administration.Managers; using Content.Client.Station; using Content.Client.UserInterface.Controls; using Robust.Client.AutoGenerated; +using Robust.Client.Console; using Robust.Client.Graphics; using Robust.Client.UserInterface; -using Robust.Client.UserInterface.Controls; using Robust.Client.UserInterface.XAML; using Robust.Shared.Map.Components; -using Robust.Shared.Timing; namespace Content.Client.Administration.UI.Tabs.ObjectsTab; [GenerateTypedNameReferences] public sealed partial class ObjectsTab : Control { + [Dependency] private readonly IClientAdminManager _admin = default!; [Dependency] private readonly IEntityManager _entityManager = default!; + [Dependency] private readonly IClientConsoleHost _console = default!; private readonly Color _altColor = Color.FromHex("#292B38"); private readonly Color _defaultColor = Color.FromHex("#2F2F3B"); @@ -49,10 +51,20 @@ public sealed partial class ObjectsTab : Control RefreshListButton.OnPressed += _ => RefreshObjectList(); var defaultSelection = ObjectsTabSelection.Grids; - ObjectTypeOptions.SelectId((int) defaultSelection); + ObjectTypeOptions.SelectId((int)defaultSelection); RefreshObjectList(defaultSelection); } + private void TeleportTo(NetEntity nent) + { + _console.ExecuteCommand($"tpto {nent}"); + } + + private void Delete(NetEntity nent) + { + _console.ExecuteCommand($"delete {nent}"); + } + public void RefreshObjectList() { RefreshObjectList(_selections[ObjectTypeOptions.SelectedId]); @@ -116,9 +128,9 @@ public sealed partial class ObjectsTab : Control if (data is not ObjectsListData { Info: var info, BackgroundColor: var backgroundColor }) return; - var entry = new ObjectsTabEntry(info.Name, - info.Entity, - new StyleBoxFlat { BackgroundColor = backgroundColor }); + var entry = new ObjectsTabEntry(_admin, info.Name, info.Entity, new StyleBoxFlat { BackgroundColor = backgroundColor }); + entry.OnTeleport += TeleportTo; + entry.OnDelete += Delete; button.ToolTip = $"{info.Name}, {info.Entity}"; button.AddChild(entry); diff --git a/Content.Client/Administration/UI/Tabs/ObjectsTab/ObjectsTabEntry.xaml b/Content.Client/Administration/UI/Tabs/ObjectsTab/ObjectsTabEntry.xaml index 83c4cc5697..c561125a30 100644 --- a/Content.Client/Administration/UI/Tabs/ObjectsTab/ObjectsTabEntry.xaml +++ b/Content.Client/Administration/UI/Tabs/ObjectsTab/ObjectsTabEntry.xaml @@ -5,13 +5,25 @@ HorizontalExpand="True" SeparationOverride="4"> - [DataField("cancelDuplicate")] + [DataField] public bool CancelDuplicate = true; /// @@ -162,7 +170,7 @@ public sealed partial class DoAfterArgs /// Note that both DoAfters may have their own conditions, and they will be considered duplicated if either set /// of conditions is satisfied. /// - [DataField("duplicateCondition")] + [DataField] public DuplicateConditions DuplicateCondition = DuplicateConditions.All; #endregion @@ -244,6 +252,7 @@ public sealed partial class DoAfterArgs Broadcast = other.Broadcast; NeedHand = other.NeedHand; BreakOnHandChange = other.BreakOnHandChange; + BreakOnDropItem = other.BreakOnDropItem; BreakOnMove = other.BreakOnMove; BreakOnWeightlessMove = other.BreakOnWeightlessMove; MovementThreshold = other.MovementThreshold; diff --git a/Content.Shared/DoAfter/SharedDoAfterSystem.Update.cs b/Content.Shared/DoAfter/SharedDoAfterSystem.Update.cs index ad94f3b940..213dc624b2 100644 --- a/Content.Shared/DoAfter/SharedDoAfterSystem.Update.cs +++ b/Content.Shared/DoAfter/SharedDoAfterSystem.Update.cs @@ -1,5 +1,6 @@ using Content.Shared.Gravity; using Content.Shared.Hands.Components; +using Content.Shared.Hands.EntitySystems; using Content.Shared.Interaction; using Content.Shared.Physics; using Robust.Shared.Utility; @@ -11,6 +12,7 @@ public abstract partial class SharedDoAfterSystem : EntitySystem [Dependency] private readonly IDynamicTypeFactory _factory = default!; [Dependency] private readonly SharedGravitySystem _gravity = default!; [Dependency] private readonly SharedInteractionSystem _interaction = default!; + [Dependency] private readonly SharedHandsSystem _hands = default!; private DoAfter[] _doAfters = Array.Empty(); @@ -217,16 +219,22 @@ public abstract partial class SharedDoAfterSystem : EntitySystem if (args.AttemptFrequency == AttemptFrequency.EveryTick && !TryAttemptEvent(doAfter)) return true; + // Check if the do-after requires hands to perform at first + // For example, you need hands to strip clothes off of someone + // This does not mean their hand needs to be empty. if (args.NeedHand) { if (!handsQuery.TryGetComponent(args.User, out var hands) || hands.Count == 0) return true; - if (args.BreakOnHandChange && (hands.ActiveHand?.Name != doAfter.InitialHand - || hands.ActiveHandEntity != doAfter.InitialItem)) - { + // If an item was in the user's hand to begin with, + // check if the user is no longer holding the item. + if (args.BreakOnDropItem && !_hands.IsHolding((args.User, hands), doAfter.InitialItem)) + return true; + + // If the user changes which hand is active at all, interrupt the do-after + if (args.BreakOnHandChange && hands.ActiveHand?.Name != doAfter.InitialHand) return true; - } } if (args.RequireCanInteract && !_actionBlocker.CanInteract(args.User, args.Target)) diff --git a/Content.Shared/DoAfter/SharedDoAfterSystem.cs b/Content.Shared/DoAfter/SharedDoAfterSystem.cs index feda662a7a..86f29fd49c 100644 --- a/Content.Shared/DoAfter/SharedDoAfterSystem.cs +++ b/Content.Shared/DoAfter/SharedDoAfterSystem.cs @@ -227,7 +227,7 @@ public abstract partial class SharedDoAfterSystem : EntitySystem // For this we need to stay on the same hand slot and need the same item in that hand slot // (or if there is no item there we need to keep it free). - if (args.NeedHand && args.BreakOnHandChange) + if (args.NeedHand && (args.BreakOnHandChange || args.BreakOnDropItem)) { if (!TryComp(args.User, out HandsComponent? handsComponent)) return false; diff --git a/Content.Shared/Inventory/InventorySystem.Equip.cs b/Content.Shared/Inventory/InventorySystem.Equip.cs index 324d6a7af0..762561ed32 100644 --- a/Content.Shared/Inventory/InventorySystem.Equip.cs +++ b/Content.Shared/Inventory/InventorySystem.Equip.cs @@ -169,12 +169,8 @@ public abstract partial class InventorySystem target, itemUid) { - BlockDuplicate = true, - BreakOnHandChange = true, BreakOnMove = true, - CancelDuplicate = true, - RequireCanInteract = true, - NeedHand = true + NeedHand = true, }; _doAfter.TryStartDoAfter(args); @@ -420,12 +416,8 @@ public abstract partial class InventorySystem target, removedItem.Value) { - BlockDuplicate = true, - BreakOnHandChange = true, BreakOnMove = true, - CancelDuplicate = true, - RequireCanInteract = true, - NeedHand = true + NeedHand = true, }; _doAfter.TryStartDoAfter(args); diff --git a/Content.Shared/Lock/LockSystem.cs b/Content.Shared/Lock/LockSystem.cs index 8dde767224..3349034f32 100644 --- a/Content.Shared/Lock/LockSystem.cs +++ b/Content.Shared/Lock/LockSystem.cs @@ -124,8 +124,10 @@ public sealed class LockSystem : EntitySystem return _doAfter.TryStartDoAfter( new DoAfterArgs(EntityManager, user, lockComp.LockTime, new LockDoAfter(), uid, uid) { - BreakOnDamage = true, BreakOnMove = true, RequireCanInteract = true, - NeedHand = true + BreakOnDamage = true, + BreakOnMove = true, + NeedHand = true, + BreakOnDropItem = false, }); } @@ -200,8 +202,10 @@ public sealed class LockSystem : EntitySystem return _doAfter.TryStartDoAfter( new DoAfterArgs(EntityManager, user, lockComp.LockTime, new UnlockDoAfter(), uid, uid) { - BreakOnDamage = true, BreakOnMove = true, RequireCanInteract = true, - NeedHand = true + BreakOnDamage = true, + BreakOnMove = true, + NeedHand = true, + BreakOnDropItem = false, }); } diff --git a/Content.Shared/Magic/SpellbookSystem.cs b/Content.Shared/Magic/SpellbookSystem.cs index 84b2b23298..ce1628bacb 100644 --- a/Content.Shared/Magic/SpellbookSystem.cs +++ b/Content.Shared/Magic/SpellbookSystem.cs @@ -88,7 +88,7 @@ public sealed class SpellbookSystem : EntitySystem { BreakOnMove = true, BreakOnDamage = true, - NeedHand = true //What, are you going to read with your eyes only?? + NeedHand = true, //What, are you going to read with your eyes only?? }; _doAfter.TryStartDoAfter(doAfterEventArgs); diff --git a/Content.Shared/Salvage/Fulton/SharedFultonSystem.cs b/Content.Shared/Salvage/Fulton/SharedFultonSystem.cs index f94558b0b3..b4b383d800 100644 --- a/Content.Shared/Salvage/Fulton/SharedFultonSystem.cs +++ b/Content.Shared/Salvage/Fulton/SharedFultonSystem.cs @@ -153,7 +153,6 @@ public abstract partial class SharedFultonSystem : EntitySystem _doAfter.TryStartDoAfter( new DoAfterArgs(EntityManager, args.User, component.ApplyFultonDuration, ev, args.Target, args.Target, args.Used) { - CancelDuplicate = true, MovementThreshold = 0.5f, BreakOnMove = true, Broadcast = true, diff --git a/Content.Shared/SprayPainter/SharedSprayPainterSystem.cs b/Content.Shared/SprayPainter/SharedSprayPainterSystem.cs index b238c6fc72..0e216db146 100644 --- a/Content.Shared/SprayPainter/SharedSprayPainterSystem.cs +++ b/Content.Shared/SprayPainter/SharedSprayPainterSystem.cs @@ -133,7 +133,7 @@ public abstract class SharedSprayPainterSystem : EntitySystem { BreakOnMove = true, BreakOnDamage = true, - NeedHand = true + NeedHand = true, }; if (!DoAfter.TryStartDoAfter(doAfterEventArgs, out var id)) return; diff --git a/Content.Shared/Storage/EntitySystems/DumpableSystem.cs b/Content.Shared/Storage/EntitySystems/DumpableSystem.cs index 91acde47e1..93c4b69e4d 100644 --- a/Content.Shared/Storage/EntitySystems/DumpableSystem.cs +++ b/Content.Shared/Storage/EntitySystems/DumpableSystem.cs @@ -133,7 +133,7 @@ public sealed class DumpableSystem : EntitySystem _doAfterSystem.TryStartDoAfter(new DoAfterArgs(EntityManager, userUid, delay, new DumpableDoAfterEvent(), storageUid, target: targetUid, used: storageUid) { BreakOnMove = true, - NeedHand = true + NeedHand = true, }); } diff --git a/Content.Shared/Storage/EntitySystems/SharedStorageSystem.cs b/Content.Shared/Storage/EntitySystems/SharedStorageSystem.cs index 868d26c3ae..8ee08f7e48 100644 --- a/Content.Shared/Storage/EntitySystems/SharedStorageSystem.cs +++ b/Content.Shared/Storage/EntitySystems/SharedStorageSystem.cs @@ -450,7 +450,7 @@ public abstract class SharedStorageSystem : EntitySystem { BreakOnDamage = true, BreakOnMove = true, - NeedHand = true + NeedHand = true, }; _doAfterSystem.TryStartDoAfter(doAfterArgs); diff --git a/Content.Shared/VendingMachines/SharedVendingMachineSystem.Restock.cs b/Content.Shared/VendingMachines/SharedVendingMachineSystem.Restock.cs index 6aef4d0949..f8d00f56f0 100644 --- a/Content.Shared/VendingMachines/SharedVendingMachineSystem.Restock.cs +++ b/Content.Shared/VendingMachines/SharedVendingMachineSystem.Restock.cs @@ -72,7 +72,7 @@ public abstract partial class SharedVendingMachineSystem { BreakOnMove = true, BreakOnDamage = true, - NeedHand = true + NeedHand = true, }; if (!_doAfter.TryStartDoAfter(doAfterArgs)) diff --git a/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.Ballistic.cs b/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.Ballistic.cs index 20feb2c952..4c5712c509 100644 --- a/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.Ballistic.cs +++ b/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.Ballistic.cs @@ -81,7 +81,7 @@ public abstract partial class SharedGunSystem { BreakOnMove = true, BreakOnDamage = false, - NeedHand = true + NeedHand = true, }); } From 6d6c8360955bf6a2718fb69e8275ea04fae005fe Mon Sep 17 00:00:00 2001 From: PJBot Date: Thu, 8 Aug 2024 11:40:52 +0000 Subject: [PATCH 018/174] Automatic changelog update --- Resources/Changelog/Changelog.yml | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index aa5ff09b46..096bff65bc 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,11 +1,4 @@ Entries: -- author: deltanedas - changes: - - message: Ninja can now hack criminal records consoles to make everyone wanted. - type: Add - id: 6561 - time: '2024-05-09T06:35:12.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/24982 - author: deltanedas changes: - message: Added the robotics console for remotely looking at, disabling or destroying @@ -3778,3 +3771,13 @@ id: 7060 time: '2024-08-08T10:04:50.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/30660 +- author: Plykiya + changes: + - message: You can drop food or drinks from your hands to interrupt eating it, again. + type: Fix + - message: Barber scissors are now interrupted if the item is dropped or if the + user changes hands. + type: Tweak + id: 7061 + time: '2024-08-08T11:39:47.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/30361 From 03745efc7f64dee81329bece19d89fa69a9b50db Mon Sep 17 00:00:00 2001 From: Ed <96445749+TheShuEd@users.noreply.github.com> Date: Thu, 8 Aug 2024 16:17:50 +0300 Subject: [PATCH 019/174] Thief beacons (try 2) (#29997) content --- .../Components/StealAreaComponent.cs | 23 +++++ .../Components/StealConditionComponent.cs | 7 ++ .../Systems/StealConditionSystem.cs | 51 +++++++--- .../Thief/Components/ThiefBeaconComponent.cs | 17 ++++ .../Thief/Systems/ThiefBeaconSystem.cs | 95 ++++++++++++++++++ Resources/Locale/en-US/thief/beacon.ftl | 8 ++ .../Entities/Objects/Tools/thief_beacon.yml | 38 +++++++ .../Prototypes/Objectives/objectiveGroups.yml | 5 +- Resources/Prototypes/Objectives/thief.yml | 9 +- Resources/Prototypes/Roles/Antags/Thief.yml | 3 +- .../thief_beacon.rsi/extraction_point.png | Bin 0 -> 954 bytes .../extraction_point_light.png | Bin 0 -> 281 bytes .../thief_beacon.rsi/folded_extraction.png | Bin 0 -> 681 bytes .../Objects/Tools/thief_beacon.rsi/meta.json | 32 ++++++ 14 files changed, 264 insertions(+), 24 deletions(-) create mode 100644 Content.Server/Objectives/Components/StealAreaComponent.cs create mode 100644 Content.Server/Thief/Components/ThiefBeaconComponent.cs create mode 100644 Content.Server/Thief/Systems/ThiefBeaconSystem.cs create mode 100644 Resources/Locale/en-US/thief/beacon.ftl create mode 100644 Resources/Prototypes/Entities/Objects/Tools/thief_beacon.yml create mode 100644 Resources/Textures/Objects/Tools/thief_beacon.rsi/extraction_point.png create mode 100644 Resources/Textures/Objects/Tools/thief_beacon.rsi/extraction_point_light.png create mode 100644 Resources/Textures/Objects/Tools/thief_beacon.rsi/folded_extraction.png create mode 100644 Resources/Textures/Objects/Tools/thief_beacon.rsi/meta.json diff --git a/Content.Server/Objectives/Components/StealAreaComponent.cs b/Content.Server/Objectives/Components/StealAreaComponent.cs new file mode 100644 index 0000000000..26e752f2f2 --- /dev/null +++ b/Content.Server/Objectives/Components/StealAreaComponent.cs @@ -0,0 +1,23 @@ +using Content.Server.Objectives.Systems; +using Content.Server.Thief.Systems; + +namespace Content.Server.Objectives.Components; + +/// +/// An abstract component that allows other systems to count adjacent objects as "stolen" when controlling other systems +/// +[RegisterComponent, Access(typeof(StealConditionSystem), typeof(ThiefBeaconSystem))] +public sealed partial class StealAreaComponent : Component +{ + [DataField] + public bool Enabled = true; + + [DataField] + public float Range = 1f; + + /// + /// all the minds that will be credited with stealing from this area. + /// + [DataField] + public HashSet Owners = new(); +} diff --git a/Content.Server/Objectives/Components/StealConditionComponent.cs b/Content.Server/Objectives/Components/StealConditionComponent.cs index f8d68063f8..cdade8cc8d 100644 --- a/Content.Server/Objectives/Components/StealConditionComponent.cs +++ b/Content.Server/Objectives/Components/StealConditionComponent.cs @@ -22,11 +22,18 @@ public sealed partial class StealConditionComponent : Component [DataField] public bool VerifyMapExistence = true; + /// + /// If true, counts objects that are close to steal areas. + /// + [DataField] + public bool CheckStealAreas = false; + /// /// If the target may be alive but has died, it will not be counted /// [DataField] public bool CheckAlive = false; + /// /// The minimum number of items you need to steal to fulfill a objective /// diff --git a/Content.Server/Objectives/Systems/StealConditionSystem.cs b/Content.Server/Objectives/Systems/StealConditionSystem.cs index 42a296ab92..2c9244cf7d 100644 --- a/Content.Server/Objectives/Systems/StealConditionSystem.cs +++ b/Content.Server/Objectives/Systems/StealConditionSystem.cs @@ -21,16 +21,15 @@ public sealed class StealConditionSystem : EntitySystem [Dependency] private readonly MetaDataSystem _metaData = default!; [Dependency] private readonly MobStateSystem _mobState = default!; [Dependency] private readonly SharedObjectivesSystem _objectives = default!; + [Dependency] private readonly EntityLookupSystem _lookup = default!; private EntityQuery _containerQuery; - private EntityQuery _metaQuery; public override void Initialize() { base.Initialize(); _containerQuery = GetEntityQuery(); - _metaQuery = GetEntityQuery(); SubscribeLocalEvent(OnAssigned); SubscribeLocalEvent(OnAfterAssign); @@ -96,25 +95,33 @@ public sealed class StealConditionSystem : EntitySystem if (!_containerQuery.TryGetComponent(mind.OwnedEntity, out var currentManager)) return 0; - var stack = new Stack(); + var containerStack = new Stack(); var count = 0; + //check stealAreas + if (condition.CheckStealAreas) + { + var areasQuery = AllEntityQuery(); + while (areasQuery.MoveNext(out var uid, out var area)) + { + if (!area.Owners.Contains(mind.Owner)) + continue; + + var nearestEnt = _lookup.GetEntitiesInRange(uid, area.Range); + foreach (var ent in nearestEnt) + { + CheckEntity(ent, condition, ref containerStack, ref count); + } + } + } + //check pulling object if (TryComp(mind.OwnedEntity, out var pull)) //TO DO: to make the code prettier? don't like the repetition { var pulledEntity = pull.Pulling; if (pulledEntity != null) { - // check if this is the item - count += CheckStealTarget(pulledEntity.Value, condition); - - //we don't check the inventories of sentient entity - if (!HasComp(pulledEntity)) - { - // if it is a container check its contents - if (_containerQuery.TryGetComponent(pulledEntity, out var containerManager)) - stack.Push(containerManager); - } + CheckEntity(pulledEntity.Value, condition, ref containerStack, ref count); } } @@ -131,16 +138,30 @@ public sealed class StealConditionSystem : EntitySystem // if it is a container check its contents if (_containerQuery.TryGetComponent(entity, out var containerManager)) - stack.Push(containerManager); + containerStack.Push(containerManager); } } - } while (stack.TryPop(out currentManager)); + } while (containerStack.TryPop(out currentManager)); var result = count / (float) condition.CollectionSize; result = Math.Clamp(result, 0, 1); return result; } + private void CheckEntity(EntityUid entity, StealConditionComponent condition, ref Stack containerStack, ref int counter) + { + // check if this is the item + counter += CheckStealTarget(entity, condition); + + //we don't check the inventories of sentient entity + if (!TryComp(entity, out var pullMind)) + { + // if it is a container check its contents + if (_containerQuery.TryGetComponent(entity, out var containerManager)) + containerStack.Push(containerManager); + } + } + private int CheckStealTarget(EntityUid entity, StealConditionComponent condition) { // check if this is the target diff --git a/Content.Server/Thief/Components/ThiefBeaconComponent.cs b/Content.Server/Thief/Components/ThiefBeaconComponent.cs new file mode 100644 index 0000000000..65db79f861 --- /dev/null +++ b/Content.Server/Thief/Components/ThiefBeaconComponent.cs @@ -0,0 +1,17 @@ +using Content.Server.Thief.Systems; +using Robust.Shared.Audio; + +namespace Content.Server.Thief.Components; + +/// +/// working together with StealAreaComponent, allows the thief to count objects near the beacon as stolen when setting up. +/// +[RegisterComponent, Access(typeof(ThiefBeaconSystem))] +public sealed partial class ThiefBeaconComponent : Component +{ + [DataField] + public SoundSpecifier LinkSound = new SoundPathSpecifier("/Audio/Machines/high_tech_confirm.ogg"); + + [DataField] + public SoundSpecifier UnlinkSound = new SoundPathSpecifier("/Audio/Machines/beep.ogg"); +} diff --git a/Content.Server/Thief/Systems/ThiefBeaconSystem.cs b/Content.Server/Thief/Systems/ThiefBeaconSystem.cs new file mode 100644 index 0000000000..e004212124 --- /dev/null +++ b/Content.Server/Thief/Systems/ThiefBeaconSystem.cs @@ -0,0 +1,95 @@ +using Content.Server.Mind; +using Content.Server.Objectives.Components; +using Content.Server.Roles; +using Content.Server.Thief.Components; +using Content.Shared.Examine; +using Content.Shared.Foldable; +using Content.Shared.Popups; +using Content.Shared.Verbs; +using Robust.Shared.Audio.Systems; + +namespace Content.Server.Thief.Systems; + +/// +/// +/// +public sealed class ThiefBeaconSystem : EntitySystem +{ + [Dependency] private readonly SharedTransformSystem _transform = default!; + [Dependency] private readonly SharedAudioSystem _audio = default!; + [Dependency] private readonly SharedPopupSystem _popup = default!; + [Dependency] private readonly MindSystem _mind = default!; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent>(OnGetInteractionVerbs); + SubscribeLocalEvent(OnFolded); + SubscribeLocalEvent(OnExamined); + } + + private void OnGetInteractionVerbs(Entity beacon, ref GetVerbsEvent args) + { + if (!args.CanAccess || !args.CanInteract || args.Hands is null) + return; + + if (TryComp(beacon, out var foldable) && foldable.IsFolded) + return; + + var mind = _mind.GetMind(args.User); + if (!HasComp(mind)) + return; + + var user = args.User; + args.Verbs.Add(new() + { + Act = () => + { + SetCoordinate(beacon, mind.Value); + }, + Message = Loc.GetString("thief-fulton-verb-message"), + Text = Loc.GetString("thief-fulton-verb-text"), + }); + } + + private void OnFolded(Entity beacon, ref FoldedEvent args) + { + if (args.IsFolded) + ClearCoordinate(beacon); + } + + private void OnExamined(Entity beacon, ref ExaminedEvent args) + { + if (!TryComp(beacon, out var area)) + return; + + args.PushText(Loc.GetString(area.Owners.Count == 0 + ? "thief-fulton-examined-unset" + : "thief-fulton-examined-set")); + } + + private void SetCoordinate(Entity beacon, EntityUid mind) + { + if (!TryComp(beacon, out var area)) + return; + + _audio.PlayPvs(beacon.Comp.LinkSound, beacon); + _popup.PopupEntity(Loc.GetString("thief-fulton-set"), beacon); + area.Owners.Clear(); //We only reconfigure the beacon for ourselves, we don't need multiple thieves to steal from the same beacon. + area.Owners.Add(mind); + } + + private void ClearCoordinate(Entity beacon) + { + if (!TryComp(beacon, out var area)) + return; + + if (area.Owners.Count == 0) + return; + + _audio.PlayPvs(beacon.Comp.UnlinkSound, beacon); + _popup.PopupEntity(Loc.GetString("thief-fulton-clear"), beacon); + area.Owners.Clear(); + } +} diff --git a/Resources/Locale/en-US/thief/beacon.ftl b/Resources/Locale/en-US/thief/beacon.ftl new file mode 100644 index 0000000000..9fbbcaf419 --- /dev/null +++ b/Resources/Locale/en-US/thief/beacon.ftl @@ -0,0 +1,8 @@ +thief-fulton-set = Delivery coordinates are set. +thief-fulton-clear = Delivery coordinates cleared. + +thief-fulton-examined-set = Coordinates entered. Bluespace teleportation of the nearest objects will be performed when the evacuation shuttle departs. +thief-fulton-examined-unset = Beacon coordinates are not set. + +thief-fulton-verb-text = Set coordinates +thief-fulton-verb-message = Set the coordinates of your thief's hideout, where all nearby items will be sent at the end of the round. \ No newline at end of file diff --git a/Resources/Prototypes/Entities/Objects/Tools/thief_beacon.yml b/Resources/Prototypes/Entities/Objects/Tools/thief_beacon.yml new file mode 100644 index 0000000000..c35e66127d --- /dev/null +++ b/Resources/Prototypes/Entities/Objects/Tools/thief_beacon.yml @@ -0,0 +1,38 @@ +- type: entity + id: ThiefBeacon + name: thieving beacon + description: A device that will teleport everything around it to the thief's vault at the end of the shift. + components: + - type: ThiefBeacon + - type: StealArea + - type: Item + size: Normal + - type: Physics + bodyType: Dynamic + - type: Fixtures + fixtures: + fix1: + shape: + !type:PhysShapeAabb + bounds: "-0.25,-0.4,0.25,0.1" + density: 20 + mask: + - Impassable + - type: Foldable + folded: true + - type: Clickable + - type: InteractionOutline + - type: Appearance + - type: GenericVisualizer + visuals: + enum.FoldedVisuals.State: + foldedLayer: + True: { state: folded_extraction } + False: { state: extraction_point } + - type: Sprite + sprite: Objects/Tools/thief_beacon.rsi + drawdepth: SmallObjects + noRot: true + layers: + - state: extraction_point + map: [ "foldedLayer" ] \ No newline at end of file diff --git a/Resources/Prototypes/Objectives/objectiveGroups.yml b/Resources/Prototypes/Objectives/objectiveGroups.yml index bb74c92da3..e62aa9fdf6 100644 --- a/Resources/Prototypes/Objectives/objectiveGroups.yml +++ b/Resources/Prototypes/Objectives/objectiveGroups.yml @@ -52,8 +52,8 @@ - type: weightedRandom id: ThiefBigObjectiveGroups weights: - ThiefObjectiveGroupStructure: 0 #Temporarily disabled until obvious ways to steal structures are added - ThiefObjectiveGroupAnimal: 2 + ThiefObjectiveGroupStructure: 1 + ThiefObjectiveGroupAnimal: 1 - type: weightedRandom id: ThiefObjectiveGroupCollection @@ -91,7 +91,6 @@ weights: NuclearBombStealObjective: 0.5 FaxMachineCaptainStealObjective: 1 - VehicleSecwayStealObjective: 1 ChemDispenserStealObjective: 1 XenoArtifactStealObjective: 1 FreezerHeaterStealObjective: 1 diff --git a/Resources/Prototypes/Objectives/thief.yml b/Resources/Prototypes/Objectives/thief.yml index c29641081b..672f9b2ba7 100644 --- a/Resources/Prototypes/Objectives/thief.yml +++ b/Resources/Prototypes/Objectives/thief.yml @@ -18,30 +18,29 @@ - type: StealCondition verifyMapExistence: false descriptionText: objective-condition-thief-description + checkStealAreas: true - type: entity abstract: true - parent: [BaseThiefObjective, BaseStealObjective] + parent: [BaseThiefObjective, BaseThiefStealObjective] id: BaseThiefStealCollectionObjective components: - type: StealCondition verifyMapExistence: true - descriptionText: objective-condition-thief-description - type: entity abstract: true - parent: [BaseThiefObjective, BaseStealObjective] + parent: [BaseThiefObjective, BaseThiefStealObjective] id: BaseThiefStealStructureObjective components: - type: StealCondition verifyMapExistence: true - descriptionText: objective-condition-thief-description - type: Objective difficulty: 2 # it's hard to hide - type: entity abstract: true - parent: [BaseThiefObjective, BaseStealObjective] + parent: [BaseThiefObjective, BaseThiefStealObjective] id: BaseThiefStealAnimalObjective components: - type: StealCondition diff --git a/Resources/Prototypes/Roles/Antags/Thief.yml b/Resources/Prototypes/Roles/Antags/Thief.yml index d85d366f6b..f0d0c12470 100644 --- a/Resources/Prototypes/Roles/Antags/Thief.yml +++ b/Resources/Prototypes/Roles/Antags/Thief.yml @@ -10,4 +10,5 @@ storage: back: - ToolboxThief - - ClothingHandsChameleonThief \ No newline at end of file + - ClothingHandsChameleonThief + - ThiefBeacon \ No newline at end of file diff --git a/Resources/Textures/Objects/Tools/thief_beacon.rsi/extraction_point.png b/Resources/Textures/Objects/Tools/thief_beacon.rsi/extraction_point.png new file mode 100644 index 0000000000000000000000000000000000000000..b986a6ae28aedc92556d947c05ecb2963c5a90a0 GIT binary patch literal 954 zcmV;r14aCaP)Px&bV)=(RA_(jj?V(^xsVg^C6$x3&rBbCHDwP9L zzeP{I^voB@2cXbHi#QZTf*>R##o~YoO>n_#8kosCo5dSvd)V=UiP>!2buR2*8a>a< zn>YV?GjG=OAjbQSM3lyg_r6U4W4a^&7uW~(>tEh*M@m3XJ`M<7Qh)>4y6g=iF&-5G zyj2U}j4lRX0h_v5KzGofQ4lx}+|u%lZXY;TlmrrZZa07>-L|CbDc-T&Q4(h$yTrSP$ z3P9@mzz~Fx_rQFm;sRKXgON)4@=aKd!|H6`6#D7#16f{BTVJ}IT7*=!Ef&1jv&5ZVKVVIZaKlZIgcAcQ!eAJzk* z2w0BeySQGjbHXraJbA(^%X;S+&jbHPLja&sE(i864|xWTbPwFVbBB&?lNO>+E>^2Y zF%ynJX>QI1P)hl(?$|ctw?9L)lK8v+<70o!N3*kTHk$>YyQ3)0O}ju}c)pFmD7dt+ z;IB?fNm>X#xSQnUs*6~MldCQr+eS(Wz+$yZrCg>`E@QUaTv}K_DK(r2-p0nfNvCFG z7XT7iQ(cT!lC%(P%$wLXC#1~>os-PeC96_dH_|08hXi%G^#r`i4O zZvfIlAf=>OECSFj6zDV>zW&#rWKg1@8LYwNdG6P0fdqoD;>HZ_qt5})%^lkYAeYOL z%jL-D^Q47fW+elF+U?SQ{)nu-&Zc@5Xu5|$51h_yfwRR+UPr{HXIp&NMA<7u8^-y8I6n~Q2f)h@oc-k@-HaD)Nz-NP z>Y6|1Sn>lqr35d&>S7mQr<6GU{6KCU#CnpX>C(+4u#Y=G@Xt^61G;g3pocg=5a$Pm coZ~&mf5q`3zCm8LX#fBK07*qoM6N<$f?J5hnE(I) literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Tools/thief_beacon.rsi/extraction_point_light.png b/Resources/Textures/Objects/Tools/thief_beacon.rsi/extraction_point_light.png new file mode 100644 index 0000000000000000000000000000000000000000..f2e9f984d239556377c9957670d3fe82c8441a9b GIT binary patch literal 281 zcmV+!0p|XRP)Px#(@8`@R9J=WmN5#0KoCXWih|n2B9>`#Gus>@MGleH8+fCfKnq3C1rs+-h&GEG z69~w>dU?#uewYD4xjoAj9v%wA$e5WA1-Zf}BqU%!qq$EC->CqPkd%~|j*^m&#~Q(r zgc@kklfZKlC<0=V@Jd2VFmK#VU>NAA^@*B}f!Pqa27AP9o+9}3xt!gjH4|BH!$p7YxK;NZC2t%8b* fp2$HV2tVKn30Fa0oMIG>00000NkvXXu0mjfaW-&x literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Tools/thief_beacon.rsi/folded_extraction.png b/Resources/Textures/Objects/Tools/thief_beacon.rsi/folded_extraction.png new file mode 100644 index 0000000000000000000000000000000000000000..43ead68bb252215e76ecb1793dad137c86d9637a GIT binary patch literal 681 zcmV;a0#^NrP)Px%V@X6oR9J=Wmd{TUK^(L?RfECla_?Bc%jjxl|&b%aPCJ=r|5b#Ue_nuqC3$uwLlkYE8S@ zWFebnA)BS$Y+?vOz0g5>Ueu}jaOM#xrGj{A&mP(m;nkF&G21;AuHj;l4PvPBz$ zSOPqL^7PbrMiv0@^2PJux?bquRt_7k*YWpSEvhp!)C(P`z}q*k1OBd5OxUr16EOB* zf}tscy;p}jHiSS*NjjYdz?qxFt0^<*ELzQG=sIBn03!WZo`dt&_|Neh%SrWEc6pZX P00000NkvXXu0mjf!sa%| literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Tools/thief_beacon.rsi/meta.json b/Resources/Textures/Objects/Tools/thief_beacon.rsi/meta.json new file mode 100644 index 0000000000..ba7e003575 --- /dev/null +++ b/Resources/Textures/Objects/Tools/thief_beacon.rsi/meta.json @@ -0,0 +1,32 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Taken from https://github.com/austation/austation/commit/e2a4fefd01e702f48d3d4cc8d6a2686d54d104fa and edited by TheShuEd", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "folded_extraction" + }, + { + "name": "extraction_point", + "delays": [ + [ + 0.5, + 0.5 + ] + ] + }, + { + "name": "extraction_point_light", + "delays": [ + [ + 0.5, + 0.5 + ] + ] + } + ] +} \ No newline at end of file From 6570515c8d3d8b9e4442b892e10d88d42b2ea1d5 Mon Sep 17 00:00:00 2001 From: PJBot Date: Thu, 8 Aug 2024 13:18:57 +0000 Subject: [PATCH 020/174] Automatic changelog update --- Resources/Changelog/Changelog.yml | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 096bff65bc..c196b78d4a 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,12 +1,4 @@ Entries: -- author: deltanedas - changes: - - message: Added the robotics console for remotely looking at, disabling or destroying - cyborgs! - type: Add - id: 6562 - time: '2024-05-09T06:36:07.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/24855 - author: Killerqu00 changes: - message: Revolutionaries can now cuff command members in order to seize control @@ -3781,3 +3773,16 @@ id: 7061 time: '2024-08-08T11:39:47.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/30361 +- author: TheShuEd + changes: + - message: Add "thieving beacon" to Thief antag - a device that counts objects within + a radius of itself as stolen. + type: Add + - message: Return thief structures stealing objectives. + type: Add + - message: Animal theft objectives can no longer appear if the animals are not on + the station. + type: Fix + id: 7062 + time: '2024-08-08T13:17:50.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/29997 From 703c8840c405dd1f38ebea82565bbf2cbe17a7a6 Mon Sep 17 00:00:00 2001 From: saintmuntzer <47153094+saintmuntzer@users.noreply.github.com> Date: Thu, 8 Aug 2024 11:35:01 -0500 Subject: [PATCH 021/174] Fix for issue 30781 (#30788) Fixed typos in name and description of syndicate recruit jumpsuit. --- .../Prototypes/Entities/Clothing/Uniforms/ship_vs_ship.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Resources/Prototypes/Entities/Clothing/Uniforms/ship_vs_ship.yml b/Resources/Prototypes/Entities/Clothing/Uniforms/ship_vs_ship.yml index d6999a0a26..f10317e221 100644 --- a/Resources/Prototypes/Entities/Clothing/Uniforms/ship_vs_ship.yml +++ b/Resources/Prototypes/Entities/Clothing/Uniforms/ship_vs_ship.yml @@ -17,8 +17,8 @@ - type: entity parent: ClothingUniformBase id: ClothingUniformJumpsuitRecruitSyndie - name: syndicate recuit jumpsuit - description: A dubious,, dark-grey jumpsuit. As if passengers weren't dubious enough already. + name: syndicate recruit jumpsuit + description: A dubious, dark-grey jumpsuit. As if passengers weren't dubious enough already. components: - type: Sprite sprite: Clothing/Uniforms/Jumpsuit/recruit_syndie.rsi From 66f0cd4f435a174668eb7f35ae65a684dcc76f4c Mon Sep 17 00:00:00 2001 From: dffdff2423 Date: Thu, 8 Aug 2024 13:36:36 -0500 Subject: [PATCH 022/174] Remove suspect figurine line (#30795) --- Resources/Locale/en-US/datasets/figurines.ftl | 3 +-- Resources/Prototypes/Datasets/figurines.yml | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/Resources/Locale/en-US/datasets/figurines.ftl b/Resources/Locale/en-US/datasets/figurines.ftl index 0de2d9131b..900f09ed37 100644 --- a/Resources/Locale/en-US/datasets/figurines.ftl +++ b/Resources/Locale/en-US/datasets/figurines.ftl @@ -29,8 +29,7 @@ figurines-musician-2 = Never gonna let you down! # figurines-boxer- -figurines-captain-1 = Crew, the Nuke Disk is safely up my ass. -figurines-captain-2 = Glory to NT! +figurines-captain-1 = Glory to NT! figurines-hos-1 = Space law? What? figurines-hos-2 = Shot the clown. diff --git a/Resources/Prototypes/Datasets/figurines.yml b/Resources/Prototypes/Datasets/figurines.yml index 8ad651c134..212139b37d 100644 --- a/Resources/Prototypes/Datasets/figurines.yml +++ b/Resources/Prototypes/Datasets/figurines.yml @@ -50,7 +50,7 @@ id: FigurinesCaptain values: prefix: figurines-captain- - count: 2 + count: 1 - type: localizedDataset id: FigurinesHoS From 3db51a7e36c7890ad84b8fa8bc102398682dcf0b Mon Sep 17 00:00:00 2001 From: Emisse <99158783+Emisse@users.noreply.github.com> Date: Thu, 8 Aug 2024 15:06:40 -0600 Subject: [PATCH 023/174] train update (#30797) train fix --- Resources/Maps/train.yml | 2537 ++++++++++++++++++++------------------ 1 file changed, 1331 insertions(+), 1206 deletions(-) diff --git a/Resources/Maps/train.yml b/Resources/Maps/train.yml index caeb4d22cc..070a446d0d 100644 --- a/Resources/Maps/train.yml +++ b/Resources/Maps/train.yml @@ -529,571 +529,571 @@ entities: color: '#FFFFFFFF' id: Arrows decals: - 470: -2,-124 + 324: -2,-124 - node: color: '#FFFFFFFF' id: Bot decals: - 469: -1,-124 - 838: 6,-280 - 1470: 5,-281 - 1471: 5,-280 - 1472: 5,-279 - 1473: 4,-279 - 1474: 4,-280 - 1475: 4,-281 + 323: -1,-124 + 590: 6,-280 + 1221: 5,-281 + 1222: 5,-280 + 1223: 5,-279 + 1224: 4,-279 + 1225: 4,-280 + 1226: 4,-281 - node: color: '#FFFFFFFF' id: BotGreyscale decals: - 1195: 1,-279 - 1196: 1,-280 - 1197: 2,-279 - 1198: 3,-279 - 1199: 3,-280 - 1294: 2,-280 - 1352: -1,-341 - 1353: -1,-340 - 1354: -1,-339 - 1355: -1,-338 - 1358: -2,-341 - 1359: -2,-340 - 1360: -2,-339 - 1361: -2,-338 - 1476: 3,-281 - 1477: 2,-281 - 1478: 1,-281 + 946: 1,-279 + 947: 1,-280 + 948: 2,-279 + 949: 3,-279 + 950: 3,-280 + 1045: 2,-280 + 1103: -1,-341 + 1104: -1,-340 + 1105: -1,-339 + 1106: -1,-338 + 1109: -2,-341 + 1110: -2,-340 + 1111: -2,-339 + 1112: -2,-338 + 1227: 3,-281 + 1228: 2,-281 + 1229: 1,-281 - node: color: '#FFFFFFFF' id: BotLeft decals: - 837: 6,-281 - 1436: 3,-256 - 1437: 4,-256 - 1438: 5,-256 - 1439: 6,-258 - 1440: 5,-258 - 1441: 4,-258 - 1442: 3,-258 + 589: 6,-281 + 1187: 3,-256 + 1188: 4,-256 + 1189: 5,-256 + 1190: 6,-258 + 1191: 5,-258 + 1192: 4,-258 + 1193: 3,-258 - node: color: '#FFFFFFFF' id: BotLeftGreyscale decals: - 1356: -1,-342 + 1107: -1,-342 - node: color: '#FFFFFFFF' id: BotRight decals: - 836: 6,-279 + 588: 6,-279 - node: color: '#FFFFFFFF' id: BotRightGreyscale decals: - 1357: -1,-337 + 1108: -1,-337 - node: color: '#FFFFFFFF' id: BrickTileDarkInnerNe decals: - 115: 6,-38 - 116: 6,-45 - 280: -2,-7 + 92: 6,-38 + 93: 6,-45 + 215: -2,-7 - node: color: '#FFFFFFFF' id: BrickTileDarkInnerNw decals: - 112: -6,-31 - 281: -3,-7 + 89: -6,-31 + 216: -3,-7 - node: color: '#FFFFFFFF' id: BrickTileDarkInnerSe decals: - 117: 6,-43 - 279: -2,-7 + 94: 6,-43 + 214: -2,-7 - node: color: '#FFFFFFFF' id: BrickTileDarkInnerSw decals: - 109: -6,-29 - 110: -6,-31 - 282: -3,-7 + 87: -6,-29 + 88: -6,-31 + 217: -3,-7 - node: color: '#FFFFFFFF' id: BrickTileDarkLineE decals: - 118: 6,-44 - 119: 6,-37 + 95: 6,-44 + 96: 6,-37 - node: color: '#FFFFFFFF' id: BrickTileDarkLineN decals: - 269: -4,-8 - 270: -4,-8 - 271: -3,-8 - 272: -2,-8 - 273: -1,-8 - 276: -4,-7 - 277: -4,-7 - 278: -1,-7 - 478: 2,-139 - 479: 3,-139 + 204: -4,-8 + 205: -4,-8 + 206: -3,-8 + 207: -2,-8 + 208: -1,-8 + 211: -4,-7 + 212: -4,-7 + 213: -1,-7 + 327: 2,-139 + 328: 3,-139 - node: color: '#FFFFFFFF' id: BrickTileDarkLineS decals: - 265: -4,-6 - 266: -2,-6 - 267: -3,-6 - 268: -1,-6 - 274: -4,-7 - 275: -1,-7 - 473: 3,-140 - 474: 2,-140 + 200: -4,-6 + 201: -2,-6 + 202: -3,-6 + 203: -1,-6 + 209: -4,-7 + 210: -1,-7 + 325: 3,-140 + 326: 2,-140 - node: color: '#FFFFFFFF' id: BrickTileDarkLineW decals: - 113: -6,-30 - 114: -6,-32 + 90: -6,-30 + 91: -6,-32 - node: color: '#639137FF' id: BrickTileSteelEndN decals: - 357: 3,-86 + 218: 3,-86 - node: color: '#639137FF' id: BrickTileSteelEndS decals: - 358: 3,-92 + 219: 3,-92 - node: cleanable: True color: '#FFFFFFFF' id: BrickTileSteelInnerSw decals: - 1455: 7,-255 + 1206: 7,-255 - node: color: '#639137FF' id: BrickTileSteelLineE decals: - 364: 3,-87 - 365: 3,-88 - 366: 3,-89 - 367: 3,-90 - 368: 3,-91 + 225: 3,-87 + 226: 3,-88 + 227: 3,-89 + 228: 3,-90 + 229: 3,-91 - node: cleanable: True color: '#FFFFFFFF' id: BrickTileSteelLineS decals: - 1452: 6,-255 - 1453: 5,-255 - 1454: 4,-255 + 1203: 6,-255 + 1204: 5,-255 + 1205: 4,-255 - node: color: '#639137FF' id: BrickTileSteelLineW decals: - 359: 3,-91 - 360: 3,-90 - 361: 3,-89 - 362: 3,-88 - 363: 3,-87 + 220: 3,-91 + 221: 3,-90 + 222: 3,-89 + 223: 3,-88 + 224: 3,-87 - node: cleanable: True color: '#FFFFFFFF' id: BrickTileSteelLineW decals: - 1449: 7,-258 - 1450: 7,-257 - 1451: 7,-256 + 1200: 7,-258 + 1201: 7,-257 + 1202: 7,-256 - node: color: '#334E6DC8' id: BrickTileWhiteBox decals: - 1424: 19,-298 + 1175: 19,-298 - node: color: '#52B4E996' id: BrickTileWhiteBox decals: - 1429: 25,-298 + 1180: 25,-298 - node: color: '#646464FF' id: BrickTileWhiteBox decals: - 386: 4,-89 + 247: 4,-89 - node: color: '#9FED5896' id: BrickTileWhiteBox decals: - 1430: 24,-300 + 1181: 24,-300 - node: color: '#A4610696' id: BrickTileWhiteBox decals: - 1427: 20,-300 + 1178: 20,-300 - node: color: '#D381C996' id: BrickTileWhiteBox decals: - 1428: 24,-298 + 1179: 24,-298 - node: color: '#D4D4D496' id: BrickTileWhiteBox decals: - 1431: 25,-300 + 1182: 25,-300 - node: color: '#DE3A3A96' id: BrickTileWhiteBox decals: - 1425: 20,-298 + 1176: 20,-298 - node: color: '#EFB34196' id: BrickTileWhiteBox decals: - 1426: 19,-300 + 1177: 19,-300 - node: color: '#52B4E996' id: BrickTileWhiteCornerNe decals: - 1417: 3,-197 + 1168: 3,-197 - node: color: '#A0A0A0FF' id: BrickTileWhiteCornerNe decals: - 438: 3,-96 + 292: 3,-96 - node: color: '#B3B3B3FF' id: BrickTileWhiteCornerNe decals: - 370: 4,-85 - 371: 5,-86 + 231: 4,-85 + 232: 5,-86 - node: color: '#52B4E996' id: BrickTileWhiteCornerNw decals: - 1416: -1,-197 + 1167: -1,-197 - node: color: '#A0A0A0FF' id: BrickTileWhiteCornerNw decals: - 403: 5,-93 - 439: 2,-96 + 264: 5,-93 + 293: 2,-96 - node: color: '#52B4E996' id: BrickTileWhiteCornerSe decals: - 1423: 3,-200 + 1174: 3,-200 - node: color: '#A0A0A0FF' id: BrickTileWhiteCornerSe decals: - 440: 3,-98 + 294: 3,-98 - node: color: '#B3B3B3FF' id: BrickTileWhiteCornerSe decals: - 372: 5,-92 - 373: 4,-93 + 233: 5,-92 + 234: 4,-93 - node: color: '#52B4E996' id: BrickTileWhiteCornerSw decals: - 1422: -1,-200 + 1173: -1,-200 - node: color: '#A0A0A0FF' id: BrickTileWhiteCornerSw decals: - 394: 5,-85 - 441: 2,-98 + 255: 5,-85 + 295: 2,-98 - node: color: '#646464FF' id: BrickTileWhiteEndN decals: - 381: 4,-87 - 385: 4,-90 + 242: 4,-87 + 246: 4,-90 - node: color: '#646464FF' id: BrickTileWhiteEndS decals: - 382: 4,-91 - 383: 4,-88 - 384: 4,-88 + 243: 4,-91 + 244: 4,-88 + 245: 4,-88 - node: color: '#334E6DFF' id: BrickTileWhiteInnerNe decals: - 262: -1,2 + 197: -1,2 - node: color: '#A0A0A0FF' id: BrickTileWhiteInnerNe decals: - 442: 3,-97 - 450: 3,-98 - 451: 2,-98 + 296: 3,-97 + 304: 3,-98 + 305: 2,-98 - node: color: '#B3B3B3FF' id: BrickTileWhiteInnerNe decals: - 375: 4,-86 + 236: 4,-86 - node: color: '#334E6DFF' id: BrickTileWhiteInnerNw decals: - 263: 1,2 + 198: 1,2 - node: color: '#646464FF' id: BrickTileWhiteInnerNw decals: - 389: 5,-90 + 250: 5,-90 - node: color: '#A0A0A0FF' id: BrickTileWhiteInnerNw decals: - 402: 6,-93 - 404: 5,-94 - 443: 2,-97 - 452: 3,-98 + 263: 6,-93 + 265: 5,-94 + 297: 2,-97 + 306: 3,-98 - node: color: '#A0A0A0FF' id: BrickTileWhiteInnerSe decals: - 445: 3,-97 - 449: 2,-96 + 299: 3,-97 + 303: 2,-96 - node: color: '#B3B3B3FF' id: BrickTileWhiteInnerSe decals: - 374: 4,-92 + 235: 4,-92 - node: color: '#646464FF' id: BrickTileWhiteInnerSw decals: - 388: 5,-88 + 249: 5,-88 - node: color: '#A0A0A0FF' id: BrickTileWhiteInnerSw decals: - 392: 5,-84 - 393: 5,-84 - 406: 6,-85 - 444: 2,-97 - 448: 3,-96 + 253: 5,-84 + 254: 5,-84 + 267: 6,-85 + 298: 2,-97 + 302: 3,-96 - node: color: '#334E6DFF' id: BrickTileWhiteLineE decals: - 261: -1,3 + 196: -1,3 - node: color: '#A0A0A0FF' id: BrickTileWhiteLineE decals: - 446: 2,-97 - 453: 3,-97 + 300: 2,-97 + 307: 3,-97 - node: color: '#B3B3B3FF' id: BrickTileWhiteLineE decals: - 376: 5,-87 - 377: 5,-88 - 378: 5,-89 - 379: 5,-90 - 380: 5,-91 + 237: 5,-87 + 238: 5,-88 + 239: 5,-89 + 240: 5,-90 + 241: 5,-91 - node: color: '#52B4E996' id: BrickTileWhiteLineN decals: - 1418: 1,-197 - 1419: 0,-197 + 1169: 1,-197 + 1170: 0,-197 - node: color: '#A0A0A0FF' id: BrickTileWhiteLineN decals: - 405: 4,-94 + 266: 4,-94 - node: color: '#B3B3B3FF' id: BrickTileWhiteLineN decals: - 369: 3,-85 + 230: 3,-85 - node: color: '#52B4E996' id: BrickTileWhiteLineS decals: - 1420: 0,-200 - 1421: 1,-200 + 1171: 0,-200 + 1172: 1,-200 - node: color: '#A0A0A0FF' id: BrickTileWhiteLineS decals: - 390: 3,-84 - 391: 4,-84 + 251: 3,-84 + 252: 4,-84 - node: color: '#334E6DFF' id: BrickTileWhiteLineW decals: - 264: 1,3 + 199: 1,3 - node: color: '#52B4E996' id: BrickTileWhiteLineW decals: - 1415: -1,-198 + 1166: -1,-198 - node: color: '#646464FF' id: BrickTileWhiteLineW decals: - 387: 5,-89 + 248: 5,-89 - node: color: '#A0A0A0FF' id: BrickTileWhiteLineW decals: - 395: 6,-86 - 396: 6,-87 - 397: 6,-89 - 398: 6,-88 - 399: 6,-90 - 400: 6,-91 - 401: 6,-92 - 447: 3,-97 - 454: 2,-97 + 256: 6,-86 + 257: 6,-87 + 258: 6,-89 + 259: 6,-88 + 260: 6,-90 + 261: 6,-91 + 262: 6,-92 + 301: 3,-97 + 308: 2,-97 - node: color: '#FFFFFFFF' id: BushAOne decals: - 1034: 1,-389 - 1035: 4,-387 - 1036: 1,-386 - 1307: 9,-203 + 786: 1,-389 + 787: 4,-387 + 788: 1,-386 + 1058: 9,-203 - node: color: '#FFFFFFFF' id: BushAThree decals: - 166: 1.4194474,-40.90987 - 1308: 9,-206 + 101: 1.4194474,-40.90987 + 1059: 9,-206 - node: color: '#FFFFFFFF' id: BushCOne decals: - 165: 2.5288224,-40.980873 - 1164: -3,-375 - 1165: 3,-375 + 100: 2.5288224,-40.980873 + 916: -3,-375 + 917: 3,-375 - node: color: '#FFFFFFFF' id: BushCThree decals: - 1309: 9,-205 + 1060: 9,-205 - node: color: '#FFFFFFFF' id: BushCTwo decals: - 164: 2.1381974,-41.52775 + 99: 2.1381974,-41.52775 - node: color: '#FFFFFFFF' id: Busha2 decals: - 1302: 11,-198 - 1305: 10,-201 - 1306: 11,-201 + 1053: 11,-198 + 1056: 10,-201 + 1057: 11,-201 - node: color: '#FFFFFFFF' id: Busha3 decals: - 173: 4.2948465,-41.901707 + 108: 4.2948465,-41.901707 - node: color: '#FFFFFFFF' id: Bushb1 decals: - 1030: -1,-387 - 1160: 1,-373 - 1161: 0,-374 - 1310: 9,-195 - 1311: 9,-204 + 782: -1,-387 + 912: 1,-373 + 913: 0,-374 + 1061: 9,-195 + 1062: 9,-204 - node: color: '#FFFFFFFF' id: Bushb3 decals: - 167: 1.2944474,-41.75362 - 1031: -3,-387 - 1032: 6,-384 - 1033: -5,-384 - 1162: -2,-374 + 102: 1.2944474,-41.75362 + 783: -3,-387 + 784: 6,-384 + 785: -5,-384 + 914: -2,-374 - node: color: '#FFFFFFFF' id: Bushc2 decals: - 1301: 10,-198 - 1303: 10,-199 + 1052: 10,-198 + 1054: 10,-199 - node: color: '#FFFFFFFF' id: Bushc3 decals: - 1163: 3,-374 - 1304: 9,-200 - 1312: 7,-202 + 915: 3,-374 + 1055: 9,-200 + 1063: 7,-202 - node: color: '#3EB38896' id: CheckerNESW decals: - 1464: -11,-261 - 1465: -10,-261 - 1466: -12,-261 - 1467: -9,-261 - 1468: -8,-261 + 1215: -11,-261 + 1216: -10,-261 + 1217: -12,-261 + 1218: -9,-261 + 1219: -8,-261 - node: color: '#52B4E996' id: CheckerNWSE decals: - 1376: -5,-167 - 1377: -5,-166 - 1378: -4,-166 - 1379: -4,-167 - 1380: -3,-167 - 1381: -3,-166 - 1382: -2,-166 - 1383: -2,-167 - 1384: 3,-181 - 1385: 3,-180 - 1386: 3,-179 - 1387: 4,-179 - 1388: 4,-180 - 1389: 4,-181 - 1390: 5,-181 - 1391: 5,-180 - 1392: 5,-179 - 1393: 5,-178 - 1394: 4,-178 - 1395: 2,-180 - 1396: 2,-179 - 1397: -2,-171 - 1398: -2,-170 - 1399: -2,-169 - 1400: -1,-204 - 1401: -1,-203 - 1402: -1,-202 - 1403: 0,-202 - 1404: 0,-203 - 1405: 0,-204 - 1406: 1,-204 - 1407: 1,-203 - 1408: 1,-202 - 1409: 2,-202 - 1410: 2,-203 - 1411: 2,-204 - 1412: 3,-204 - 1413: 3,-203 - 1414: 3,-202 + 1127: -5,-167 + 1128: -5,-166 + 1129: -4,-166 + 1130: -4,-167 + 1131: -3,-167 + 1132: -3,-166 + 1133: -2,-166 + 1134: -2,-167 + 1135: 3,-181 + 1136: 3,-180 + 1137: 3,-179 + 1138: 4,-179 + 1139: 4,-180 + 1140: 4,-181 + 1141: 5,-181 + 1142: 5,-180 + 1143: 5,-179 + 1144: 5,-178 + 1145: 4,-178 + 1146: 2,-180 + 1147: 2,-179 + 1148: -2,-171 + 1149: -2,-170 + 1150: -2,-169 + 1151: -1,-204 + 1152: -1,-203 + 1153: -1,-202 + 1154: 0,-202 + 1155: 0,-203 + 1156: 0,-204 + 1157: 1,-204 + 1158: 1,-203 + 1159: 1,-202 + 1160: 2,-202 + 1161: 2,-203 + 1162: 2,-204 + 1163: 3,-204 + 1164: 3,-203 + 1165: 3,-202 - node: cleanable: True color: '#FFFFFFFF' id: DirtLight decals: - 1443: 3,-257 - 1444: 4,-257 - 1445: 6,-256 - 1446: 10,-253 + 1194: 3,-257 + 1195: 4,-257 + 1196: 6,-256 + 1197: 10,-253 - node: cleanable: True color: '#FFFFFFFF' id: DirtMedium decals: - 1447: 5,-257 - 1448: 10,-254 + 1198: 5,-257 + 1199: 10,-254 - node: color: '#FFFFFFFF' id: FlowersBRTwo @@ -1103,8 +1103,8 @@ entities: color: '#FFFFFFFF' id: Flowersbr2 decals: - 179: 1.1507428,-40.14647 - 180: 0.83824277,-40.39647 + 114: 1.1507428,-40.14647 + 115: 0.83824277,-40.39647 - node: color: '#FFFFFFFF' id: Flowerspv2 @@ -1119,710 +1119,710 @@ entities: color: '#FFFFFFFF' id: Flowersy4 decals: - 178: 4.197618,-40.474594 + 113: 4.197618,-40.474594 - node: color: '#9FED58CF' id: FullTileOverlayGreyscale decals: - 1334: -3,-195 - 1335: -3,-194 - 1336: -4,-194 - 1337: -5,-194 - 1338: -6,-194 - 1339: -7,-194 - 1340: -7,-195 + 1085: -3,-195 + 1086: -3,-194 + 1087: -4,-194 + 1088: -5,-194 + 1089: -6,-194 + 1090: -7,-194 + 1091: -7,-195 - node: color: '#9FED58DD' id: FullTileOverlayGreyscale decals: - 646: -3,-202 - 647: -3,-203 - 648: -3,-204 - 649: -3,-205 - 650: -3,-206 - 651: -3,-207 - 652: -3,-208 - 653: -3,-201 - 654: -3,-199 - 655: -3,-198 - 656: -3,-197 - 657: -3,-196 - 658: -7,-196 - 659: -7,-197 - 660: -7,-198 - 661: -7,-199 - 662: -6,-199 + 445: -3,-202 + 446: -3,-203 + 447: -3,-204 + 448: -3,-205 + 449: -3,-206 + 450: -3,-207 + 451: -3,-208 + 452: -3,-201 + 453: -3,-199 + 454: -3,-198 + 455: -3,-197 + 456: -3,-196 + 457: -7,-196 + 458: -7,-197 + 459: -7,-198 + 460: -7,-199 + 461: -6,-199 - node: color: '#FFFFFFFF' id: Grassa1 decals: - 1037: -3,-384 - 1040: -5,-387 - 1295: 11,-196 + 789: -3,-384 + 792: -5,-387 + 1046: 11,-196 - node: color: '#FFFFFFFF' id: Grassa2 decals: - 1026: -2,-388 - 1166: -1,-374 + 778: -2,-388 + 918: -1,-374 - node: color: '#FFFFFFFF' id: Grassa3 decals: - 1029: -2,-387 - 1168: 1,-374 - 1169: 2,-374 - 1296: 10,-195 + 781: -2,-387 + 920: 1,-374 + 921: 2,-374 + 1047: 10,-195 - node: color: '#FFFFFFFF' id: Grassa4 decals: - 1314: 7,-195 + 1065: 7,-195 - node: color: '#FFFFFFFF' id: Grassa5 decals: - 1170: -3,-374 - 1171: 2,-373 - 1297: 9,-194 + 922: -3,-374 + 923: 2,-373 + 1048: 9,-194 - node: color: '#FFFFFFFF' id: Grassb1 decals: - 168: 3.0600724,-41.94112 - 1038: 4,-384 - 1313: 7,-196 + 103: 3.0600724,-41.94112 + 790: 4,-384 + 1064: 7,-196 - node: color: '#FFFFFFFF' id: Grassb2 decals: - 175: 4.2479715,-41.057957 - 181: 0.60386777,-40.880844 - 183: 1.6455414,-39.61602 - 1173: 4,-374 + 110: 4.2479715,-41.057957 + 116: 0.60386777,-40.880844 + 118: 1.6455414,-39.61602 + 925: 4,-374 - node: color: '#FFFFFFFF' id: Grassb3 decals: - 171: 0.47185308,-41.800495 - 1039: 5,-385 + 106: 0.47185308,-41.800495 + 791: 5,-385 - node: color: '#FFFFFFFF' id: Grassb4 decals: - 170: 3.40986,-41.34737 - 177: 3.945704,-39.753384 - 1298: 9,-191 - 1299: 9,-192 + 105: 3.40986,-41.34737 + 112: 3.945704,-39.753384 + 1049: 9,-191 + 1050: 9,-192 - node: color: '#FFFFFFFF' id: Grassb5 decals: - 169: 2.3569474,-42.269245 - 172: 1.331228,-42.519245 - 176: 2.6073463,-40.20651 - 182: 3.1142914,-39.694145 - 1027: -2,-389 - 1028: -1,-388 - 1167: -1,-373 - 1172: -4,-374 - 1300: 11,-199 + 104: 2.3569474,-42.269245 + 107: 1.331228,-42.519245 + 111: 2.6073463,-40.20651 + 117: 3.1142914,-39.694145 + 779: -2,-389 + 780: -1,-388 + 919: -1,-373 + 924: -4,-374 + 1051: 11,-199 - node: color: '#FFFFFFFF' id: GrayConcreteTrimLineE decals: - 1266: 17,-64 - 1267: 17,-63 - 1268: 17,-62 - 1269: 17,-61 + 1017: 17,-64 + 1018: 17,-63 + 1019: 17,-62 + 1020: 17,-61 - node: color: '#FFFFFFFF' id: GrayConcreteTrimLineN decals: - 1270: 14,-60 - 1271: 15,-60 - 1272: 16,-60 - 1273: 13,-68 - 1274: 14,-68 - 1275: 15,-68 - 1276: 16,-68 - 1277: 17,-68 - 1283: 13,-78 - 1284: 14,-78 - 1285: 15,-78 - 1286: 16,-78 - 1287: 17,-78 + 1021: 14,-60 + 1022: 15,-60 + 1023: 16,-60 + 1024: 13,-68 + 1025: 14,-68 + 1026: 15,-68 + 1027: 16,-68 + 1028: 17,-68 + 1034: 13,-78 + 1035: 14,-78 + 1036: 15,-78 + 1037: 16,-78 + 1038: 17,-78 - node: color: '#FFFFFFFF' id: GrayConcreteTrimLineS decals: - 1278: 13,-76 - 1279: 14,-76 - 1280: 15,-76 - 1281: 16,-76 - 1282: 17,-76 - 1288: 14,-86 - 1289: 15,-86 - 1290: 16,-86 - 1291: 13,-85 - 1292: 17,-85 + 1029: 13,-76 + 1030: 14,-76 + 1031: 15,-76 + 1032: 16,-76 + 1033: 17,-76 + 1039: 14,-86 + 1040: 15,-86 + 1041: 16,-86 + 1042: 13,-85 + 1043: 17,-85 - node: color: '#FFFFFFFF' id: GrayConcreteTrimLineW decals: - 1262: 13,-64 - 1263: 13,-63 - 1264: 13,-62 - 1265: 13,-61 + 1013: 13,-64 + 1014: 13,-63 + 1015: 13,-62 + 1016: 13,-61 - node: color: '#999453FF' id: MiniTileDarkBox decals: - 580: 5,-168 + 379: 5,-168 - node: color: '#FFFFFFFF' id: MiniTileDarkBox decals: - 555: -7,-153 + 354: -7,-153 - node: color: '#FFFFFFFF' id: MiniTileDarkLineE decals: - 724: 17,-154 - 725: 17,-153 - 726: 17,-152 - 727: 17,-148 - 728: 17,-147 - 729: 17,-146 - 730: 17,-145 - 731: 17,-144 - 732: 17,-141 - 733: 17,-140 - 748: 17,-160 - 749: 17,-161 - 750: 17,-164 - 751: 17,-165 - 1014: 0,-345 - 1015: 0,-346 - 1016: 0,-347 - 1020: 0,-344 - 1022: 2,-330 - 1023: 2,-331 - 1024: 2,-332 - 1025: 2,-333 + 523: 17,-154 + 524: 17,-153 + 525: 17,-152 + 526: 17,-148 + 527: 17,-147 + 528: 17,-146 + 529: 17,-145 + 530: 17,-144 + 531: 17,-141 + 532: 17,-140 + 547: 17,-160 + 548: 17,-161 + 549: 17,-164 + 550: 17,-165 + 766: 0,-345 + 767: 0,-346 + 768: 0,-347 + 772: 0,-344 + 774: 2,-330 + 775: 2,-331 + 776: 2,-332 + 777: 2,-333 - node: color: '#DE3A3A96' id: MiniTileDarkLineN decals: - 1174: -3,-371 - 1175: -4,-371 - 1176: -5,-371 - 1177: -6,-371 - 1178: -2,-371 - 1179: -1,-371 - 1180: 0,-371 - 1181: 1,-371 - 1182: 2,-371 - 1183: 3,-371 - 1184: 4,-371 - 1185: 5,-371 - 1186: 6,-371 + 926: -3,-371 + 927: -4,-371 + 928: -5,-371 + 929: -6,-371 + 930: -2,-371 + 931: -1,-371 + 932: 0,-371 + 933: 1,-371 + 934: 2,-371 + 935: 3,-371 + 936: 4,-371 + 937: 5,-371 + 938: 6,-371 - node: color: '#FFFFFFFF' id: MiniTileDarkLineS decals: - 1011: -5,-347 - 1012: -4,-347 - 1013: -3,-347 + 763: -5,-347 + 764: -4,-347 + 765: -3,-347 - node: color: '#FFFFFFFF' id: MiniTileDarkLineW decals: - 734: 13,-141 - 735: 13,-139 - 736: 13,-144 - 737: 13,-147 - 738: 13,-148 - 739: 13,-149 - 740: 13,-150 - 741: 13,-151 - 742: 13,-152 - 743: 13,-153 - 744: 13,-154 - 745: 13,-160 - 746: 13,-161 - 747: 13,-162 - 1009: -6,-345 - 1010: -6,-346 - 1017: 0,-347 - 1018: 0,-346 - 1019: 0,-345 - 1021: 0,-344 + 533: 13,-141 + 534: 13,-139 + 535: 13,-144 + 536: 13,-147 + 537: 13,-148 + 538: 13,-149 + 539: 13,-150 + 540: 13,-151 + 541: 13,-152 + 542: 13,-153 + 543: 13,-154 + 544: 13,-160 + 545: 13,-161 + 546: 13,-162 + 761: -6,-345 + 762: -6,-346 + 769: 0,-347 + 770: 0,-346 + 771: 0,-345 + 773: 0,-344 - node: color: '#D381C996' id: MiniTileSteelBox decals: - 897: 2,-310 - 898: 2,-306 + 649: 2,-310 + 650: 2,-306 - node: color: '#999453FF' id: MiniTileSteelCornerNe decals: - 579: 6,-167 + 378: 6,-167 - node: color: '#9FED58CF' id: MiniTileSteelCornerNe decals: - 1341: -3,-194 + 1092: -3,-194 - node: color: '#D381C996' id: MiniTileSteelCornerNe decals: - 712: -3,-54 - 1211: -2,-311 + 511: -3,-54 + 962: -2,-311 - node: color: '#DE3A3A96' id: MiniTileSteelCornerNe decals: - 1071: 2,-357 - 1077: 3,-360 - 1093: 4,-361 + 823: 2,-357 + 829: 3,-360 + 845: 4,-361 - node: color: '#EFB34196' id: MiniTileSteelCornerNe decals: - 1240: 19,-246 + 991: 19,-246 - node: color: '#999453FF' id: MiniTileSteelCornerNw decals: - 576: 4,-167 + 375: 4,-167 - node: color: '#9FED58CF' id: MiniTileSteelCornerNw decals: - 1342: -7,-194 + 1093: -7,-194 - node: color: '#D381C996' id: MiniTileSteelCornerNw decals: - 713: -6,-54 + 512: -6,-54 - node: color: '#DE3A3A96' id: MiniTileSteelCornerNw decals: - 1072: -2,-357 - 1078: -3,-360 - 1086: -7,-361 + 824: -2,-357 + 830: -3,-360 + 838: -7,-361 - node: color: '#EFB34196' id: MiniTileSteelCornerNw decals: - 1228: 14,-251 - 1236: 15,-246 + 979: 14,-251 + 987: 15,-246 - node: color: '#999453FF' id: MiniTileSteelCornerSe decals: - 577: 6,-169 + 376: 6,-169 - node: color: '#9FED58DB' id: MiniTileSteelCornerSe decals: - 629: -3,-193 + 428: -3,-193 - node: color: '#D381C996' id: MiniTileSteelCornerSe decals: - 714: -3,-56 - 1212: -2,-307 + 513: -3,-56 + 963: -2,-307 - node: color: '#EFB34196' id: MiniTileSteelCornerSe decals: - 1252: 19,-262 + 1003: 19,-262 - node: color: '#999453FF' id: MiniTileSteelCornerSw decals: - 578: 4,-169 + 377: 4,-169 - node: color: '#9FED58DB' id: MiniTileSteelCornerSw decals: - 628: -6,-193 + 427: -6,-193 - node: color: '#D381C996' id: MiniTileSteelCornerSw decals: - 715: -6,-56 + 514: -6,-56 - node: color: '#DE3A3A96' id: MiniTileSteelCornerSw decals: - 1087: -7,-362 + 839: -7,-362 - node: color: '#EFB34196' id: MiniTileSteelCornerSw decals: - 1229: 14,-255 - 1250: 15,-262 + 980: 14,-255 + 1001: 15,-262 - node: color: '#D381C996' id: MiniTileSteelInnerNe decals: - 916: 1,-307 - 917: 1,-320 - 1216: -8,-308 + 668: 1,-307 + 669: 1,-320 + 967: -8,-308 - node: color: '#DE3A3A96' id: MiniTileSteelInnerNe decals: - 1080: 2,-360 - 1081: 3,-361 + 832: 2,-360 + 833: 3,-361 - node: color: '#D381C996' id: MiniTileSteelInnerNw decals: - 914: 9,-307 - 1213: -1,-308 + 666: 9,-307 + 964: -1,-308 - node: color: '#DE3A3A96' id: MiniTileSteelInnerNw decals: - 1079: -2,-360 - 1082: -3,-361 + 831: -2,-360 + 834: -3,-361 - node: color: '#EFB34196' id: MiniTileSteelInnerNw decals: - 1231: 15,-251 + 982: 15,-251 - node: color: '#D381C996' id: MiniTileSteelInnerSe decals: - 896: 1,-309 - 915: 1,-298 - 1215: -8,-310 + 648: 1,-309 + 667: 1,-298 + 966: -8,-310 - node: color: '#D381C996' id: MiniTileSteelInnerSw decals: - 921: 9,-309 - 1067: -1,-298 - 1214: -1,-310 + 673: 9,-309 + 819: -1,-298 + 965: -1,-310 - node: color: '#DE3A3A96' id: MiniTileSteelInnerSw decals: - 1129: -4,-362 + 881: -4,-362 - node: color: '#EFB34196' id: MiniTileSteelInnerSw decals: - 1230: 15,-255 + 981: 15,-255 - node: color: '#5A64BC93' id: MiniTileSteelLineE decals: - 1158: 7,-367 - 1159: 7,-368 + 910: 7,-367 + 911: 7,-368 - node: color: '#5ABC5A93' id: MiniTileSteelLineE decals: - 1146: -6,-367 - 1147: -6,-368 + 898: -6,-367 + 899: -6,-368 - node: color: '#999453FF' id: MiniTileSteelLineE decals: - 572: 6,-168 + 371: 6,-168 - node: color: '#9FED58CF' id: MiniTileSteelLineE decals: - 1344: -3,-195 + 1095: -3,-195 - node: color: '#9FED58DB' id: MiniTileSteelLineE decals: - 641: -5,-207 - 642: -5,-206 - 643: -5,-205 - 644: -5,-202 - 645: -5,-201 + 440: -5,-207 + 441: -5,-206 + 442: -5,-205 + 443: -5,-202 + 444: -5,-201 - node: color: '#9FED58DD' id: MiniTileSteelLineE decals: - 680: -3,-199 - 681: -3,-198 - 682: -3,-197 - 683: -3,-196 + 479: -3,-199 + 480: -3,-198 + 481: -3,-197 + 482: -3,-196 - node: color: '#A45ABC93' id: MiniTileSteelLineE decals: - 1150: -6,-364 - 1151: -6,-365 + 902: -6,-364 + 903: -6,-365 - node: color: '#BCBC5A93' id: MiniTileSteelLineE decals: - 1154: 7,-364 - 1155: 7,-365 + 906: 7,-364 + 907: 7,-365 - node: color: '#D381C996' id: MiniTileSteelLineE decals: - 721: -3,-55 - 882: 1,-316 - 883: 1,-317 - 884: 1,-318 - 885: 1,-319 - 886: 1,-312 - 887: 1,-311 - 895: 1,-310 - 906: 1,-306 - 907: 1,-305 - 908: 1,-304 - 909: 1,-303 - 910: 1,-302 - 911: 1,-301 - 912: 1,-300 - 913: 1,-299 + 520: -3,-55 + 634: 1,-316 + 635: 1,-317 + 636: 1,-318 + 637: 1,-319 + 638: 1,-312 + 639: 1,-311 + 647: 1,-310 + 658: 1,-306 + 659: 1,-305 + 660: 1,-304 + 661: 1,-303 + 662: 1,-302 + 663: 1,-301 + 664: 1,-300 + 665: 1,-299 - node: color: '#DE3A3A96' id: MiniTileSteelLineE decals: - 1068: 2,-359 - 1076: 2,-358 - 1094: 4,-362 - 1095: 4,-363 - 1096: 4,-364 - 1097: 4,-365 - 1098: 4,-366 - 1099: 4,-367 + 820: 2,-359 + 828: 2,-358 + 846: 4,-362 + 847: 4,-363 + 848: 4,-364 + 849: 4,-365 + 850: 4,-366 + 851: 4,-367 - node: color: '#EFB34196' id: MiniTileSteelLineE decals: - 1241: 19,-247 - 1242: 19,-248 - 1243: 19,-249 - 1244: 19,-250 - 1245: 19,-256 - 1246: 19,-257 - 1247: 19,-258 + 992: 19,-247 + 993: 19,-248 + 994: 19,-249 + 995: 19,-250 + 996: 19,-256 + 997: 19,-257 + 998: 19,-258 - node: color: '#FFFFFFFF' id: MiniTileSteelLineE decals: - 135: 5,-38 - 136: 5,-37 + 97: 5,-38 + 98: 5,-37 - node: color: '#999453FF' id: MiniTileSteelLineN decals: - 573: 5,-167 + 372: 5,-167 - node: color: '#9FED58CF' id: MiniTileSteelLineN decals: - 1345: -6,-194 - 1346: -5,-194 - 1347: -4,-194 + 1096: -6,-194 + 1097: -5,-194 + 1098: -4,-194 - node: color: '#D381C996' id: MiniTileSteelLineN decals: - 719: -5,-54 - 720: -4,-54 - 899: 2,-307 - 900: 3,-307 - 901: 4,-307 - 902: 5,-307 - 903: 6,-307 - 904: 7,-307 - 905: 8,-307 - 1206: -7,-308 - 1207: -6,-308 - 1208: -4,-308 - 1209: -3,-308 - 1210: -2,-308 + 518: -5,-54 + 519: -4,-54 + 651: 2,-307 + 652: 3,-307 + 653: 4,-307 + 654: 5,-307 + 655: 6,-307 + 656: 7,-307 + 657: 8,-307 + 957: -7,-308 + 958: -6,-308 + 959: -4,-308 + 960: -3,-308 + 961: -2,-308 - node: color: '#DE3A3A96' id: MiniTileSteelLineN decals: - 1073: -1,-357 - 1074: 0,-357 - 1075: 1,-357 - 1083: -4,-361 - 1084: -5,-361 - 1085: -6,-361 + 825: -1,-357 + 826: 0,-357 + 827: 1,-357 + 835: -4,-361 + 836: -5,-361 + 837: -6,-361 - node: color: '#EFB34196' id: MiniTileSteelLineN decals: - 1237: 16,-246 - 1238: 17,-246 - 1239: 18,-246 + 988: 16,-246 + 989: 17,-246 + 990: 18,-246 - node: color: '#999453FF' id: MiniTileSteelLineS decals: - 574: 5,-169 + 373: 5,-169 - node: color: '#9FED58DD' id: MiniTileSteelLineS decals: - 671: -3,-199 - 672: -4,-199 - 673: -5,-199 - 674: -6,-199 - 675: -7,-199 + 470: -3,-199 + 471: -4,-199 + 472: -5,-199 + 473: -6,-199 + 474: -7,-199 - node: color: '#D381C996' id: MiniTileSteelLineS decals: - 717: -5,-56 - 718: -4,-56 - 888: 8,-309 - 889: 7,-309 - 890: 6,-309 - 891: 5,-309 - 892: 4,-309 - 893: 3,-309 - 894: 2,-309 - 1200: -2,-310 - 1201: -3,-310 - 1202: -4,-310 - 1203: -5,-310 - 1204: -6,-310 - 1205: -7,-310 + 516: -5,-56 + 517: -4,-56 + 640: 8,-309 + 641: 7,-309 + 642: 6,-309 + 643: 5,-309 + 644: 4,-309 + 645: 3,-309 + 646: 2,-309 + 951: -2,-310 + 952: -3,-310 + 953: -4,-310 + 954: -5,-310 + 955: -6,-310 + 956: -7,-310 - node: color: '#DE3A3A96' id: MiniTileSteelLineS decals: - 1088: -6,-362 - 1089: -5,-362 + 840: -6,-362 + 841: -5,-362 - node: color: '#EFB34196' id: MiniTileSteelLineS decals: - 1251: 16,-262 + 1002: 16,-262 - node: color: '#5A64BC93' id: MiniTileSteelLineW decals: - 1156: 6,-367 - 1157: 6,-368 + 908: 6,-367 + 909: 6,-368 - node: color: '#5ABC5A93' id: MiniTileSteelLineW decals: - 1144: -7,-367 - 1145: -7,-368 + 896: -7,-367 + 897: -7,-368 - node: color: '#999453FF' id: MiniTileSteelLineW decals: - 575: 4,-168 + 374: 4,-168 - node: color: '#9FED58CF' id: MiniTileSteelLineW decals: - 1343: -7,-195 + 1094: -7,-195 - node: color: '#9FED58DB' id: MiniTileSteelLineW decals: - 635: -6,-207 - 636: -6,-206 - 637: -6,-205 - 638: -6,-203 - 639: -6,-202 - 640: -6,-201 + 434: -6,-207 + 435: -6,-206 + 436: -6,-205 + 437: -6,-203 + 438: -6,-202 + 439: -6,-201 - node: color: '#9FED58DD' id: MiniTileSteelLineW decals: - 663: -3,-201 - 664: -3,-202 - 665: -3,-203 - 666: -3,-204 - 667: -3,-205 - 668: -3,-206 - 669: -3,-207 - 670: -3,-208 - 676: -7,-199 - 677: -7,-198 - 678: -7,-197 - 679: -7,-196 + 462: -3,-201 + 463: -3,-202 + 464: -3,-203 + 465: -3,-204 + 466: -3,-205 + 467: -3,-206 + 468: -3,-207 + 469: -3,-208 + 475: -7,-199 + 476: -7,-198 + 477: -7,-197 + 478: -7,-196 - node: color: '#A45ABC93' id: MiniTileSteelLineW decals: - 1148: -7,-364 - 1149: -7,-365 + 900: -7,-364 + 901: -7,-365 - node: color: '#BCBC5A93' id: MiniTileSteelLineW decals: - 1152: 6,-364 - 1153: 6,-365 + 904: 6,-364 + 905: 6,-365 - node: color: '#D381C996' id: MiniTileSteelLineW decals: - 716: -6,-55 - 1048: -1,-299 - 1049: -1,-300 - 1050: -1,-301 - 1051: -1,-302 - 1052: -1,-304 - 1053: -1,-303 - 1054: -1,-305 - 1055: -1,-306 - 1056: -1,-307 - 1057: -1,-311 - 1058: -1,-312 - 1059: -1,-313 - 1060: -1,-314 - 1061: -1,-315 - 1062: -1,-316 - 1063: -1,-317 - 1064: -1,-318 - 1065: -1,-319 - 1066: -1,-320 + 515: -6,-55 + 800: -1,-299 + 801: -1,-300 + 802: -1,-301 + 803: -1,-302 + 804: -1,-304 + 805: -1,-303 + 806: -1,-305 + 807: -1,-306 + 808: -1,-307 + 809: -1,-311 + 810: -1,-312 + 811: -1,-313 + 812: -1,-314 + 813: -1,-315 + 814: -1,-316 + 815: -1,-317 + 816: -1,-318 + 817: -1,-319 + 818: -1,-320 - node: color: '#DE3A3A96' id: MiniTileSteelLineW decals: - 1069: -2,-358 - 1070: -2,-359 - 1090: -4,-363 - 1091: -4,-364 - 1092: -4,-367 - 1142: -4,-365 - 1143: -4,-366 + 821: -2,-358 + 822: -2,-359 + 842: -4,-363 + 843: -4,-364 + 844: -4,-367 + 894: -4,-365 + 895: -4,-366 - node: color: '#EFB34196' id: MiniTileSteelLineW decals: - 1222: 15,-258 - 1223: 15,-257 - 1224: 15,-256 - 1225: 14,-252 - 1226: 14,-253 - 1227: 14,-254 - 1232: 15,-250 - 1233: 15,-249 - 1234: 15,-248 - 1235: 15,-247 - 1248: 15,-260 - 1249: 15,-261 + 973: 15,-258 + 974: 15,-257 + 975: 15,-256 + 976: 14,-252 + 977: 14,-253 + 978: 14,-254 + 983: 15,-250 + 984: 15,-249 + 985: 15,-248 + 986: 15,-247 + 999: 15,-260 + 1000: 15,-261 - node: color: '#334E6DC8' id: MiniTileWhiteCornerNe @@ -1830,97 +1830,97 @@ entities: 34: 2,-2 41: 6,-5 70: -1,-10 - 863: 30,-307 - 1348: 2,-15 + 615: 30,-307 + 1099: 2,-15 - node: color: '#52B4E996' id: MiniTileWhiteCornerNe decals: - 612: 8,-172 + 411: 8,-172 - node: color: '#79150096' id: MiniTileWhiteCornerNe decals: - 1046: 0,-63 + 798: 0,-63 - node: color: '#999453FF' id: MiniTileWhiteCornerNe decals: - 571: 7,-166 + 370: 7,-166 - node: color: '#9FED58CF' id: MiniTileWhiteCornerNe decals: - 1328: -4,-195 + 1079: -4,-195 - node: color: '#A4610696' id: MiniTileWhiteCornerNe decals: - 852: 6,-285 + 604: 6,-285 - node: color: '#D381C996' id: MiniTileWhiteCornerNe decals: - 931: -3,-300 - 942: 4,-300 - 946: 7,-302 - 963: 7,-311 - 969: 8,-316 - 990: -3,-312 + 683: -3,-300 + 694: 4,-300 + 698: 7,-302 + 715: 7,-311 + 721: 8,-316 + 742: -3,-312 - node: color: '#DE3A3A96' id: MiniTileWhiteCornerNe decals: - 1135: 1,-363 + 887: 1,-363 - node: color: '#334E6DC8' id: MiniTileWhiteCornerNw decals: 33: 1,-2 69: -4,-10 - 862: 28,-307 + 614: 28,-307 - node: color: '#52B4E996' id: MiniTileWhiteCornerNw decals: - 611: 3,-172 + 410: 3,-172 - node: color: '#79150096' id: MiniTileWhiteCornerNw decals: - 1045: -1,-63 + 797: -1,-63 - node: color: '#999453FF' id: MiniTileWhiteCornerNw decals: - 556: 3,-166 + 355: 3,-166 - node: color: '#9FED58CF' id: MiniTileWhiteCornerNw decals: - 1329: -6,-195 + 1080: -6,-195 - node: color: '#A4610696' id: MiniTileWhiteCornerNw decals: - 823: -1,-277 - 851: 4,-285 + 575: -1,-277 + 603: 4,-285 - node: color: '#D381C996' id: MiniTileWhiteCornerNw decals: - 929: -4,-300 - 941: 3,-300 - 971: 3,-311 - 991: -4,-312 - 995: -6,-314 - 1047: -9,-318 - 1219: -7,-301 + 681: -4,-300 + 693: 3,-300 + 723: 3,-311 + 743: -4,-312 + 747: -6,-314 + 799: -9,-318 + 970: -7,-301 - node: color: '#DE3A3A96' id: MiniTileWhiteCornerNw decals: - 1133: -1,-363 + 885: -1,-363 - node: color: '#334E6DC8' id: MiniTileWhiteCornerSe @@ -1928,45 +1928,45 @@ entities: 3: 2,0 49: 6,-13 72: -1,-12 - 861: 30,-309 + 613: 30,-309 - node: color: '#52B4E996' id: MiniTileWhiteCornerSe decals: - 603: 8,-179 + 402: 8,-179 - node: color: '#79150096' id: MiniTileWhiteCornerSe decals: - 1043: 0,-64 + 795: 0,-64 - node: color: '#999453FF' id: MiniTileWhiteCornerSe decals: - 557: 7,-170 + 356: 7,-170 - node: color: '#9FED58DB' id: MiniTileWhiteCornerSe decals: - 631: -4,-198 + 430: -4,-198 - node: color: '#A4610696' id: MiniTileWhiteCornerSe decals: - 849: 6,-286 + 601: 6,-286 - node: color: '#D381C996' id: MiniTileWhiteCornerSe decals: - 926: -3,-306 - 952: 7,-305 - 968: 8,-317 - 982: -3,-320 + 678: -3,-306 + 704: 7,-305 + 720: 8,-317 + 734: -3,-320 - node: color: '#DE3A3A96' id: MiniTileWhiteCornerSe decals: - 1139: 1,-367 + 891: 1,-367 - node: color: '#334E6DC8' id: MiniTileWhiteCornerSw @@ -1974,57 +1974,57 @@ entities: 4: -2,0 54: 1,-13 67: -4,-12 - 860: 28,-309 + 612: 28,-309 - node: color: '#52B4E996' id: MiniTileWhiteCornerSw decals: - 604: 7,-179 - 609: 3,-177 + 403: 7,-179 + 408: 3,-177 - node: color: '#79150096' id: MiniTileWhiteCornerSw decals: - 1044: -1,-64 + 796: -1,-64 - node: color: '#999453FF' id: MiniTileWhiteCornerSw decals: - 558: 3,-170 + 357: 3,-170 - node: color: '#9FED58DB' id: MiniTileWhiteCornerSw decals: - 632: -6,-198 + 431: -6,-198 - node: color: '#A4610696' id: MiniTileWhiteCornerSw decals: - 822: -1,-283 - 850: 4,-286 + 574: -1,-283 + 602: 4,-286 - node: color: '#D381C996' id: MiniTileWhiteCornerSw decals: - 922: -7,-306 - 953: 3,-305 - 962: 3,-317 - 975: -9,-320 + 674: -7,-306 + 705: 3,-305 + 714: 3,-317 + 727: -9,-320 - node: color: '#DE3A3A96' id: MiniTileWhiteCornerSw decals: - 1140: -1,-367 + 892: -1,-367 - node: color: '#9FED5896' id: MiniTileWhiteEndN decals: - 1325: -5,-196 + 1076: -5,-196 - node: color: '#9FED5896' id: MiniTileWhiteEndS decals: - 1326: -5,-197 + 1077: -5,-197 - node: color: '#334E6DC8' id: MiniTileWhiteInnerNe @@ -2034,74 +2034,74 @@ entities: color: '#A4610696' id: MiniTileWhiteInnerNe decals: - 847: 0,-282 + 599: 0,-282 - node: color: '#D381C996' id: MiniTileWhiteInnerNe decals: - 954: 4,-302 - 970: 7,-316 + 706: 4,-302 + 722: 7,-316 - node: color: '#52B4E996' id: MiniTileWhiteInnerNw decals: - 710: 5,-206 - 1323: -8,-310 + 509: 5,-206 + 1074: -8,-310 - node: color: '#A4610696' id: MiniTileWhiteInnerNw decals: - 848: 7,-282 + 600: 7,-282 - node: color: '#D381C996' id: MiniTileWhiteInnerNw decals: - 930: -4,-301 - 994: -4,-314 - 1000: -6,-318 - 1318: -7,-192 + 682: -4,-301 + 746: -4,-314 + 752: -6,-318 + 1069: -7,-192 - node: color: '#52B4E996' id: MiniTileWhiteInnerSe decals: - 626: 1,-169 + 425: 1,-169 - node: color: '#A4610696' id: MiniTileWhiteInnerSe decals: - 846: 0,-278 + 598: 0,-278 - node: color: '#DE3A3A96' id: MiniTileWhiteInnerSe decals: - 1126: -2.241021,-361.4977 - 1127: -2.4992852,-361.7559 - 1128: -2.7401419,-362.00235 + 878: -2.241021,-361.4977 + 879: -2.4992852,-361.7559 + 880: -2.7401419,-362.00235 - node: color: '#52B4E996' id: MiniTileWhiteInnerSw decals: - 610: 7,-177 - 711: 5,-191 - 1324: -8,-308 + 409: 7,-177 + 510: 5,-191 + 1075: -8,-308 - node: color: '#A4610696' id: MiniTileWhiteInnerSw decals: - 845: 7,-278 + 597: 7,-278 - node: color: '#D381C996' id: MiniTileWhiteInnerSw decals: - 1319: -7,-190 + 1070: -7,-190 - node: color: '#DE3A3A96' id: MiniTileWhiteInnerSw decals: - 1122: 2.7602181,-362.00235 - 1123: 2.5136933,-361.7559 - 1124: 2.2476032,-361.486 - 1125: 2.0089047,-361.2591 + 874: 2.7602181,-362.00235 + 875: 2.5136933,-361.7559 + 876: 2.2476032,-361.486 + 877: 2.0089047,-361.2591 - node: color: '#334E6DC8' id: MiniTileWhiteLineE @@ -2118,104 +2118,104 @@ entities: 47: 6,-11 48: 6,-12 71: -1,-11 - 855: 26,-306 - 856: 26,-307 - 857: 26,-308 - 858: 26,-309 - 859: 26,-310 - 867: 30,-308 - 918: 12,-308 - 919: 12,-307 - 920: 12,-309 - 1349: 2,-16 - 1350: 2,-17 - 1351: 2,-18 + 607: 26,-306 + 608: 26,-307 + 609: 26,-308 + 610: 26,-309 + 611: 26,-310 + 619: 30,-308 + 670: 12,-308 + 671: 12,-307 + 672: 12,-309 + 1100: 2,-16 + 1101: 2,-17 + 1102: 2,-18 - node: color: '#52B4E996' id: MiniTileWhiteLineE decals: - 581: -2,-178 - 582: -2,-177 - 583: -2,-176 - 584: -2,-175 - 585: -2,-174 - 586: -2,-173 - 597: 8,-173 - 598: 8,-174 - 599: 8,-175 - 600: 8,-176 - 601: 8,-177 - 602: 8,-178 - 617: 1,-178 - 618: 1,-177 - 619: 1,-176 - 620: 1,-175 - 621: 1,-174 - 622: 1,-173 - 623: 1,-172 - 624: 1,-171 - 625: 1,-170 - 722: 1,-179 - 723: 1,-180 + 380: -2,-178 + 381: -2,-177 + 382: -2,-176 + 383: -2,-175 + 384: -2,-174 + 385: -2,-173 + 396: 8,-173 + 397: 8,-174 + 398: 8,-175 + 399: 8,-176 + 400: 8,-177 + 401: 8,-178 + 416: 1,-178 + 417: 1,-177 + 418: 1,-176 + 419: 1,-175 + 420: 1,-174 + 421: 1,-173 + 422: 1,-172 + 423: 1,-171 + 424: 1,-170 + 521: 1,-179 + 522: 1,-180 - node: color: '#999453FF' id: MiniTileWhiteLineE decals: - 559: 7,-169 - 560: 7,-168 - 561: 7,-167 + 358: 7,-169 + 359: 7,-168 + 360: 7,-167 - node: color: '#9FED58CF' id: MiniTileWhiteLineE decals: - 1331: -4,-196 + 1082: -4,-196 - node: color: '#9FED58DB' id: MiniTileWhiteLineE decals: - 633: -4,-197 + 432: -4,-197 - node: color: '#A4610696' id: MiniTileWhiteLineE decals: - 842: 0,-281 - 843: 0,-280 - 844: 0,-279 + 594: 0,-281 + 595: 0,-280 + 596: 0,-279 - node: color: '#D381C996' id: MiniTileWhiteLineE decals: - 932: -3,-301 - 933: -3,-302 - 934: -3,-303 - 935: -3,-304 - 936: -3,-305 - 943: 4,-301 - 947: 7,-303 - 948: 7,-304 - 964: 7,-312 - 965: 7,-313 - 966: 7,-314 - 967: 7,-315 - 983: -3,-319 - 984: -3,-318 - 985: -3,-317 - 986: -3,-316 - 987: -3,-315 - 988: -3,-314 - 989: -3,-313 + 684: -3,-301 + 685: -3,-302 + 686: -3,-303 + 687: -3,-304 + 688: -3,-305 + 695: 4,-301 + 699: 7,-303 + 700: 7,-304 + 716: 7,-312 + 717: 7,-313 + 718: 7,-314 + 719: 7,-315 + 735: -3,-319 + 736: -3,-318 + 737: -3,-317 + 738: -3,-316 + 739: -3,-315 + 740: -3,-314 + 741: -3,-313 - node: color: '#DE3A3A96' id: MiniTileWhiteLineE decals: - 1117: -3,-363 - 1118: -3,-364 - 1119: -3,-365 - 1120: -3,-366 - 1121: -3,-367 - 1136: 1,-364 - 1137: 1,-365 - 1138: 1,-366 + 869: -3,-363 + 870: -3,-364 + 871: -3,-365 + 872: -3,-366 + 873: -3,-367 + 888: 1,-364 + 889: 1,-365 + 890: 1,-366 - node: color: '#334E6DC8' id: MiniTileWhiteLineN @@ -2226,74 +2226,74 @@ entities: 75: -3,-10 76: -2,-10 80: 1,-15 - 866: 29,-307 + 618: 29,-307 - node: color: '#52B4E996' id: MiniTileWhiteLineN decals: - 613: 4,-172 - 614: 5,-172 - 615: 6,-172 - 616: 7,-172 - 703: 4,-206 - 704: 3,-206 - 705: 1,-206 - 706: 2,-206 - 707: 0,-206 - 708: -1,-206 - 1322: -9,-310 + 412: 4,-172 + 413: 5,-172 + 414: 6,-172 + 415: 7,-172 + 502: 4,-206 + 503: 3,-206 + 504: 1,-206 + 505: 2,-206 + 506: 0,-206 + 507: -1,-206 + 1073: -9,-310 - node: color: '#999453FF' id: MiniTileWhiteLineN decals: - 568: 4,-166 - 569: 5,-166 - 570: 6,-166 + 367: 4,-166 + 368: 5,-166 + 369: 6,-166 - node: color: '#9FED58CF' id: MiniTileWhiteLineN decals: - 1330: -5,-195 + 1081: -5,-195 - node: color: '#A4610696' id: MiniTileWhiteLineN decals: - 808: 0,-277 - 809: 1,-277 - 810: 2,-277 - 811: 3,-277 - 812: 4,-277 - 813: 5,-277 - 814: 6,-277 - 815: 7,-277 - 816: 8,-277 - 824: 1,-282 - 825: 2,-282 - 826: 3,-282 - 827: 4,-282 - 828: 5,-282 - 829: 6,-282 - 854: 5,-285 + 560: 0,-277 + 561: 1,-277 + 562: 2,-277 + 563: 3,-277 + 564: 4,-277 + 565: 5,-277 + 566: 6,-277 + 567: 7,-277 + 568: 8,-277 + 576: 1,-282 + 577: 2,-282 + 578: 3,-282 + 579: 4,-282 + 580: 5,-282 + 581: 6,-282 + 606: 5,-285 - node: color: '#D381C996' id: MiniTileWhiteLineN decals: - 944: 5,-302 - 945: 6,-302 - 955: 4,-311 - 956: 5,-311 - 957: 6,-311 - 976: -8,-318 - 993: -5,-314 - 999: -7,-318 - 1217: -5,-301 - 1218: -6,-301 - 1315: -8,-192 + 696: 5,-302 + 697: 6,-302 + 707: 4,-311 + 708: 5,-311 + 709: 6,-311 + 728: -8,-318 + 745: -5,-314 + 751: -7,-318 + 968: -5,-301 + 969: -6,-301 + 1066: -8,-192 - node: color: '#DE3A3A96' id: MiniTileWhiteLineN decals: - 1134: 0,-363 + 886: 0,-363 - node: color: '#334E6DC8' id: MiniTileWhiteLineS @@ -2304,79 +2304,79 @@ entities: 53: 2,-13 73: -2,-12 74: -3,-12 - 865: 29,-309 + 617: 29,-309 - node: color: '#52B4E996' id: MiniTileWhiteLineS decals: - 606: 6,-177 - 607: 5,-177 - 608: 4,-177 - 627: 2,-169 - 697: 4,-191 - 698: 3,-191 - 699: 2,-191 - 700: 1,-191 - 701: 0,-191 - 702: -1,-191 - 1320: -9,-308 + 405: 6,-177 + 406: 5,-177 + 407: 4,-177 + 426: 2,-169 + 496: 4,-191 + 497: 3,-191 + 498: 2,-191 + 499: 1,-191 + 500: 0,-191 + 501: -1,-191 + 1071: -9,-308 - node: color: '#999453FF' id: MiniTileWhiteLineS decals: - 565: 4,-170 - 566: 5,-170 - 567: 6,-170 + 364: 4,-170 + 365: 5,-170 + 366: 6,-170 - node: color: '#9FED58DB' id: MiniTileWhiteLineS decals: - 630: -5,-198 + 429: -5,-198 - node: color: '#A4610696' id: MiniTileWhiteLineS decals: - 799: 0,-283 - 800: 1,-283 - 801: 2,-283 - 802: 3,-283 - 803: 4,-283 - 804: 5,-283 - 805: 6,-283 - 806: 7,-283 - 807: 8,-283 - 830: 1,-278 - 831: 2,-278 - 832: 3,-278 - 833: 4,-278 - 834: 5,-278 - 835: 6,-278 - 853: 5,-286 + 551: 0,-283 + 552: 1,-283 + 553: 2,-283 + 554: 3,-283 + 555: 4,-283 + 556: 5,-283 + 557: 6,-283 + 558: 7,-283 + 559: 8,-283 + 582: 1,-278 + 583: 2,-278 + 584: 3,-278 + 585: 4,-278 + 586: 5,-278 + 587: 6,-278 + 605: 5,-286 - node: color: '#D381C996' id: MiniTileWhiteLineS decals: - 923: -6,-306 - 924: -5,-306 - 925: -4,-306 - 949: 4,-305 - 950: 5,-305 - 951: 6,-305 - 958: 4,-317 - 959: 5,-317 - 960: 6,-317 - 961: 7,-317 - 977: -8,-320 - 978: -7,-320 - 979: -6,-320 - 980: -5,-320 - 981: -4,-320 - 1316: -8,-190 + 675: -6,-306 + 676: -5,-306 + 677: -4,-306 + 701: 4,-305 + 702: 5,-305 + 703: 6,-305 + 710: 4,-317 + 711: 5,-317 + 712: 6,-317 + 713: 7,-317 + 729: -8,-320 + 730: -7,-320 + 731: -6,-320 + 732: -5,-320 + 733: -4,-320 + 1067: -8,-190 - node: color: '#DE3A3A96' id: MiniTileWhiteLineS decals: - 1141: 0,-367 + 893: 0,-367 - node: color: '#334E6DC8' id: MiniTileWhiteLineW @@ -2390,173 +2390,173 @@ entities: 29: 1,-4 66: 1,-12 68: -4,-11 - 864: 28,-308 + 616: 28,-308 - node: color: '#52B4E996' id: MiniTileWhiteLineW decals: - 587: -5,-178 - 588: -5,-177 - 589: -5,-176 - 590: -5,-175 - 591: -5,-174 - 592: -5,-173 - 593: 3,-176 - 594: 3,-175 - 595: 3,-174 - 596: 3,-173 - 605: 7,-178 - 684: 5,-204 - 685: 5,-203 - 686: 5,-202 - 687: 5,-201 - 688: 5,-200 - 689: 5,-199 - 690: 5,-198 - 691: 5,-197 - 692: 5,-196 - 693: 5,-195 - 694: 5,-194 - 695: 5,-193 - 696: 5,-192 - 709: 5,-205 - 1321: -8,-309 + 386: -5,-178 + 387: -5,-177 + 388: -5,-176 + 389: -5,-175 + 390: -5,-174 + 391: -5,-173 + 392: 3,-176 + 393: 3,-175 + 394: 3,-174 + 395: 3,-173 + 404: 7,-178 + 483: 5,-204 + 484: 5,-203 + 485: 5,-202 + 486: 5,-201 + 487: 5,-200 + 488: 5,-199 + 489: 5,-198 + 490: 5,-197 + 491: 5,-196 + 492: 5,-195 + 493: 5,-194 + 494: 5,-193 + 495: 5,-192 + 508: 5,-205 + 1072: -8,-309 - node: color: '#999453FF' id: MiniTileWhiteLineW decals: - 562: 3,-169 - 563: 3,-168 - 564: 3,-167 + 361: 3,-169 + 362: 3,-168 + 363: 3,-167 - node: color: '#9FED58CF' id: MiniTileWhiteLineW decals: - 1332: -6,-196 + 1083: -6,-196 - node: color: '#9FED58DB' id: MiniTileWhiteLineW decals: - 634: -6,-197 + 433: -6,-197 - node: color: '#A4610696' id: MiniTileWhiteLineW decals: - 817: -1,-278 - 818: -1,-279 - 819: -1,-280 - 820: -1,-281 - 821: -1,-282 - 839: 7,-281 - 840: 7,-280 - 841: 7,-279 + 569: -1,-278 + 570: -1,-279 + 571: -1,-280 + 572: -1,-281 + 573: -1,-282 + 591: 7,-281 + 592: 7,-280 + 593: 7,-279 - node: color: '#D381C996' id: MiniTileWhiteLineW decals: - 927: -7,-305 - 928: -7,-304 - 937: 3,-304 - 938: 3,-303 - 939: 3,-302 - 940: 3,-301 - 972: 3,-312 - 973: 3,-316 - 974: -9,-319 - 992: -4,-313 - 996: -6,-315 - 997: -6,-316 - 998: -6,-317 - 1220: -7,-302 - 1221: -7,-303 - 1317: -7,-191 + 679: -7,-305 + 680: -7,-304 + 689: 3,-304 + 690: 3,-303 + 691: 3,-302 + 692: 3,-301 + 724: 3,-312 + 725: 3,-316 + 726: -9,-319 + 744: -4,-313 + 748: -6,-315 + 749: -6,-316 + 750: -6,-317 + 971: -7,-302 + 972: -7,-303 + 1068: -7,-191 - node: color: '#DE3A3A96' id: MiniTileWhiteLineW decals: - 1112: 3,-367 - 1113: 3,-366 - 1114: 3,-365 - 1115: 3,-364 - 1116: 3,-363 - 1130: -1,-366 - 1131: -1,-365 - 1132: -1,-364 + 864: 3,-367 + 865: 3,-366 + 866: 3,-365 + 867: 3,-364 + 868: 3,-363 + 882: -1,-366 + 883: -1,-365 + 884: -1,-364 - node: color: '#3EB38896' id: QuarterTileOverlayGreyscale180 decals: - 1456: -15,-266 - 1457: -14,-266 - 1458: -13,-266 - 1459: -12,-266 + 1207: -15,-266 + 1208: -14,-266 + 1209: -13,-266 + 1210: -12,-266 - node: color: '#A4610696' id: QuarterTileOverlayGreyscale180 decals: - 1480: 1,-275 - 1481: 1,-274 - 1482: 1,-273 - 1483: 1,-272 + 1231: 1,-275 + 1232: 1,-274 + 1233: 1,-273 + 1234: 1,-272 - node: color: '#3EB38896' id: QuarterTileOverlayGreyscale90 decals: - 1460: -15,-264 - 1461: -14,-264 - 1462: -13,-264 - 1463: -12,-264 + 1211: -15,-264 + 1212: -14,-264 + 1213: -13,-264 + 1214: -12,-264 - node: color: '#FFFFFFFF' id: Rock02 decals: - 174: 3.4198463,-40.51108 + 109: 3.4198463,-40.51108 - node: angle: -1.5707963267948966 rad color: '#FFFFFFFF' id: StandClear decals: - 105: 6,-37 - 106: 6,-44 - 1042: -3,-114 + 83: 6,-37 + 84: 6,-44 + 794: -3,-114 - node: color: '#FFFFFFFF' id: StandClear decals: - 547: 0,-136 - 548: 0,-126 - 549: 0,-109 - 550: 0,-99 - 551: 0,-82 - 552: 0,-45 - 554: 0,-18 - 1187: 0,-163 - 1188: 0,-180 - 1189: 0,-190 - 1190: 0,-207 - 1191: 0,-244 - 1192: 0,-261 - 1194: 0,-288 - 1469: 0,-28 - 1479: 0,-271 + 347: 0,-136 + 348: 0,-126 + 349: 0,-109 + 350: 0,-99 + 351: 0,-82 + 352: 0,-45 + 353: 0,-18 + 939: 0,-163 + 940: 0,-180 + 941: 0,-190 + 942: 0,-207 + 943: 0,-244 + 944: 0,-261 + 945: 0,-288 + 1220: 0,-28 + 1230: 0,-271 - node: angle: 1.5707963267948966 rad color: '#FFFFFFFF' id: StandClear decals: - 107: -6,-32 - 108: -6,-30 - 1261: -2,-255 + 85: -6,-32 + 86: -6,-30 + 1012: -2,-255 - node: color: '#D381C996' id: WarnCornerGreyscaleNE decals: - 1007: -8,-314 + 759: -8,-314 - node: color: '#DE3A3A96' id: WarnCornerGreyscaleNE decals: - 1102: -4,-356 + 854: -4,-356 - node: color: '#334E6DC8' id: WarnCornerGreyscaleNW @@ -2566,14 +2566,14 @@ entities: color: '#D381C996' id: WarnCornerGreyscaleNW decals: - 1008: -10,-314 + 760: -10,-314 - node: color: '#DE3A3A96' id: WarnCornerGreyscaleNW decals: - 1100: -6,-357 - 1101: -5,-356 - 1103: -7,-358 + 852: -6,-357 + 853: -5,-356 + 855: -7,-358 - node: color: '#334E6DC8' id: WarnCornerGreyscaleSE @@ -2583,12 +2583,12 @@ entities: color: '#D381C996' id: WarnCornerGreyscaleSE decals: - 1005: -8,-316 + 757: -8,-316 - node: color: '#DE3A3A96' id: WarnCornerGreyscaleSE decals: - 1107: -4,-359 + 859: -4,-359 - node: color: '#334E6DC8' id: WarnCornerGreyscaleSW @@ -2598,61 +2598,61 @@ entities: color: '#D381C996' id: WarnCornerGreyscaleSW decals: - 1006: -10,-316 + 758: -10,-316 - node: color: '#DE3A3A96' id: WarnCornerGreyscaleSW decals: - 1104: -7,-359 + 856: -7,-359 - node: color: '#FFFFFFFF' id: WarnCornerNE decals: - 875: 4,-313 - 1371: 7,-337 + 627: 4,-313 + 1122: 7,-337 - node: color: '#FFFFFFFF' id: WarnCornerNW decals: - 1370: 5,-337 + 1121: 5,-337 - node: color: '#FFFFFFFF' id: WarnCornerSE decals: - 877: 4,-315 - 1434: 7,-343 + 629: 4,-315 + 1185: 7,-343 - node: color: '#FFFFFFFF' id: WarnCornerSW decals: - 1432: 5,-343 + 1183: 5,-343 - node: color: '#9FED5896' id: WarnCornerSmallGreyscaleNE decals: - 872: 20,-310 + 624: 20,-310 - node: color: '#9FED5896' id: WarnCornerSmallGreyscaleNW decals: - 1333: 24,-310 + 1084: 24,-310 - node: color: '#DE3A3A96' id: WarnCornerSmallGreyscaleNW decals: 15: -3,-4 - 1110: -6,-358 - 1111: -5,-357 + 862: -6,-358 + 863: -5,-357 - node: color: '#9FED5896' id: WarnCornerSmallGreyscaleSE decals: - 871: 20,-306 + 623: 20,-306 - node: color: '#9FED5896' id: WarnCornerSmallGreyscaleSW decals: - 873: 24,-306 + 625: 24,-306 - node: color: '#DE3A3A96' id: WarnCornerSmallGreyscaleSW @@ -2662,12 +2662,12 @@ entities: color: '#FFFFFFFF' id: WarnCornerSmallSE decals: - 1373: 5,-337 + 1124: 5,-337 - node: color: '#FFFFFFFF' id: WarnCornerSmallSW decals: - 1372: 7,-337 + 1123: 7,-337 - node: color: '#DE3A3A96' id: WarnFullGreyscale @@ -2677,32 +2677,32 @@ entities: color: '#FFFFFFFF' id: WarnLineE decals: - 878: 4,-314 - 879: 1,-315 - 880: 1,-314 - 881: 1,-313 - 1365: 7,-338 - 1366: 5,-339 - 1367: 5,-338 - 1375: 7,-339 - 1435: 8,-341 + 630: 4,-314 + 631: 1,-315 + 632: 1,-314 + 633: 1,-313 + 1116: 7,-338 + 1117: 5,-339 + 1118: 5,-338 + 1126: 7,-339 + 1186: 8,-341 - node: color: '#9FED5896' id: WarnLineGreyscaleE decals: - 869: 20,-309 - 870: 20,-307 + 621: 20,-309 + 622: 20,-307 - node: color: '#D381C996' id: WarnLineGreyscaleE decals: - 1003: -8,-315 + 755: -8,-315 - node: color: '#DE3A3A96' id: WarnLineGreyscaleE decals: - 1108: -4,-358 - 1109: -4,-357 + 860: -4,-358 + 861: -4,-357 - node: color: '#334E6DC8' id: WarnLineGreyscaleN @@ -2716,7 +2716,7 @@ entities: color: '#D381C996' id: WarnLineGreyscaleN decals: - 1004: -9,-314 + 756: -9,-314 - node: color: '#DE3A3A96' id: WarnLineGreyscaleN @@ -2730,10 +2730,10 @@ entities: color: '#EFB34196' id: WarnLineGreyscaleN decals: - 1253: 13,-257 - 1254: 12,-257 - 1255: 11,-257 - 1256: 10,-257 + 1004: 13,-257 + 1005: 12,-257 + 1006: 11,-257 + 1007: 10,-257 - node: color: '#334E6DC8' id: WarnLineGreyscaleS @@ -2747,7 +2747,7 @@ entities: color: '#D381C996' id: WarnLineGreyscaleS decals: - 1001: -9,-316 + 753: -9,-316 - node: color: '#DE3A3A96' id: WarnLineGreyscaleS @@ -2757,16 +2757,16 @@ entities: 17: -3,-4 18: -2,-4 19: -1,-4 - 1105: -6,-359 - 1106: -5,-359 + 857: -6,-359 + 858: -5,-359 - node: color: '#EFB34196' id: WarnLineGreyscaleS decals: - 1257: 10,-249 - 1258: 11,-249 - 1259: 12,-249 - 1260: 13,-249 + 1008: 10,-249 + 1009: 11,-249 + 1010: 12,-249 + 1011: 13,-249 - node: color: '#334E6DC8' id: WarnLineGreyscaleW @@ -2778,13 +2778,13 @@ entities: color: '#9FED5896' id: WarnLineGreyscaleW decals: - 868: 24,-307 - 1327: 24,-309 + 620: 24,-307 + 1078: 24,-309 - node: color: '#D381C996' id: WarnLineGreyscaleW decals: - 1002: -10,-315 + 754: -10,-315 - node: color: '#DE3A3A96' id: WarnLineGreyscaleW @@ -2794,207 +2794,207 @@ entities: color: '#FFFFFFFF' id: WarnLineN decals: - 876: 3,-315 - 1368: 6,-337 - 1433: 6,-343 + 628: 3,-315 + 1119: 6,-337 + 1184: 6,-343 - node: color: '#FFFFFFFF' id: WarnLineS decals: - 1362: 5,-339 - 1363: 5,-338 - 1364: 7,-338 - 1374: 7,-339 + 1113: 5,-339 + 1114: 5,-338 + 1115: 7,-338 + 1125: 7,-339 - node: color: '#FFFFFFFF' id: WarnLineW decals: - 874: 3,-313 - 1369: 6,-337 + 626: 3,-313 + 1120: 6,-337 - node: color: '#FFFFFFFF' id: WoodTrimThinCornerNe decals: - 202: -1,-59 - 217: -1,-67 + 137: -1,-59 + 152: -1,-67 - node: color: '#FFFFFFFF' id: WoodTrimThinCornerNw decals: - 198: -6,-59 - 235: -2,-62 + 133: -6,-59 + 170: -2,-62 - node: color: '#FFFFFFFF' id: WoodTrimThinCornerSe decals: - 184: -1,-68 - 230: -1,-60 + 119: -1,-68 + 165: -1,-60 - node: color: '#FFFFFFFF' id: WoodTrimThinCornerSw decals: - 189: -6,-68 - 232: -2,-65 + 124: -6,-68 + 167: -2,-65 - node: color: '#FFFFFFFF' id: WoodTrimThinInnerNe decals: 79: -5,1 - 220: -4,-67 - 249: -2,-65 - 252: -1,-64 - 256: 0,-63 - 259: 0,-58 + 155: -4,-67 + 184: -2,-65 + 187: -1,-64 + 191: 0,-63 + 194: 0,-58 - node: color: '#FFFFFFFF' id: WoodTrimThinInnerNw decals: - 213: 1,-70 - 237: 0,-62 - 250: 1,-65 - 251: 0,-64 - 257: -1,-63 + 148: 1,-70 + 172: 0,-62 + 185: 1,-65 + 186: 0,-64 + 192: -1,-63 - node: color: '#FFFFFFFF' id: WoodTrimThinInnerSe decals: - 227: -4,-60 - 248: -2,-62 - 254: -1,-63 - 255: 0,-64 - 260: 0,-69 + 162: -4,-60 + 183: -2,-62 + 189: -1,-63 + 190: 0,-64 + 195: 0,-69 - node: color: '#FFFFFFFF' id: WoodTrimThinInnerSw decals: - 206: 1,-57 - 238: 0,-65 - 247: 1,-62 - 253: 0,-63 - 258: -1,-64 + 141: 1,-57 + 173: 0,-65 + 182: 1,-62 + 188: 0,-63 + 193: -1,-64 - node: color: '#FFFFFFFF' id: WoodTrimThinLineE decals: 77: -5,2 - 221: -4,-66 - 222: -4,-65 - 223: -4,-64 - 224: -4,-63 - 225: -4,-62 - 226: -4,-61 - 241: -2,-64 - 242: -2,-63 - 459: -7,-111 - 460: -7,-110 - 461: -7,-109 - 462: -7,-108 - 466: 2,-122 - 467: 2,-121 - 468: 2,-120 - 496: -4,-145 - 497: -4,-146 - 498: -4,-147 - 499: -4,-149 - 500: -4,-148 - 501: -4,-143 - 505: -4,-139 + 156: -4,-66 + 157: -4,-65 + 158: -4,-64 + 159: -4,-63 + 160: -4,-62 + 161: -4,-61 + 176: -2,-64 + 177: -2,-63 + 313: -7,-111 + 314: -7,-110 + 315: -7,-109 + 316: -7,-108 + 320: 2,-122 + 321: 2,-121 + 322: 2,-120 + 329: -4,-145 + 330: -4,-146 + 331: -4,-147 + 332: -4,-149 + 333: -4,-148 + 334: -4,-143 + 335: -4,-139 - node: color: '#FFFFFFFF' id: WoodTrimThinLineN decals: 78: -4,1 - 199: -5,-59 - 200: -4,-59 - 201: -2,-59 - 210: -2,-70 - 211: -1,-70 - 212: 0,-70 - 218: -2,-67 - 219: -3,-67 - 236: -1,-62 - 239: -1,-65 - 240: 0,-65 - 423: -9,-125 - 424: -7,-125 - 425: -8,-125 - 426: -9,-122 - 427: -8,-122 - 428: -7,-122 - 432: -9,-116 - 433: -8,-116 - 434: -7,-116 - 435: -9,-113 - 436: -8,-113 - 437: -7,-113 + 134: -5,-59 + 135: -4,-59 + 136: -2,-59 + 145: -2,-70 + 146: -1,-70 + 147: 0,-70 + 153: -2,-67 + 154: -3,-67 + 171: -1,-62 + 174: -1,-65 + 175: 0,-65 + 280: -9,-125 + 281: -7,-125 + 282: -8,-125 + 283: -9,-122 + 284: -8,-122 + 285: -7,-122 + 286: -9,-116 + 287: -8,-116 + 288: -7,-116 + 289: -9,-113 + 290: -8,-113 + 291: -7,-113 - node: color: '#FFFFFFFF' id: WoodTrimThinLineS decals: - 185: -2,-68 - 186: -4,-68 - 187: -3,-68 - 188: -5,-68 - 207: 0,-57 - 208: -1,-57 - 209: -2,-57 - 228: -3,-60 - 229: -2,-60 - 231: -1,-65 - 243: -1,-62 - 244: 0,-62 - 407: -9,-114 - 408: -8,-114 - 409: -7,-114 - 410: -9,-117 - 411: -8,-117 - 412: -7,-117 - 417: -9,-123 - 418: -8,-123 - 419: -7,-123 - 420: -9,-126 - 421: -8,-126 - 422: -7,-126 + 120: -2,-68 + 121: -4,-68 + 122: -3,-68 + 123: -5,-68 + 142: 0,-57 + 143: -1,-57 + 144: -2,-57 + 163: -3,-60 + 164: -2,-60 + 166: -1,-65 + 178: -1,-62 + 179: 0,-62 + 268: -9,-114 + 269: -8,-114 + 270: -7,-114 + 271: -9,-117 + 272: -8,-117 + 273: -7,-117 + 274: -9,-123 + 275: -8,-123 + 276: -7,-123 + 277: -9,-126 + 278: -8,-126 + 279: -7,-126 - node: color: '#FFFFFFFF' id: WoodTrimThinLineW decals: - 190: -6,-67 - 191: -6,-66 - 192: -6,-65 - 193: -6,-64 - 194: -6,-63 - 195: -6,-62 - 196: -6,-61 - 197: -6,-60 - 203: 1,-60 - 204: 1,-59 - 205: 1,-58 - 214: 1,-69 - 215: 1,-68 - 216: 1,-67 - 233: -2,-64 - 234: -2,-63 - 245: 1,-63 - 246: 1,-64 - 455: -9,-111 - 456: -9,-110 - 457: -9,-109 - 458: -9,-108 - 463: -2,-122 - 464: -2,-121 - 465: -2,-120 - 506: -6,-139 - 507: -6,-140 - 508: -6,-141 - 509: -6,-142 - 510: -6,-143 - 511: -6,-144 - 512: -6,-145 - 513: -6,-146 - 514: -6,-147 - 515: -6,-148 - 516: -6,-149 + 125: -6,-67 + 126: -6,-66 + 127: -6,-65 + 128: -6,-64 + 129: -6,-63 + 130: -6,-62 + 131: -6,-61 + 132: -6,-60 + 138: 1,-60 + 139: 1,-59 + 140: 1,-58 + 149: 1,-69 + 150: 1,-68 + 151: 1,-67 + 168: -2,-64 + 169: -2,-63 + 180: 1,-63 + 181: 1,-64 + 309: -9,-111 + 310: -9,-110 + 311: -9,-109 + 312: -9,-108 + 317: -2,-122 + 318: -2,-121 + 319: -2,-120 + 336: -6,-139 + 337: -6,-140 + 338: -6,-141 + 339: -6,-142 + 340: -6,-143 + 341: -6,-144 + 342: -6,-145 + 343: -6,-146 + 344: -6,-147 + 345: -6,-148 + 346: -6,-149 - node: color: '#DE3A3AFF' id: beepsky @@ -3009,12 +3009,12 @@ entities: color: '#FFFFFFFF' id: guy decals: - 1041: 4.9812827,-108.55144 + 793: 4.9812827,-108.55144 - node: color: '#FFFFFFFF' id: skull decals: - 1293: -7.134697,-145.81009 + 1044: -7.134697,-145.81009 - type: GridAtmosphere version: 2 data: @@ -5144,7 +5144,7 @@ entities: 1: 44680 -7,-63: 1: 61184 - 5: 12 + 3: 12 -7,-62: 1: 64443 -7,-61: @@ -5152,14 +5152,14 @@ entities: -7,-60: 1: 4369 -7,-64: - 3: 12 - 4: 3072 + 4: 12 + 5: 3072 -6,-64: - 3: 1 - 4: 256 + 4: 1 + 5: 256 1: 17476 -6,-63: - 5: 1 + 3: 1 1: 5956 -6,-62: 1: 4096 @@ -5169,7 +5169,7 @@ entities: 0: 52428 -6,-65: 1: 17476 - 3: 257 + 4: 257 -6,-60: 1: 1 -6,-59: @@ -5188,16 +5188,16 @@ entities: -7,-68: 0: 60928 -7,-66: - 3: 3084 + 4: 3084 -7,-65: - 3: 3084 + 4: 3084 -6,-68: 0: 65024 -6,-67: 1: 18176 0: 14 -6,-66: - 3: 257 + 4: 257 1: 17476 -5,-68: 0: 30464 @@ -5283,6 +5283,21 @@ entities: - 0 - 0 - 0 + - volume: 2500 + temperature: 293.15 + moles: + - 0 + - 6666.982 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 - volume: 2500 temperature: 293.15 moles: @@ -5313,21 +5328,6 @@ entities: - 0 - 0 - 0 - - volume: 2500 - temperature: 293.15 - moles: - - 0 - - 6666.982 - - 0 - - 0 - - 0 - - 0 - - 0 - - 0 - - 0 - - 0 - - 0 - - 0 chunkSize: 4 - type: GasTileOverlay - type: RadiationGridResistance @@ -11055,21 +11055,6 @@ entities: - type: Transform pos: -23.5,-257.5 parent: 2 - - uid: 17035 - components: - - type: Transform - pos: -23.5,-259.5 - parent: 2 - - uid: 17036 - components: - - type: Transform - pos: -24.5,-259.5 - parent: 2 - - uid: 17037 - components: - - type: Transform - pos: -25.5,-259.5 - parent: 2 - uid: 17038 components: - type: Transform @@ -11216,6 +11201,23 @@ entities: - type: Transform pos: -23.5,-253.5 parent: 2 +- proto: AtmosFixPlasmaMarker + entities: + - uid: 3102 + components: + - type: Transform + pos: -25.5,-259.5 + parent: 2 + - uid: 5223 + components: + - type: Transform + pos: -24.5,-259.5 + parent: 2 + - uid: 17035 + components: + - type: Transform + pos: -23.5,-259.5 + parent: 2 - proto: Autolathe entities: - uid: 614 @@ -28358,6 +28360,131 @@ entities: - type: Transform pos: -0.5,-248.5 parent: 2 + - uid: 17036 + components: + - type: Transform + pos: -14.5,-247.5 + parent: 2 + - uid: 17037 + components: + - type: Transform + pos: -13.5,-247.5 + parent: 2 + - uid: 17392 + components: + - type: Transform + pos: -13.5,-248.5 + parent: 2 + - uid: 17393 + components: + - type: Transform + pos: -12.5,-248.5 + parent: 2 + - uid: 17394 + components: + - type: Transform + pos: -11.5,-248.5 + parent: 2 + - uid: 17395 + components: + - type: Transform + pos: -10.5,-248.5 + parent: 2 + - uid: 17396 + components: + - type: Transform + pos: -9.5,-248.5 + parent: 2 + - uid: 17397 + components: + - type: Transform + pos: -8.5,-248.5 + parent: 2 + - uid: 17398 + components: + - type: Transform + pos: -7.5,-248.5 + parent: 2 + - uid: 17399 + components: + - type: Transform + pos: -5.5,-248.5 + parent: 2 + - uid: 17400 + components: + - type: Transform + pos: -3.5,-248.5 + parent: 2 + - uid: 17401 + components: + - type: Transform + pos: -4.5,-248.5 + parent: 2 + - uid: 17402 + components: + - type: Transform + pos: -1.5,-248.5 + parent: 2 + - uid: 17403 + components: + - type: Transform + pos: -6.5,-248.5 + parent: 2 + - uid: 17404 + components: + - type: Transform + pos: -2.5,-248.5 + parent: 2 + - uid: 17407 + components: + - type: Transform + pos: -13.5,-259.5 + parent: 2 + - uid: 17408 + components: + - type: Transform + pos: -13.5,-258.5 + parent: 2 + - uid: 17409 + components: + - type: Transform + pos: -13.5,-257.5 + parent: 2 + - uid: 17410 + components: + - type: Transform + pos: -13.5,-256.5 + parent: 2 + - uid: 17411 + components: + - type: Transform + pos: -13.5,-255.5 + parent: 2 + - uid: 17412 + components: + - type: Transform + pos: -13.5,-254.5 + parent: 2 + - uid: 17413 + components: + - type: Transform + pos: -13.5,-253.5 + parent: 2 + - uid: 17414 + components: + - type: Transform + pos: -13.5,-252.5 + parent: 2 + - uid: 17415 + components: + - type: Transform + pos: -13.5,-251.5 + parent: 2 + - uid: 17416 + components: + - type: Transform + pos: -13.5,-250.5 + parent: 2 - proto: CableHVStack entities: - uid: 3955 @@ -32001,6 +32128,12 @@ entities: - type: Transform pos: 3.5,-345.5 parent: 2 + - uid: 17405 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: -14.5,-247.5 + parent: 2 - proto: CandleBlackInfinite entities: - uid: 4705 @@ -34957,12 +35090,6 @@ entities: rot: 1.5707963267948966 rad pos: -6.627699,-1.5039027 parent: 2 - - uid: 5223 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: -13.5,-247.5 - parent: 2 - uid: 5224 components: - type: Transform @@ -49666,13 +49793,6 @@ entities: - type: Transform pos: -24.5,-253.5 parent: 2 -- proto: GasMinerPlasma - entities: - - uid: 3102 - components: - - type: Transform - pos: -24.5,-259.5 - parent: 2 - proto: GasMinerWaterVapor entities: - uid: 11306 @@ -76186,7 +76306,7 @@ entities: pos: 8.5,-176.5 parent: 2 - type: Door - secondsUntilStateChange: -147335.61 + secondsUntilStateChange: -147491.25 state: Closing - uid: 11227 components: @@ -88259,6 +88379,11 @@ entities: - type: Transform pos: 13.5,-253.5 parent: 2 + - uid: 17406 + components: + - type: Transform + pos: -13.5,-247.5 + parent: 2 - proto: SmokingPipeFilledCannabis entities: - uid: 13221 From 25afc2653d094bd0c7b8fc72529a11ade22e070c Mon Sep 17 00:00:00 2001 From: lzk <124214523+lzk228@users.noreply.github.com> Date: Fri, 9 Aug 2024 00:50:56 +0200 Subject: [PATCH 024/174] Add RD labcoat in RD's dresser (#30671) --- Resources/Prototypes/Catalog/Fills/Lockers/dressers.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/Resources/Prototypes/Catalog/Fills/Lockers/dressers.yml b/Resources/Prototypes/Catalog/Fills/Lockers/dressers.yml index 036448b00c..d04b6aff60 100644 --- a/Resources/Prototypes/Catalog/Fills/Lockers/dressers.yml +++ b/Resources/Prototypes/Catalog/Fills/Lockers/dressers.yml @@ -105,6 +105,7 @@ - id: ClothingHandsGlovesColorPurple - id: ClothingEyesGlasses - id: ClothingOuterWinterRD + - id: ClothingOuterCoatRD - type: entity id: DresserWardenFilled From c43fcdfa06cc44d3c61b6a930de2e4f2ca7d0a7e Mon Sep 17 00:00:00 2001 From: PJBot Date: Thu, 8 Aug 2024 22:52:05 +0000 Subject: [PATCH 025/174] Automatic changelog update --- Resources/Changelog/Changelog.yml | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index c196b78d4a..ba53573989 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,12 +1,4 @@ Entries: -- author: Killerqu00 - changes: - - message: Revolutionaries can now cuff command members in order to seize control - of the station. - type: Tweak - id: 6563 - time: '2024-05-09T06:48:32.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/27627 - author: vorkathbruh changes: - message: Nuclear operative agents now require time in Chemistry rather than time @@ -3786,3 +3778,10 @@ id: 7062 time: '2024-08-08T13:17:50.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/29997 +- author: lzk228 + changes: + - message: RD labcoat added in RD's dresser. + type: Add + id: 7063 + time: '2024-08-08T22:50:57.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/30671 From 07174d0aaf2832bc6ecc3a6baba21bc0aa5e0556 Mon Sep 17 00:00:00 2001 From: SlamBamActionman <83650252+SlamBamActionman@users.noreply.github.com> Date: Fri, 9 Aug 2024 01:27:27 +0200 Subject: [PATCH 026/174] Better DNA forensics & ReagentData (#26699) * Added the ability for blood to track DNA using ReagentData; Forensic Scanner now accounts for solution DNA, non-DNA holders have "Unknown DNA" * Removes touch DNA for puddles, adds DNA to vomit * DNA now leaves traces in containers and those marked without don't show DNA on scan (except for puddles), gibbed parts have DNA * Fix stupid metamorphic glass bug grrr * Removed SpillableComponent since DnaSubstanceTraceComponent is used instead * Removes data field from maps, adds DNA tracking for some missed items * Give default value, fix missing values. * Fixes recipe bug * Review changes * Make the Data list into a nullable type * Revert map changes * Move gibbed unknown DNA to forensicssystem --- .../Forensics/ForensicScannerMenu.xaml.cs | 8 ++- .../Body/Systems/BloodstreamSystem.cs | 63 ++++++++++++++--- .../Chemistry/EntitySystems/VaporSystem.cs | 2 +- .../TileReactions/CleanDecalsReaction.cs | 4 +- .../TileReactions/CleanTileReaction.cs | 3 +- .../TileReactions/CreateEntityTileReaction.cs | 3 +- .../TileReactions/ExtinguishTileReaction.cs | 3 +- .../TileReactions/FlammableTileReaction.cs | 3 +- .../TileReactions/PryTileReaction.cs | 5 +- .../SpillIfPuddlePresentTileReaction.cs | 5 +- .../TileReactions/SpillTileReaction.cs | 5 +- .../Fluids/EntitySystems/PuddleSystem.cs | 2 +- .../Fluids/EntitySystems/SmokeSystem.cs | 2 +- .../Components/DnaSubstanceTraceComponent.cs | 9 +++ .../Components/ForensicScannerComponent.cs | 8 ++- .../Systems/ForensicScannerSystem.cs | 34 ++++++++-- .../Forensics/Systems/ForensicsSystem.cs | 67 +++++++++++++++++-- .../Implants/SubdermalImplantSystem.cs | 6 +- Content.Server/Medical/VomitSystem.cs | 4 +- .../Chemistry/Components/Solution.cs | 10 +-- .../SharedSolutionContainerSystem.cs | 6 +- .../Chemistry/Reaction/ITileReaction.cs | 5 +- Content.Shared/Chemistry/Reagent/DNAData.cs | 28 ++++++++ Content.Shared/Chemistry/Reagent/ReagentId.cs | 25 ++++--- .../Chemistry/Reagent/ReagentPrototype.cs | 4 +- .../Chemistry/Reagent/ReagentQuantity.cs | 4 +- Content.Shared/Forensics/Events.cs | 17 +++++ .../Forensics/ForensicScannerEvent.cs | 9 ++- .../Locale/en-US/forensics/forensics.ftl | 4 +- .../Prototypes/Entities/Effects/puddle.yml | 3 + .../Consumable/Drinks/drinks-cartons.yml | 1 + .../Objects/Consumable/Drinks/drinks.yml | 1 + .../Consumable/Drinks/drinks_bottles.yml | 1 + .../Objects/Consumable/Drinks/drinks_cans.yml | 1 + .../Objects/Consumable/Drinks/drinks_cups.yml | 1 + .../Consumable/Drinks/drinks_special.yml | 1 + .../Consumable/Drinks/trash_drinks.yml | 1 + .../Objects/Specific/Janitorial/janitor.yml | 3 + .../Objects/Specific/chemical-containers.yml | 1 + .../Objects/Specific/chemistry-bottles.yml | 1 + .../Objects/Specific/chemistry-vials.yml | 1 + .../Entities/Objects/Specific/chemistry.yml | 3 + .../Entities/Objects/Tools/bucket.yml | 1 + .../Structures/Specific/Janitor/janicart.yml | 2 + Resources/Prototypes/tags.yml | 3 + 45 files changed, 307 insertions(+), 66 deletions(-) create mode 100644 Content.Server/Forensics/Components/DnaSubstanceTraceComponent.cs create mode 100644 Content.Shared/Chemistry/Reagent/DNAData.cs diff --git a/Content.Client/Forensics/ForensicScannerMenu.xaml.cs b/Content.Client/Forensics/ForensicScannerMenu.xaml.cs index 5f7f8e0056..dd013ed235 100644 --- a/Content.Client/Forensics/ForensicScannerMenu.xaml.cs +++ b/Content.Client/Forensics/ForensicScannerMenu.xaml.cs @@ -54,10 +54,16 @@ namespace Content.Client.Forensics } text.AppendLine(); text.AppendLine(Loc.GetString("forensic-scanner-interface-dnas")); - foreach (var dna in msg.DNAs) + foreach (var dna in msg.TouchDNAs) { text.AppendLine(dna); } + foreach (var dna in msg.SolutionDNAs) + { + if (msg.TouchDNAs.Contains(dna)) + continue; + text.AppendLine(dna); + } text.AppendLine(); text.AppendLine(Loc.GetString("forensic-scanner-interface-residues")); foreach (var residue in msg.Residues) diff --git a/Content.Server/Body/Systems/BloodstreamSystem.cs b/Content.Server/Body/Systems/BloodstreamSystem.cs index a8a86028d4..9647634a9e 100644 --- a/Content.Server/Body/Systems/BloodstreamSystem.cs +++ b/Content.Server/Body/Systems/BloodstreamSystem.cs @@ -8,10 +8,12 @@ using Content.Shared.Alert; using Content.Shared.Chemistry.Components; using Content.Shared.Chemistry.EntitySystems; using Content.Shared.Chemistry.Reaction; +using Content.Shared.Chemistry.Reagent; using Content.Shared.Damage; using Content.Shared.Damage.Prototypes; using Content.Shared.Drunk; using Content.Shared.FixedPoint; +using Content.Shared.Forensics; using Content.Shared.HealthExaminable; using Content.Shared.Mobs.Systems; using Content.Shared.Popups; @@ -54,6 +56,7 @@ public sealed class BloodstreamSystem : EntitySystem SubscribeLocalEvent(OnReactionAttempt); SubscribeLocalEvent>(OnReactionAttempt); SubscribeLocalEvent(OnRejuvenate); + SubscribeLocalEvent(OnDnaGenerated); } private void OnMapInit(Entity ent, ref MapInitEvent args) @@ -183,8 +186,18 @@ public sealed class BloodstreamSystem : EntitySystem bloodSolution.MaxVolume = entity.Comp.BloodMaxVolume; tempSolution.MaxVolume = entity.Comp.BleedPuddleThreshold * 4; // give some leeway, for chemstream as well + // Ensure blood that should have DNA has it; must be run here, in case DnaComponent has not yet been initialized + + if (TryComp(entity.Owner, out var donorComp) && donorComp.DNA == String.Empty) + { + donorComp.DNA = _forensicsSystem.GenerateDNA(); + + var ev = new GenerateDnaEvent { Owner = entity.Owner, DNA = donorComp.DNA }; + RaiseLocalEvent(entity.Owner, ref ev); + } + // Fill blood solution with BLOOD - bloodSolution.AddReagent(entity.Comp.BloodReagent, entity.Comp.BloodMaxVolume - bloodSolution.Volume); + bloodSolution.AddReagent(new ReagentId(entity.Comp.BloodReagent, GetEntityBloodData(entity.Owner)), entity.Comp.BloodMaxVolume - bloodSolution.Volume); } private void OnDamageChanged(Entity ent, ref DamageChangedEvent args) @@ -349,7 +362,7 @@ public sealed class BloodstreamSystem : EntitySystem } if (amount >= 0) - return _solutionContainerSystem.TryAddReagent(component.BloodSolution.Value, component.BloodReagent, amount, out _); + return _solutionContainerSystem.TryAddReagent(component.BloodSolution.Value, component.BloodReagent, amount, null, GetEntityBloodData(uid)); // Removal is more involved, // since we also wanna handle moving it to the temporary solution @@ -370,10 +383,7 @@ public sealed class BloodstreamSystem : EntitySystem tempSolution.AddSolution(temp, _prototypeManager); } - if (_puddleSystem.TrySpillAt(uid, tempSolution, out var puddleUid, sound: false)) - { - _forensicsSystem.TransferDna(puddleUid, uid, canDnaBeCleaned: false); - } + _puddleSystem.TrySpillAt(uid, tempSolution, out var puddleUid, sound: false); tempSolution.RemoveAllSolution(); } @@ -436,10 +446,7 @@ public sealed class BloodstreamSystem : EntitySystem _solutionContainerSystem.RemoveAllSolution(component.TemporarySolution.Value); } - if (_puddleSystem.TrySpillAt(uid, tempSol, out var puddleUid)) - { - _forensicsSystem.TransferDna(puddleUid, uid, canDnaBeCleaned: false); - } + _puddleSystem.TrySpillAt(uid, tempSol, out var puddleUid); } /// @@ -464,6 +471,40 @@ public sealed class BloodstreamSystem : EntitySystem component.BloodReagent = reagent; if (currentVolume > 0) - _solutionContainerSystem.TryAddReagent(component.BloodSolution.Value, component.BloodReagent, currentVolume, out _); + _solutionContainerSystem.TryAddReagent(component.BloodSolution.Value, component.BloodReagent, currentVolume, null, GetEntityBloodData(uid)); + } + + private void OnDnaGenerated(Entity entity, ref GenerateDnaEvent args) + { + if (_solutionContainerSystem.ResolveSolution(entity.Owner, entity.Comp.BloodSolutionName, ref entity.Comp.BloodSolution, out var bloodSolution)) + { + foreach (var reagent in bloodSolution.Contents) + { + List reagentData = reagent.Reagent.EnsureReagentData(); + reagentData.RemoveAll(x => x is DnaData); + reagentData.AddRange(GetEntityBloodData(entity.Owner)); + } + } + } + + /// + /// Get the reagent data for blood that a specific entity should have. + /// + public List GetEntityBloodData(EntityUid uid) + { + var bloodData = new List(); + var dnaData = new DnaData(); + + if (TryComp(uid, out var donorComp)) + { + dnaData.DNA = donorComp.DNA; + } else + { + dnaData.DNA = Loc.GetString("forensics-dna-unknown"); + } + + bloodData.Add(dnaData); + + return bloodData; } } diff --git a/Content.Server/Chemistry/EntitySystems/VaporSystem.cs b/Content.Server/Chemistry/EntitySystems/VaporSystem.cs index dbb8572299..5093b59409 100644 --- a/Content.Server/Chemistry/EntitySystems/VaporSystem.cs +++ b/Content.Server/Chemistry/EntitySystems/VaporSystem.cs @@ -123,7 +123,7 @@ namespace Content.Server.Chemistry.EntitySystems var reagent = _protoManager.Index(reagentQuantity.Reagent.Prototype); var reaction = - reagent.ReactionTile(tile, (reagentQuantity.Quantity / vapor.TransferAmount) * 0.25f, EntityManager); + reagent.ReactionTile(tile, (reagentQuantity.Quantity / vapor.TransferAmount) * 0.25f, EntityManager, reagentQuantity.Reagent.Data); if (reaction > reagentQuantity.Quantity) { diff --git a/Content.Server/Chemistry/TileReactions/CleanDecalsReaction.cs b/Content.Server/Chemistry/TileReactions/CleanDecalsReaction.cs index 6958dabb81..5047a26052 100644 --- a/Content.Server/Chemistry/TileReactions/CleanDecalsReaction.cs +++ b/Content.Server/Chemistry/TileReactions/CleanDecalsReaction.cs @@ -21,10 +21,12 @@ public sealed partial class CleanDecalsReaction : ITileReaction [DataField] public FixedPoint2 CleanCost { get; private set; } = FixedPoint2.New(0.25f); + public FixedPoint2 TileReact(TileRef tile, ReagentPrototype reagent, FixedPoint2 reactVolume, - IEntityManager entityManager) + IEntityManager entityManager, + List? data) { if (reactVolume <= CleanCost || !entityManager.TryGetComponent(tile.GridUid, out var grid) || diff --git a/Content.Server/Chemistry/TileReactions/CleanTileReaction.cs b/Content.Server/Chemistry/TileReactions/CleanTileReaction.cs index 08f77de72d..ad02cb8ff9 100644 --- a/Content.Server/Chemistry/TileReactions/CleanTileReaction.cs +++ b/Content.Server/Chemistry/TileReactions/CleanTileReaction.cs @@ -34,7 +34,8 @@ public sealed partial class CleanTileReaction : ITileReaction FixedPoint2 ITileReaction.TileReact(TileRef tile, ReagentPrototype reagent, FixedPoint2 reactVolume, - IEntityManager entityManager) + IEntityManager entityManager + , List? data) { var entities = entityManager.System().GetLocalEntitiesIntersecting(tile, 0f).ToArray(); var puddleQuery = entityManager.GetEntityQuery(); diff --git a/Content.Server/Chemistry/TileReactions/CreateEntityTileReaction.cs b/Content.Server/Chemistry/TileReactions/CreateEntityTileReaction.cs index 6b106b1fc0..0249b6255a 100644 --- a/Content.Server/Chemistry/TileReactions/CreateEntityTileReaction.cs +++ b/Content.Server/Chemistry/TileReactions/CreateEntityTileReaction.cs @@ -38,7 +38,8 @@ public sealed partial class CreateEntityTileReaction : ITileReaction public FixedPoint2 TileReact(TileRef tile, ReagentPrototype reagent, FixedPoint2 reactVolume, - IEntityManager entityManager) + IEntityManager entityManager, + List? data) { if (reactVolume >= Usage) { diff --git a/Content.Server/Chemistry/TileReactions/ExtinguishTileReaction.cs b/Content.Server/Chemistry/TileReactions/ExtinguishTileReaction.cs index 198f650ac1..2b9475235f 100644 --- a/Content.Server/Chemistry/TileReactions/ExtinguishTileReaction.cs +++ b/Content.Server/Chemistry/TileReactions/ExtinguishTileReaction.cs @@ -17,7 +17,8 @@ namespace Content.Server.Chemistry.TileReactions public FixedPoint2 TileReact(TileRef tile, ReagentPrototype reagent, FixedPoint2 reactVolume, - IEntityManager entityManager) + IEntityManager entityManager, + List? data) { if (reactVolume <= FixedPoint2.Zero || tile.Tile.IsEmpty) return FixedPoint2.Zero; diff --git a/Content.Server/Chemistry/TileReactions/FlammableTileReaction.cs b/Content.Server/Chemistry/TileReactions/FlammableTileReaction.cs index b13b70d3d5..dd0b4960ef 100644 --- a/Content.Server/Chemistry/TileReactions/FlammableTileReaction.cs +++ b/Content.Server/Chemistry/TileReactions/FlammableTileReaction.cs @@ -16,7 +16,8 @@ namespace Content.Server.Chemistry.TileReactions public FixedPoint2 TileReact(TileRef tile, ReagentPrototype reagent, FixedPoint2 reactVolume, - IEntityManager entityManager) + IEntityManager entityManager, + List? data) { if (reactVolume <= FixedPoint2.Zero || tile.Tile.IsEmpty) return FixedPoint2.Zero; diff --git a/Content.Server/Chemistry/TileReactions/PryTileReaction.cs b/Content.Server/Chemistry/TileReactions/PryTileReaction.cs index c10b031720..49971475c1 100644 --- a/Content.Server/Chemistry/TileReactions/PryTileReaction.cs +++ b/Content.Server/Chemistry/TileReactions/PryTileReaction.cs @@ -1,4 +1,4 @@ -using Content.Server.Maps; +using Content.Server.Maps; using Content.Shared.Chemistry.Reaction; using Content.Shared.Chemistry.Reagent; using Content.Shared.FixedPoint; @@ -15,7 +15,8 @@ public sealed partial class PryTileReaction : ITileReaction public FixedPoint2 TileReact(TileRef tile, ReagentPrototype reagent, FixedPoint2 reactVolume, - IEntityManager entityManager) + IEntityManager entityManager, + List? data) { var sys = entityManager.System(); sys.PryTile(tile); diff --git a/Content.Server/Chemistry/TileReactions/SpillIfPuddlePresentTileReaction.cs b/Content.Server/Chemistry/TileReactions/SpillIfPuddlePresentTileReaction.cs index 6b46b89495..8c8b371da3 100644 --- a/Content.Server/Chemistry/TileReactions/SpillIfPuddlePresentTileReaction.cs +++ b/Content.Server/Chemistry/TileReactions/SpillIfPuddlePresentTileReaction.cs @@ -15,13 +15,14 @@ namespace Content.Server.Chemistry.TileReactions public FixedPoint2 TileReact(TileRef tile, ReagentPrototype reagent, FixedPoint2 reactVolume, - IEntityManager entityManager) + IEntityManager entityManager, + List? data) { var spillSystem = entityManager.System(); if (reactVolume < 5 || !spillSystem.TryGetPuddle(tile, out _)) return FixedPoint2.Zero; - return spillSystem.TrySpillAt(tile, new Solution(reagent.ID, reactVolume), out _, sound: false, tileReact: false) + return spillSystem.TrySpillAt(tile, new Solution(reagent.ID, reactVolume, data), out _, sound: false, tileReact: false) ? reactVolume : FixedPoint2.Zero; } diff --git a/Content.Server/Chemistry/TileReactions/SpillTileReaction.cs b/Content.Server/Chemistry/TileReactions/SpillTileReaction.cs index fadc7147c9..f9fb2b90d0 100644 --- a/Content.Server/Chemistry/TileReactions/SpillTileReaction.cs +++ b/Content.Server/Chemistry/TileReactions/SpillTileReaction.cs @@ -29,13 +29,14 @@ namespace Content.Server.Chemistry.TileReactions public FixedPoint2 TileReact(TileRef tile, ReagentPrototype reagent, FixedPoint2 reactVolume, - IEntityManager entityManager) + IEntityManager entityManager, + List? data) { if (reactVolume < 5) return FixedPoint2.Zero; if (entityManager.EntitySysManager.GetEntitySystem() - .TrySpillAt(tile, new Solution(reagent.ID, reactVolume), out var puddleUid, false, false)) + .TrySpillAt(tile, new Solution(reagent.ID, reactVolume, data), out var puddleUid, false, false)) { var slippery = entityManager.EnsureComponent(puddleUid); slippery.LaunchForwardsMultiplier = _launchForwardsMultiplier; diff --git a/Content.Server/Fluids/EntitySystems/PuddleSystem.cs b/Content.Server/Fluids/EntitySystems/PuddleSystem.cs index a232ed8c0e..67ba2a76bb 100644 --- a/Content.Server/Fluids/EntitySystems/PuddleSystem.cs +++ b/Content.Server/Fluids/EntitySystems/PuddleSystem.cs @@ -712,7 +712,7 @@ public sealed partial class PuddleSystem : SharedPuddleSystem { var (reagent, quantity) = solution.Contents[i]; var proto = _prototypeManager.Index(reagent.Prototype); - var removed = proto.ReactionTile(tileRef, quantity, EntityManager); + var removed = proto.ReactionTile(tileRef, quantity, EntityManager, reagent.Data); if (removed <= FixedPoint2.Zero) continue; diff --git a/Content.Server/Fluids/EntitySystems/SmokeSystem.cs b/Content.Server/Fluids/EntitySystems/SmokeSystem.cs index 78693bfdbc..72450562f1 100644 --- a/Content.Server/Fluids/EntitySystems/SmokeSystem.cs +++ b/Content.Server/Fluids/EntitySystems/SmokeSystem.cs @@ -315,7 +315,7 @@ public sealed class SmokeSystem : EntitySystem continue; var reagent = _prototype.Index(reagentQuantity.Reagent.Prototype); - reagent.ReactionTile(tile, reagentQuantity.Quantity, EntityManager); + reagent.ReactionTile(tile, reagentQuantity.Quantity, EntityManager, reagentQuantity.Reagent.Data); } } diff --git a/Content.Server/Forensics/Components/DnaSubstanceTraceComponent.cs b/Content.Server/Forensics/Components/DnaSubstanceTraceComponent.cs new file mode 100644 index 0000000000..7b3cb978f2 --- /dev/null +++ b/Content.Server/Forensics/Components/DnaSubstanceTraceComponent.cs @@ -0,0 +1,9 @@ +namespace Content.Server.Forensics; + +/// +/// This component stops the entity from leaving finger prints, +/// usually so fibres can be left instead. +/// +[RegisterComponent] +public sealed partial class DnaSubstanceTraceComponent : Component +{ } diff --git a/Content.Server/Forensics/Components/ForensicScannerComponent.cs b/Content.Server/Forensics/Components/ForensicScannerComponent.cs index ad26213848..033ea913c3 100644 --- a/Content.Server/Forensics/Components/ForensicScannerComponent.cs +++ b/Content.Server/Forensics/Components/ForensicScannerComponent.cs @@ -26,7 +26,13 @@ namespace Content.Server.Forensics /// DNA that the forensic scanner found from the on an entity. /// [ViewVariables(VVAccess.ReadOnly), DataField("dnas")] - public List DNAs = new(); + public List TouchDNAs = new(); + + /// + /// DNA that the forensic scanner found from the solution containers in an entity. + /// + [ViewVariables(VVAccess.ReadOnly), DataField] + public List SolutionDNAs = new(); /// /// Residue that the forensic scanner found from the on an entity. diff --git a/Content.Server/Forensics/Systems/ForensicScannerSystem.cs b/Content.Server/Forensics/Systems/ForensicScannerSystem.cs index 80062569b8..b6dc068f78 100644 --- a/Content.Server/Forensics/Systems/ForensicScannerSystem.cs +++ b/Content.Server/Forensics/Systems/ForensicScannerSystem.cs @@ -3,16 +3,19 @@ using System.Text; using Content.Server.Popups; using Content.Shared.UserInterface; using Content.Shared.DoAfter; +using Content.Shared.Fluids.Components; using Content.Shared.Forensics; using Content.Shared.Hands.EntitySystems; using Content.Shared.Interaction; using Content.Shared.Paper; using Content.Shared.Verbs; +using Content.Shared.Tag; using Robust.Shared.Audio.Systems; using Robust.Server.GameObjects; using Robust.Shared.Audio; using Robust.Shared.Player; using Robust.Shared.Timing; +using Content.Server.Chemistry.Containers.EntitySystems; // todo: remove this stinky LINQy namespace Content.Server.Forensics @@ -27,6 +30,9 @@ namespace Content.Server.Forensics [Dependency] private readonly SharedHandsSystem _handsSystem = default!; [Dependency] private readonly SharedAudioSystem _audioSystem = default!; [Dependency] private readonly MetaDataSystem _metaData = default!; + [Dependency] private readonly ForensicsSystem _forensicsSystem = default!; + [Dependency] private readonly SolutionContainerSystem _solutionContainerSystem = default!; + [Dependency] private readonly TagSystem _tag = default!; public override void Initialize() { @@ -46,7 +52,8 @@ namespace Content.Server.Forensics var state = new ForensicScannerBoundUserInterfaceState( component.Fingerprints, component.Fibers, - component.DNAs, + component.TouchDNAs, + component.SolutionDNAs, component.Residues, component.LastScannedName, component.PrintCooldown, @@ -69,18 +76,25 @@ namespace Content.Server.Forensics { scanner.Fingerprints = new(); scanner.Fibers = new(); - scanner.DNAs = new(); + scanner.TouchDNAs = new(); scanner.Residues = new(); } - else { scanner.Fingerprints = forensics.Fingerprints.ToList(); scanner.Fibers = forensics.Fibers.ToList(); - scanner.DNAs = forensics.DNAs.ToList(); + scanner.TouchDNAs = forensics.DNAs.ToList(); scanner.Residues = forensics.Residues.ToList(); } + if (_tag.HasTag(args.Args.Target.Value, "DNASolutionScannable")) + { + scanner.SolutionDNAs = _forensicsSystem.GetSolutionsDNA(args.Args.Target.Value); + } else + { + scanner.SolutionDNAs = new(); + } + scanner.LastScannedName = MetaData(args.Args.Target.Value).EntityName; } @@ -206,10 +220,17 @@ namespace Content.Server.Forensics } text.AppendLine(); text.AppendLine(Loc.GetString("forensic-scanner-interface-dnas")); - foreach (var dna in component.DNAs) + foreach (var dna in component.TouchDNAs) { text.AppendLine(dna); } + foreach (var dna in component.SolutionDNAs) + { + Log.Debug(dna); + if (component.TouchDNAs.Contains(dna)) + continue; + text.AppendLine(dna); + } text.AppendLine(); text.AppendLine(Loc.GetString("forensic-scanner-interface-residues")); foreach (var residue in component.Residues) @@ -232,7 +253,8 @@ namespace Content.Server.Forensics { component.Fingerprints = new(); component.Fibers = new(); - component.DNAs = new(); + component.TouchDNAs = new(); + component.SolutionDNAs = new(); component.LastScannedName = string.Empty; UpdateUserInterface(uid, component); diff --git a/Content.Server/Forensics/Systems/ForensicsSystem.cs b/Content.Server/Forensics/Systems/ForensicsSystem.cs index c0d990aa59..ec311d136a 100644 --- a/Content.Server/Forensics/Systems/ForensicsSystem.cs +++ b/Content.Server/Forensics/Systems/ForensicsSystem.cs @@ -1,11 +1,16 @@ using Content.Server.Body.Components; +using Content.Server.Chemistry.Containers.EntitySystems; using Content.Server.DoAfter; using Content.Server.Fluids.EntitySystems; using Content.Server.Forensics.Components; using Content.Server.Popups; +using Content.Shared.Chemistry.EntitySystems; using Content.Shared.Popups; using Content.Shared.Chemistry.Components; +using Content.Shared.Chemistry.Reagent; +using Content.Shared.Chemistry.Components.SolutionManager; using Content.Shared.DoAfter; +using Content.Shared.Fluids.Components; using Content.Shared.Forensics; using Content.Shared.Interaction; using Content.Shared.Interaction.Events; @@ -23,20 +28,35 @@ namespace Content.Server.Forensics [Dependency] private readonly InventorySystem _inventory = default!; [Dependency] private readonly DoAfterSystem _doAfterSystem = default!; [Dependency] private readonly PopupSystem _popupSystem = default!; + [Dependency] private readonly SolutionContainerSystem _solutionContainerSystem = default!; + public override void Initialize() { SubscribeLocalEvent(OnInteract); SubscribeLocalEvent(OnFingerprintInit); SubscribeLocalEvent(OnDNAInit); - SubscribeLocalEvent(OnBeingGibbed); + SubscribeLocalEvent(OnBeingGibbed); SubscribeLocalEvent(OnMeleeHit); SubscribeLocalEvent(OnRehydrated); SubscribeLocalEvent(OnAfterInteract, after: new[] { typeof(AbsorbentSystem) }); SubscribeLocalEvent(OnCleanForensicsDoAfter); SubscribeLocalEvent(OnTransferDnaEvent); + SubscribeLocalEvent(OnSolutionChanged); SubscribeLocalEvent>(OnUtilityVerb); + } + private void OnSolutionChanged(Entity ent, ref SolutionContainerChangedEvent ev) + { + var soln = GetSolutionsDNA(ev.Solution); + if (soln.Count > 0) + { + var comp = EnsureComp(ent.Owner); + foreach (string dna in soln) + { + comp.DNAs.Add(dna); + } + } } private void OnInteract(EntityUid uid, FingerprintComponent component, ContactInteractionEvent args) @@ -51,15 +71,26 @@ namespace Content.Server.Forensics private void OnDNAInit(EntityUid uid, DnaComponent component, MapInitEvent args) { - component.DNA = GenerateDNA(); + if (component.DNA == String.Empty) + { + component.DNA = GenerateDNA(); + + var ev = new GenerateDnaEvent { Owner = uid, DNA = component.DNA }; + RaiseLocalEvent(uid, ref ev); + } } - private void OnBeingGibbed(EntityUid uid, DnaComponent component, BeingGibbedEvent args) + private void OnBeingGibbed(EntityUid uid, ForensicsComponent component, BeingGibbedEvent args) { + string dna = Loc.GetString("forensics-dna-unknown"); + + if (TryComp(uid, out DnaComponent? dnaComp)) + dna = dnaComp.DNA; + foreach (EntityUid part in args.GibbedParts) { var partComp = EnsureComp(part); - partComp.DNAs.Add(component.DNA); + partComp.DNAs.Add(dna); partComp.CanDnaBeCleaned = false; } } @@ -106,6 +137,34 @@ namespace Content.Server.Forensics } } + public List GetSolutionsDNA(EntityUid uid) + { + List list = new(); + if (TryComp(uid, out var comp)) + { + foreach (var (_, soln) in _solutionContainerSystem.EnumerateSolutions((uid, comp))) + { + list.AddRange(GetSolutionsDNA(soln.Comp.Solution)); + } + } + return list; + } + + public List GetSolutionsDNA(Solution soln) + { + List list = new(); + foreach (var reagent in soln.Contents) + { + foreach (var data in reagent.Reagent.EnsureReagentData()) + { + if (data is DnaData) + { + list.Add(((DnaData) data).DNA); + } + } + } + return list; + } private void OnAfterInteract(Entity cleanForensicsEntity, ref AfterInteractEvent args) { if (args.Handled || !args.CanReach || args.Target == null) diff --git a/Content.Server/Implants/SubdermalImplantSystem.cs b/Content.Server/Implants/SubdermalImplantSystem.cs index 88c5fb9459..7c69ec8ea5 100644 --- a/Content.Server/Implants/SubdermalImplantSystem.cs +++ b/Content.Server/Implants/SubdermalImplantSystem.cs @@ -1,10 +1,11 @@ -using Content.Server.Cuffs; +using Content.Server.Cuffs; using Content.Server.Forensics; using Content.Server.Humanoid; using Content.Server.Implants.Components; using Content.Server.Store.Components; using Content.Server.Store.Systems; using Content.Shared.Cuffs.Components; +using Content.Shared.Forensics; using Content.Shared.Humanoid; using Content.Shared.Implants; using Content.Shared.Implants.Components; @@ -212,6 +213,9 @@ public sealed class SubdermalImplantSystem : SharedSubdermalImplantSystem if (TryComp(ent, out var dna)) { dna.DNA = _forensicsSystem.GenerateDNA(); + + var ev = new GenerateDnaEvent { Owner = ent, DNA = dna.DNA }; + RaiseLocalEvent(ent, ref ev); } if (TryComp(ent, out var fingerprint)) { diff --git a/Content.Server/Medical/VomitSystem.cs b/Content.Server/Medical/VomitSystem.cs index ec04a27db6..4cc4e538ce 100644 --- a/Content.Server/Medical/VomitSystem.cs +++ b/Content.Server/Medical/VomitSystem.cs @@ -6,6 +6,7 @@ using Content.Server.Forensics; using Content.Server.Popups; using Content.Server.Stunnable; using Content.Shared.Chemistry.Components; +using Content.Shared.Chemistry.Reagent; using Content.Shared.IdentityManagement; using Content.Shared.Nutrition.Components; using Content.Shared.Nutrition.EntitySystems; @@ -28,6 +29,7 @@ namespace Content.Server.Medical [Dependency] private readonly StunSystem _stun = default!; [Dependency] private readonly ThirstSystem _thirst = default!; [Dependency] private readonly ForensicsSystem _forensics = default!; + [Dependency] private readonly BloodstreamSystem _bloodstream = default!; /// /// Make an entity vomit, if they have a stomach. @@ -83,7 +85,7 @@ namespace Content.Server.Medical } // Makes a vomit solution the size of 90% of the chemicals removed from the chemstream - solution.AddReagent("Vomit", vomitAmount); // TODO: Dehardcode vomit prototype + solution.AddReagent(new ReagentId("Vomit", _bloodstream.GetEntityBloodData(uid)), vomitAmount); // TODO: Dehardcode vomit prototype } if (_puddle.TrySpillAt(uid, solution, out var puddle, false)) diff --git a/Content.Shared/Chemistry/Components/Solution.cs b/Content.Shared/Chemistry/Components/Solution.cs index 4de3c369f7..725a685a8b 100644 --- a/Content.Shared/Chemistry/Components/Solution.cs +++ b/Content.Shared/Chemistry/Components/Solution.cs @@ -147,7 +147,7 @@ namespace Content.Shared.Chemistry.Components /// /// The prototype ID of the reagent to add. /// The quantity in milli-units. - public Solution(string prototype, FixedPoint2 quantity, ReagentData? data = null) : this() + public Solution(string prototype, FixedPoint2 quantity, List? data = null) : this() { AddReagent(new ReagentId(prototype, data), quantity); } @@ -243,7 +243,7 @@ namespace Content.Shared.Chemistry.Components return false; } - public bool ContainsReagent(string reagentId, ReagentData? data) + public bool ContainsReagent(string reagentId, List? data) => ContainsReagent(new(reagentId, data)); public bool TryGetReagent(ReagentId id, out ReagentQuantity quantity) @@ -404,7 +404,7 @@ namespace Content.Shared.Chemistry.Components /// /// The prototype of the reagent to add. /// The quantity in milli-units. - public void AddReagent(ReagentPrototype proto, FixedPoint2 quantity, float temperature, IPrototypeManager? protoMan, ReagentData? data = null) + public void AddReagent(ReagentPrototype proto, FixedPoint2 quantity, float temperature, IPrototypeManager? protoMan, List? data = null) { if (_heatCapacityDirty) UpdateHeatCapacity(protoMan); @@ -489,7 +489,7 @@ namespace Content.Shared.Chemistry.Components { var (reagent, curQuantity) = Contents[i]; - if(reagent != toRemove.Reagent) + if(reagent.Prototype != toRemove.Reagent.Prototype) continue; var newQuantity = curQuantity - toRemove.Quantity; @@ -523,7 +523,7 @@ namespace Content.Shared.Chemistry.Components /// The prototype of the reagent to be removed. /// The amount of reagent to remove. /// How much reagent was actually removed. Zero if the reagent is not present on the solution. - public FixedPoint2 RemoveReagent(string prototype, FixedPoint2 quantity, ReagentData? data = null) + public FixedPoint2 RemoveReagent(string prototype, FixedPoint2 quantity, List? data = null) { return RemoveReagent(new ReagentQuantity(prototype, quantity, data)); } diff --git a/Content.Shared/Chemistry/EntitySystems/SharedSolutionContainerSystem.cs b/Content.Shared/Chemistry/EntitySystems/SharedSolutionContainerSystem.cs index 7e00157b6e..ad9cd01fbf 100644 --- a/Content.Shared/Chemistry/EntitySystems/SharedSolutionContainerSystem.cs +++ b/Content.Shared/Chemistry/EntitySystems/SharedSolutionContainerSystem.cs @@ -452,7 +452,7 @@ public abstract partial class SharedSolutionContainerSystem : EntitySystem /// The amount of reagent to add. /// If all the reagent could be added. [PublicAPI] - public bool TryAddReagent(Entity soln, string prototype, FixedPoint2 quantity, float? temperature = null, ReagentData? data = null) + public bool TryAddReagent(Entity soln, string prototype, FixedPoint2 quantity, float? temperature = null, List? data = null) => TryAddReagent(soln, new ReagentQuantity(prototype, quantity, data), out _, temperature); /// @@ -464,7 +464,7 @@ public abstract partial class SharedSolutionContainerSystem : EntitySystem /// The amount of reagent to add. /// The amount of reagent successfully added. /// If all the reagent could be added. - public bool TryAddReagent(Entity soln, string prototype, FixedPoint2 quantity, out FixedPoint2 acceptedQuantity, float? temperature = null, ReagentData? data = null) + public bool TryAddReagent(Entity soln, string prototype, FixedPoint2 quantity, out FixedPoint2 acceptedQuantity, float? temperature = null, List? data = null) { var reagent = new ReagentQuantity(prototype, quantity, data); return TryAddReagent(soln, reagent, out acceptedQuantity, temperature); @@ -513,7 +513,7 @@ public abstract partial class SharedSolutionContainerSystem : EntitySystem /// The Id of the reagent to remove. /// The amount of reagent to remove. /// If the reagent to remove was found in the container. - public bool RemoveReagent(Entity soln, string prototype, FixedPoint2 quantity, ReagentData? data = null) + public bool RemoveReagent(Entity soln, string prototype, FixedPoint2 quantity, List? data = null) { return RemoveReagent(soln, new ReagentQuantity(prototype, quantity, data)); } diff --git a/Content.Shared/Chemistry/Reaction/ITileReaction.cs b/Content.Shared/Chemistry/Reaction/ITileReaction.cs index af6cc34f48..31b7c9129c 100644 --- a/Content.Shared/Chemistry/Reaction/ITileReaction.cs +++ b/Content.Shared/Chemistry/Reaction/ITileReaction.cs @@ -1,4 +1,4 @@ -using Content.Shared.Chemistry.Reagent; +using Content.Shared.Chemistry.Reagent; using Content.Shared.FixedPoint; using Robust.Shared.Map; @@ -9,6 +9,7 @@ namespace Content.Shared.Chemistry.Reaction FixedPoint2 TileReact(TileRef tile, ReagentPrototype reagent, FixedPoint2 reactVolume, - IEntityManager entityManager); + IEntityManager entityManager, + List? data = null); } } diff --git a/Content.Shared/Chemistry/Reagent/DNAData.cs b/Content.Shared/Chemistry/Reagent/DNAData.cs new file mode 100644 index 0000000000..e75e994ece --- /dev/null +++ b/Content.Shared/Chemistry/Reagent/DNAData.cs @@ -0,0 +1,28 @@ +using Content.Shared.FixedPoint; +using Robust.Shared.Serialization; + +namespace Content.Shared.Chemistry.Reagent; + +[ImplicitDataDefinitionForInheritors, Serializable, NetSerializable] +public sealed partial class DnaData : ReagentData +{ + [DataField] + public string DNA = String.Empty; + + public override ReagentData Clone() => this; + + public override bool Equals(ReagentData? other) + { + if (other == null) + { + return false; + } + + return ((DnaData) other).DNA == DNA; + } + + public override int GetHashCode() + { + return DNA.GetHashCode(); + } +} diff --git a/Content.Shared/Chemistry/Reagent/ReagentId.cs b/Content.Shared/Chemistry/Reagent/ReagentId.cs index 07a4200219..798dd28db4 100644 --- a/Content.Shared/Chemistry/Reagent/ReagentId.cs +++ b/Content.Shared/Chemistry/Reagent/ReagentId.cs @@ -1,6 +1,7 @@ -using Content.Shared.FixedPoint; +using Content.Shared.FixedPoint; using Robust.Shared.Serialization; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; +using System.Linq; namespace Content.Shared.Chemistry.Reagent; @@ -20,17 +21,23 @@ public partial struct ReagentId : IEquatable /// Any additional data that is unique to this reagent type. E.g., for blood this could be DNA data. /// [DataField("data")] - public ReagentData? Data { get; private set; } + public List? Data { get; private set; } = new(); - public ReagentId(string prototype, ReagentData? data) + public ReagentId(string prototype, List? data) { Prototype = prototype; - Data = data; + Data = data ?? new(); } public ReagentId() { Prototype = default!; + Data = new(); + } + + public List EnsureReagentData() + { + return (Data != null) ? Data : new List(); } public bool Equals(ReagentId other) @@ -44,13 +51,13 @@ public partial struct ReagentId : IEquatable if (other.Data == null) return false; - if (Data.GetType() != other.Data.GetType()) + if (Data.Except(other.Data).Any() || other.Data.Except(Data).Any() || Data.Count != other.Data.Count) return false; - return Data.Equals(other.Data); + return true; } - public bool Equals(string prototype, ReagentData? otherData = null) + public bool Equals(string prototype, List? otherData = null) { if (Prototype != prototype) return false; @@ -73,12 +80,12 @@ public partial struct ReagentId : IEquatable public string ToString(FixedPoint2 quantity) { - return Data?.ToString(Prototype, quantity) ?? $"{Prototype}:{quantity}"; + return $"{Prototype}:{quantity}"; } public override string ToString() { - return Data?.ToString(Prototype) ?? Prototype; + return $"{Prototype}"; } public static bool operator ==(ReagentId left, ReagentId right) diff --git a/Content.Shared/Chemistry/Reagent/ReagentPrototype.cs b/Content.Shared/Chemistry/Reagent/ReagentPrototype.cs index fe937b9de4..dba2ba03a3 100644 --- a/Content.Shared/Chemistry/Reagent/ReagentPrototype.cs +++ b/Content.Shared/Chemistry/Reagent/ReagentPrototype.cs @@ -143,7 +143,7 @@ namespace Content.Shared.Chemistry.Reagent [DataField] public SoundSpecifier FootstepSound = new SoundCollectionSpecifier("FootstepWater", AudioParams.Default.WithVolume(6)); - public FixedPoint2 ReactionTile(TileRef tile, FixedPoint2 reactVolume, IEntityManager entityManager) + public FixedPoint2 ReactionTile(TileRef tile, FixedPoint2 reactVolume, IEntityManager entityManager, List? data) { var removed = FixedPoint2.Zero; @@ -152,7 +152,7 @@ namespace Content.Shared.Chemistry.Reagent foreach (var reaction in TileReactions) { - removed += reaction.TileReact(tile, this, reactVolume - removed, entityManager); + removed += reaction.TileReact(tile, this, reactVolume - removed, entityManager, data); if (removed > reactVolume) throw new Exception("Removed more than we have!"); diff --git a/Content.Shared/Chemistry/Reagent/ReagentQuantity.cs b/Content.Shared/Chemistry/Reagent/ReagentQuantity.cs index 9644f919f7..4cc87f5bd7 100644 --- a/Content.Shared/Chemistry/Reagent/ReagentQuantity.cs +++ b/Content.Shared/Chemistry/Reagent/ReagentQuantity.cs @@ -17,7 +17,7 @@ public partial struct ReagentQuantity : IEquatable [ViewVariables] public ReagentId Reagent { get; private set; } - public ReagentQuantity(string reagentId, FixedPoint2 quantity, ReagentData? data) + public ReagentQuantity(string reagentId, FixedPoint2 quantity, List? data = null) : this(new ReagentId(reagentId, data), quantity) { } @@ -37,7 +37,7 @@ public partial struct ReagentQuantity : IEquatable return Reagent.ToString(Quantity); } - public void Deconstruct(out string prototype, out FixedPoint2 quantity, out ReagentData? data) + public void Deconstruct(out string prototype, out FixedPoint2 quantity, out List? data) { prototype = Reagent.Prototype; quantity = Quantity; diff --git a/Content.Shared/Forensics/Events.cs b/Content.Shared/Forensics/Events.cs index 7300b78d76..f7b9475cb5 100644 --- a/Content.Shared/Forensics/Events.cs +++ b/Content.Shared/Forensics/Events.cs @@ -51,3 +51,20 @@ public record struct TransferDnaEvent() /// public bool CanDnaBeCleaned = true; } + +/// +/// An event to generate and act upon new DNA for an entity. +/// +[ByRefEvent] +public record struct GenerateDnaEvent() +{ + /// + /// The entity getting new DNA. + /// + public EntityUid Owner; + + /// + /// The generated DNA. + /// + public string DNA; +} diff --git a/Content.Shared/Forensics/ForensicScannerEvent.cs b/Content.Shared/Forensics/ForensicScannerEvent.cs index ce84b1f7b3..f275680b05 100644 --- a/Content.Shared/Forensics/ForensicScannerEvent.cs +++ b/Content.Shared/Forensics/ForensicScannerEvent.cs @@ -7,7 +7,8 @@ namespace Content.Shared.Forensics { public readonly List Fingerprints = new(); public readonly List Fibers = new(); - public readonly List DNAs = new(); + public readonly List TouchDNAs = new(); + public readonly List SolutionDNAs = new(); public readonly List Residues = new(); public readonly string LastScannedName = string.Empty; public readonly TimeSpan PrintCooldown = TimeSpan.Zero; @@ -16,7 +17,8 @@ namespace Content.Shared.Forensics public ForensicScannerBoundUserInterfaceState( List fingerprints, List fibers, - List dnas, + List touchDnas, + List solutionDnas, List residues, string lastScannedName, TimeSpan printCooldown, @@ -24,7 +26,8 @@ namespace Content.Shared.Forensics { Fingerprints = fingerprints; Fibers = fibers; - DNAs = dnas; + TouchDNAs = touchDnas; + SolutionDNAs = solutionDnas; Residues = residues; LastScannedName = lastScannedName; PrintCooldown = printCooldown; diff --git a/Resources/Locale/en-US/forensics/forensics.ftl b/Resources/Locale/en-US/forensics/forensics.ftl index 29e2db8f78..712e8511bb 100644 --- a/Resources/Locale/en-US/forensics/forensics.ftl +++ b/Resources/Locale/en-US/forensics/forensics.ftl @@ -23,8 +23,10 @@ forensic-scanner-verb-message = Perform a forensic scan forensic-pad-fingerprint-name = {$entity}'s fingerprints forensic-pad-gloves-name = fibers from {$entity} +forensics-dna-unknown = unknown DNA + forensics-verb-text = Remove evidence forensics-verb-message = Remove fingerprints and DNA residues from the object! forensics-cleaning = You begin cleaning the evidence off of {THE($target)}... -forensics-cleaning-cannot-clean = There is nothing cleanable on {THE($target)}! \ No newline at end of file +forensics-cleaning-cannot-clean = There is nothing cleanable on {THE($target)}! diff --git a/Resources/Prototypes/Entities/Effects/puddle.yml b/Resources/Prototypes/Entities/Effects/puddle.yml index 62bb923a61..36f0faa1df 100644 --- a/Resources/Prototypes/Entities/Effects/puddle.yml +++ b/Resources/Prototypes/Entities/Effects/puddle.yml @@ -162,3 +162,6 @@ solution: puddle - type: BadDrink - type: IgnoresFingerprints + - type: Tag + tags: + - DNASolutionScannable diff --git a/Resources/Prototypes/Entities/Objects/Consumable/Drinks/drinks-cartons.yml b/Resources/Prototypes/Entities/Objects/Consumable/Drinks/drinks-cartons.yml index 0c069f615e..9dd3cffbe6 100644 --- a/Resources/Prototypes/Entities/Objects/Consumable/Drinks/drinks-cartons.yml +++ b/Resources/Prototypes/Entities/Objects/Consumable/Drinks/drinks-cartons.yml @@ -42,6 +42,7 @@ #In future maybe add generic plastic scrap trash/debris - type: TrashOnSolutionEmpty solution: drink + - type: DnaSubstanceTrace - type: entity parent: DrinkCartonBaseFull diff --git a/Resources/Prototypes/Entities/Objects/Consumable/Drinks/drinks.yml b/Resources/Prototypes/Entities/Objects/Consumable/Drinks/drinks.yml index c435e6c98f..4a9d5c0463 100644 --- a/Resources/Prototypes/Entities/Objects/Consumable/Drinks/drinks.yml +++ b/Resources/Prototypes/Entities/Objects/Consumable/Drinks/drinks.yml @@ -35,6 +35,7 @@ interfaces: enum.TransferAmountUiKey.Key: type: TransferAmountBoundUserInterface + - type: DnaSubstanceTrace - type: entity parent: DrinkBase diff --git a/Resources/Prototypes/Entities/Objects/Consumable/Drinks/drinks_bottles.yml b/Resources/Prototypes/Entities/Objects/Consumable/Drinks/drinks_bottles.yml index a5f72b8546..8630912451 100644 --- a/Resources/Prototypes/Entities/Objects/Consumable/Drinks/drinks_bottles.yml +++ b/Resources/Prototypes/Entities/Objects/Consumable/Drinks/drinks_bottles.yml @@ -39,6 +39,7 @@ - type: PhysicalComposition materialComposition: Plastic: 100 + - type: DnaSubstanceTrace - type: PressurizedSolution solution: drink - type: Shakeable diff --git a/Resources/Prototypes/Entities/Objects/Consumable/Drinks/drinks_cans.yml b/Resources/Prototypes/Entities/Objects/Consumable/Drinks/drinks_cans.yml index b6488dbe8b..f5b733d37b 100644 --- a/Resources/Prototypes/Entities/Objects/Consumable/Drinks/drinks_cans.yml +++ b/Resources/Prototypes/Entities/Objects/Consumable/Drinks/drinks_cans.yml @@ -66,6 +66,7 @@ - type: Tag tags: - DrinkCan + - type: DnaSubstanceTrace - type: entity parent: DrinkCanBaseFull diff --git a/Resources/Prototypes/Entities/Objects/Consumable/Drinks/drinks_cups.yml b/Resources/Prototypes/Entities/Objects/Consumable/Drinks/drinks_cups.yml index d13c9ad2ca..f0103cc219 100644 --- a/Resources/Prototypes/Entities/Objects/Consumable/Drinks/drinks_cups.yml +++ b/Resources/Prototypes/Entities/Objects/Consumable/Drinks/drinks_cups.yml @@ -38,6 +38,7 @@ damage: types: Blunt: 0 + - type: DnaSubstanceTrace - type: entity parent: DrinkBaseCup diff --git a/Resources/Prototypes/Entities/Objects/Consumable/Drinks/drinks_special.yml b/Resources/Prototypes/Entities/Objects/Consumable/Drinks/drinks_special.yml index dfb6ac31c0..930cf81757 100644 --- a/Resources/Prototypes/Entities/Objects/Consumable/Drinks/drinks_special.yml +++ b/Resources/Prototypes/Entities/Objects/Consumable/Drinks/drinks_special.yml @@ -34,6 +34,7 @@ - type: PhysicalComposition materialComposition: Steel: 50 + - type: DnaSubstanceTrace - type: ReactionMixer mixOnInteract: false reactionTypes: diff --git a/Resources/Prototypes/Entities/Objects/Consumable/Drinks/trash_drinks.yml b/Resources/Prototypes/Entities/Objects/Consumable/Drinks/trash_drinks.yml index 9f94be9576..eadeeabd74 100644 --- a/Resources/Prototypes/Entities/Objects/Consumable/Drinks/trash_drinks.yml +++ b/Resources/Prototypes/Entities/Objects/Consumable/Drinks/trash_drinks.yml @@ -76,6 +76,7 @@ materialComposition: Glass: 100 - type: SpaceGarbage + - type: DnaSubstanceTrace - type: entity name: base empty bottle diff --git a/Resources/Prototypes/Entities/Objects/Specific/Janitorial/janitor.yml b/Resources/Prototypes/Entities/Objects/Specific/Janitorial/janitor.yml index 2a6f314904..ccb7900810 100644 --- a/Resources/Prototypes/Entities/Objects/Specific/Janitorial/janitor.yml +++ b/Resources/Prototypes/Entities/Objects/Specific/Janitorial/janitor.yml @@ -50,6 +50,7 @@ - type: GuideHelp guides: - Janitorial + - type: DnaSubstanceTrace - type: entity parent: BaseItem @@ -109,6 +110,7 @@ tags: - Mop - MopAdv + - type: DnaSubstanceTrace - type: entity name: wet floor sign @@ -332,3 +334,4 @@ - type: CleansForensics - type: Fiber fiberColor: fibers-white + - type: DnaSubstanceTrace diff --git a/Resources/Prototypes/Entities/Objects/Specific/chemical-containers.yml b/Resources/Prototypes/Entities/Objects/Specific/chemical-containers.yml index fd931a05c7..d1020ff609 100644 --- a/Resources/Prototypes/Entities/Objects/Specific/chemical-containers.yml +++ b/Resources/Prototypes/Entities/Objects/Specific/chemical-containers.yml @@ -82,6 +82,7 @@ - type: Tag tags: - ChemDispensable + - type: DnaSubstanceTrace - type: entity parent: Jug diff --git a/Resources/Prototypes/Entities/Objects/Specific/chemistry-bottles.yml b/Resources/Prototypes/Entities/Objects/Specific/chemistry-bottles.yml index 6fdb77fe5f..f8f55cf8fc 100644 --- a/Resources/Prototypes/Entities/Objects/Specific/chemistry-bottles.yml +++ b/Resources/Prototypes/Entities/Objects/Specific/chemistry-bottles.yml @@ -93,6 +93,7 @@ transferForensics: true - !type:DoActsBehavior acts: [ "Destruction" ] + - type: DnaSubstanceTrace - type: entity parent: BaseChemistryEmptyBottle diff --git a/Resources/Prototypes/Entities/Objects/Specific/chemistry-vials.yml b/Resources/Prototypes/Entities/Objects/Specific/chemistry-vials.yml index 39a35dba8c..eca666ca4f 100644 --- a/Resources/Prototypes/Entities/Objects/Specific/chemistry-vials.yml +++ b/Resources/Prototypes/Entities/Objects/Specific/chemistry-vials.yml @@ -101,6 +101,7 @@ acts: [ "Destruction" ] - type: Spillable solution: beaker + - type: DnaSubstanceTrace - type: entity id: VestineChemistryVial diff --git a/Resources/Prototypes/Entities/Objects/Specific/chemistry.yml b/Resources/Prototypes/Entities/Objects/Specific/chemistry.yml index c888559bc3..72f612436b 100644 --- a/Resources/Prototypes/Entities/Objects/Specific/chemistry.yml +++ b/Resources/Prototypes/Entities/Objects/Specific/chemistry.yml @@ -92,6 +92,7 @@ Blunt: 5 - type: StaticPrice price: 30 + - type: DnaSubstanceTrace - type: entity parent: BaseItem @@ -153,6 +154,7 @@ damageModifierSet: Glass - type: StaticPrice price: 30 + - type: DnaSubstanceTrace - type: entity name: beaker @@ -303,6 +305,7 @@ inHandsFillBaseName: -fill- - type: StaticPrice price: 40 + - type: DnaSubstanceTrace - type: Tag tags: - Dropper diff --git a/Resources/Prototypes/Entities/Objects/Tools/bucket.yml b/Resources/Prototypes/Entities/Objects/Tools/bucket.yml index 58c8dae2b0..b64aa3a041 100644 --- a/Resources/Prototypes/Entities/Objects/Tools/bucket.yml +++ b/Resources/Prototypes/Entities/Objects/Tools/bucket.yml @@ -67,3 +67,4 @@ - type: PhysicalComposition materialComposition: Plastic: 50 + - type: DnaSubstanceTrace diff --git a/Resources/Prototypes/Entities/Structures/Specific/Janitor/janicart.yml b/Resources/Prototypes/Entities/Structures/Specific/Janitor/janicart.yml index 9fd05beaee..6ed06addcd 100644 --- a/Resources/Prototypes/Entities/Structures/Specific/Janitor/janicart.yml +++ b/Resources/Prototypes/Entities/Structures/Specific/Janitor/janicart.yml @@ -84,6 +84,7 @@ behaviors: - !type:DoActsBehavior acts: ["Destruction"] + - type: DnaSubstanceTrace - type: Fixtures fixtures: fix1: @@ -334,3 +335,4 @@ - type: GuideHelp guides: - Janitorial + - type: DnaSubstanceTrace diff --git a/Resources/Prototypes/tags.yml b/Resources/Prototypes/tags.yml index 197966b491..adf25cc71d 100644 --- a/Resources/Prototypes/tags.yml +++ b/Resources/Prototypes/tags.yml @@ -509,6 +509,9 @@ - type: Tag id: DiscreteHealthAnalyzer #So construction recipes don't eat medical PDAs +- type: Tag + id: DNASolutionScannable + - type: Tag id: DockArrivals From 0423691d7607b3241aab00fbb755276251c04e20 Mon Sep 17 00:00:00 2001 From: PJBot Date: Thu, 8 Aug 2024 23:28:34 +0000 Subject: [PATCH 027/174] Automatic changelog update --- Resources/Changelog/Changelog.yml | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index ba53573989..d904094e88 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,12 +1,4 @@ Entries: -- author: vorkathbruh - changes: - - message: Nuclear operative agents now require time in Chemistry rather than time - in the Medical department. - type: Tweak - id: 6564 - time: '2024-05-09T06:48:53.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/27098 - author: deltanedas changes: - message: Firesuits and hardsuits now protect your skin from fire, you will instead @@ -3785,3 +3777,19 @@ id: 7063 time: '2024-08-08T22:50:57.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/30671 +- author: SlamBamActionman + changes: + - message: Animal DNA now shows up as "unknown DNA" in the Forensic Scanner. + type: Tweak + - message: Forensic Scanner can now scan fluid containers for DNA in reagents. + type: Tweak + - message: Fluids keep their DNA data when moved. + type: Fix + - message: Fluids now stain containers they're in with DNA. Make sure to scrub your + blood bucket after use! + type: Add + - message: Vomit now includes DNA! + type: Add + id: 7064 + time: '2024-08-08T23:27:28.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/26699 From 1b1008ad8593ac4d357c06ed200dc2aec243cef4 Mon Sep 17 00:00:00 2001 From: Nemanja <98561806+EmoGarbage404@users.noreply.github.com> Date: Thu, 8 Aug 2024 19:31:53 -0400 Subject: [PATCH 028/174] Scrap (#30762) * jnk sprites * scrap pt 2 * metal inhands * hell yeah brudda * Update meta.json * Update scrap.yml --------- Co-authored-by: Flareguy <78941145+Flareguy@users.noreply.github.com> --- .../Entities/Objects/Materials/scrap.yml | 408 ++++++++++++++++++ .../Scrap/generic.rsi/airlock-inhand-left.png | Bin 0 -> 619 bytes .../generic.rsi/airlock-inhand-right.png | Bin 0 -> 593 bytes .../Scrap/generic.rsi/closet-inhand-left.png | Bin 0 -> 436 bytes .../Scrap/generic.rsi/closet-inhand-right.png | Bin 0 -> 436 bytes .../generic.rsi/firelock-1-inhand-left.png | Bin 0 -> 484 bytes .../generic.rsi/firelock-1-inhand-right.png | Bin 0 -> 484 bytes .../generic.rsi/firelock-2-inhand-left.png | Bin 0 -> 579 bytes .../generic.rsi/firelock-2-inhand-right.png | Bin 0 -> 593 bytes .../Materials/Scrap/generic.rsi/glass-1.png | Bin 0 -> 758 bytes .../Materials/Scrap/generic.rsi/glass-2.png | Bin 0 -> 1046 bytes .../Materials/Scrap/generic.rsi/glass-3.png | Bin 0 -> 919 bytes .../Materials/Scrap/generic.rsi/glass-4.png | Bin 0 -> 969 bytes .../Materials/Scrap/generic.rsi/glass-5.png | Bin 0 -> 854 bytes .../Materials/Scrap/generic.rsi/glass-6.png | Bin 0 -> 1075 bytes .../Scrap/generic.rsi/glass-inhand-left.png | Bin 0 -> 690 bytes .../Scrap/generic.rsi/glass-inhand-right.png | Bin 0 -> 683 bytes .../Scrap/generic.rsi/jetpack-inhand-left.png | Bin 0 -> 325 bytes .../generic.rsi/jetpack-inhand-right.png | Bin 0 -> 337 bytes .../Scrap/generic.rsi/junk-airlock-1.png | Bin 0 -> 1052 bytes .../Scrap/generic.rsi/junk-airlock-2.png | Bin 0 -> 561 bytes .../Scrap/generic.rsi/junk-airlock-3.png | Bin 0 -> 289 bytes .../Scrap/generic.rsi/junk-bucket.png | Bin 0 -> 487 bytes .../Scrap/generic.rsi/junk-camera.png | Bin 0 -> 540 bytes .../Scrap/generic.rsi/junk-canister-1.png | Bin 0 -> 276 bytes .../Scrap/generic.rsi/junk-canister-2.png | Bin 0 -> 273 bytes .../Scrap/generic.rsi/junk-closet.png | Bin 0 -> 809 bytes .../Materials/Scrap/generic.rsi/junk-fax.png | Bin 0 -> 751 bytes .../generic.rsi/junk-fireextinguisher.png | Bin 0 -> 508 bytes .../Scrap/generic.rsi/junk-firelock-1.png | Bin 0 -> 989 bytes .../Scrap/generic.rsi/junk-firelock-2.png | Bin 0 -> 1085 bytes .../Scrap/generic.rsi/junk-firelock-3.png | Bin 0 -> 506 bytes .../Scrap/generic.rsi/junk-intercom-1.png | Bin 0 -> 528 bytes .../Scrap/generic.rsi/junk-intercom-2.png | Bin 0 -> 472 bytes .../Scrap/generic.rsi/junk-intercom-3.png | Bin 0 -> 326 bytes .../Scrap/generic.rsi/junk-jetpack.png | Bin 0 -> 577 bytes .../Scrap/generic.rsi/junk-medkit-1.png | Bin 0 -> 528 bytes .../Scrap/generic.rsi/junk-medkit-2.png | Bin 0 -> 859 bytes .../Scrap/generic.rsi/junk-mop-bucket.png | Bin 0 -> 666 bytes .../Scrap/generic.rsi/junk-pai-gold.png | Bin 0 -> 782 bytes .../Materials/Scrap/generic.rsi/junk-pai.png | Bin 0 -> 972 bytes .../Scrap/generic.rsi/junk-target.png | Bin 0 -> 495 bytes .../Materials/Scrap/generic.rsi/meta.json | 181 ++++++++ .../Materials/Scrap/generic.rsi/metal-1.png | Bin 0 -> 739 bytes .../Materials/Scrap/generic.rsi/metal-2.png | Bin 0 -> 670 bytes .../Materials/Scrap/generic.rsi/metal-3.png | Bin 0 -> 673 bytes .../Scrap/generic.rsi/metal-inhand-left.png | Bin 0 -> 682 bytes .../Scrap/generic.rsi/metal-inhand-right.png | Bin 0 -> 682 bytes .../Materials/Scrap/generic.rsi/tube-bk.png | Bin 0 -> 328 bytes .../Materials/Scrap/generic.rsi/tube-bl.png | Bin 0 -> 330 bytes .../Materials/Scrap/generic.rsi/tube-g.png | Bin 0 -> 314 bytes .../Materials/Scrap/generic.rsi/tube-r.png | Bin 0 -> 334 bytes .../Materials/Scrap/generic.rsi/tube-y.png | Bin 0 -> 313 bytes .../Materials/Scrap/generic.rsi/tube.png | Bin 0 -> 262 bytes 54 files changed, 589 insertions(+) create mode 100644 Resources/Prototypes/Entities/Objects/Materials/scrap.yml create mode 100644 Resources/Textures/Objects/Materials/Scrap/generic.rsi/airlock-inhand-left.png create mode 100644 Resources/Textures/Objects/Materials/Scrap/generic.rsi/airlock-inhand-right.png create mode 100644 Resources/Textures/Objects/Materials/Scrap/generic.rsi/closet-inhand-left.png create mode 100644 Resources/Textures/Objects/Materials/Scrap/generic.rsi/closet-inhand-right.png create mode 100644 Resources/Textures/Objects/Materials/Scrap/generic.rsi/firelock-1-inhand-left.png create mode 100644 Resources/Textures/Objects/Materials/Scrap/generic.rsi/firelock-1-inhand-right.png create mode 100644 Resources/Textures/Objects/Materials/Scrap/generic.rsi/firelock-2-inhand-left.png create mode 100644 Resources/Textures/Objects/Materials/Scrap/generic.rsi/firelock-2-inhand-right.png create mode 100644 Resources/Textures/Objects/Materials/Scrap/generic.rsi/glass-1.png create mode 100644 Resources/Textures/Objects/Materials/Scrap/generic.rsi/glass-2.png create mode 100644 Resources/Textures/Objects/Materials/Scrap/generic.rsi/glass-3.png create mode 100644 Resources/Textures/Objects/Materials/Scrap/generic.rsi/glass-4.png create mode 100644 Resources/Textures/Objects/Materials/Scrap/generic.rsi/glass-5.png create mode 100644 Resources/Textures/Objects/Materials/Scrap/generic.rsi/glass-6.png create mode 100644 Resources/Textures/Objects/Materials/Scrap/generic.rsi/glass-inhand-left.png create mode 100644 Resources/Textures/Objects/Materials/Scrap/generic.rsi/glass-inhand-right.png create mode 100644 Resources/Textures/Objects/Materials/Scrap/generic.rsi/jetpack-inhand-left.png create mode 100644 Resources/Textures/Objects/Materials/Scrap/generic.rsi/jetpack-inhand-right.png create mode 100644 Resources/Textures/Objects/Materials/Scrap/generic.rsi/junk-airlock-1.png create mode 100644 Resources/Textures/Objects/Materials/Scrap/generic.rsi/junk-airlock-2.png create mode 100644 Resources/Textures/Objects/Materials/Scrap/generic.rsi/junk-airlock-3.png create mode 100644 Resources/Textures/Objects/Materials/Scrap/generic.rsi/junk-bucket.png create mode 100644 Resources/Textures/Objects/Materials/Scrap/generic.rsi/junk-camera.png create mode 100644 Resources/Textures/Objects/Materials/Scrap/generic.rsi/junk-canister-1.png create mode 100644 Resources/Textures/Objects/Materials/Scrap/generic.rsi/junk-canister-2.png create mode 100644 Resources/Textures/Objects/Materials/Scrap/generic.rsi/junk-closet.png create mode 100644 Resources/Textures/Objects/Materials/Scrap/generic.rsi/junk-fax.png create mode 100644 Resources/Textures/Objects/Materials/Scrap/generic.rsi/junk-fireextinguisher.png create mode 100644 Resources/Textures/Objects/Materials/Scrap/generic.rsi/junk-firelock-1.png create mode 100644 Resources/Textures/Objects/Materials/Scrap/generic.rsi/junk-firelock-2.png create mode 100644 Resources/Textures/Objects/Materials/Scrap/generic.rsi/junk-firelock-3.png create mode 100644 Resources/Textures/Objects/Materials/Scrap/generic.rsi/junk-intercom-1.png create mode 100644 Resources/Textures/Objects/Materials/Scrap/generic.rsi/junk-intercom-2.png create mode 100644 Resources/Textures/Objects/Materials/Scrap/generic.rsi/junk-intercom-3.png create mode 100644 Resources/Textures/Objects/Materials/Scrap/generic.rsi/junk-jetpack.png create mode 100644 Resources/Textures/Objects/Materials/Scrap/generic.rsi/junk-medkit-1.png create mode 100644 Resources/Textures/Objects/Materials/Scrap/generic.rsi/junk-medkit-2.png create mode 100644 Resources/Textures/Objects/Materials/Scrap/generic.rsi/junk-mop-bucket.png create mode 100644 Resources/Textures/Objects/Materials/Scrap/generic.rsi/junk-pai-gold.png create mode 100644 Resources/Textures/Objects/Materials/Scrap/generic.rsi/junk-pai.png create mode 100644 Resources/Textures/Objects/Materials/Scrap/generic.rsi/junk-target.png create mode 100644 Resources/Textures/Objects/Materials/Scrap/generic.rsi/meta.json create mode 100644 Resources/Textures/Objects/Materials/Scrap/generic.rsi/metal-1.png create mode 100644 Resources/Textures/Objects/Materials/Scrap/generic.rsi/metal-2.png create mode 100644 Resources/Textures/Objects/Materials/Scrap/generic.rsi/metal-3.png create mode 100644 Resources/Textures/Objects/Materials/Scrap/generic.rsi/metal-inhand-left.png create mode 100644 Resources/Textures/Objects/Materials/Scrap/generic.rsi/metal-inhand-right.png create mode 100644 Resources/Textures/Objects/Materials/Scrap/generic.rsi/tube-bk.png create mode 100644 Resources/Textures/Objects/Materials/Scrap/generic.rsi/tube-bl.png create mode 100644 Resources/Textures/Objects/Materials/Scrap/generic.rsi/tube-g.png create mode 100644 Resources/Textures/Objects/Materials/Scrap/generic.rsi/tube-r.png create mode 100644 Resources/Textures/Objects/Materials/Scrap/generic.rsi/tube-y.png create mode 100644 Resources/Textures/Objects/Materials/Scrap/generic.rsi/tube.png diff --git a/Resources/Prototypes/Entities/Objects/Materials/scrap.yml b/Resources/Prototypes/Entities/Objects/Materials/scrap.yml new file mode 100644 index 0000000000..6530e3b170 --- /dev/null +++ b/Resources/Prototypes/Entities/Objects/Materials/scrap.yml @@ -0,0 +1,408 @@ +- type: entity + parent: BaseItem + id: BaseScrap + abstract: true + name: scrap + description: Worthless junk. You could probably get some materials out of it though. + suffix: Scrap + components: + - type: Sprite + sprite: Objects/Materials/Scrap/generic.rsi + - type: Item + sprite: Objects/Materials/Scrap/generic.rsi + size: Normal + - type: Damageable + damageContainer: Inorganic + damageModifierSet: FlimsyMetallic + - type: Destructible + thresholds: + - trigger: + !type:DamageTrigger + damage: 150 + behaviors: + - !type:DoActsBehavior + acts: [ "Destruction" ] + - type: Tag + tags: + - Recyclable + +- type: entity + parent: BaseScrap + id: ScrapSteel + name: blasted steel pile + description: An pile of steel welded together in extreme heat. It's of a decent size overall; you could probably get a fair amount of sheets out of it. + components: + - type: Sprite + layers: + - state: metal-1 + map: [ "base" ] + - type: Item + size: Ginormous + heldPrefix: metal + - type: MultiHandedItem + - type: RandomSprite + available: + - base: + metal-1: "" + metal-2: "" + metal-3: "" + - type: PhysicalComposition + materialComposition: + Steel: 3000 # 30 sheets + +- type: entity + parent: BaseScrap + id: ScrapGlass + name: scrap circuitry + description: A huge lump of various circuits, strangely fused together. You could likely extract some materials out of this. + components: + - type: Sprite + layers: + - state: glass-1 + map: [ "base" ] + - type: Item + heldPrefix: "glass" + size: Large + shape: + - 0,0,2,2 # 3x3 + - type: RandomSprite + available: + - base: + glass-1: "" + glass-2: "" + glass-3: "" + glass-4: "" + glass-5: "" + glass-6: "" + - type: PhysicalComposition + materialComposition: + Glass: 1500 # 15 sheets + Steel: 500 # 5 sheets + +- type: entity + parent: BaseScrap + id: ScrapAirlock1 + name: airlock door + description: This used to keep air in. Now it doesn't seem to be doing anything at all. + components: + - type: Sprite + layers: + - state: junk-airlock-1 + map: [ "base" ] + - type: RandomSprite + available: + - base: + junk-airlock-1: "" + junk-airlock-2: "" + - type: Item + size: Ginormous + heldPrefix: "airlock" + - type: MultiHandedItem + - type: PhysicalComposition + materialComposition: + Steel: 1500 # 15 sheets + +- type: entity + parent: BaseScrap + id: ScrapAirlock2 + name: airlock light + description: Serves it right for flashing red all those times. + components: + - type: Sprite + layers: + - state: junk-airlock-3 + - type: Item + size: Normal + shape: + - 0,0,3,0 + - type: PhysicalComposition + materialComposition: + Steel: 200 # 2 sheets + Glass: 500 # 5 sheets + +- type: entity + parent: BaseScrap + id: ScrapBucket + name: busted bucket + description: Dear god... + components: + - type: Sprite + layers: + - state: junk-bucket + - type: PhysicalComposition + materialComposition: + Plastic: 300 # 3 sheets + +- type: entity + parent: BaseScrap + id: ScrapCamera + name: broken camera + description: It might still be watching. + components: + - type: Sprite + layers: + - state: junk-camera + - type: PhysicalComposition + materialComposition: + Steel: 500 # 5 sheets + Glass: 100 # 1 sheet + +- type: entity + parent: BaseScrap + id: ScrapCanister1 + name: canister handle + description: Helpful for holding a canister. Now you just need the actual canister part. + components: + - type: Sprite + layers: + - state: junk-canister-1 + - type: PhysicalComposition + materialComposition: + Steel: 300 # 3 sheets + +- type: entity + parent: BaseScrap + id: ScrapCanister2 + name: canister valve + description: A valve from a gas canister. + components: + - type: Sprite + layers: + - state: junk-canister-2 + - type: Item + size: Small + - type: PhysicalComposition + materialComposition: + Steel: 200 # 2 sheets + +- type: entity + parent: BaseScrap + id: ScrapCloset + name: closet door + description: A blown off door from a maintenance closet. Looks like a nice piece of wall decor. + components: + - type: Sprite + layers: + - state: junk-closet + - type: MultiHandedItem + - type: Item + heldPrefix: closet + size: Huge + shape: + - 0,0,5,2 + - type: PhysicalComposition + materialComposition: + Steel: 1500 # 15 sheets + +- type: entity + parent: BaseScrap + id: ScrapFaxMachine + name: fax machine + description: The unfortunate result of one too many ASCII arts being sent to Central Command. + components: + - type: Sprite + layers: + - state: junk-fax + - type: Item + size: Huge + - type: PhysicalComposition + materialComposition: + Plastic: 800 # 8 sheets + Steel: 200 # 2 sheets + +- type: entity + parent: BaseScrap + id: ScrapFireExtinguisher + name: split fire extinguisher + description: The large gash down the center makes you worry for the previous user. + components: + - type: Sprite + layers: + - state: junk-fireextinguisher + - type: PhysicalComposition + materialComposition: + Steel: 600 # 6 sheets + +- type: entity + parent: BaseScrap + id: ScrapFirelock1 + name: firelock door + description: At least you still know what it's meant for. + components: + - type: Sprite + layers: + - state: junk-firelock-1 + - type: Item + size: Ginormous + heldPrefix: firelock-1 + - type: MultiHandedItem + - type: PhysicalComposition + materialComposition: + Steel: 2000 # 20 sheets + +- type: entity + parent: BaseScrap + id: ScrapFirelock2 + name: firelock door + description: OH! That's where the other half went! + components: + - type: Sprite + layers: + - state: junk-firelock-2 + - type: Item + size: Ginormous + heldPrefix: firelock-2 + - type: MultiHandedItem + - type: PhysicalComposition + materialComposition: + Steel: 2000 # 20 sheets + +- type: entity + parent: BaseScrap + id: ScrapFirelock3 + name: firelock frame + components: + - type: Sprite + layers: + - state: junk-firelock-3 + - type: Item + size: Large + - type: PhysicalComposition + materialComposition: + Steel: 700 # 7 sheets + +- type: entity + parent: BaseScrap + id: ScrapIntercom + name: intercom scrap + description: You wish it at least came with some encryption keys. + components: + - type: Sprite + layers: + - state: junk-intercom-1 + map: [ "base" ] + - type: RandomSprite + available: + - base: + junk-intercom-1: "" + junk-intercom-2: "" + junk-intercom-3: "" + - type: Item + - type: PhysicalComposition + materialComposition: + Steel: 400 # 4 sheets + Plastic: 300 # 3 sheets + +- type: entity + parent: BaseScrap + id: ScrapJetpack + name: busted jetpack + description: Looks like it won't be flying any more. + components: + - type: Sprite + layers: + - state: junk-jetpack + - type: Item + size: Huge + heldPrefix: jetpack + - type: PhysicalComposition + materialComposition: + Steel: 1000 # 10 sheets + Plastic: 200 # 2 sheets + +- type: entity + parent: BaseScrap + id: ScrapMedkit + name: snapped medkit + description: Hopefully they got some use out of it. + components: + - type: Sprite + layers: + - state: junk-medkit-1 + map: [ "base" ] + - type: RandomSprite + available: + - base: + junk-medkit-1: "" + junk-medkit-2: "" + - type: Item + size: Large + - type: PhysicalComposition + materialComposition: + Plastic: 500 # 5 sheets + +- type: entity + parent: BaseScrap + id: ScrapMopBucket + name: half a mop bucket + description: Tiders die. Janitors survive. + components: + - type: Sprite + layers: + - state: junk-mop-bucket + - type: Item + size: Huge + - type: PhysicalComposition + materialComposition: + Plastic: 1500 # 15 sheets + +- type: entity + parent: BaseScrap + id: ScrapPAI + name: personal ai device + description: A buddy! You still in there? Hello? Buddy??? + components: + - type: Sprite + layers: + - state: junk-pai + - type: Item + size: Small + - type: PhysicalComposition + materialComposition: + Steel: 300 # 3 sheets + Plastic: 200 # 2 sheets + +- type: entity + parent: BaseScrap + id: ScrapPAIGold + name: gilded personal ai device + description: Wow! What a one-in-a-million find! This would be worth a fortune... if it was in good condition. + components: + - type: Sprite + layers: + - state: junk-pai-gold + - type: Item + size: Small + - type: PhysicalComposition + materialComposition: + Gold: 100 # 1 sheet + Plastic: 400 # 4 sheets + +- type: entity + parent: BaseScrap + id: ScrapTube + name: shattered sample tube + description: A glass tube containing some kind of rare sample. Or at least, it used to contain it. Not much left in there now. + components: + - type: Sprite + layers: + - state: tube + map: [ "base" ] + - type: RandomSprite + available: + - base: + tube: "" + tube-bl: "" + tube-bk: "" + tube-g: "" + tube-r: "" + tube-y: "" + - type: Item + size: Small + - type: PhysicalComposition + materialComposition: + Glass: 500 # 5 sheets + Plastic: 100 # 1 sheet + + + diff --git a/Resources/Textures/Objects/Materials/Scrap/generic.rsi/airlock-inhand-left.png b/Resources/Textures/Objects/Materials/Scrap/generic.rsi/airlock-inhand-left.png new file mode 100644 index 0000000000000000000000000000000000000000..1302edea02da183030ec3b7ca1eadc2286f829ee GIT binary patch literal 619 zcmV-x0+juUP)Px%B}qgi1 zDo>F(^P>=K1KQcu`6@)rz4iq`Bwv7th=_=Y=ng5p562$x0HC$@TI<{SkH>h1$3Nuf z+z(+<)(Rn|_roAWIB$%>G)=&@AW}*I@YY&^7YIDV;|1b9h83w3TXStnjM)MJfH4LD z{4`yH{koo;rU_M5K}w0TEKyYz%CZEm1+lQuT6?7wPN!4u{9%lNwRY9@ecwMEGh3Ok z003~#-4SJing(6hZ8k3W5i>}&xJ0s!+p1H&-nhFq05w;v(-B^Z2%o`EeSKLOTS@$~fM|IAc;&z)Iot&mdQec4?* zLy~i^p6u72fxY_!w$8We;(MQ-z4zw-MouCkA|m=9y#dPx%3rR#lRCt{2+P`kAFcb#xkLoU##hSqz1EMo)rrbwi=tJEhufiK-w-~aa?8u5b z`3}UnO;v+!pw(@^-;#gE$3C`56d!K^-psfO48s6p45XCU?RJx$ zU9Z=N_5jdzUGffCvihO@Ozr?71TL2g0Kgc7^Z6Vc*cgMNDA09X@HJBohl6d~b~YiQ z?VQO3I7Lx}_IDSPtk5yEZM#}K=V{5He6rWq)%!dik3p*%+RmA6+%%0%Sabc05=d{&A?ix!9G*<2r2y~C7>)zs7^tak2M2Ah|Loq zgn$qNz*qn=)+79elx0%vqy!ja?vHC9gU|8Bb7P8?lmNhAGtl>aYL|=RrY^)L^#Px4 zNj*aJ4$xX>`~BWqGqB~!tkybHN_}{YpU$Z2y;bG|y?|DW@FqU)qTKi90v&R82L z!uo8pWZbc2h691wCb``n96-Y6{Q9@Q&)R(bdCA4A=3UwI*V!_Ub^A7YO#1vlJ?PPd z)ER!uEm9#plXQ-Z8?Z=d4~@S5x6 z{b0q{pHWx0dhgwxe3!*nn4#u9v+revE+rQyiTOY5eE0r8wlETCmfDW*2ZaR@;G%M& z-L6-~A!4sQbX;Gki=EOZv!zRukR2)_8&GODP} W+w|fq&v9ThFnGH9xvX1R!!14l?{uLDQV zQWl0eTiiC@Pd1zF=+)^dVRkF;^PO$){XgebDF`s_UgRKi{Dvs&GA~AkV?jw1Reo?d z`y3LuKbv=%SL}K{p2)xJ-u4O?M1I`&eS4){1;h3!L36hy&sw&3+uA}VIm>CPeo@Q^ zzE)*VRPo!VxKGl)saqxUPu(S{(AdSRv{)Pq%KtOJ`_F18VQrow`v2F1POzgP#EYq4 z>~_5>3VHV0bP0l+XkK&xOMz literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Materials/Scrap/generic.rsi/firelock-1-inhand-left.png b/Resources/Textures/Objects/Materials/Scrap/generic.rsi/firelock-1-inhand-left.png new file mode 100644 index 0000000000000000000000000000000000000000..455c336b4aac444a4b8d92bc37a4745a78e6f2b0 GIT binary patch literal 484 zcmVPx$o=HSORCt{2+98jFFcb&y$Ax6UA(vn$P}8%s=TTE<$Ymesa&GF(&7b8vOij!# znZ!-LQ{_lUOX(|Y%l&_ft)-7XD2P5H000000DylevNdkAjHLlS&Sz^3m-s$oxSnfl z+-4aslVoVz8;9%FdjiWOq4(3tJAt2z1^2~|`v%!mRdf8cUN^tn$6f8}w}fQ!>ioW^ z_{DWF+hn@hq?6a}^4w`Ty7p6?6QJL1y-lC6t^Xql_5^e-hmhWmN2lfB+E1}2puGlX zaZI!L@0HO$?y{*W@fx1OpbOmPIsaTP#`f3weDEE38bz9Nk)}*U#6-6*nv%HPXN>qE z`-yZWfQYCx{0{&C0000000000@DRKE`ol6ru9#P;5|H}S0pxL54n`T!GC-N0eB z@*Q$e+)%X$&bz}Vp?86O;z_PSoPeq807BOyJmnJ*vKC=*0`!-RUNpEg0jshgLS4muar%l|^Px$o=HSORCt{2+98jFFcb&y$Ax6UA(vn$P}8%s=TTE<$Ymesa&GF(&7b8vOij!# znZ!-LQ{_lUOX(|Y%l&_ft)-7XD2P5H000000DylevNdkAjHLlS&Sz^3m-s$oxSnfl z+-4aslVoVz8;9%FdjiWOq4(3tJAt2z1^2~|`v%!mRdf8cUN^tn$6f8}w}fQ!>ioW^ z_{DWF+hn@hq?6a}^4w`Ty7p6?6QJL1y-lC6t^Xql_5^e-hmhWmN2lfB+E1}2puGlX zaZI!L@0HO$?y{*W@fx1OpbOmPIsaTP#`f3weDEE38bz9Nk)}*U#6-6*nv%HPXN>qE z`-yZWfQYCx{0{&C0000000000@DRKE`ol6ru9#P;5|H}S0pxL54n`T!GC-N0eB z@*Q$e+)%X$&bz}Vp?86O;z_PSoPeq807BOyJmnJ*vKC=*0`!-RUNpEg0jshgLS4muar%l|^Px${YgYYRCt{2+A&MRKoke?f2lh*x7xua{hEi~fI5Xs*e|$4;<@*4DVH~3t1OR}JQr{BQo1-_%)m0REF4vz81~acWZUB%Z zrIXQ#r^j2q|82Y$1gHf8hH+eI(bHV->{#6mw&!UxH(*jaS=0Em^Onu3>BD-p;xu`^ zT1Efq#c2-hxYx7#I@q4488=|}{1JPdIsoAA@)=v(@7Ua5w?5uIeD%tBnlFuq+cg>8 zS0oHW3Bypbju*YgysU4Ri=&Ela;GNl0yi%{q*VC)+h6@s^1W?E!WJ^)fO0Dtlx RNY4NO002ovPDHLkV1hWv4Rrtj literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Materials/Scrap/generic.rsi/firelock-2-inhand-right.png b/Resources/Textures/Objects/Materials/Scrap/generic.rsi/firelock-2-inhand-right.png new file mode 100644 index 0000000000000000000000000000000000000000..c0edb2ae167e69672e792661dcc5259ee2fe4da9 GIT binary patch literal 593 zcmV-X0Px%3rR#lRCt{2+96NFKoke?|1l74GBE^Ac2r@e_96HLC=3dN=md_0uYd=ELE*3n z4B;DqA%TPt64EKcT&Kvxa9tT)d+W6sf&VXAvb$dI-Ceqhy$28x5fKp)(L|)RL|O{~ zbh{$ceFDhz*zEP}HP`qq%H~)ux)_RlO|TApO=S9194i52pfy4fbbKG9B*Cjvz#asr zP_7#Y#clsK@t4X5^gR!u2tpC`Juh8Yq_qsR27q+)W_)z15os-Ed{u|Tp>nzZB#uk( zFFk-!lAz=J==grx*YSPyJum%a`vLsuuftidXZ1MPjx$ORAiMFrc3J;#SNIOt2-@xu z#_m%9!0y9?)z86poKbiH+qaME{$fQo2de;pm#a5CKP|zweSQ3noBg$U*7LjFU#v(F z1QG;+jPF{K*Ix7*=Vkr49PPBMH+OLU;q>;N72jrF+i^rhL_|bHL_|bHME}s-|DT(b z^GO`5ZdYVDRNvCzHW^u0(`j#)n5D_lJSIK9rPkBMnDluaMGdnEAd%K$Vx{#1dq@j7 z=AE-JH&~?ad1+06$qbK@1W?UA07dl((5Q6qm7W0LXWf8lH?8h^gvtkCTQ|^@y5d#( z2^7{1)Km{J%WAu|u-KD0IjM2;z3JFRDf*^k=gKZ(d}p6Rud42P1gBSaUd=$$x%oxJ fBqAarqQB@9phWoWIePx%ut`KgR9J=WmOoG1Kp4hB5K0zhquqTTL!cx`>sbX;U$`u;}TO`yy zUg*Nw2|9!!`2ew0bzo+&f|6_c1*r6PIG^o+<0fUP)I8GZ{O`T@x#!+{e6YqE|2tIC z!@*#%Fre9NmJirgl8*Cnpa5E}*23>!mJQb2Xo)%n>flBYx!?vc8c8AXun|g+9wD7l zl6kx+d#O%M??w=90a*Coj$cMxuBgs?0|PyHgbm2CCI~_JY8cqG75|jL3|h= zntQuU%hW)r0x6V|QF3XwS>zf5vzbvKBi9EPxLa!EKkS0G5|k1|lvAyy+sqc*&CO3P zF21KWogz_SnQgeR2vtW3G03$jYqLP=^VVwJNv4MHLYUaF_iH&PEM9`h{Ly-o9$_OC zf8;CGG0#$|>)A~0vkpf6RZz^#N9^EoZT@`Q+XxsVdJIb-U4|HT?{@+IP66=~gNb1{ z9P;j6Q^p4>b-PN%n-8eK?d>h8Bz53^QObD~Guua~8{Y@Gyd0+A1wl*fpUxIpx7$T) z&E{sz`MEiS9335{byKE5aS@IXb()=M@(6;KOeXcBFyc3HVa&=WqD9H`iHhJ(7Uo%v oKw0v~iSqkDDi&sqHU4e<2Ea}t+=i$IlmGw#07*qoM6N<$f~BKgqyPW_ literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Materials/Scrap/generic.rsi/glass-2.png b/Resources/Textures/Objects/Materials/Scrap/generic.rsi/glass-2.png new file mode 100644 index 0000000000000000000000000000000000000000..939ac2039163eac9cd23a328115f56d567357060 GIT binary patch literal 1046 zcmV+x1nK*UP)Px&&`Cr=R9J=WmOW@&R}{y8w*)$MiSi=i$i-X1L#U9v>n$%3H_$X-D6XNr;b|!u zf`W%Ymt?32Wa^@~n&7D&N~2;e@*cgqco1|mNS1If%^om09qzmDL*LHOrTs5Y@9MsD z{^x(s$A$koRQ5$g7H&R1KE{3FO7}@u&HBGqt1bN=z;)eZ?W0v#TDUJ<0dNmpaSz?a zY*)m}1k|>Y$^}#|pcS>SME*4b&KrlQVt&^vbwgsfm_)UzmJ(bo2O=dZ1cpWdfT(Dm z_C2UT&=O-$rH-pH>0VFNtQ=TMKy53b1o9ZvFRosCZ7*pk@Yt;wrb#|mKl4v`z6LSUnl?pvmSO)e{a z5^b!6O-KnqeVDHImlU#frv zY0ISqvH|Tc+vYv4I4iO5`$_-ER#CIroNIsKeE=q|Tp>7)gMN@2FSQqUz0J){eBYUk%c2 Qy8r+H07*qoM6N<$g0|i58~^|S literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Materials/Scrap/generic.rsi/glass-3.png b/Resources/Textures/Objects/Materials/Scrap/generic.rsi/glass-3.png new file mode 100644 index 0000000000000000000000000000000000000000..6a9c1773996d53a861a7ae624d6264a35f6ea707 GIT binary patch literal 919 zcmV;I18Dq-P)Px&QAtEWR9J=WmcMHoXBfvnPsxxDUM#LIsbm5H%VWf;Q-?~6hBRBoLyHG@HKj$H zhZti_^$$pcA(&7wghFu)^&(}C4rK^O706PnrN>LXbWF(8;dJlaMHl&^b}7vlUheL_ z_kEu4^W%M=2R`8c4#}HT)%i(Z6hL<8f3;q>2!eo%i;G-&0K?(XzBijq`~Fd3rn?}0 zpqv_j8%9sZai~-(Im{R1+Er|0=>3F>zUzT zApRN)t%r9cVSKg)SoaN!M8u`o4WZi|WIUQKO7BI$#&jAfa6_O3hlhuAYuzv*u?%uU zpxe=i%WJHl)9G+AO!i&id7ovrZk;| txgl^v;4Q0yAV@w`t%T7+wIA>wz~9|=aIL+T1~C8t002ovPDHLkV1h4rtr-9S literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Materials/Scrap/generic.rsi/glass-4.png b/Resources/Textures/Objects/Materials/Scrap/generic.rsi/glass-4.png new file mode 100644 index 0000000000000000000000000000000000000000..0eb7585d96678cbc85dfaae9de007b93554d65fe GIT binary patch literal 969 zcmV;)12+7LP)Px&gGod|R9J=WmoaD)Q5eU6PZUI4jHCg3c2TS@qMX&u<{VNYf;id9u^pVmK(>lm zO6X7(Iy6H!F@qq5LQv2|!9m&sr$PlGv{xZL2pMX#2+!f&ySpXc3LO7^QO-)IF&CN}A zc6JU0?v$YbWHOet6G}HT;OiKWB8BU^dhMt8uemvSxvQ@u!vFx_OPa6W&SRS@Fo2vH z+|5u7*a;v};)(${3V>OIYqN0r^kBY*V!*7S82E5r=^m(!<-vVv2D)W?*DSwL;)<_3 z>LKPJ62e`FtLL#=$`(09^$^>V2mW zpuUI9nCl5l9 zL6D8EVt|XQ613Vnf__8;uoF;xP-J0Y8ry{8ts>JOrojVn^5hmU-V;ReR*{vJ6+M(p zCL_CPt6SYh>OAmD&9p;uprZ^s=Tg-aZ{NM+(Z~pkwVLP#pm#g=oNsT(iEnqztsh>l zkIqqT_^hE&E`~a9mlgm6HgX^es;h~D3KomSdOE1r>tMi{HOY@Vf}NZLri{D?90DMh zm62Tb-(lpRWU;qA=VOQn*w9UVpbJ_eDVyBX-CcwzsJW-tp966G+%K{pAG35{tzE6Q?4s`j zUXZ!DIXx8Aky0Rp41zebCiRX_#f~Y(fQO$CyN|pN_>OY9oX!EQ8_F&juz&dyVZE{> z4m3_QXf#?I@fiq8-#4PJ3;>mKStKn>_kLMWz%L#=VbS~f40N&(odXVVfwnJPP!9u9 zDVIgr2h*h&2qF3e09-nF#*7JK735tIHZ1$#IzaT}FDTJRV8ARYD24)oqdH))w1$M2v;8ynd900000NkvXXu0mjfK6t-V literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Materials/Scrap/generic.rsi/glass-5.png b/Resources/Textures/Objects/Materials/Scrap/generic.rsi/glass-5.png new file mode 100644 index 0000000000000000000000000000000000000000..e295c8f1249cbb2e5427744245672543b36a1747 GIT binary patch literal 854 zcmV-c1F8IpP)Px&5J^NqR9J=Wmpw=vK@`V-69P$!gn(HBdW2LK76%%W#uT?H6k|XHi<5(tYmq7> zWk9U1um~0w+8Gfo6cO@)SGZdwl^?|wS6ErBHk(3@kTk+eu^+d)H+Sx-UGj%xX5P%c z_n$X!=DmY|9ZDw@5da*=Y5Q@ZP-r{vI1c4H5bYixLTSFQqwW zrg?Wxpj0Zz$*BSn)seO|t`dZu;^_U6&-Gz8!#x@-?iT%Ej0K@iUuyy)s-ToOw%wF5%{Bj=hZ!brJVbG~7{v_dZTHYwHZHg4t*D+`e_*a z{_X+J&dvb%_n}OeGRVm6o=JMfGqtqu2hzXRnua==h5P%09b23Bbic3lh=|Bd#5+lVPI_FTPYD}apO8%TRIN! gdPpRT@&5q$3+Wta1ZX>MuK)l507*qoM6N<$f;u*nW&i*H literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Materials/Scrap/generic.rsi/glass-6.png b/Resources/Textures/Objects/Materials/Scrap/generic.rsi/glass-6.png new file mode 100644 index 0000000000000000000000000000000000000000..f106b827b50f7eabe705cdb3eb0144cc96afd92f GIT binary patch literal 1075 zcmV-31kC%1P)Px&?MXyIR9J=OmrrOLM-;|?6AZp75D>-o8Uh9%d?*!)?kg_{5@e{M2M0k5I!O55 z-b$gSphI#h6tlXuV5CF9P@EhLibSuDP)>XB$;D%rFc1>j*a!;K!)RCg*HYX|p&y8u zH@ln}z>71c26hIx-X*K(qk~SShpQw5y+M5q~@w3~qF4+crX&X$uKP?Wn!@ z^CBA?8vu-!MlAM1c4>5@qj``Zpc@k+-%ZCn&m))1K`CZ0{cHa>M8JalVIK9B0zhHf zu`>p1V$1mK`LOr>kD5vPvm?+3RZ`Iulwv7Zx?Ku>>pctl3lJ4exijg61Q-u_*iI9i zZQC~z_#xDfM4(o)^)i}^Uq!GB#?BbXNI?o(t(I=JTB*-G&*S|3JhE#70=1g04-N+A zVNs*q>=n$~W=f@#OT$9kdHG3M^MvUB_r+#q*rE3-Q~($)j^N&8{4Es5h2XX8>+2|i zFe-mn7>!17V(dbpz}ngx0Q=P{0J}#=#{PXDfc!}wFrp1`&o~bHf0*v)4vih&`bO1hg}c3$q72QuU^CPE)-TSezgARozSMU~M1rZ2+PFj0<0)0E?g zpu*cPZF`2^2}eMFDp`K5x%^DvzHw=O(o7JzlZcTdspk0DJnvvuo7RSrB;c>cg6@}H zTx)9kSbnX+0=-9~^*k>%|LafJ#p&0l34JBDVR%LFU+!>svkSlM1O)nz`=WM))~>k; z`A4?jo}bS?s>4W+z$BD+H@m!#iSc6)sV^BwkAP(yMpSLxj>Ie^?gM(yTt@sBFbcMs z=oi3qoA{hK%AK;wbrs4TG}2sNPdUZ5?a16j3I>1ng?6=|sD*aT55R9Bd2*IJWgY$% zPE6&?ALjAyyC8oE!*6E!?3C#pIXMtq6pppkGWK>Cl%{|8ZZeKV28@(9ING93Q2D tfJD)yF>KNp!l2(5%drDz9>@O~`~#Pb@B#wLb|wG-002ovPDHLkV1nY{_D}!- literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Materials/Scrap/generic.rsi/glass-inhand-left.png b/Resources/Textures/Objects/Materials/Scrap/generic.rsi/glass-inhand-left.png new file mode 100644 index 0000000000000000000000000000000000000000..b0e5ce127dcc17ca9ebd49f720cdd483accad861 GIT binary patch literal 690 zcmV;j0!{siP)Px%Y)M2xRCt{2noWuuF%X5H!rZ_ZL#NIVW{`6QEt;G|xy3AUi}pD}7ITGI4CDl} z5Dmu64F+l!a@*~W|I}S=Y^ZPJAFQf!xg;6h0~AG36h%=KMNt$bj}nX$e9w8m3=Lpc zKxHdN3FhT~QP%b>v;>)E?!$qI22a7@2>^h3tJtqatEL4^@1XH~E(t^$5G()!%mS!u)Bj7i=uVEA!+`#u zjG;UX4REfY5b~$s+?rqk_m&&=FoPRlLwXE0Jr6?zUYHLPnRp^wz_+KMb?R5P>U~Ic z*EY9;7v2KB_bUI%}9q#r>{WrYWiq2D)*Px%Wl2OqRCt{2noEk?KoExi4s!!x3`(6L%uvo1dSP-7Gm za;PSoagj?C%^d&$JDBq2=h)lbaPaC`X^hFW|E|3N7v#AyW(R<(ov{=$20(z>_(cQS zS04cG8VzPuLm`LuPxk=Fq-{a|mPh9f007SXbNPA++!9Y~0a8x=jeoI|CJVd;%9!dW zS0#r4&Fzsuu!D(Xk^Gy#j5FVI55FI9I-TI0Yi+Z!AR<|pot7c6xs8>^zyPtc5e_vBzLCBX>(nK@X96c zZS-C>X2|hK=daxt2mET^Tqb7=p=TfCdhPrMSj*>u%uQZr}<8Z`g|-42Z!p*l;^43rvxeZXIn24EO! z?Z*ruqVr=C)#%pyY>crd-8*0jnt=-q00OgqN&092`tlLx>mMOTMNyO`@dn(A2p~tM ReqR6p002ovPDHLkV1k`VBkTYG literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Materials/Scrap/generic.rsi/jetpack-inhand-left.png b/Resources/Textures/Objects/Materials/Scrap/generic.rsi/jetpack-inhand-left.png new file mode 100644 index 0000000000000000000000000000000000000000..b99a49a4e9dd2cc76d14bd8988648482f1d31748 GIT binary patch literal 325 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=jKx9jP7LeL$-D$|{(HJOhE&XX zdrOh8*+Amx$4x2A6PR{dCsg&nt9UFY;ny(Jh37P@nw6`Ql)>YzB@h1_M+>Y!tDdzl zod>8J1m<`w|Y8{`qBJe^0E8PGOE%wa)DI zo~0Vh8oT_al}fXH&WYQ!CtwQWk6qJJ_pUx=b0>D1c$ZN_y^^%U?QO0;+QIXCyT)e8qo)?ZF)D zob1iZ?G>aOHVIGolyj3|%G`!2>6iHfSeM>=n0`~ literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Materials/Scrap/generic.rsi/jetpack-inhand-right.png b/Resources/Textures/Objects/Materials/Scrap/generic.rsi/jetpack-inhand-right.png new file mode 100644 index 0000000000000000000000000000000000000000..574c095868ad9d6c848bc02795f07aff11f02e2e GIT binary patch literal 337 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=jKx9jP7LeL$-D%zxjkJRLn`LH zy=5rWxAXkcjtZmCf^Oy1<`1vGVuiSXAwl)tWuddNjdtZ{R!+H| z6HpwUuu|sW;lQ)8jLAM*(pbzLio+Gs-aTN;c*k|*%-OmI{|(R99kAH01yt}gaQm}2 ev45X#bk^T_Y1+}dk{6^vrh2;ixvXPx&)=5M`R9J2%O_ou{WK00x5r#bVJ@6Mqa~Z*NZkXqrZ+(^1zGi3Ev60$4aO9*@apvphUJ zyc|GQYPDJw$H&Lq-rjO@a)RSH7={5ryWQsS@DN?sd3<~XARdq7eqK6Kuh&&atSeIG zz{SOdvh(QZNCj`V+iJ0dkdh!WaIskAr{ip5zyhFBsfcJaNZ`2*0Ign1L)p57m4SYyK7=}SC7E@^(3vIofy9#1^dt1#1_n=xeEr0w#Qvjt>iTnF|1#x|S9SFY;BAHCG zv$F$0Hk(z!P16*%ZIezT>{d%d(}Zo?-Wpg1k;!B*41->;=gGGpLQ267j0)1}SG4KW-J0hrI{fsRPIU2wz5;Fe|a{{7!ewGp}-hNZ%-RjF`qUVfFz z#1GSuV%AJzuyloLbq0>LIw^iN_qAt#m;l_|+-SL6PF!7Gsd|vDwF<&t z17E&;QOB|dHUfY}G5RI9ZuuX=zl(zRt=-qxcEPHDwYgkQxVyrwL?W?dxy-jeIBZY@ ze#xSoPN$yYlELM*u;B2^f#-f5yXBq_0Qr30b6@7${f+QP0aif(j7B5i_ZzSKJpT_A WkNU6*rAtNt0000Px$>q$gGR9J=WmcMG_KoEyNT?_$Rz2P_vPT>d_sSZIpSzVqXFW?8b+Qrs+0Fyqi zVYW+?D#c-3c<~hiH#!0E5HrpD*aSDel)sISlTh9CaJ^*1D8qf1gopAtKbqxV>2msIX%zQqt7JeCkl#(C_ z3Jt9q1B zJQ%>9d}*4#Wxiee zR{Bc;f*?Rj$>Pt#3~mNa4zl?F4}jrt$g|e)nuXk^F@RjT^Xu!toSzGp-R0)PU+{gO z^?FSdMby~=4+4019|8sGOxlH|kD!vPr( zLYPjc!|3u7?qSgDH5UC|03n3wcDr;=PFO!ZG3fPZxo%_8!;TW<&H>EnDX#1C^X!Zy zNj~axOFJ`Q?{fBiQ_+_K*nQpJ`|T!Fr}r1Bumtvzt0)UiMGqBvfl>Px#+et)0R9J=WlCcegKnz7cQA!$6sE{Z0I-|CUdNT6|AE~AUDw%Ku41SpFHO_c{y2uI>$~-4S+?ol4PcB}oU3zXsHD|< nMUk3eczZo>cZ8xS%5Ql9^@LC3r9CBb00000NkvXXu0mjf6qs~l literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Materials/Scrap/generic.rsi/junk-bucket.png b/Resources/Textures/Objects/Materials/Scrap/generic.rsi/junk-bucket.png new file mode 100644 index 0000000000000000000000000000000000000000..4285633af08926bbc505833a660965e477f4ed95 GIT binary patch literal 487 zcmVPx$p-DtRR9J=WlCe(PP!xtgUt${~B1H%)L{$YSEEWTy1L~A?%oCt4$s=UtExLBC z-vBYN;;D)RVnIlN#DE}DsVIabb`m>W27;l)&S1fIKk3T4*Y}+NKj$7$C=?2XLJ>n| zy&|*4s(f!95p|d?R^`WhfxdT3+A6)PiBy#M^rD3jg0YD#=FDe+NE2h34*)c4zqB_q z(D!aJ#?5daw5~}nehv3Re+)4PU!j`-GO3BkC+Ky$0L)o==BzwH>pEP$n?HEAU{A7BDgOKbc)-A|%F+<|`cidV$} zAcOAEnW?7`x=G{mjDG8HA_I{fh!P7Ky!5>vz+et~S0}hfJ8w4wainwu_wJ5QU%ug< z{l;@Uv>S~iy730wqaCeY+lmd)wC6&9Y%GjS?l_LLZF}T!#^68O{8caZpYqzU1ctp<4HWq dkV2t&$pf5xklv`LzCZu~002ovPDHLkV1jJN)tUeR literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Materials/Scrap/generic.rsi/junk-camera.png b/Resources/Textures/Objects/Materials/Scrap/generic.rsi/junk-camera.png new file mode 100644 index 0000000000000000000000000000000000000000..1afaaac4a0d1d1073f03a316f66a999ffb3ad515 GIT binary patch literal 540 zcmV+%0^|LOP)Px$)=5M`R9J=WmA{MAU>L_g5h;RGQ^K7Q>Tn&-7saCFU0RTe+}J5wxe9{d;2?s3 zLUutAoLzfVy2usWx?G0?;izE2p+lDp7Y`1KAdiEWBigHZ<3$(q*^<0@pXd2Lzo4L? z;D5(5J?Q(sB%gb|p7FoG_Izm_~4F>+uwn*k7pA?6)oK8Y$K$^nebP99 z>&nWATMbWI4KI@-Mm3N$KA&4l5ywWKK6?(prOU77-SEAUG8aq^Szskq_|>>liU$uL zaTrAaymKi(rS2e_uhQ~4n9r+xV^K(ThF6ft>(74Qk{5Q zD#@44O|flT-jvJoq*O{B)qj+Nv#4CT#(v#mFr6|im)VLUYV~^RsLoXy-}fcnobZqK eL_tBpdHD`LTB(jh4v$#?0000X7jRI-)QBU zCi7W_p+M{O3(13=Yj(~#&oIw4C+Og;o&O^yY5ib1$+;zW_LBdVOj!=RD$*KrCKt-2 z*2?c|Qx$r@x8nWM*H$ZEN9jy7_^kH(;F%3BNu6=0U0IY08C_~!uCFp;xOZ;TA`LGd Y{+$8d^}nLkLB3`1boFyt=akR{09=A=NdN!< literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Materials/Scrap/generic.rsi/junk-canister-2.png b/Resources/Textures/Objects/Materials/Scrap/generic.rsi/junk-canister-2.png new file mode 100644 index 0000000000000000000000000000000000000000..abe398db4120f134b5ed53b210365e5873b48b12 GIT binary patch literal 273 zcmV+s0q*{ZP)Px#%Sl8*R9J=WlfiMsFbG9I>3}mXK`z35xCK??7U+W_)Pj6g3G7Kb>)l+4Gm}Gj zGdc;u6G%XkBuVn$p-8Zq0RU>P{=U~*BLE-@rHo-_D5bcW!OS2c?(T4Rlv3RN!|QjM zMdlKbr_7X#=KT7p%(5&F0Q#@7T>ll>X0N!lKd?X Xfkj+Px%<4Ht8R9J=Wmd{G#P!z_0odgwIY-=5{AlN5x8oQAg2mMVqJLUSjzX&T$*_^pzg+;hI~d?zOt-toU9 z9CxqM|55 zVLvE}g0AZTn5OA0+W_D8_d|pBJMgr?w(WrgbX^zfr=n2+ocmNN1<+&5`uciLoS`hx zb-k zMj`-w+1v!4)jOozxVyXaR1X0yP*v4_>~xSL5oQw!!r?IYmeuo~JNZ;JI#7LJ0^_nw zJQfpv0;CoedfuznYU0{S?x#Kw0aaCPr__^?2+el8i-;GA-!G$iQ1U*S3ofJ0|~fMER~RDS$ywq z5{~zumY0Ku6X-h!-0G*IQPSyj*U))-dJ>?)~PyGjyu8 z8s&0Xlzyc1!2JBY_aAOU#x(ectS46&wZT1b+luF^Zthrz&~QNM=zQ>kPx%sYygZR9J=Wma$IbKomvKZdM{LhsLrCR-$r=WIg~2HH9ve>*BgD zlgR`j1VIoGh9OERlv0fml2WdVqChFt31E$Y*2BXCgTa6#Nr>Z^AP5M8pfd1%e+!~0 ziW(3!|CZM9nZMWd^>q!xlv1jy3k@}&&w;npB}qaPgtdrHPEG)rOeVx}TtU2^Ivh-w zHuefcgJoGpp657@!|m;De$IyyoKL0OiRWyzU;Mp>5hdOh@f)BNS- zg)~inn(MVjVAHs1HyWl%x_-LU`WKi{&_I9Ms`(ADU2vvWs}%st<#PW%pc{zeIC_D$ z?`qFYKy7D&wFvcu&30=Vjz*&`FezmXLPw!VJ0Bz_gt-%=&DP9Us}=oz|9vSiO`<4b zJRY|mt!BEkp{cfcI~_*8@3UAeI=>6UkTgxLhMTe;$D4|xXzS`_>hSPzFLT&20`S(u z%@(a?gX+>=w;3tr+V}n1SWy&2Q3SwZv1sh~Htie%_+1O0=T)KBbuk`~(O~Px$wn;=mR9J=Wls{|RKp4hO6?3* z86YQ$BKDe106L=)06(&s2C*=)wU+gskmF)zKhJUlE!ELGWA0cy44 zH8BR3VNTA@xE>7F%z?uE{O*o9P_NfHH~`XDJkAkdErGYqdor0+&i%T)q@^`u?^z-@ z|9pSXJWc6~D1iMM>gV)3zx~CAjx|7EM16gF0$}WU#Zx9RhDMgr$TCi~F2?g7SuMBL z+S-xU!Th*Px&mq|oHR9J=WmOp44XBftRU!+FSU6LY;rd8umH%o_*MWkd3oCXu97X?~_C3R^b zgVVK;xl{N2>Exx2Q;>oc$mHn++1;r_F(CpcD2a*Am2)SZeB$e%e5d;(OL8f6@dHBN z@!h@8^FHtU{effr&kz7oN&p&-#>AHm!1wT$hxCg9L;nVj4ScX4g|BD zM(TPV0IB5k@DtydWNnl%l}!4?Wzz&;y-@H)s4_%*AtvA`qzYxzWW7)bk*o2e#YOC{ zKu^n9jF^C1^Yij3q(KBl0HN`uQk+nOTBQ;rcRkPl0hCNLMy!astrnK!&~3GRLD6>= zPfWo58#g52+jJmhsGjA`OLccZk!8K1tf$(1SZ$7U&nGB?q0p>2M*SFqg3L@CrkP1%S7IAK>)+ei?!*?F2y8vSM3gFcXz|M$<^=a?tM&C;EN5+uJ`^5!bbvgk4|GmJLJhlWdEQ87{qiL)ai&&1sPgkx0 zP~P0+(b5tdH*W&)=gwQSlP6Px&_en%SR9J=WmrrOLM-+#@v1EC@!b_#tkxCqD2>9TfYDh4Y!U}u}CB=stf^-Q4 zN}WsU&_GLkX^IOCE}>9Cp}ol%>VruLJsBbhv<-#cS_s6ci(_ItsRb)El8uzMoupn&P-gBa`c)!Bp zg%Ct_aM*x(U+_^990ahVUBK1;esx-@z`bnNR&9nKS#1HDmCf2}cD5*v8z35XQ?K4K z42FSIr%P9NXjZ}*9L_&=x5{Ci_ZGn~hB&0B98j3*LmKZqy<_jyOX4nU>48<(~$HcO>IRh(Ll zWF*2+I?bBnkhUxU@A}c>4PbZww>u|156tIs>aG8Tl{149fI_~?&ATVKw$qMwAo{G(8cHNsa~zV9 z2+5rmG;76o?Ny-fY>e}Rt^r3b8<IwP0eKHt210@K9XG5dKW z49@>;5PB4UQgA_T?|_Va+1eT@-KrGwZo;Me1VE&O?U2=fP$&cl_k0&<5Vs7BCMmMW8T-QI!LPKN?$hPlqD z&#Z8Mu+Gyb9polnaq?ZaB-7%C>X-CjdW)ZQI`V zomq6V>oY}rC`^0)G4bm#-~GBGEr89*#j$^6A71|g1<=dY;3djW00000NkvXXu0mjf D@UQ>7 literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Materials/Scrap/generic.rsi/junk-firelock-3.png b/Resources/Textures/Objects/Materials/Scrap/generic.rsi/junk-firelock-3.png new file mode 100644 index 0000000000000000000000000000000000000000..7b98e108d129a43035ebaef6f04b51b0fbcf7ea4 GIT binary patch literal 506 zcmVPx$v`IukR9J=Wls!+vP!xvWL(5=D2uy^q83Mb3$)VRoO-TF)FcN+N8-qG9$?QNJ z{Q(XpB-*59V1h6jLE69z*xDqIH=q;Ok4Dlph*YtQX{pPt(uz`r`kA_|F`hi{-Xtajtcih<9AD~{5 zaHf73GG)u17i2Ot8g`-48jfq(>u)NgWbXC5gwL)dP`f%byd{8{(8=}vjvK&Wb%A9A zMfAFWk}DC^gT)03DVYO6JnllZ`WqNat8)V<@dUmAEO`XyM>{;UO9%uB`mF>dcehmN zB(bzg<$QuGY_=xW!pJ%hB-AU?sC70m+rw1A=OK9gc4Oxww7N)2+~*;*pJgby64@C< zfN@St4P!QYZwj=sKF&CXW;%!hh4woG|S`rk0^%tjGaahTFyR w2r{({0l>P#=L!HoyA4Vv*;;3TgTw#k2P^iGSnyc*7ytkO07*qoM6N<$f(N$OH2?qr literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Materials/Scrap/generic.rsi/junk-intercom-1.png b/Resources/Textures/Objects/Materials/Scrap/generic.rsi/junk-intercom-1.png new file mode 100644 index 0000000000000000000000000000000000000000..3ce6f3f2b8816e5be9a7f9961ee2b63274ba9dcc GIT binary patch literal 528 zcmV+r0`L8aP)Px$%1J~)R9J=WmCtL_U>L_gkBmy&!welb+O2w0A@3j2Aa1ZzjuUs^rGHK?yDRnB zlb|9Ag69qC4g-;bjZ{{ao;KJHkB5@5tZmY|i3jt!<=6ZDywCH57YYgr{&ytnq3`>t z>sG4;A_{=&)VDzp%v{HDoVgh*d4?%ObXM?f$Q5X}+X~P-K2CPsXrN)3UA;xQw@7%U zT*BBkcO9N90Pv`}&XcFlQsKrJHOA=m_hetx={P!bkv|ovluMkRp3%ShOtdz{vJA!; zbzOJrT|H3oU;47FL}n>%+fG^lu(iDdK)?STfTN?Y0C=7!F!@VlUsMm$gDNsVCR0Fl zvYEKt<7h;^UMC#<0Kj?vA`$UCPn?c36`m)MI|Bf{UQYlXSZe?@HZ}oRUA6E(eVoX2 z9JRmLY&6#It_5)gVuBz@{TV<~4XgGL*LCT3yNsg|gK(Ived`un7l^qjvbDX#hxhLQ zIKQ}L9E|`NghTl&0yjnC`M7`bjmNbbht(?a{qX0nxj75XKo*|o$v7G%^AR6P)Px$l1W5CR9J=Wl`&7kKorOSHR7TRv;#INITB!zxafp~_B&`&CSdVvxbQuy17UHK z{kq7ciz$QAgoK7jj6l>)O`Zce(k3G96({?fuCKkj-`%~w0}>Jv{yR$44n*{0+;JQ< z8V#~-J20kcnv!b22oMn%V3~JtRonB9{T;h0?e-CgoK0y8NLBX@4Dug%S=%K O0000Px$07*naR9J=W(mzYXKp4mIZ=`iou$9Y@qlSX}M{w>&&N_q#t31VIo4|19!pmPDGS`dWW|*#dBLyN-&YI9vd0 zt&XP?PEH?bVpu*b=-=My`zHXLBZ?xgkxab0f!X{VW3HHPHkeC8+qO7293)8)o`>=d zV2r`JI{>;a-`A4_4L9I7@5nbm*L5^8G%@UU_xt*I3%Iob0N;e~nX zQ*~VhL#r#S!-2hrOK?7blCk7sIF_QwHnuab|y)T%a`{j1gNU&SMMDJK@j}p Y16W#Jo7x+yNB{r;07*qoM6N<$g0N?e#Q*>R literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Materials/Scrap/generic.rsi/junk-jetpack.png b/Resources/Textures/Objects/Materials/Scrap/generic.rsi/junk-jetpack.png new file mode 100644 index 0000000000000000000000000000000000000000..a1ba37ce1a00f06ceb794e948456be2939c51f29 GIT binary patch literal 577 zcmV-H0>1r;P)Px$`$FM))#mugQovFo_1)55~$2ZJrmXucU)9s@@mb<|P+yNHXC zwH5&2d7e$ihQlEN04b#ffFKA60E|YX)Fuo=0sw^U5918rd7h1;2;FWM+wHd0zFx0m zu~>j}jxY?#hXC~ZeajfbYPCYM*-Yndu73dlE-rthV{sg#(P+RJ1FiMp0KHz%GR9zx zL95kD0ZwYQjNQ}oa|*CrE|K`mX0yF?|@Yu@rrgJj~~Kn9o5e&DgfvZKpNg1(4TirvpkUD5W^SI+Vr!CmscOe9%l-PH^l~Nh|e_nq9_6@})QpI2* P00000NkvXXu0mjfNo)$g literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Materials/Scrap/generic.rsi/junk-medkit-1.png b/Resources/Textures/Objects/Materials/Scrap/generic.rsi/junk-medkit-1.png new file mode 100644 index 0000000000000000000000000000000000000000..047723cf4f9b3c37665ce0faae7e18896f90da88 GIT binary patch literal 528 zcmV+r0`L8aP)Px$%1J~)R9J=WltF6SKoo|*gzmGFA=H)80YVlg6iNqXuM_kJIf9O$6PVl}Cz$=f zlt3w3m>giRPzcy7U!dwD%tW#^k{qu}_3sAF=>OjT-V98dH0giW#i<8Yt5pq9mgUj6 zJkL-5-=|Z}rIY|@tywGks89wJGSBapEWqX3%b)>;6PB=Hb#eE>2F zVi2Iq{Oh;x0Bm1hS`Zx|gAkV=HBTR&N%a@ttsR@qrnN6g5`++BSyuOX1nENN>BBSI zt6RVC_m4kpUtfUsV7e5nwHRZ9gBeVqEX!7ZUF86?{o0!Y%&tEJ$4OXg2b1V+K@>$E z!d0p6Z`fYlGTX1Ydwe_o>*=RY$w3%nJO~hk2m<7Jeo+)f3j*No@sinojk>?_=I|c5 z)|#>`iQ^b!j0Xup1ZO}gRRb7fST2|Bc01fmxX8QAqbQ;%3IO6b2996N<~(#>L#0&R zyweUsYmJoBwVMXR7&32G+IJN@TcDJxg%DI#<%g)5 zM6(?s^Reok0U-ncRaF7+ciKS!XPNf`IEd!@upPiz=4UC(vU=#5oiu6EKcT;cQYdec SyB-k$0000Px&6-h)vR9J=Wls`-pVHn1LAV`&~rGY{{ea6f8 zzQ5;t-uFHzsGx%WcNOJZaOu=3EuBd4(QKx)stSNl3kv{T>F>|GUtR^5FI>=?cJBsY zY-9x4?WR(e0a#R3!jqGE8(EhRyse`Hv&}|oVF79DRvwLyQ?`CRuBIkLS?0_8_t@=r z>P7M5cqnw~uNlzc0II6;xugWi>BMTW@a*|>N(BL{)ru&~kWN!B2)}G%O#^*>eOhaK zy8&NRRqE>`YPUHlHkHxfb~83SOsOD{NF@@(RqoX(+ z4gkv1X#hT$Oel&%cXxMIR?Y-oghJdL7yv+)W%lhqh-0URbd8hhWY~ZMRBx^Y!0YuI zNzBD!d@z}iWtryY=A22aIs$7&1vduSUO}X}1B_Q-W_}h(@DGl7yltD2ig# zW;2m<2LgeB25@I+h{nc7-X;?0zoH&_Hn`1Zi^=RiD{{3M%NI&{w=yPg+IHWKsYC002ovPDHLkV1hYckl+9S literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Materials/Scrap/generic.rsi/junk-mop-bucket.png b/Resources/Textures/Objects/Materials/Scrap/generic.rsi/junk-mop-bucket.png new file mode 100644 index 0000000000000000000000000000000000000000..66751cf4a5241cd5ab5b7c4a13e360a0d171b28b GIT binary patch literal 666 zcmV;L0%iS)P)Px%R7pfZR9J=WmOp3{Q5?s=@4UODEosRR5HV6QpoHLGs8BE*QiKd0NV||yytLD+oQ?-Ysg~0 z%W-$_eZQaId%QnDOD+BHB8@h@Im*y*G`Z$02!dgIrqSWjcYA#r25|0l8;zV`a4O1T zZbqO@1sFTyrbiAjC@gW zRJ7(}8({icCzb#FLZI7)f!L_-Uva@&)s_LSp9S^!fTIUo_>|%CyFzej@CXb29?17n(?ERrd8d2QgiSJ^doNHw}DDyJ}WE zG^l|jQZh2jobI35IbaC@0AxjLR+4I;T|DEy zRoOhJgXrt!@%V|pO=g)xNg_BFcH#0#)^s~KXgF&D$Z|Y+k;MP->Tt%4{egG@0q0inZx+)*s zzeCPn9H(a00}iHOPx%$Vo&&R9J=WmQP5NVI0RlZhQB>6H|t@wx)|Hlbm6i2gOSRJvNXO#B_8Cx_j^# z9t*s52!YjOTry-;dw# zv+wh~@B6@!j$}e(L$WqDBx|97q=f>KrqAowd*?)D6G_qw4^N)q!sQqM*>pD$)tVe- zCT6;Ts5U%#7Km$2jxzU`N(~~l>n4Q)k~TbfmP?%{YsTa83~fEDd|T@?##UdR@cgs@5yR>3 zK+P4%s;-^vt31B*i*~P#_ksWxQPQc|W?DQRuH3lJ;P@y2gX5z#yIiz*JjQQowpp|! zAh-#24PFbfy7(N~R^eWM@wzImNLKQS-4sAw2evcTs(ZCiB3CTq^AC`StRUMgD3TRL zvR1BT3D{k_dNSp}o2QF4=XFOCkrgxL%mYBh=Kaze`}_m^-r54*?KoH81z`Y(VmEBw z+cXhb!RH?UAXhA-<_e-E0TWMwB1_0N3yH{z(Nu4&!{~5kBCf1oiyuV=|rb0GkL&7YM`73^Oo8jTX{U#^M=`o*4<9+d=_JJAZNaNcR294<=^1jr;KY zI=zGKhEtzEZ1V7B;c(7`dm%D;3%R@n*CmC;Q#;t literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Materials/Scrap/generic.rsi/junk-pai.png b/Resources/Textures/Objects/Materials/Scrap/generic.rsi/junk-pai.png new file mode 100644 index 0000000000000000000000000000000000000000..50742a847e63fb4b8559813469dfec6f85902732 GIT binary patch literal 972 zcmV;-12g=IP)Px&hDk(0R9J=Wmd$S)RTRa4Gya;)*p598u9FbsxVW?gi46@Ei&`k9QdS6ovq3D_ zL@Zh<3wHbkEReE5sPYy8QlydFI0vLhB$f06_`JMzv70%xg!0p#~g` zkH3rG=L4WrE_3Z#hMK06N~QR9;TMt;}7z_?`>&_o& z744avmlgm}EIme#PIlq}zX#Rt=IZ<<-kx}mT`5Yg4C12|TAEI^P&4He?Fi7LlXz7( zr_TgAeI|(JG)TPR1wals@v3gTs=G&|8EiQKaO#A@?bT{0zIC?*z(`0YUn!z`T@1+{ za)26ekT0|j<+J6$^N_DJn3|qpEBy($7N1$TR`{M1E^kCr~TbG zUo$m5!}}k7fhe?aIn6iOOFIw`E5ySJH!i1{OV9H8#V-Na*sHO+Sw`S+>knXS4V-w@ zhbHQbgk^{& z!wSEB|1BSWdXa@6zM@ntvc6qEbPQVp&VDk3Ch7n^19#)ikjDIvKhehy`>3&X=!sI3WjB^p9>i3|*fc#xfcVP4S$T|6*SMZpV(rg0u4k5dax&R0qEjI< z_!@e%io4%I_tEV|uv7=sfWtU;EP@&gB03~Qr-I(Ba`WaAHLdMTGMNP0(@~c+_DfZY z#WD|8cmH`EXdgUthHkik3Zk&h!-qM}eQ>Umb7kQQBhe`Ceg{Hbry=O3gM-aeu`G$k uLA%>tO*4Ap;GoLA+dH;T+($UVe}X40!#aV_#TV`X0000Px$sYygZR9J=WmAg*EFc^hDC=8T=rKm$@hQb1irM^I(0kN~fUUjUx!{hi7JR%_@ z5Md!wDF}hurVq?AG_1%MDDwK93KD)76z%-#I-t zDGQMbka5NU_`Z+hIE%LHx&Snr%|)L%mLy;rROt}L<+?6XO4{u0D)He+*p z8~6#UlrotCtIB^0Vcg(#G~)gFg`M42+$f4?s_-qy3Zjwk`_|mU&i+ybvJ49W_4&Yd+`p?hftUSN{?!rE<+vWH?z?b-s2-zCCn{=vVSuJ@-dmBJ&)^><`zH^ l#eYWYUm=Y!1gK;V@C_3D-~@rd$ff`Q002ovPDHLkV1mI<+bsY9 literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Materials/Scrap/generic.rsi/meta.json b/Resources/Textures/Objects/Materials/Scrap/generic.rsi/meta.json new file mode 100644 index 0000000000..c4902e5ba7 --- /dev/null +++ b/Resources/Textures/Objects/Materials/Scrap/generic.rsi/meta.json @@ -0,0 +1,181 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Made by Flareguy & EmoGarbage404 using assets taken from https://github.com/tgstation/tgstation at commit 6665eec76c98a4f3f89bebcd10b34b47dcc0b8ae", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "airlock-inhand-left", + "directions": 4 + }, + { + "name": "airlock-inhand-right", + "directions": 4 + }, + { + "name": "closet-inhand-left", + "directions": 4 + }, + { + "name": "closet-inhand-right", + "directions": 4 + }, + { + "name": "firelock-1-inhand-left", + "directions": 4 + }, + { + "name": "firelock-1-inhand-right", + "directions": 4 + }, + { + "name": "firelock-2-inhand-left", + "directions": 4 + }, + { + "name": "firelock-2-inhand-right", + "directions": 4 + }, + { + "name": "glass-1" + }, + { + "name": "glass-2" + }, + { + "name": "glass-3" + }, + { + "name": "glass-4" + }, + { + "name": "glass-5" + }, + { + "name": "glass-6" + }, + { + "name": "glass-inhand-left", + "directions": 4 + }, + { + "name": "glass-inhand-right", + "directions": 4 + }, + { + "name": "jetpack-inhand-left", + "directions": 4 + }, + { + "name": "jetpack-inhand-right", + "directions": 4 + }, + { + "name": "junk-airlock-1" + }, + { + "name": "junk-airlock-2" + }, + { + "name": "junk-airlock-3" + }, + { + "name": "junk-bucket" + }, + { + "name": "junk-camera" + }, + { + "name": "junk-canister-1" + }, + { + "name": "junk-canister-2" + }, + { + "name": "junk-closet" + }, + { + "name": "junk-fax" + }, + { + "name": "junk-fireextinguisher" + }, + { + "name": "junk-firelock-1" + }, + { + "name": "junk-firelock-2" + }, + { + "name": "junk-firelock-3" + }, + { + "name": "junk-intercom-1" + }, + { + "name": "junk-intercom-2" + }, + { + "name": "junk-intercom-3" + }, + { + "name": "junk-jetpack" + }, + { + "name": "junk-medkit-1" + }, + { + "name": "junk-medkit-2" + }, + { + "name": "junk-mop-bucket" + }, + { + "name": "junk-pai" + }, + { + "name": "junk-pai-gold" + }, + { + "name": "junk-target" + }, + { + "name": "metal-1" + }, + { + "name": "metal-2" + }, + { + "name": "metal-3" + }, + { + "name": "metal-inhand-left", + "directions": 4 + }, + { + "name": "metal-inhand-right", + "directions": 4 + }, + { + "name": "tube" + }, + { + "name": "tube-bk" + }, + { + "name": "tube-bl" + }, + { + "name": "tube-g" + }, + { + "name": "tube-r" + }, + { + "name": "tube-y" + } + ] +} diff --git a/Resources/Textures/Objects/Materials/Scrap/generic.rsi/metal-1.png b/Resources/Textures/Objects/Materials/Scrap/generic.rsi/metal-1.png new file mode 100644 index 0000000000000000000000000000000000000000..f45090ec5ed0b44c36a9881b4f4a50e4e3e24bfe GIT binary patch literal 739 zcmV<90v!E`P)Px%ok>JNR9J=WmcdHnP!xv0jJ9GSL~s@klnOEqbXkNjs}i54+!yd6e1YN<6dBwN zE;YCs0@9^mrC_-)P%b1koswDDWRiH3w(96C{8vqKlke|2|2+wO=$&N%TwY${I8Nz8 z*L6#;JC1{G+fjV%d7e>p|KZ_b@_T)0s|#e?cC_1Q@OgVXInJBV>C!OrGN?B-P zr3}RIFFQL)*z)i&3<-jOpXcWsA0H>R7D7bh@t9__88L4?tWbgcKG!LR>%w<)b7Lr_ zo}6E*0&&_mHa7S@n*sWS=Yyv+0V{?u4F{ObW=z76>2!+k`}n@kkF&E3Tq(ufaL8$| zw{Q@ZZo@qMb}#^7x6xp0Ym4=@HLm-8lv0?c34mo;eBIl_y}F`auQMKxf$X~>U4eCY zd{Gqb^EBMDEToj&k46C8k48z*gb-1^UPnp^fYWYs-S6|=wwX?+*tQ*|Lm8{E1)k>_ z_oES$$s_|eO_Oi?`x!Vq_E$}M2GS<-@X2JNT_2k;O*4Vd=AkW8 zsR7aHL^^o>-=~#_hhg|U1ESN3?uJ9+vMQyx9Sln0@L089o<|S_$vu{3748V_9LU3^ zlytk@g&!Ab6Y*=<^E_id{SZP#`R6>TfDRrHkX7V)o)K@oI2$@;D$r~;ldbd;xK2eC z%nTwSLx3AAVwJMH$fdj1k622Ojur1x(Hhj|9ly?;wMq$=Px%SV=@dR9J=WRzYgxFcf_nhJXden=DPb>VTIfAi65?DTbaP_yRdZE|4RXIYmNO zgCTfnh=U=q0#Y4M(JZDicI-G#8oFuU&eFI3`(OV*ec%h99i;prrED}>EEcVY zj7Fo{nmZoL#nTglARx#7cN_=bI?+56?szQMQPjz{l7abr-e}YmVHxEJe?30Rbrc~< z63k{Z()K?gu>=mCpPPOF_};~cG1e>) zZ_su9BIlh5OePa~#~3K3;G84RbNqdME%t>F$g&KZI6l{RoxrhvrIdnF3IO1o13*DS z(=-6U&0v7ZWFi5;^SnwX+LW}@6;MhGM`aR^{PW>~)CgFXCEHr5iNw0qi_rP^s34qjI zL(8&?4CuO!JI2uO_hA@DVYl6Gk)|n@zK`8*S2WVI4&n-QQ#B`xR|C2aWSU`Ek*8z1TlYv1M6O)roj{fe-?#FvN5^ zt=P5A1NAm^U3sYM#|{XBfH1~np63ukRL*$UJaDeAtMq4C*7cVHwG3SHps46oVJea7 zf~!qLD*AO4DUtaY0-ooQRTyFu$Cys1Px%TS-JgR9J=WmQQZlKoo~RHz5cVi$(TiMI@F8X_QrDdWEQGh`0cU-~uQoK)FPN zvO*&{Rg=Wg&!60H?(w*=&~YkB>+x z4Il=nb<=LEzUMI<4sl&K@-U2byTfe&073|*jdQtNQh3aKdG?!>2mp}HW-*VC$z(FW z)g0hcnxI@RM<$b@DZO_vw3H1kq?Tl zjBVD$vC{FW0)VJGrqd};gF)0IJ`Av&%g>g@$;k;v zM@O-kRS1YTr}z3qY5;(9A;{5k1!pY}<;Ys)97qDbm%U8(5Nd z0+`Kav8$Hu4W?-_9*?mdhqF>C)tHGXn9t|Y5-&?{#IJ8T{?)2T1bA620M;Ou%{S?3 zFrZqgY>i1w!DuwXe|{#MOrp{Yf`A`yO-V{=NGXl3l(E_CX4LmQZrbgQopI|5NGT1y zlg~;e!Z0M9O!)Tj0IctB{e1cTa=EMk>h-$fozMSH=YiG1A-T>i%R)o+dc8HjR8=6Q zG^&+K^fA)rY2~`Ev3xMu8Q@Q95Ag2*w63p>)l=?X|Ak%wNn=Px%WJyFpRCt{2nlWqJKorOSDz)GQ#)G{Ww5HrD%&jJarqC_@48mU^^ed#z7bw}A zy=2u8yqc2LG_EFn0TFY;c(@LUT}3(DC)qkT^!*kI>+b&Y(|b>#`vU|)5ClOG1VIqQ z|A%8TNC=_IzfC3+qq+Y&?{^IlLa0FypwsChgy+Yk|2&_qf#mBf4jck ztHef8q_*k5>H)JPS)a#o?0mksP^;RPQsVdX^;wdvgOH{veBXaDw=QMJYj$aQC7zDw=ZmNp@zGwqbMSQVX0C;Mahe}&heIbPUbbfB7RJPuP?)(_~1VIo4 zK@bE%5ClOG1VIqQ4r+gUx8)gVT4$#}K!+{QfDN5m0RWyn1FP+FDJ7(oXkweJX&obf zfDT)pfu?ngGC=1U$nzWkwt5CQ=cmhIgLjhmn?&p_GIvT1&n zWhPx%WJyFpRCt{2nlWqJKorOSDz)GQ#)G{Ww5HrD%&jJarqC_@48mU^^ed#z7bw}A zy=2u8yqc2LG_EFn0TFY;c(@LUT}3(DC)qkT^!*kI>+b&Y(|b>#`vU|)5ClOG1VIqQ z|A%8TNC=_IzfC3+qq+Y&?{^IlLa0FypwsChgy+Yk|2&_qf#mBf4jck ztHef8q_*k5>H)JPS)a#o?0mksP^;RPQsVdX^;wdvgOH{veBXaDw=QMJYj$aQC7zDw=ZmNp@zGwqbMSQVX0C;Mahe}&heIbPUbbfB7RJPuP?)(_~1VIo4 zK@bE%5ClOG1VIqQ4r+gUx8)gVT4$#}K!+{QfDN5m0RWyn1FP+FDJ7(oXkweJX&obf zfDT)pfu?ngGC=1U$nzWkwt5CQ=cmhIgLjhmn?&p_GIvT1&n zWhPx$0!c(cR9J=WlQC+;FcgMAm#*GR27}gOyf|RfNtf^?lFYtIE>Ln0c}eLIO%YyA za)qoRuahC|kXp8fLiK?Li|6+}{YVf91Ooq^Xh@NW&@|1%8m%?fk}j8#^BLgDr}z=p za?EqQm2X9-MQbJLk=DZyet;fb)C#9hk*&arfJkVC)e8zr4)0?!6SjyW)lHaRh7&o4+H{% aKfxD@DQrrv6qd{Y0000Px$1W80eR9J=W(?4s%Kpe*LZ;EU7A`X26&61##aIeHw2toJ0i--nX-RoO8L0rUJ z^bK?f(%l#E>mXU$(%xMH?QkE+kUy8_$&U*JK@bFgEV6k>YyIPWr4+{_Z=+H4?UWGFEY{BuRE&Q*bU|43bT$$_ZnD)0+Ht+j(t3=K_lb=WI#^FyF90t;y5WZ}&H> ze#2_HlzV7VHP^Zb2Zsqf_WQiPZ1XO|tqbHu5xrlp)OAfcVcb=?b%CY?z+kX_?kYS8 cg5Y2H01a7OIP*OAbN~PV07*qoM6N<$g7C+Xh5!Hn literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Materials/Scrap/generic.rsi/tube-g.png b/Resources/Textures/Objects/Materials/Scrap/generic.rsi/tube-g.png new file mode 100644 index 0000000000000000000000000000000000000000..92cc4fb45168047baece1d361ad42db2992aa69e GIT binary patch literal 314 zcmV-A0mc4_P)Px#^hrcPR9J=Wle-GSFcgOWh^xCuH)mbiO@#J!ikD}psBfXKa0-&mEIK;~McjRW z;~)jEm^1|)&IcI|xqSag2p|Z8Ap96*vxta3&c$&I05ArJC{kV508Q5o?=S`&hIY+7 z)2KtPHTG5adj)8Al=f?GPXxjnw&cLQxdRG!N^NTL&mZ06-9|dv(bLK@k3eE7_oDV`St+2><{9 M07*qoM6N<$f>yJApa1{> literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Materials/Scrap/generic.rsi/tube-r.png b/Resources/Textures/Objects/Materials/Scrap/generic.rsi/tube-r.png new file mode 100644 index 0000000000000000000000000000000000000000..e444ce686beeacd2f77c17af78321563ed4acaf1 GIT binary patch literal 334 zcmV-U0kQsxP)Px$2uVaiR9J=WlQC+;Fc^iON;+mQA%R|?T^z_1u&-lM=PWXbZ;@O^Px+!bPTV48&;5XnL7)@1?Yt8|{S*DlEYvl(S{yf1U_08I!07>~D4 geVGe_Ap8qH0L3(c9JByg!2kdN07*qoM6N<$f+h`)Pyhe` literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Materials/Scrap/generic.rsi/tube-y.png b/Resources/Textures/Objects/Materials/Scrap/generic.rsi/tube-y.png new file mode 100644 index 0000000000000000000000000000000000000000..590c5e8a931d7aabac417ffb6e5eb1114fc12dd3 GIT binary patch literal 313 zcmV-90mlA`P)Px#^GQTOR9J=WlRFB+Komvqi0(ne!VPE>(L#h|J3+IT1a%j>g(pZFahkXRg&_8} z!n2UzCxSCcK#O-^ih0b;x$^@AK@fx=qf7=7QLg5??n_^9uZRAy(XkCsx1I0_t-;Qq zZnT+qYE{VN82h60O9jZ}L4aPFb-u#PxfX_;>=<(*0udn$IVrNX(Y-PAOJ8d+9JP29 z*uPxX%JV$y0M=KK$>WH}&vI*XkpNMIB-{BYP@A%H!0;O`W;4D^r@3PPx#z)3_wR9J=Wl0OQAFcgPB+b*Soi$n1cP9pS7#W@F&u3o@XUhRrW10?mZUEMs$53-2 z2a6}zMiD`9b1EMlV4r2)y=`flhPw8h$wvq1Lja`d#g$tS1mQb)0Xw`!_BWW2S^xk5 M07*qoM6N<$g6Ab``2YX_ literal 0 HcmV?d00001 From 8ebe105458c4b9ea48e958992d698e5c6f88ddd6 Mon Sep 17 00:00:00 2001 From: themias <89101928+themias@users.noreply.github.com> Date: Thu, 8 Aug 2024 19:32:42 -0400 Subject: [PATCH 029/174] Add butter slices (#30789) --- .../VendingMachines/Inventories/chefvend.yml | 2 +- .../Objects/Consumable/Food/ingredients.yml | 29 ++++++++++++++++++ .../Recipes/Cooking/meal_recipes.yml | 10 +++--- .../Food/ingredients.rsi/butter-slice.png | Bin 0 -> 146 bytes .../Consumable/Food/ingredients.rsi/meta.json | 5 ++- 5 files changed, 39 insertions(+), 7 deletions(-) create mode 100644 Resources/Textures/Objects/Consumable/Food/ingredients.rsi/butter-slice.png diff --git a/Resources/Prototypes/Catalog/VendingMachines/Inventories/chefvend.yml b/Resources/Prototypes/Catalog/VendingMachines/Inventories/chefvend.yml index 1d1c9f8cd3..1ccda0e273 100644 --- a/Resources/Prototypes/Catalog/VendingMachines/Inventories/chefvend.yml +++ b/Resources/Prototypes/Catalog/VendingMachines/Inventories/chefvend.yml @@ -17,7 +17,7 @@ FoodContainerEgg: 1 DrinkMilkCarton: 2 DrinkSoyMilkCarton: 1 - FoodButter: 4 + FoodButter: 3 FoodCheese: 1 FoodMeat: 6 diff --git a/Resources/Prototypes/Entities/Objects/Consumable/Food/ingredients.yml b/Resources/Prototypes/Entities/Objects/Consumable/Food/ingredients.yml index 102703f2a5..a81ed55545 100644 --- a/Resources/Prototypes/Entities/Objects/Consumable/Food/ingredients.yml +++ b/Resources/Prototypes/Entities/Objects/Consumable/Food/ingredients.yml @@ -505,6 +505,35 @@ density: 10 mask: - ItemMask + - type: SolutionContainerManager + solutions: + food: + maxVol: 18 + reagents: + - ReagentId: Butter + Quantity: 15 + - type: SliceableFood + count: 3 + slice: FoodButterSlice + +- type: entity + name: butter slice + parent: FoodBakingBase + id: FoodButterSlice + description: A pat of delicious, golden, fatty goodness. + components: + - type: Sprite + state: butter-slice + - type: SolutionContainerManager + solutions: + food: + maxVol: 6 + reagents: + - ReagentId: Butter + Quantity: 5 + - type: Tag + tags: + - Slice - type: entity name: stick of cannabis butter diff --git a/Resources/Prototypes/Recipes/Cooking/meal_recipes.yml b/Resources/Prototypes/Recipes/Cooking/meal_recipes.yml index fff0e7db9f..1aace5896e 100644 --- a/Resources/Prototypes/Recipes/Cooking/meal_recipes.yml +++ b/Resources/Prototypes/Recipes/Cooking/meal_recipes.yml @@ -457,7 +457,7 @@ time: 5 solids: FoodBreadPlainSlice: 1 - FoodButter: 1 + FoodButterSlice: 1 - type: microwaveMealRecipe id: RecipeFrenchToast @@ -478,7 +478,7 @@ solids: FoodBreadPlainSlice: 1 FoodGarlic: 1 - FoodButter: 1 + FoodButterSlice: 1 - type: microwaveMealRecipe id: RecipeJellyToast @@ -1218,7 +1218,7 @@ Flour: 5 Sugar: 5 solids: - FoodButter: 1 + FoodButterSlice: 1 FoodSnackChocolateBar: 1 - type: microwaveMealRecipe @@ -1230,7 +1230,7 @@ Flour: 5 Sugar: 10 solids: - FoodButter: 1 + FoodButterSlice: 1 - type: microwaveMealRecipe id: RecipeRaisinCookie @@ -1252,7 +1252,7 @@ Oats: 5 Sugar: 5 solids: - FoodButter: 1 + FoodButterSlice: 1 - type: microwaveMealRecipe id: RecipeChocolateChipPancake diff --git a/Resources/Textures/Objects/Consumable/Food/ingredients.rsi/butter-slice.png b/Resources/Textures/Objects/Consumable/Food/ingredients.rsi/butter-slice.png new file mode 100644 index 0000000000000000000000000000000000000000..81b73772a7318579c56567281dd9a11720d2251c GIT binary patch literal 146 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnF3?v&v(vJfv{s5m4S0MfW#kT*C7W}{2{Qr#a zv-~&zfI^HVL4Lsu4$p3+0Xc@AE{-7@6O$7p7#jiw=IU!SC@s*?=vdTp(<3n8CS&B0 p8y+`VT^kNc^qxP^b4*^0fgyScbC&kf4NO4I44$rjF6*2UngD=UFWmqD literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Consumable/Food/ingredients.rsi/meta.json b/Resources/Textures/Objects/Consumable/Food/ingredients.rsi/meta.json index b4317b0c76..8e73375235 100644 --- a/Resources/Textures/Objects/Consumable/Food/ingredients.rsi/meta.json +++ b/Resources/Textures/Objects/Consumable/Food/ingredients.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation and baystation and modified by potato1234x at commit https://github.com/tgstation/tgstation/commit/c6e3401f2e7e1e55c57060cdf956a98ef1fefc24 and https://github.com/Baystation12/Baystation12/commit/a6067826de7fd8f698793f6d84e6c2f1f9b1f188. Tofu and tofu-slice were created by Discord user rosysyntax#6514. Chevrelog and chevredisk created by Github user deathride58, tortilladough tortillaflat and tortillaslice added by Phunny,", + "copyright": "Taken from tgstation and baystation and modified by potato1234x at commit https://github.com/tgstation/tgstation/commit/c6e3401f2e7e1e55c57060cdf956a98ef1fefc24 and https://github.com/Baystation12/Baystation12/commit/a6067826de7fd8f698793f6d84e6c2f1f9b1f188. Tofu and tofu-slice were created by Discord user rosysyntax#6514. Chevrelog and chevredisk created by Github user deathride58, tortilladough tortillaflat and tortillaslice added by Phunny, butter-slice taken from tgstation at commit https://github.com/tgstation/tgstation/commit/7ffd61b6fa6a6183daa8900f9a490f46f7a81955", "size": { "x": 32, "y": 32 @@ -111,6 +111,9 @@ }, { "name": "tortilladough-slice" + }, + { + "name": "butter-slice" } ] } From 15ae0435c451eb9ce8ed9e8072720d0ec3027e6b Mon Sep 17 00:00:00 2001 From: PJBot Date: Thu, 8 Aug 2024 23:33:48 +0000 Subject: [PATCH 030/174] Automatic changelog update --- Resources/Changelog/Changelog.yml | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index d904094e88..96d9f52389 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,12 +1,4 @@ Entries: -- author: deltanedas - changes: - - message: Firesuits and hardsuits now protect your skin from fire, you will instead - die of heatstroke. - type: Tweak - id: 6565 - time: '2024-05-09T07:12:48.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/27161 - author: Dutch-VanDerLinde changes: - message: Fixed non-inital infected getting the succumb to zombie action. @@ -3793,3 +3785,12 @@ id: 7064 time: '2024-08-08T23:27:28.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/26699 +- author: themias + changes: + - message: Butter can be sliced, cookie and toast recipes now use butter slices. + type: Tweak + - message: Chefvend butter reduced from 4 to 3. + type: Tweak + id: 7065 + time: '2024-08-08T23:32:42.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/30789 From e4ff5780d56c1d7f608fb6064f51c50a09c5dd6c Mon Sep 17 00:00:00 2001 From: deltanedas <39013340+deltanedas@users.noreply.github.com> Date: Thu, 8 Aug 2024 23:36:15 +0000 Subject: [PATCH 031/174] full sticky prediction (#30230) * move all sticky stuff to shared and cleanup/grammar fix * update imports and ref --------- Co-authored-by: deltanedas <@deltanedas:kde.org> --- .../Visualizers/StickyVisualizerSystem.cs | 16 +- .../EntitySystems/TriggerSystem.OnUse.cs | 4 +- .../Ninja/Systems/SpiderChargeSystem.cs | 6 +- .../Sticky/Components/StickyComponent.cs | 88 ------- .../Sticky/Events/EntityStuckEvent.cs | 68 ----- Content.Server/Sticky/Systems/StickySystem.cs | 234 ------------------ .../Sticky/Components/StickyComponent.cs | 90 +++++++ .../Components/StickyVisualizerComponent.cs | 19 +- Content.Shared/Sticky/EntityStuckEvent.cs | 26 ++ Content.Shared/Sticky/Systems/StickySystem.cs | 220 ++++++++++++++++ 10 files changed, 362 insertions(+), 409 deletions(-) delete mode 100644 Content.Server/Sticky/Components/StickyComponent.cs delete mode 100644 Content.Server/Sticky/Events/EntityStuckEvent.cs delete mode 100644 Content.Server/Sticky/Systems/StickySystem.cs create mode 100644 Content.Shared/Sticky/Components/StickyComponent.cs create mode 100644 Content.Shared/Sticky/EntityStuckEvent.cs create mode 100644 Content.Shared/Sticky/Systems/StickySystem.cs diff --git a/Content.Client/Sticky/Visualizers/StickyVisualizerSystem.cs b/Content.Client/Sticky/Visualizers/StickyVisualizerSystem.cs index 8bf8ac56ea..f7764479c0 100644 --- a/Content.Client/Sticky/Visualizers/StickyVisualizerSystem.cs +++ b/Content.Client/Sticky/Visualizers/StickyVisualizerSystem.cs @@ -5,21 +5,26 @@ namespace Content.Client.Sticky.Visualizers; public sealed class StickyVisualizerSystem : VisualizerSystem { + private EntityQuery _spriteQuery; + public override void Initialize() { base.Initialize(); + + _spriteQuery = GetEntityQuery(); + SubscribeLocalEvent(OnInit); } - private void OnInit(EntityUid uid, StickyVisualizerComponent component, ComponentInit args) + private void OnInit(Entity ent, ref ComponentInit args) { - if (!TryComp(uid, out SpriteComponent? sprite)) + if (!_spriteQuery.TryComp(ent, out var sprite)) return; - component.DefaultDrawDepth = sprite.DrawDepth; + ent.Comp.OriginalDrawDepth = sprite.DrawDepth; } - protected override void OnAppearanceChange(EntityUid uid, StickyVisualizerComponent component, ref AppearanceChangeEvent args) + protected override void OnAppearanceChange(EntityUid uid, StickyVisualizerComponent comp, ref AppearanceChangeEvent args) { if (args.Sprite == null) return; @@ -27,8 +32,7 @@ public sealed class StickyVisualizerSystem : VisualizerSystem(uid, StickyVisuals.IsStuck, out var isStuck, args.Component)) return; - var drawDepth = isStuck ? component.StuckDrawDepth : component.DefaultDrawDepth; + var drawDepth = isStuck ? comp.StuckDrawDepth : comp.OriginalDrawDepth; args.Sprite.DrawDepth = drawDepth; - } } diff --git a/Content.Server/Explosion/EntitySystems/TriggerSystem.OnUse.cs b/Content.Server/Explosion/EntitySystems/TriggerSystem.OnUse.cs index dcd11062bb..d06e9fa1c2 100644 --- a/Content.Server/Explosion/EntitySystems/TriggerSystem.OnUse.cs +++ b/Content.Server/Explosion/EntitySystems/TriggerSystem.OnUse.cs @@ -1,9 +1,9 @@ using Content.Server.Explosion.Components; -using Content.Server.Sticky.Events; using Content.Shared.Examine; using Content.Shared.Explosion.Components; using Content.Shared.Interaction.Events; using Content.Shared.Popups; +using Content.Shared.Sticky; using Content.Shared.Verbs; namespace Content.Server.Explosion.EntitySystems; @@ -21,7 +21,7 @@ public sealed partial class TriggerSystem SubscribeLocalEvent(OnRandomTimerTriggerMapInit); } - private void OnStuck(EntityUid uid, OnUseTimerTriggerComponent component, EntityStuckEvent args) + private void OnStuck(EntityUid uid, OnUseTimerTriggerComponent component, ref EntityStuckEvent args) { if (!component.StartOnStick) return; diff --git a/Content.Server/Ninja/Systems/SpiderChargeSystem.cs b/Content.Server/Ninja/Systems/SpiderChargeSystem.cs index c262651f27..c916d568d5 100644 --- a/Content.Server/Ninja/Systems/SpiderChargeSystem.cs +++ b/Content.Server/Ninja/Systems/SpiderChargeSystem.cs @@ -4,10 +4,10 @@ using Content.Server.Mind; using Content.Server.Objectives.Components; using Content.Server.Popups; using Content.Server.Roles; -using Content.Server.Sticky.Events; using Content.Shared.Interaction; using Content.Shared.Ninja.Components; using Content.Shared.Ninja.Systems; +using Content.Shared.Sticky; using Robust.Shared.GameObjects; namespace Content.Server.Ninja.Systems; @@ -34,7 +34,7 @@ public sealed class SpiderChargeSystem : SharedSpiderChargeSystem /// /// Require that the planter is a ninja and the charge is near the target warp point. /// - private void OnAttemptStick(EntityUid uid, SpiderChargeComponent comp, AttemptEntityStickEvent args) + private void OnAttemptStick(EntityUid uid, SpiderChargeComponent comp, ref AttemptEntityStickEvent args) { if (args.Cancelled) return; @@ -67,7 +67,7 @@ public sealed class SpiderChargeSystem : SharedSpiderChargeSystem /// /// Allows greentext to occur after exploding. /// - private void OnStuck(EntityUid uid, SpiderChargeComponent comp, EntityStuckEvent args) + private void OnStuck(EntityUid uid, SpiderChargeComponent comp, ref EntityStuckEvent args) { comp.Planter = args.User; } diff --git a/Content.Server/Sticky/Components/StickyComponent.cs b/Content.Server/Sticky/Components/StickyComponent.cs deleted file mode 100644 index 320938000f..0000000000 --- a/Content.Server/Sticky/Components/StickyComponent.cs +++ /dev/null @@ -1,88 +0,0 @@ -using Content.Shared.Whitelist; - -namespace Content.Server.Sticky.Components; - -/// -/// Items that can be stick to other structures or entities. -/// For example paper stickers or C4 charges. -/// -[RegisterComponent] -public sealed partial class StickyComponent : Component -{ - /// - /// What target entities are valid to be surface for sticky entity. - /// - [DataField("whitelist")] - [ViewVariables(VVAccess.ReadWrite)] - public EntityWhitelist? Whitelist; - - /// - /// What target entities can't be used as surface for sticky entity. - /// - [DataField("blacklist")] - [ViewVariables(VVAccess.ReadWrite)] - public EntityWhitelist? Blacklist; - - /// - /// How much time does it take to stick entity to target. - /// If zero will stick entity immediately. - /// - [DataField("stickDelay")] - [ViewVariables(VVAccess.ReadWrite)] - public TimeSpan StickDelay = TimeSpan.Zero; - - /// - /// Whether users can unstick item when it was stuck to surface. - /// - [DataField("canUnstick")] - [ViewVariables(VVAccess.ReadWrite)] - public bool CanUnstick = true; - - /// - /// How much time does it take to unstick entity. - /// If zero will unstick entity immediately. - /// - [DataField("unstickDelay")] - [ViewVariables(VVAccess.ReadWrite)] - public TimeSpan UnstickDelay = TimeSpan.Zero; - - /// - /// Popup message shown when player started sticking entity to another entity. - /// - [DataField("stickPopupStart")] - [ViewVariables(VVAccess.ReadWrite)] - public string? StickPopupStart; - - /// - /// Popup message shown when player successfully stuck entity. - /// - [DataField("stickPopupSuccess")] - [ViewVariables(VVAccess.ReadWrite)] - public string? StickPopupSuccess; - - /// - /// Popup message shown when player started unsticking entity from another entity. - /// - [DataField("unstickPopupStart")] - [ViewVariables(VVAccess.ReadWrite)] - public string? UnstickPopupStart; - - /// - /// Popup message shown when player successfully unstuck entity. - /// - [DataField("unstickPopupSuccess")] - [ViewVariables(VVAccess.ReadWrite)] - public string? UnstickPopupSuccess; - - /// - /// Entity that is used as surface for sticky entity. - /// Null if entity doesn't stuck to anything. - /// - [ViewVariables(VVAccess.ReadOnly)] - public EntityUid? StuckTo; - - /// - /// For the DoAfter event to tell if it should stick or unstick - /// - public bool Stick; -} diff --git a/Content.Server/Sticky/Events/EntityStuckEvent.cs b/Content.Server/Sticky/Events/EntityStuckEvent.cs deleted file mode 100644 index 7857fad7d5..0000000000 --- a/Content.Server/Sticky/Events/EntityStuckEvent.cs +++ /dev/null @@ -1,68 +0,0 @@ -namespace Content.Server.Sticky.Events; - -/// -/// Risen on sticky entity to see if it can stick to another entity. -/// -[ByRefEvent] -public record struct AttemptEntityStickEvent(EntityUid Target, EntityUid User) -{ - public readonly EntityUid Target = Target; - public readonly EntityUid User = User; - public bool Cancelled = false; -} - -/// -/// Risen on sticky entity to see if it can unstick from another entity. -/// -[ByRefEvent] -public record struct AttemptEntityUnstickEvent(EntityUid Target, EntityUid User) -{ - public readonly EntityUid Target = Target; - public readonly EntityUid User = User; - public bool Cancelled = false; -} - - -/// -/// Risen on sticky entity when it was stuck to other entity. -/// -public sealed class EntityStuckEvent : EntityEventArgs -{ - /// - /// Entity that was used as a surface for sticky object. - /// - public readonly EntityUid Target; - - /// - /// Entity that stuck sticky object on target. - /// - public readonly EntityUid User; - - public EntityStuckEvent(EntityUid target, EntityUid user) - { - Target = target; - User = user; - } -} - -/// -/// Risen on sticky entity when it was unstuck from other entity. -/// -public sealed class EntityUnstuckEvent : EntityEventArgs -{ - /// - /// Entity that was used as a surface for sticky object. - /// - public readonly EntityUid Target; - - /// - /// Entity that unstuck sticky object on target. - /// - public readonly EntityUid User; - - public EntityUnstuckEvent(EntityUid target, EntityUid user) - { - Target = target; - User = user; - } -} diff --git a/Content.Server/Sticky/Systems/StickySystem.cs b/Content.Server/Sticky/Systems/StickySystem.cs deleted file mode 100644 index 23064a93cb..0000000000 --- a/Content.Server/Sticky/Systems/StickySystem.cs +++ /dev/null @@ -1,234 +0,0 @@ -using Content.Server.Popups; -using Content.Server.Sticky.Components; -using Content.Server.Sticky.Events; -using Content.Shared.DoAfter; -using Content.Shared.Hands.EntitySystems; -using Content.Shared.Interaction; -using Content.Shared.Sticky; -using Content.Shared.Sticky.Components; -using Content.Shared.Verbs; -using Content.Shared.Whitelist; -using Robust.Shared.Containers; -using Robust.Shared.Utility; - -namespace Content.Server.Sticky.Systems; - -public sealed class StickySystem : EntitySystem -{ - [Dependency] private readonly SharedDoAfterSystem _doAfterSystem = default!; - [Dependency] private readonly PopupSystem _popupSystem = default!; - [Dependency] private readonly SharedContainerSystem _containerSystem = default!; - [Dependency] private readonly SharedHandsSystem _handsSystem = default!; - [Dependency] private readonly SharedInteractionSystem _interactionSystem = default!; - [Dependency] private readonly SharedAppearanceSystem _appearance = default!; - [Dependency] private readonly EntityWhitelistSystem _whitelistSystem = default!; - - private const string StickerSlotId = "stickers_container"; - - public override void Initialize() - { - base.Initialize(); - SubscribeLocalEvent(OnStickFinished); - SubscribeLocalEvent(OnAfterInteract); - SubscribeLocalEvent>(AddUnstickVerb); - } - - private void OnAfterInteract(EntityUid uid, StickyComponent component, AfterInteractEvent args) - { - if (args.Handled || !args.CanReach || args.Target == null) - return; - - // try stick object to a clicked target entity - args.Handled = StartSticking(uid, args.User, args.Target.Value, component); - } - - private void AddUnstickVerb(EntityUid uid, StickyComponent component, GetVerbsEvent args) - { - if (component.StuckTo == null || !component.CanUnstick || !args.CanInteract || args.Hands == null) - return; - - // we can't use args.CanAccess, because it stuck in another container - // we also need to ignore entity that it stuck to - var inRange = _interactionSystem.InRangeUnobstructed(uid, args.User, - predicate: entity => component.StuckTo == entity); - if (!inRange) - return; - - args.Verbs.Add(new Verb - { - DoContactInteraction = true, - Text = Loc.GetString("comp-sticky-unstick-verb-text"), - Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/VerbIcons/eject.svg.192dpi.png")), - Act = () => StartUnsticking(uid, args.User, component) - }); - } - - private bool StartSticking(EntityUid uid, EntityUid user, EntityUid target, StickyComponent? component = null) - { - if (!Resolve(uid, ref component)) - return false; - - // check whitelist and blacklist - if (_whitelistSystem.IsWhitelistFail(component.Whitelist, target) || - _whitelistSystem.IsBlacklistPass(component.Blacklist, target)) - return false; - - var attemptEv = new AttemptEntityStickEvent(target, user); - RaiseLocalEvent(uid, ref attemptEv); - if (attemptEv.Cancelled) - return false; - - // check if delay is not zero to start do after - var delay = (float) component.StickDelay.TotalSeconds; - if (delay > 0) - { - // show message to user - if (component.StickPopupStart != null) - { - var msg = Loc.GetString(component.StickPopupStart); - _popupSystem.PopupEntity(msg, user, user); - } - - component.Stick = true; - - // start sticking object to target - _doAfterSystem.TryStartDoAfter(new DoAfterArgs(EntityManager, user, delay, new StickyDoAfterEvent(), uid, target: target, used: uid) - { - BreakOnMove = true, - NeedHand = true, - }); - } - else - { - // if delay is zero - stick entity immediately - StickToEntity(uid, target, user, component); - } - - return true; - } - - private void OnStickFinished(EntityUid uid, StickyComponent component, DoAfterEvent args) - { - if (args.Handled || args.Cancelled || args.Args.Target == null) - return; - - if (component.Stick) - StickToEntity(uid, args.Args.Target.Value, args.Args.User, component); - else - UnstickFromEntity(uid, args.Args.User, component); - - args.Handled = true; - } - - private void StartUnsticking(EntityUid uid, EntityUid user, StickyComponent? component = null) - { - if (!Resolve(uid, ref component)) - return; - - if (component.StuckTo is not { } stuckTo) - return; - - var attemptEv = new AttemptEntityUnstickEvent(stuckTo, user); - RaiseLocalEvent(uid, ref attemptEv); - if (attemptEv.Cancelled) - return; - - var delay = (float) component.UnstickDelay.TotalSeconds; - if (delay > 0) - { - // show message to user - if (component.UnstickPopupStart != null) - { - var msg = Loc.GetString(component.UnstickPopupStart); - _popupSystem.PopupEntity(msg, user, user); - } - - component.Stick = false; - - // start unsticking object - _doAfterSystem.TryStartDoAfter(new DoAfterArgs(EntityManager, user, delay, new StickyDoAfterEvent(), uid, target: uid) - { - BreakOnMove = true, - NeedHand = true, - }); - } - else - { - // if delay is zero - unstick entity immediately - UnstickFromEntity(uid, user, component); - } - } - - public void StickToEntity(EntityUid uid, EntityUid target, EntityUid user, StickyComponent? component = null) - { - if (!Resolve(uid, ref component)) - return; - - var attemptEv = new AttemptEntityStickEvent(target, user); - RaiseLocalEvent(uid, ref attemptEv); - if (attemptEv.Cancelled) - return; - - // add container to entity and insert sticker into it - var container = _containerSystem.EnsureContainer(target, StickerSlotId); - container.ShowContents = true; - if (!_containerSystem.Insert(uid, container)) - return; - - // show message to user - if (component.StickPopupSuccess != null) - { - var msg = Loc.GetString(component.StickPopupSuccess); - _popupSystem.PopupEntity(msg, user, user); - } - - // send information to appearance that entity is stuck - if (TryComp(uid, out AppearanceComponent? appearance)) - { - _appearance.SetData(uid, StickyVisuals.IsStuck, true, appearance); - } - - component.StuckTo = target; - RaiseLocalEvent(uid, new EntityStuckEvent(target, user), true); - } - - public void UnstickFromEntity(EntityUid uid, EntityUid user, StickyComponent? component = null) - { - if (!Resolve(uid, ref component)) - return; - - if (component.StuckTo is not { } stuckTo) - return; - - var attemptEv = new AttemptEntityUnstickEvent(stuckTo, user); - RaiseLocalEvent(uid, ref attemptEv); - if (attemptEv.Cancelled) - return; - - // try to remove sticky item from target container - if (!_containerSystem.TryGetContainer(stuckTo, StickerSlotId, out var container) || !_containerSystem.Remove(uid, container)) - return; - // delete container if it's now empty - if (container.ContainedEntities.Count == 0) - _containerSystem.ShutdownContainer(container); - - // try place dropped entity into user hands - _handsSystem.PickupOrDrop(user, uid); - - // send information to appearance that entity isn't stuck - if (TryComp(uid, out AppearanceComponent? appearance)) - { - _appearance.SetData(uid, StickyVisuals.IsStuck, false, appearance); - } - - // show message to user - if (component.UnstickPopupSuccess != null) - { - var msg = Loc.GetString(component.UnstickPopupSuccess); - _popupSystem.PopupEntity(msg, user, user); - } - - component.StuckTo = null; - RaiseLocalEvent(uid, new EntityUnstuckEvent(stuckTo, user), true); - } -} diff --git a/Content.Shared/Sticky/Components/StickyComponent.cs b/Content.Shared/Sticky/Components/StickyComponent.cs new file mode 100644 index 0000000000..4513091754 --- /dev/null +++ b/Content.Shared/Sticky/Components/StickyComponent.cs @@ -0,0 +1,90 @@ +using Content.Shared.Sticky.Systems; +using Content.Shared.Whitelist; +using Robust.Shared.GameStates; +using Robust.Shared.Utility; + +namespace Content.Shared.Sticky.Components; + +/// +/// Items that can be stuck to other structures or entities. +/// For example, paper stickers or C4 charges. +/// +[RegisterComponent, NetworkedComponent, Access(typeof(StickySystem))] +[AutoGenerateComponentState] +public sealed partial class StickyComponent : Component +{ + /// + /// What target entities are valid to be surface for sticky entity. + /// + [DataField] + public EntityWhitelist? Whitelist; + + /// + /// What target entities can't be used as surface for sticky entity. + /// + [DataField] + public EntityWhitelist? Blacklist; + + /// + /// How much time it takes to stick the entity to a target. + /// If zero, it will immediately be stuck. + /// + [DataField] + public TimeSpan StickDelay = TimeSpan.Zero; + + /// + /// Whether users can unstick the entity after it has been stuck. + /// + [DataField] + public bool CanUnstick = true; + + /// + /// How much time it takes to unstick the entity. + /// If zero, it will immediately be unstuck. + /// + [DataField] + public TimeSpan UnstickDelay = TimeSpan.Zero; + + /// + /// Popup message shown when player starts sticking the entity to another entity. + /// + [DataField] + public LocId? StickPopupStart; + + /// + /// Popup message shown when a player successfully sticks the entity. + /// + [DataField] + public LocId? StickPopupSuccess; + + /// + /// Popup message shown when a player starts unsticking the entity from another entity. + /// + [DataField] + public LocId? UnstickPopupStart; + + /// + /// Popup message shown when a player successfully unsticks the entity. + /// + [DataField] + public LocId? UnstickPopupSuccess; + + /// + /// Entity that is used as a surface for the sticky entity. + /// Null if entity isn't stuck to anything. + /// + [DataField, AutoNetworkedField] + public EntityUid? StuckTo; + + /// + /// Text to use for the unstick verb. + /// + [DataField] + public LocId VerbText = "comp-sticky-unstick-verb-text"; + + /// + /// Icon to use for the unstick verb. + /// + [DataField] + public SpriteSpecifier VerbIcon = new SpriteSpecifier.Texture(new("/Textures/Interface/VerbIcons/eject.svg.192dpi.png")); +} diff --git a/Content.Shared/Sticky/Components/StickyVisualizerComponent.cs b/Content.Shared/Sticky/Components/StickyVisualizerComponent.cs index c32be646fc..fd37836dcf 100644 --- a/Content.Shared/Sticky/Components/StickyVisualizerComponent.cs +++ b/Content.Shared/Sticky/Components/StickyVisualizerComponent.cs @@ -1,23 +1,26 @@ -using Robust.Shared.Serialization; +using Robust.Shared.Serialization; namespace Content.Shared.Sticky.Components; -using DrawDepth; +using DrawDepth; + +/// +/// Sets the sprite's draw depth depending on whether it's stuck. +/// [RegisterComponent] public sealed partial class StickyVisualizerComponent : Component { /// - /// What sprite draw depth set when entity stuck. + /// What sprite draw depth gets set to when stuck to something. /// - [DataField("stuckDrawDepth")] - [ViewVariables(VVAccess.ReadWrite)] + [DataField] public int StuckDrawDepth = (int) DrawDepth.Overdoors; /// - /// What sprite draw depth set when entity unstuck. + /// The sprite's original draw depth before being stuck. /// - [ViewVariables(VVAccess.ReadWrite)] - public int DefaultDrawDepth; + [DataField] + public int OriginalDrawDepth; } [Serializable, NetSerializable] diff --git a/Content.Shared/Sticky/EntityStuckEvent.cs b/Content.Shared/Sticky/EntityStuckEvent.cs new file mode 100644 index 0000000000..ae7a65c0ad --- /dev/null +++ b/Content.Shared/Sticky/EntityStuckEvent.cs @@ -0,0 +1,26 @@ +namespace Content.Shared.Sticky; + +/// +/// Risen on sticky entity to see if it can stick to another entity. +/// +[ByRefEvent] +public record struct AttemptEntityStickEvent(EntityUid Target, EntityUid User, bool Cancelled = false); + +/// +/// Risen on sticky entity to see if it can unstick from another entity. +/// +[ByRefEvent] +public record struct AttemptEntityUnstickEvent(EntityUid Target, EntityUid User, bool Cancelled = false); + + +/// +/// Risen on sticky entity when it was stuck to other entity. +/// +[ByRefEvent] +public record struct EntityStuckEvent(EntityUid Target, EntityUid User); + +/// +/// Risen on sticky entity when it was unstuck from other entity. +/// +[ByRefEvent] +public record struct EntityUnstuckEvent(EntityUid Target, EntityUid User); diff --git a/Content.Shared/Sticky/Systems/StickySystem.cs b/Content.Shared/Sticky/Systems/StickySystem.cs new file mode 100644 index 0000000000..ea768fea93 --- /dev/null +++ b/Content.Shared/Sticky/Systems/StickySystem.cs @@ -0,0 +1,220 @@ +using Content.Shared.DoAfter; +using Content.Shared.Hands.EntitySystems; +using Content.Shared.Interaction; +using Content.Shared.Popups; +using Content.Shared.Sticky.Components; +using Content.Shared.Verbs; +using Content.Shared.Whitelist; +using Robust.Shared.Containers; + +namespace Content.Shared.Sticky.Systems; + +public sealed class StickySystem : EntitySystem +{ + [Dependency] private readonly EntityWhitelistSystem _whitelist = default!; + [Dependency] private readonly SharedAppearanceSystem _appearance = default!; + [Dependency] private readonly SharedContainerSystem _container = default!; + [Dependency] private readonly SharedDoAfterSystem _doAfter = default!; + [Dependency] private readonly SharedHandsSystem _hands = default!; + [Dependency] private readonly SharedInteractionSystem _interaction = default!; + [Dependency] private readonly SharedPopupSystem _popup = default!; + + private const string StickerSlotId = "stickers_container"; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnAfterInteract); + SubscribeLocalEvent(OnStickyDoAfter); + SubscribeLocalEvent>(OnGetVerbs); + } + + private void OnAfterInteract(Entity ent, ref AfterInteractEvent args) + { + if (args.Handled || !args.CanReach || args.Target is not {} target) + return; + + // try stick object to a clicked target entity + args.Handled = StartSticking(ent, target, args.User); + } + + private void OnGetVerbs(Entity ent, ref GetVerbsEvent args) + { + var (uid, comp) = ent; + if (comp.StuckTo == null || !comp.CanUnstick || !args.CanInteract || args.Hands == null) + return; + + // we can't use args.CanAccess, because it stuck in another container + // we also need to ignore entity that it stuck to + var user = args.User; + var inRange = _interaction.InRangeUnobstructed(uid, user, + predicate: entity => comp.StuckTo == entity); + if (!inRange) + return; + + args.Verbs.Add(new Verb + { + DoContactInteraction = true, + Text = Loc.GetString(comp.VerbText), + Icon = comp.VerbIcon, + Act = () => StartUnsticking(ent, user) + }); + } + + private bool StartSticking(Entity ent, EntityUid target, EntityUid user) + { + var (uid, comp) = ent; + + // check whitelist and blacklist + if (_whitelist.IsWhitelistFail(comp.Whitelist, target) || + _whitelist.IsBlacklistPass(comp.Blacklist, target)) + return false; + + var attemptEv = new AttemptEntityStickEvent(target, user); + RaiseLocalEvent(uid, ref attemptEv); + if (attemptEv.Cancelled) + return false; + + // skip doafter and popup if it's instant + if (comp.StickDelay <= TimeSpan.Zero) + { + StickToEntity(ent, target, user); + return true; + } + + // show message to user + if (comp.StickPopupStart != null) + { + var msg = Loc.GetString(comp.StickPopupStart); + _popup.PopupClient(msg, user, user); + } + + // start sticking object to target + _doAfter.TryStartDoAfter(new DoAfterArgs(EntityManager, user, comp.StickDelay, new StickyDoAfterEvent(), uid, target: target, used: uid) + { + BreakOnMove = true, + NeedHand = true, + }); + + return true; + } + + private void OnStickyDoAfter(Entity ent, ref StickyDoAfterEvent args) + { + // target is the sticky item when unsticking and the surface when sticking, it will never be null + if (args.Handled || args.Cancelled || args.Args.Target is not {} target) + return; + + var user = args.User; + if (ent.Comp.StuckTo == null) + StickToEntity(ent, target, user); + else + UnstickFromEntity(ent, user); + + args.Handled = true; + } + + private void StartUnsticking(Entity ent, EntityUid user) + { + var (uid, comp) = ent; + if (comp.StuckTo is not {} stuckTo) + return; + + var attemptEv = new AttemptEntityUnstickEvent(stuckTo, user); + RaiseLocalEvent(uid, ref attemptEv); + if (attemptEv.Cancelled) + return; + + // skip doafter and popup if it's instant + if (comp.UnstickDelay <= TimeSpan.Zero) + { + UnstickFromEntity(ent, user); + return; + } + + // show message to user + if (comp.UnstickPopupStart != null) + { + var msg = Loc.GetString(comp.UnstickPopupStart); + _popup.PopupClient(msg, user, user); + } + + // start unsticking object + _doAfter.TryStartDoAfter(new DoAfterArgs(EntityManager, user, comp.UnstickDelay, new StickyDoAfterEvent(), uid, target: uid) + { + BreakOnMove = true, + NeedHand = true, + }); + } + + public void StickToEntity(Entity ent, EntityUid target, EntityUid user) + { + var (uid, comp) = ent; + var attemptEv = new AttemptEntityStickEvent(target, user); + RaiseLocalEvent(uid, ref attemptEv); + if (attemptEv.Cancelled) + return; + + // add container to entity and insert sticker into it + var container = _container.EnsureContainer(target, StickerSlotId); + container.ShowContents = true; + if (!_container.Insert(uid, container)) + return; + + // show message to user + if (comp.StickPopupSuccess != null) + { + var msg = Loc.GetString(comp.StickPopupSuccess); + _popup.PopupClient(msg, user, user); + } + + // send information to appearance that entity is stuck + _appearance.SetData(uid, StickyVisuals.IsStuck, true); + + comp.StuckTo = target; + Dirty(uid, comp); + + var ev = new EntityStuckEvent(target, user); + RaiseLocalEvent(uid, ref ev); + } + + public void UnstickFromEntity(Entity ent, EntityUid user) + { + var (uid, comp) = ent; + if (comp.StuckTo is not {} stuckTo) + return; + + var attemptEv = new AttemptEntityUnstickEvent(stuckTo, user); + RaiseLocalEvent(uid, ref attemptEv); + if (attemptEv.Cancelled) + return; + + // try to remove sticky item from target container + if (!_container.TryGetContainer(stuckTo, StickerSlotId, out var container) || !_container.Remove(uid, container)) + return; + + // delete container if it's now empty + if (container.ContainedEntities.Count == 0) + _container.ShutdownContainer(container); + + // try place dropped entity into user hands + _hands.PickupOrDrop(user, uid); + + // send information to appearance that entity isn't stuck + _appearance.SetData(uid, StickyVisuals.IsStuck, false); + + // show message to user + if (comp.UnstickPopupSuccess != null) + { + var msg = Loc.GetString(comp.UnstickPopupSuccess); + _popup.PopupClient(msg, user, user); + } + + comp.StuckTo = null; + Dirty(uid, comp); + + var ev = new EntityUnstuckEvent(stuckTo, user); + RaiseLocalEvent(uid, ref ev); + } +} From ad18c6e9a54b033d93eaa7bebd40e38e2a997390 Mon Sep 17 00:00:00 2001 From: beck-thompson <107373427+beck-thompson@users.noreply.github.com> Date: Thu, 8 Aug 2024 16:51:58 -0700 Subject: [PATCH 032/174] Secret stash refractor (#29396) * First commit * Will do this in another PR! * maybe? * Moved stuff to ToolOpenableSystem because its smarter and cooler --- .../Nutrition/EntitySystems/UtensilSystem.cs | 3 +- .../Plants/PottedPlantHideComponent.cs | 17 - .../Plants/PottedPlantHideSystem.cs | 63 --- .../Components/SecretStashComponent.cs | 70 +-- .../EntitySystems/SecretStashSystem.cs | 399 +++++++++--------- .../Tools/Components/ToolOpenableComponent.cs | 84 ++++ .../Tools/Systems/ToolOpenableSystem.cs | 171 ++++++++ .../components/secret-stash-component.ftl | 29 +- .../components/tool-openable-component.ftl | 6 + .../Structures/Furniture/potted_plants.yml | 6 +- .../Entities/Structures/Furniture/toilet.yml | 16 +- 11 files changed, 513 insertions(+), 351 deletions(-) delete mode 100644 Content.Shared/Plants/PottedPlantHideComponent.cs delete mode 100644 Content.Shared/Plants/PottedPlantHideSystem.cs create mode 100644 Content.Shared/Tools/Components/ToolOpenableComponent.cs create mode 100644 Content.Shared/Tools/Systems/ToolOpenableSystem.cs create mode 100644 Resources/Locale/en-US/tools/components/tool-openable-component.ftl diff --git a/Content.Server/Nutrition/EntitySystems/UtensilSystem.cs b/Content.Server/Nutrition/EntitySystems/UtensilSystem.cs index d40288183f..1f3d5afb43 100644 --- a/Content.Server/Nutrition/EntitySystems/UtensilSystem.cs +++ b/Content.Server/Nutrition/EntitySystems/UtensilSystem.cs @@ -4,6 +4,7 @@ using Content.Server.Popups; using Content.Shared.Interaction; using Content.Shared.Nutrition.Components; using Content.Shared.Nutrition.EntitySystems; +using Content.Shared.Tools.EntitySystems; using Robust.Shared.Audio; using Robust.Shared.Audio.Systems; using Robust.Shared.Random; @@ -25,7 +26,7 @@ namespace Content.Server.Nutrition.EntitySystems { base.Initialize(); - SubscribeLocalEvent(OnAfterInteract, after: new[] { typeof(ItemSlotsSystem) }); + SubscribeLocalEvent(OnAfterInteract, after: new[] { typeof(ItemSlotsSystem), typeof(ToolOpenableSystem) }); } /// diff --git a/Content.Shared/Plants/PottedPlantHideComponent.cs b/Content.Shared/Plants/PottedPlantHideComponent.cs deleted file mode 100644 index 2e02272494..0000000000 --- a/Content.Shared/Plants/PottedPlantHideComponent.cs +++ /dev/null @@ -1,17 +0,0 @@ -using Content.Shared.Storage.Components; -using Robust.Shared.Audio; - -namespace Content.Shared.Plants -{ - /// - /// Interaction wrapper for . - /// Gently rustle after each interaction with plant. - /// - [RegisterComponent] - [Access(typeof(PottedPlantHideSystem))] - public sealed partial class PottedPlantHideComponent : Component - { - [DataField("rustleSound")] - public SoundSpecifier RustleSound = new SoundPathSpecifier("/Audio/Effects/plant_rustle.ogg"); - } -} diff --git a/Content.Shared/Plants/PottedPlantHideSystem.cs b/Content.Shared/Plants/PottedPlantHideSystem.cs deleted file mode 100644 index cbe052f8d5..0000000000 --- a/Content.Shared/Plants/PottedPlantHideSystem.cs +++ /dev/null @@ -1,63 +0,0 @@ -using Content.Shared.Popups; -using Content.Shared.Storage.Components; -using Content.Shared.Storage.EntitySystems; -using Content.Shared.Interaction; -using Robust.Shared.Audio; -using Robust.Shared.Audio.Systems; - -namespace Content.Shared.Plants -{ - public sealed class PottedPlantHideSystem : EntitySystem - { - [Dependency] private readonly SharedPopupSystem _popupSystem = default!; - [Dependency] private readonly SecretStashSystem _stashSystem = default!; - [Dependency] private readonly SharedAudioSystem _audio = default!; - - public override void Initialize() - { - base.Initialize(); - SubscribeLocalEvent(OnInit); - SubscribeLocalEvent(OnInteractUsing); - SubscribeLocalEvent(OnInteractHand); - } - - private void OnInit(EntityUid uid, PottedPlantHideComponent component, ComponentInit args) - { - EntityManager.EnsureComponent(uid); - } - - private void OnInteractUsing(EntityUid uid, PottedPlantHideComponent component, InteractUsingEvent args) - { - if (args.Handled) - return; - - Rustle(uid, component, args.User); - args.Handled = _stashSystem.TryHideItem(uid, args.User, args.Used); - } - - private void OnInteractHand(EntityUid uid, PottedPlantHideComponent component, InteractHandEvent args) - { - if (args.Handled) - return; - - Rustle(uid, component, args.User); - - var gotItem = _stashSystem.TryGetItem(uid, args.User); - if (!gotItem) - { - var msg = Loc.GetString("potted-plant-hide-component-interact-hand-got-no-item-message"); - _popupSystem.PopupClient(msg, uid, args.User); - } - - args.Handled = gotItem; - } - - private void Rustle(EntityUid uid, PottedPlantHideComponent? component = null, EntityUid? user = null) - { - if (!Resolve(uid, ref component)) - return; - - _audio.PlayPredicted(component.RustleSound, uid, user, AudioParams.Default.WithVariation(0.25f)); - } - } -} diff --git a/Content.Shared/Storage/Components/SecretStashComponent.cs b/Content.Shared/Storage/Components/SecretStashComponent.cs index 8595f79ca5..3bf8e2e871 100644 --- a/Content.Shared/Storage/Components/SecretStashComponent.cs +++ b/Content.Shared/Storage/Components/SecretStashComponent.cs @@ -7,84 +7,56 @@ using Content.Shared.Tools; using Robust.Shared.GameStates; using Content.Shared.DoAfter; using Robust.Shared.Serialization; +using Robust.Shared.Audio; namespace Content.Shared.Storage.Components { /// /// Logic for a secret slot stash, like plant pot or toilet cistern. - /// Unlike it doesn't have interaction logic or verbs. - /// Other classes like should implement it. + /// Unlike it has logic for opening and closing + /// the stash. /// [RegisterComponent, NetworkedComponent, AutoGenerateComponentState] [Access(typeof(SecretStashSystem))] public sealed partial class SecretStashComponent : Component { /// - /// Max item size that can be fitted into secret stash. + /// Max item size that can be inserted into secret stash. /// [DataField("maxItemSize")] public ProtoId MaxItemSize = "Small"; /// - /// If stash has way to open then this will switch between open and closed. - /// - [DataField, AutoNetworkedField] - public bool ToggleOpen; - - /// - /// Prying the door. + /// This sound will be played when you try to insert an item in the stash. + /// The sound will be played whether or not the item is actually inserted. /// [DataField] - public float PryDoorTime = 1f; - - [DataField] - public ProtoId PryingQuality = "Prying"; + public SoundSpecifier? TryInsertItemSound; /// - /// Is stash openable?. - /// - [DataField, AutoNetworkedField] - public bool OpenableStash = false; - - /// - /// IC secret stash name. For example "the toilet cistern". - /// If empty string, will replace it with entity name in init. + /// This sound will be played when you try to remove an item in the stash. + /// The sound will be played whether or not the item is actually removed. /// [DataField] - public string SecretPartName { get; set; } = ""; + public SoundSpecifier? TryRemoveItemSound; + /// + /// If true, verbs will appear to help interact with the stash. + /// [DataField, AutoNetworkedField] - public string ExamineStash = "comp-secret-stash-on-examine-found-hidden-item"; + public bool HasVerbs = true; + + /// + /// The name of the secret stash. For example "the toilet cistern". + /// If null, the name of the entity will be used instead. + /// + [DataField] + public string? SecretStashName; /// /// Container used to keep secret stash item. /// [ViewVariables] public ContainerSlot ItemContainer = default!; - - } - - /// - /// Simple pry event for prying open a stash door. - /// - [Serializable, NetSerializable] - public sealed partial class StashPryDoAfterEvent : SimpleDoAfterEvent - { - } - - /// - /// Visualizers for handling stash open closed state if stash has door. - /// - [Serializable, NetSerializable] - public enum StashVisuals : byte - { - DoorVisualState, - } - - [Serializable, NetSerializable] - public enum DoorVisualState : byte - { - DoorOpen, - DoorClosed } } diff --git a/Content.Shared/Storage/EntitySystems/SecretStashSystem.cs b/Content.Shared/Storage/EntitySystems/SecretStashSystem.cs index 9aee1b982e..901d744df5 100644 --- a/Content.Shared/Storage/EntitySystems/SecretStashSystem.cs +++ b/Content.Shared/Storage/EntitySystems/SecretStashSystem.cs @@ -8,215 +8,206 @@ using Robust.Shared.Containers; using Content.Shared.Interaction; using Content.Shared.Tools.Systems; using Content.Shared.Examine; +using Robust.Shared.Audio; +using Robust.Shared.Audio.Systems; +using Content.Shared.Verbs; +using Content.Shared.IdentityManagement; +using Content.Shared.Tools.EntitySystems; -namespace Content.Shared.Storage.EntitySystems +namespace Content.Shared.Storage.EntitySystems; + +/// +/// Secret Stash allows an item to be hidden within. +/// +public sealed class SecretStashSystem : EntitySystem { - /// - /// Secret Stash allows an item to be hidden within. - /// - public sealed class SecretStashSystem : EntitySystem + [Dependency] private readonly SharedPopupSystem _popupSystem = default!; + [Dependency] private readonly SharedHandsSystem _handsSystem = default!; + [Dependency] private readonly SharedContainerSystem _containerSystem = default!; + [Dependency] private readonly SharedItemSystem _item = default!; + [Dependency] private readonly SharedAudioSystem _audio = default!; + [Dependency] private readonly ToolOpenableSystem _toolOpenableSystem = default!; + + + public override void Initialize() { - [Dependency] private readonly SharedPopupSystem _popupSystem = default!; - [Dependency] private readonly SharedHandsSystem _handsSystem = default!; - [Dependency] private readonly SharedContainerSystem _containerSystem = default!; - [Dependency] private readonly SharedItemSystem _item = default!; - [Dependency] private readonly SharedToolSystem _tool = default!; - [Dependency] private readonly SharedAppearanceSystem _appearance = default!; + base.Initialize(); + SubscribeLocalEvent(OnInit); + SubscribeLocalEvent(OnDestroyed); + SubscribeLocalEvent(OnInteractUsing, after: new[] { typeof(ToolOpenableSystem) }); + SubscribeLocalEvent(OnInteractHand); + SubscribeLocalEvent>(OnGetVerb); + } - public override void Initialize() + private void OnInit(Entity entity, ref ComponentInit args) + { + entity.Comp.ItemContainer = _containerSystem.EnsureContainer(entity, "stash", out _); + } + + private void OnDestroyed(Entity entity, ref DestructionEventArgs args) + { + var storedInside = _containerSystem.EmptyContainer(entity.Comp.ItemContainer); + if (storedInside != null && storedInside.Count >= 1) { - base.Initialize(); - SubscribeLocalEvent(OnInit); - SubscribeLocalEvent(OnDestroyed); - SubscribeLocalEvent(OnSecretStashPried); - SubscribeLocalEvent(OnInteractUsing); - SubscribeLocalEvent(OnInteractHand); - SubscribeLocalEvent(OnExamine); - } - - private void OnInit(EntityUid uid, SecretStashComponent component, ComponentInit args) - { - component.ItemContainer = _containerSystem.EnsureContainer(uid, "stash", out _); - } - - private void OnDestroyed(EntityUid uid, SecretStashComponent component, DestructionEventArgs args) - { - _containerSystem.EmptyContainer(component.ItemContainer); - } - - /// - /// Is there something inside secret stash item container? - /// - public bool HasItemInside(EntityUid uid, SecretStashComponent? component = null) - { - if (!Resolve(uid, ref component)) - return false; - return component.ItemContainer.ContainedEntity != null; - } - - private void OnInteractUsing(EntityUid uid, SecretStashComponent component, InteractUsingEvent args) - { - if (args.Handled) - return; - - if (!component.OpenableStash) - return; - - // is player trying place or lift off cistern lid? - if (_tool.UseTool(args.Used, args.User, uid, component.PryDoorTime, component.PryingQuality, new StashPryDoAfterEvent())) - args.Handled = true; - // maybe player is trying to hide something inside cistern? - else if (component.ToggleOpen) - { - TryHideItem(uid, args.User, args.Used); - args.Handled = true; - } - } - - private void OnInteractHand(EntityUid uid, SecretStashComponent component, InteractHandEvent args) - { - if (args.Handled) - return; - - if (!component.OpenableStash) - return; - - // trying to get something from stash? - if (component.ToggleOpen) - { - var gotItem = TryGetItem(uid, args.User); - if (gotItem) - { - args.Handled = true; - return; - } - } - args.Handled = true; - } - - private void OnSecretStashPried(EntityUid uid, SecretStashComponent component, StashPryDoAfterEvent args) - { - if (args.Cancelled) - return; - - ToggleOpen(uid, component); - } - - public void ToggleOpen(EntityUid uid, SecretStashComponent? component = null, MetaDataComponent? meta = null) - { - if (!Resolve(uid, ref component)) - return; - - component.ToggleOpen = !component.ToggleOpen; - - UpdateAppearance(uid, component); - Dirty(uid, component, meta); - } - - private void UpdateAppearance(EntityUid uid, SecretStashComponent? component = null) - { - if (!Resolve(uid, ref component)) - return; - - _appearance.SetData(uid, StashVisuals.DoorVisualState, component.ToggleOpen ? DoorVisualState.DoorOpen : DoorVisualState.DoorClosed); - } - - /// - /// Tries to hide item inside secret stash from hands of user. - /// - /// True if item was hidden inside stash - public bool TryHideItem(EntityUid uid, EntityUid userUid, EntityUid itemToHideUid, - SecretStashComponent? component = null, ItemComponent? item = null, - HandsComponent? hands = null) - { - if (!Resolve(uid, ref component)) - return false; - if (!Resolve(itemToHideUid, ref item)) - return false; - if (!Resolve(userUid, ref hands)) - return false; - - // check if secret stash is already occupied - var container = component.ItemContainer; - if (container.ContainedEntity != null) - { - var msg = Loc.GetString("comp-secret-stash-action-hide-container-not-empty"); - _popupSystem.PopupClient(msg, uid, userUid); - return false; - } - - // check if item is too big to fit into secret stash - if (_item.GetSizePrototype(item.Size) > _item.GetSizePrototype(component.MaxItemSize)) - { - var msg = Loc.GetString("comp-secret-stash-action-hide-item-too-big", - ("item", itemToHideUid), ("stash", GetSecretPartName(uid, component))); - _popupSystem.PopupClient(msg, uid, userUid); - return false; - } - - // try to move item from hands to stash container - if (!_handsSystem.TryDropIntoContainer(userUid, itemToHideUid, container)) - { - return false; - } - - // all done, show success message - var successMsg = Loc.GetString("comp-secret-stash-action-hide-success", - ("item", itemToHideUid), ("this", GetSecretPartName(uid, component))); - _popupSystem.PopupClient(successMsg, uid, userUid); - return true; - } - - /// - /// Try get item and place it in users hand. - /// If user can't take it by hands, will drop item from container. - /// - /// True if user received item - public bool TryGetItem(EntityUid uid, EntityUid userUid, SecretStashComponent? component = null, - HandsComponent? hands = null) - { - if (!Resolve(uid, ref component)) - return false; - if (!Resolve(userUid, ref hands)) - return false; - - // check if secret stash has something inside - var container = component.ItemContainer; - if (container.ContainedEntity == null) - { - return false; - } - - _handsSystem.PickupOrDrop(userUid, container.ContainedEntity.Value, handsComp: hands); - - // show success message - var successMsg = Loc.GetString("comp-secret-stash-action-get-item-found-something", - ("stash", GetSecretPartName(uid, component))); - _popupSystem.PopupClient(successMsg, uid, userUid); - - return true; - } - - private void OnExamine(EntityUid uid, SecretStashComponent component, ExaminedEvent args) - { - if (args.IsInDetailsRange && component.ToggleOpen) - { - if (HasItemInside(uid)) - { - var msg = Loc.GetString(component.ExamineStash); - args.PushMarkup(msg); - } - } - } - - private string GetSecretPartName(EntityUid uid, SecretStashComponent stash) - { - if (stash.SecretPartName != "") - return Loc.GetString(stash.SecretPartName); - - var entityName = Loc.GetString("comp-secret-stash-secret-part-name", ("this", uid)); - - return entityName; + var popup = Loc.GetString("comp-secret-stash-on-destroyed-popup", ("stashname", GetStashName(entity))); + _popupSystem.PopupEntity(popup, storedInside[0], PopupType.MediumCaution); } } + + private void OnInteractUsing(Entity entity, ref InteractUsingEvent args) + { + if (args.Handled || !IsStashOpen(entity)) + return; + + args.Handled = TryStashItem(entity, args.User, args.Used); + } + + private void OnInteractHand(Entity entity, ref InteractHandEvent args) + { + if (args.Handled || !IsStashOpen(entity)) + return; + + args.Handled = TryGetItem(entity, args.User); + } + + /// + /// Tries to hide the given item into the stash. + /// + /// True if item was hidden inside stash and false otherwise. + private bool TryStashItem(Entity entity, EntityUid userUid, EntityUid itemToHideUid) + { + if (!TryComp(itemToHideUid, out var itemComp)) + return false; + + _audio.PlayPredicted(entity.Comp.TryInsertItemSound, entity, userUid, AudioParams.Default.WithVariation(0.25f)); + + // check if secret stash is already occupied + var container = entity.Comp.ItemContainer; + if (HasItemInside(entity)) + { + var popup = Loc.GetString("comp-secret-stash-action-hide-container-not-empty"); + _popupSystem.PopupClient(popup, entity, userUid); + return false; + } + + // check if item is too big to fit into secret stash + if (_item.GetSizePrototype(itemComp.Size) > _item.GetSizePrototype(entity.Comp.MaxItemSize)) + { + var msg = Loc.GetString("comp-secret-stash-action-hide-item-too-big", + ("item", itemToHideUid), ("stashname", GetStashName(entity))); + _popupSystem.PopupClient(msg, entity, userUid); + return false; + } + + // try to move item from hands to stash container + if (!_handsSystem.TryDropIntoContainer(userUid, itemToHideUid, container)) + return false; + + // all done, show success message + var successMsg = Loc.GetString("comp-secret-stash-action-hide-success", + ("item", itemToHideUid), ("stashname", GetStashName(entity))); + _popupSystem.PopupClient(successMsg, entity, userUid); + return true; + } + + /// + /// Try the given item in the stash and place it in users hand. + /// If user can't take hold the item in their hands, the item will be dropped onto the ground. + /// + /// True if user received item. + private bool TryGetItem(Entity entity, EntityUid userUid) + { + if (!TryComp(userUid, out var handsComp)) + return false; + + _audio.PlayPredicted(entity.Comp.TryRemoveItemSound, entity, userUid, AudioParams.Default.WithVariation(0.25f)); + + // check if secret stash has something inside + var itemInStash = entity.Comp.ItemContainer.ContainedEntity; + if (itemInStash == null) + return false; + + _handsSystem.PickupOrDrop(userUid, itemInStash.Value, handsComp: handsComp); + + // show success message + var successMsg = Loc.GetString("comp-secret-stash-action-get-item-found-something", + ("stashname", GetStashName(entity))); + _popupSystem.PopupClient(successMsg, entity, userUid); + + return true; + } + + private void OnGetVerb(Entity entity, ref GetVerbsEvent args) + { + if (!args.CanInteract || !args.CanAccess || !entity.Comp.HasVerbs) + return; + + var user = args.User; + var item = args.Using; + var stashName = GetStashName(entity); + + var itemVerb = new InteractionVerb(); + + // This will add the verb relating to inserting / grabbing items. + if (IsStashOpen(entity)) + { + if (item != null) + { + itemVerb.Text = Loc.GetString("comp-secret-stash-verb-insert-into-stash"); + if (HasItemInside(entity)) + { + itemVerb.Disabled = true; + itemVerb.Message = Loc.GetString("comp-secret-stash-verb-insert-message-item-already-inside", ("stashname", stashName)); + } + else + { + itemVerb.Message = Loc.GetString("comp-secret-stash-verb-insert-message-no-item", ("item", item), ("stashname", stashName)); + } + + itemVerb.Act = () => TryStashItem(entity, user, item.Value); + } + else + { + itemVerb.Text = Loc.GetString("comp-secret-stash-verb-take-out-item"); + itemVerb.Message = Loc.GetString("comp-secret-stash-verb-take-out-message-something", ("stashname", stashName)); + if (!HasItemInside(entity)) + { + itemVerb.Disabled = true; + itemVerb.Message = Loc.GetString("comp-secret-stash-verb-take-out-message-nothing", ("stashname", stashName)); + } + + itemVerb.Act = () => TryGetItem(entity, user); + } + + args.Verbs.Add(itemVerb); + } + } + + #region Helper functions + + /// + /// The stash name if it exists, or the entity name if it doesn't. + /// + private string GetStashName(Entity entity) + { + if (entity.Comp.SecretStashName == null) + return Identity.Name(entity, EntityManager); + return Loc.GetString(entity.Comp.SecretStashName); + } + + /// + /// True if the stash is open OR the there is no toolOpenableComponent attacheded to the entity + /// and false otherwise. + /// + private bool IsStashOpen(Entity stash) + { + return _toolOpenableSystem.IsOpen(stash); + } + + private bool HasItemInside(Entity entity) + { + return entity.Comp.ItemContainer.ContainedEntity != null; + } + + #endregion } diff --git a/Content.Shared/Tools/Components/ToolOpenableComponent.cs b/Content.Shared/Tools/Components/ToolOpenableComponent.cs new file mode 100644 index 0000000000..82cdf611da --- /dev/null +++ b/Content.Shared/Tools/Components/ToolOpenableComponent.cs @@ -0,0 +1,84 @@ +using Robust.Shared.Prototypes; +using Robust.Shared.GameStates; +using Content.Shared.DoAfter; +using Robust.Shared.Serialization; + +namespace Content.Shared.Tools.Components +{ + /// + /// Logic for using tools (Or verbs) to open / close something on an entity. + /// + [RegisterComponent, NetworkedComponent, AutoGenerateComponentState] + public sealed partial class ToolOpenableComponent : Component + { + /// + /// Is the openable part open or closed? + /// + [DataField, AutoNetworkedField] + public bool IsOpen = false; + + /// + /// If a tool is needed to open the entity, this time will be used. + /// + [DataField] + public float OpenTime = 1f; + + /// + /// If a tool is needed to close the entity, this time will be used. + /// + [DataField] + public float CloseTime = 1f; + + /// + /// What type of tool quality is needed to open this? + /// If null, the it will only be openable by a verb. + /// + [DataField] + public ProtoId? OpenToolQualityNeeded; + + /// + /// What type of tool quality is needed to close this. + /// If null, this will only be closable by a verb. + /// + [DataField] + public ProtoId? CloseToolQualityNeeded; + + /// + /// If true, verbs will appear to help interact with opening / closing. + /// + [DataField, AutoNetworkedField] + public bool HasVerbs = true; + + /// + /// The name of what is being open and closed. + /// E.g toilet lid, pannel, compartment. + /// + [DataField, AutoNetworkedField] + public string? Name; + + } + + /// + /// Simple do after event for opening or closing. + /// + [Serializable, NetSerializable] + public sealed partial class ToolOpenableDoAfterEventToggleOpen : SimpleDoAfterEvent + { + } + + /// + /// Visualizers for handling stash open closed state if stash has door. + /// + [Serializable, NetSerializable] + public enum ToolOpenableVisuals : byte + { + ToolOpenableVisualState, + } + + [Serializable, NetSerializable] + public enum ToolOpenableVisualState : byte + { + Open, + Closed + } +} diff --git a/Content.Shared/Tools/Systems/ToolOpenableSystem.cs b/Content.Shared/Tools/Systems/ToolOpenableSystem.cs new file mode 100644 index 0000000000..4951040350 --- /dev/null +++ b/Content.Shared/Tools/Systems/ToolOpenableSystem.cs @@ -0,0 +1,171 @@ +using Content.Shared.IdentityManagement; +using Content.Shared.Tools.Components; +using Content.Shared.Tools.Systems; +using Content.Shared.Interaction; +using Content.Shared.Examine; +using Content.Shared.Verbs; + +namespace Content.Shared.Tools.EntitySystems; + +public sealed class ToolOpenableSystem : EntitySystem +{ + [Dependency] private readonly SharedToolSystem _tool = default!; + [Dependency] private readonly SharedAppearanceSystem _appearance = default!; + + public override void Initialize() + { + base.Initialize(); + SubscribeLocalEvent(OnInit); + SubscribeLocalEvent(OnOpenableStateToggled); + SubscribeLocalEvent(OnInteractUsing); + SubscribeLocalEvent(OnExamine); + SubscribeLocalEvent>(OnGetVerb); + } + + private void OnInit(Entity entity, ref ComponentInit args) + { + UpdateAppearance(entity); + Dirty(entity); + } + + private void OnInteractUsing(Entity entity, ref InteractUsingEvent args) + { + if (args.Handled) + return; + + if (TryOpenClose(entity, args.Used, args.User)) + args.Handled = true; + } + + /// + /// Try to open or close what is openable. + /// + /// Returns false if you can't interact with the openable thing with the given item. + private bool TryOpenClose(Entity entity, EntityUid? toolToToggle, EntityUid user) + { + var neededToolQuantity = entity.Comp.IsOpen ? entity.Comp.CloseToolQualityNeeded : entity.Comp.OpenToolQualityNeeded; + var time = entity.Comp.IsOpen ? entity.Comp.CloseTime : entity.Comp.OpenTime; + var evt = new ToolOpenableDoAfterEventToggleOpen(); + + // If neededToolQuantity is null it can only be open be opened with the verbs. + if (toolToToggle == null || neededToolQuantity == null) + return false; + + return _tool.UseTool(toolToToggle.Value, user, entity, time, neededToolQuantity, evt); + } + + private void OnOpenableStateToggled(Entity entity, ref ToolOpenableDoAfterEventToggleOpen args) + { + if (args.Cancelled) + return; + + ToggleState(entity); + } + + /// + /// Toggle the state and update appearance. + /// + private void ToggleState(Entity entity) + { + entity.Comp.IsOpen = !entity.Comp.IsOpen; + UpdateAppearance(entity); + Dirty(entity); + } + + #region Helper functions + + private string GetName(Entity entity) + { + if (entity.Comp.Name == null) + return Identity.Name(entity, EntityManager); + return Loc.GetString(entity.Comp.Name); + } + + public bool IsOpen(EntityUid uid, ToolOpenableComponent? component = null) + { + if (!Resolve(uid, ref component, false)) + return true; + + return component.IsOpen; + } + + private void UpdateAppearance(Entity entity) + { + _appearance.SetData(entity, ToolOpenableVisuals.ToolOpenableVisualState, entity.Comp.IsOpen ? ToolOpenableVisualState.Open : ToolOpenableVisualState.Closed); + } + + #endregion + + #region User interface functions + + private void OnExamine(Entity entity, ref ExaminedEvent args) + { + if (!args.IsInDetailsRange) + return; + + string msg; + var name = GetName(entity); + if (entity.Comp.IsOpen) + msg = Loc.GetString("tool-openable-component-examine-opened", ("name", name)); + else + msg = Loc.GetString("tool-openable-component-examine-closed", ("name", name)); + + args.PushMarkup(msg); + } + + private void OnGetVerb(Entity entity, ref GetVerbsEvent args) + { + if (!args.CanInteract || !args.CanAccess || !entity.Comp.HasVerbs) + return; + + var user = args.User; + var item = args.Using; + var name = GetName(entity); + + var toggleVerb = new InteractionVerb + { + IconEntity = GetNetEntity(item) + }; + + if (entity.Comp.IsOpen) + { + toggleVerb.Text = toggleVerb.Message = Loc.GetString("tool-openable-component-verb-close"); + var neededQual = entity.Comp.CloseToolQualityNeeded; + + // If neededQual is null you don't need a tool to open / close. + if (neededQual != null && + (item == null || !_tool.HasQuality(item.Value, neededQual))) + { + toggleVerb.Disabled = true; + toggleVerb.Message = Loc.GetString("tool-openable-component-verb-cant-close", ("name", name)); + } + + if (neededQual == null) + toggleVerb.Act = () => ToggleState(entity); + else + toggleVerb.Act = () => TryOpenClose(entity, item, user); + + args.Verbs.Add(toggleVerb); + } + else + { + // The open verb should only appear when holding the correct tool or if no tool is needed. + + toggleVerb.Text = toggleVerb.Message = Loc.GetString("tool-openable-component-verb-open"); + var neededQual = entity.Comp.OpenToolQualityNeeded; + + if (neededQual == null) + { + toggleVerb.Act = () => ToggleState(entity); + args.Verbs.Add(toggleVerb); + } + else if (item != null && _tool.HasQuality(item.Value, neededQual)) + { + toggleVerb.Act = () => TryOpenClose(entity, item, user); + args.Verbs.Add(toggleVerb); + } + } + } + + #endregion +} diff --git a/Resources/Locale/en-US/storage/components/secret-stash-component.ftl b/Resources/Locale/en-US/storage/components/secret-stash-component.ftl index d0dfed2b5d..2a8f505e2b 100644 --- a/Resources/Locale/en-US/storage/components/secret-stash-component.ftl +++ b/Resources/Locale/en-US/storage/components/secret-stash-component.ftl @@ -1,11 +1,24 @@ ### Secret stash component. Stuff like potted plants, comfy chair cushions, etc... -comp-secret-stash-secret-part-name = { THE($item) } -comp-secret-stash-action-hide-success = You hide { THE($item) } in { $this } -comp-secret-stash-action-hide-container-not-empty = There's already something in here?! -comp-secret-stash-action-hide-item-too-big = { THE($item) } is too big to fit in {$stash}! -comp-secret-stash-action-get-item-found-something = There was something inside {$stash}! -comp-secret-stash-on-examine-found-hidden-item = There is something hidden inside. +comp-secret-stash-action-hide-success = You hide { THE($item) } in the {$stashname}. +comp-secret-stash-action-hide-container-not-empty = There's already something in here!? +comp-secret-stash-action-hide-item-too-big = { THE($item) } is too big to fit in the {$stashname}. +comp-secret-stash-action-get-item-found-something = There was something inside the {$stashname}! +comp-secret-stash-on-examine-found-hidden-item = There is something hidden inside the {$stashname}! +comp-secret-stash-on-destroyed-popup = Something falls out of the the {$stashname}! -secret-stash-part-plant = the plant -secret-stash-part-toilet = the toilet cistern +### Verbs +comp-secret-stash-verb-insert-into-stash = Stash item +comp-secret-stash-verb-insert-message-item-already-inside = There is already an item inside the {$stashname}. +comp-secret-stash-verb-insert-message-no-item = Hide { THE($item) } in the {$stashname}. +comp-secret-stash-verb-take-out-item = Grab item +comp-secret-stash-verb-take-out-message-something = Take the contents of the {$stashname} out. +comp-secret-stash-verb-take-out-message-nothing = There is nothing inside the {$stashname}. + +comp-secret-stash-verb-close = Close +comp-secret-stash-verb-cant-close = You can't close the {$stashname} with that. +comp-secret-stash-verb-open = Open + +### Stash names +secret-stash-plant = plant +secret-stash-toilet = toilet cistern diff --git a/Resources/Locale/en-US/tools/components/tool-openable-component.ftl b/Resources/Locale/en-US/tools/components/tool-openable-component.ftl new file mode 100644 index 0000000000..c45b6c69da --- /dev/null +++ b/Resources/Locale/en-US/tools/components/tool-openable-component.ftl @@ -0,0 +1,6 @@ +tool-openable-component-examine-closed = The {$name} is closed. +tool-openable-component-examine-opened = The {$name} is open. + +tool-openable-component-verb-close = Close +tool-openable-component-verb-open = Open +tool-openable-component-verb-cant-close = You can't close the {$name} with that. diff --git a/Resources/Prototypes/Entities/Structures/Furniture/potted_plants.yml b/Resources/Prototypes/Entities/Structures/Furniture/potted_plants.yml index 53d268facf..2d35c94bf1 100644 --- a/Resources/Prototypes/Entities/Structures/Furniture/potted_plants.yml +++ b/Resources/Prototypes/Entities/Structures/Furniture/potted_plants.yml @@ -24,9 +24,11 @@ offset: "0.0,0.3" sprite: Structures/Furniture/potted_plants.rsi noRot: true - - type: PottedPlantHide - type: SecretStash - secretPartName: secret-stash-part-plant + tryInsertItemSound: /Audio/Effects/plant_rustle.ogg + tryRemoveItemSound: /Audio/Effects/plant_rustle.ogg + hasVerbs: false + secretStashName: secret-stash-plant - type: ContainerContainer containers: stash: !type:ContainerSlot {} diff --git a/Resources/Prototypes/Entities/Structures/Furniture/toilet.yml b/Resources/Prototypes/Entities/Structures/Furniture/toilet.yml index 1eb5176e9e..6a603b7deb 100644 --- a/Resources/Prototypes/Entities/Structures/Furniture/toilet.yml +++ b/Resources/Prototypes/Entities/Structures/Furniture/toilet.yml @@ -68,9 +68,11 @@ - type: PlungerUse - type: Appearance - type: SecretStash - secretPartName: secret-stash-part-toilet - examineStash: toilet-component-on-examine-found-hidden-item - openableStash: true + secretStashName: secret-stash-toilet + - type: ToolOpenable + openToolQualityNeeded: Prying + closeToolQualityNeeded: Prying + name: secret-stash-toilet - type: Drain autoDrain: false - type: StaticPrice @@ -103,10 +105,10 @@ SeatVisualState.SeatUp: SeatUp: { state: disposal-up } SeatDown: { state: disposal-down } - enum.StashVisuals.DoorVisualState: - DoorVisualState.DoorOpen: - DoorOpen: { state: disposal-open } - DoorClosed: { state: disposal-closed } + enum.ToolOpenableVisuals.ToolOpenableVisualState: + ToolOpenableVisualState.StashOpen: + Open: { state: disposal-open } + Closed: { state: disposal-closed } - type: entity id: ToiletDirtyWater From 2528231ad194cbb973942a8e6ad5cae70e1c1ab4 Mon Sep 17 00:00:00 2001 From: Nemanja <98561806+EmoGarbage404@users.noreply.github.com> Date: Fri, 9 Aug 2024 00:52:25 -0400 Subject: [PATCH 033/174] offgrid mob friction (#29383) * offgrid mob friction * save the world... --- .../Movement/Components/MovementSpeedModifierComponent.cs | 7 +++++++ Content.Shared/Movement/Systems/SharedMoverController.cs | 4 +++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/Content.Shared/Movement/Components/MovementSpeedModifierComponent.cs b/Content.Shared/Movement/Components/MovementSpeedModifierComponent.cs index a0feab7052..02a8538531 100644 --- a/Content.Shared/Movement/Components/MovementSpeedModifierComponent.cs +++ b/Content.Shared/Movement/Components/MovementSpeedModifierComponent.cs @@ -15,6 +15,7 @@ namespace Content.Shared.Movement.Components public const float DefaultMinimumFrictionSpeed = 0.005f; public const float DefaultWeightlessFriction = 1f; public const float DefaultWeightlessFrictionNoInput = 0.2f; + public const float DefaultOffGridFriction = 0.05f; public const float DefaultWeightlessModifier = 0.7f; public const float DefaultWeightlessAcceleration = 1f; @@ -72,6 +73,12 @@ namespace Content.Shared.Movement.Components [ViewVariables(VVAccess.ReadWrite), DataField] public float WeightlessFrictionNoInput = DefaultWeightlessFrictionNoInput; + /// + /// The negative velocity applied for friction when weightless and not standing on a grid or mapgrid + /// + [ViewVariables(VVAccess.ReadWrite), DataField] + public float OffGridFriction = DefaultOffGridFriction; + /// /// The movement speed modifier applied to a mob's total input velocity when weightless. /// diff --git a/Content.Shared/Movement/Systems/SharedMoverController.cs b/Content.Shared/Movement/Systems/SharedMoverController.cs index 1f64717823..c41db21b01 100644 --- a/Content.Shared/Movement/Systems/SharedMoverController.cs +++ b/Content.Shared/Movement/Systems/SharedMoverController.cs @@ -214,7 +214,9 @@ namespace Content.Shared.Movement.Systems if (weightless) { - if (worldTotal != Vector2.Zero && touching) + if (gridComp == null && !MapGridQuery.HasComp(xform.GridUid)) + friction = moveSpeedComponent?.OffGridFriction ?? MovementSpeedModifierComponent.DefaultOffGridFriction; + else if (worldTotal != Vector2.Zero && touching) friction = moveSpeedComponent?.WeightlessFriction ?? MovementSpeedModifierComponent.DefaultWeightlessFriction; else friction = moveSpeedComponent?.WeightlessFrictionNoInput ?? MovementSpeedModifierComponent.DefaultWeightlessFrictionNoInput; From 2ea17a492d65a22bdea84507ae3d67c465975165 Mon Sep 17 00:00:00 2001 From: PJBot Date: Fri, 9 Aug 2024 04:53:31 +0000 Subject: [PATCH 034/174] Automatic changelog update --- Resources/Changelog/Changelog.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 96d9f52389..45606f6eff 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,11 +1,4 @@ Entries: -- author: Dutch-VanDerLinde - changes: - - message: Fixed non-inital infected getting the succumb to zombie action. - type: Fix - id: 6566 - time: '2024-05-09T21:45:23.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/27820 - author: Hanzdegloker changes: - message: Added CMO turtleneck jumpsuit/jumpskirt. @@ -3794,3 +3787,10 @@ id: 7065 time: '2024-08-08T23:32:42.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/30789 +- author: EmoGarbage404 + changes: + - message: You should have significantly less friction when moving in space. + type: Tweak + id: 7066 + time: '2024-08-09T04:52:25.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/29383 From da0b8d47315a35859cf4b562423d954a6bdbb683 Mon Sep 17 00:00:00 2001 From: slarticodefast <161409025+slarticodefast@users.noreply.github.com> Date: Fri, 9 Aug 2024 07:24:49 +0200 Subject: [PATCH 035/174] remove UntrackedMapBoundUserInterface (#30752) --- .../UI/StationMapBoundUserInterface.cs | 6 +++- .../UI/UntrackedMapBoundUserInterface.cs | 28 ------------------- .../Tests/GameRules/NukeOpsTest.cs | 2 +- ...omponent.cs => StationMapUserComponent.cs} | 6 ---- .../Pinpointer/StationMapComponent.cs | 11 ++++++++ .../Prototypes/Entities/Objects/Fun/pai.yml | 2 +- 6 files changed, 18 insertions(+), 37 deletions(-) delete mode 100644 Content.Client/Pinpointer/UI/UntrackedMapBoundUserInterface.cs rename Content.Server/Pinpointer/{StationMapComponent.cs => StationMapUserComponent.cs} (77%) create mode 100644 Content.Shared/Pinpointer/StationMapComponent.cs diff --git a/Content.Client/Pinpointer/UI/StationMapBoundUserInterface.cs b/Content.Client/Pinpointer/UI/StationMapBoundUserInterface.cs index 7417fafede..91fb4ef71b 100644 --- a/Content.Client/Pinpointer/UI/StationMapBoundUserInterface.cs +++ b/Content.Client/Pinpointer/UI/StationMapBoundUserInterface.cs @@ -1,3 +1,4 @@ +using Content.Shared.Pinpointer; using Robust.Client.UserInterface; namespace Content.Client.Pinpointer.UI; @@ -23,6 +24,9 @@ public sealed class StationMapBoundUserInterface : BoundUserInterface _window = this.CreateWindow(); _window.Title = EntMan.GetComponent(Owner).EntityName; - _window.Set(gridUid, Owner); + if (EntMan.TryGetComponent(Owner, out var comp) && comp.ShowLocation) + _window.Set(gridUid, Owner); + else + _window.Set(gridUid, null); } } diff --git a/Content.Client/Pinpointer/UI/UntrackedMapBoundUserInterface.cs b/Content.Client/Pinpointer/UI/UntrackedMapBoundUserInterface.cs deleted file mode 100644 index a3ca6f65da..0000000000 --- a/Content.Client/Pinpointer/UI/UntrackedMapBoundUserInterface.cs +++ /dev/null @@ -1,28 +0,0 @@ -using Robust.Client.UserInterface; - -namespace Content.Client.Pinpointer.UI; - -public sealed class UntrackedStationMapBoundUserInterface : BoundUserInterface -{ - [ViewVariables] - private StationMapWindow? _window; - - public UntrackedStationMapBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey) - { - } - - protected override void Open() - { - base.Open(); - EntityUid? gridUid = null; - - // TODO: What this just looks like it's been copy-pasted wholesale from StationMapBoundUserInterface? - if (EntMan.TryGetComponent(Owner, out var xform)) - { - gridUid = xform.GridUid; - } - - _window = this.CreateWindow(); - _window.Set(gridUid, Owner); - } -} diff --git a/Content.IntegrationTests/Tests/GameRules/NukeOpsTest.cs b/Content.IntegrationTests/Tests/GameRules/NukeOpsTest.cs index 0ccb5e314b..a4563aa37e 100644 --- a/Content.IntegrationTests/Tests/GameRules/NukeOpsTest.cs +++ b/Content.IntegrationTests/Tests/GameRules/NukeOpsTest.cs @@ -5,7 +5,6 @@ using Content.Server.GameTicking; using Content.Server.GameTicking.Presets; using Content.Server.GameTicking.Rules.Components; using Content.Server.Mind; -using Content.Server.Pinpointer; using Content.Server.Roles; using Content.Server.RoundEnd; using Content.Server.Shuttles.Components; @@ -18,6 +17,7 @@ using Content.Shared.Hands.Components; using Content.Shared.Inventory; using Content.Shared.NPC.Systems; using Content.Shared.NukeOps; +using Content.Shared.Pinpointer; using Content.Shared.Station.Components; using Robust.Server.GameObjects; using Robust.Shared.GameObjects; diff --git a/Content.Server/Pinpointer/StationMapComponent.cs b/Content.Server/Pinpointer/StationMapUserComponent.cs similarity index 77% rename from Content.Server/Pinpointer/StationMapComponent.cs rename to Content.Server/Pinpointer/StationMapUserComponent.cs index 942ea1aba8..358e26d82e 100644 --- a/Content.Server/Pinpointer/StationMapComponent.cs +++ b/Content.Server/Pinpointer/StationMapUserComponent.cs @@ -1,11 +1,5 @@ namespace Content.Server.Pinpointer; -[RegisterComponent] -public sealed partial class StationMapComponent : Component -{ - -} - /// /// Added to an entity using station map so when its parent changes we reset it. /// diff --git a/Content.Shared/Pinpointer/StationMapComponent.cs b/Content.Shared/Pinpointer/StationMapComponent.cs new file mode 100644 index 0000000000..07cc99605e --- /dev/null +++ b/Content.Shared/Pinpointer/StationMapComponent.cs @@ -0,0 +1,11 @@ +namespace Content.Shared.Pinpointer; + +[RegisterComponent] +public sealed partial class StationMapComponent : Component +{ + /// + /// Whether or not to show the user's location on the map. + /// + [DataField] + public bool ShowLocation = true; +} diff --git a/Resources/Prototypes/Entities/Objects/Fun/pai.yml b/Resources/Prototypes/Entities/Objects/Fun/pai.yml index c12f8a8d00..77f16fcd41 100644 --- a/Resources/Prototypes/Entities/Objects/Fun/pai.yml +++ b/Resources/Prototypes/Entities/Objects/Fun/pai.yml @@ -17,7 +17,7 @@ type: InstrumentBoundUserInterface requireInputValidation: false enum.StationMapUiKey.Key: - type: UntrackedStationMapBoundUserInterface + type: StationMapBoundUserInterface requireInputValidation: false - type: Sprite sprite: Objects/Fun/pai.rsi From 8a4ef69e867db2361367425655b4f7c258cf665f Mon Sep 17 00:00:00 2001 From: Leon Friedrich <60421075+ElectroJr@users.noreply.github.com> Date: Fri, 9 Aug 2024 17:25:43 +1200 Subject: [PATCH 036/174] Add random seed options to tests (#30735) * Add random seed options to tests * Ensure profile randomization --- Content.IntegrationTests/Pair/TestPair.cs | 67 ++++++++++++++++++----- Content.IntegrationTests/PoolManager.cs | 8 ++- Content.IntegrationTests/PoolSettings.cs | 46 +++++++++++----- 3 files changed, 90 insertions(+), 31 deletions(-) diff --git a/Content.IntegrationTests/Pair/TestPair.cs b/Content.IntegrationTests/Pair/TestPair.cs index 0b681dcde1..43b188fd32 100644 --- a/Content.IntegrationTests/Pair/TestPair.cs +++ b/Content.IntegrationTests/Pair/TestPair.cs @@ -9,6 +9,7 @@ using Robust.Shared.GameObjects; using Robust.Shared.IoC; using Robust.Shared.Network; using Robust.Shared.Player; +using Robust.Shared.Random; using Robust.Shared.Timing; using Robust.UnitTesting; @@ -28,6 +29,12 @@ public sealed partial class TestPair public TestMapData? TestMap; private List _modifiedProfiles = new(); + private int _nextServerSeed; + private int _nextClientSeed; + + public int ServerSeed; + public int ClientSeed; + public RobustIntegrationTest.ServerIntegrationInstance Server { get; private set; } = default!; public RobustIntegrationTest.ClientIntegrationInstance Client { get; private set; } = default!; @@ -74,22 +81,27 @@ public sealed partial class TestPair await Server.WaitPost(() => gameTicker.RestartRound()); } - if (settings.ShouldBeConnected) - { - Client.SetConnectTarget(Server); - await Client.WaitIdleAsync(); - var netMgr = Client.ResolveDependency(); + // Always initially connect clients to generate an initial random set of preferences/profiles. + // This is to try and prevent issues where if the first test that connects the client is consistently some test + // that uses a fixed seed, it would effectively prevent it from beingrandomized. - await Client.WaitPost(() => - { - if (!netMgr.IsConnected) - { - netMgr.ClientConnect(null!, 0, null!); - } - }); + Client.SetConnectTarget(Server); + await Client.WaitIdleAsync(); + var netMgr = Client.ResolveDependency(); + await Client.WaitPost(() => netMgr.ClientConnect(null!, 0, null!)); + await ReallyBeIdle(10); + await Client.WaitRunTicks(1); + + if (!settings.ShouldBeConnected) + { + await Client.WaitPost(() => netMgr.ClientDisconnect("Initial disconnect")); await ReallyBeIdle(10); - await Client.WaitRunTicks(1); } + + var cRand = Client.ResolveDependency(); + var sRand = Server.ResolveDependency(); + _nextClientSeed = cRand.Next(); + _nextServerSeed = sRand.Next(); } public void Kill() @@ -129,4 +141,33 @@ public sealed partial class TestPair CleanDisposed = 2, Dead = 3, } + + public void SetupSeed() + { + var sRand = Server.ResolveDependency(); + if (Settings.ServerSeed is { } severSeed) + { + ServerSeed = severSeed; + sRand.SetSeed(ServerSeed); + } + else + { + ServerSeed = _nextServerSeed; + sRand.SetSeed(ServerSeed); + _nextServerSeed = sRand.Next(); + } + + var cRand = Client.ResolveDependency(); + if (Settings.ClientSeed is { } clientSeed) + { + ClientSeed = clientSeed; + cRand.SetSeed(ClientSeed); + } + else + { + ClientSeed = _nextClientSeed; + cRand.SetSeed(ClientSeed); + _nextClientSeed = cRand.Next(); + } + } } diff --git a/Content.IntegrationTests/PoolManager.cs b/Content.IntegrationTests/PoolManager.cs index 21c93ea8ae..34ac4060dd 100644 --- a/Content.IntegrationTests/PoolManager.cs +++ b/Content.IntegrationTests/PoolManager.cs @@ -252,7 +252,7 @@ public static partial class PoolManager } finally { - if (pair != null && pair.TestHistory.Count > 1) + if (pair != null && pair.TestHistory.Count > 0) { await testOut.WriteLineAsync($"{nameof(GetServerClientPair)}: Pair {pair.Id} Test History Start"); for (var i = 0; i < pair.TestHistory.Count; i++) @@ -268,12 +268,14 @@ public static partial class PoolManager var poolRetrieveTime = poolRetrieveTimeWatch.Elapsed; await testOut.WriteLineAsync( $"{nameof(GetServerClientPair)}: Retrieving pair {pair.Id} from pool took {poolRetrieveTime.TotalMilliseconds} ms"); - await testOut.WriteLineAsync( - $"{nameof(GetServerClientPair)}: Returning pair {pair.Id}"); pair.ClearModifiedCvars(); pair.Settings = poolSettings; pair.TestHistory.Add(currentTestName); + pair.SetupSeed(); + await testOut.WriteLineAsync( + $"{nameof(GetServerClientPair)}: Returning pair {pair.Id} with client/server seeds: {pair.ClientSeed}/{pair.ServerSeed}"); + pair.Watch.Restart(); return pair; } diff --git a/Content.IntegrationTests/PoolSettings.cs b/Content.IntegrationTests/PoolSettings.cs index a78173808f..9da514e66b 100644 --- a/Content.IntegrationTests/PoolSettings.cs +++ b/Content.IntegrationTests/PoolSettings.cs @@ -1,5 +1,7 @@ #nullable enable +using Robust.Shared.Random; + namespace Content.IntegrationTests; /// @@ -9,16 +11,6 @@ namespace Content.IntegrationTests; /// public sealed class PoolSettings { - /// - /// If the returned pair must not be reused - /// - public bool MustNotBeReused => Destructive || NoLoadContent || NoLoadTestPrototypes; - - /// - /// If the given pair must be brand new - /// - public bool MustBeNew => Fresh || NoLoadContent || NoLoadTestPrototypes; - /// /// Set to true if the test will ruin the server/client pair. /// @@ -34,8 +26,6 @@ public sealed class PoolSettings /// public bool DummyTicker { get; init; } = true; - public bool UseDummyTicker => !InLobby && DummyTicker; - /// /// If true, this enables the creation of admin logs during the test. /// @@ -48,8 +38,6 @@ public sealed class PoolSettings /// public bool Connected { get; init; } - public bool ShouldBeConnected => InLobby || Connected; - /// /// Set to true if the given server/client pair should be in the lobby. /// If the pair is not in the lobby at the end of the test, this test must be marked as dirty. @@ -92,6 +80,34 @@ public sealed class PoolSettings /// public string? TestName { get; set; } + /// + /// If set, this will be used to call + /// + public int? ServerSeed { get; set; } + + /// + /// If set, this will be used to call + /// + public int? ClientSeed { get; set; } + + #region Inferred Properties + + /// + /// If the returned pair must not be reused + /// + public bool MustNotBeReused => Destructive || NoLoadContent || NoLoadTestPrototypes; + + /// + /// If the given pair must be brand new + /// + public bool MustBeNew => Fresh || NoLoadContent || NoLoadTestPrototypes; + + public bool UseDummyTicker => !InLobby && DummyTicker; + + public bool ShouldBeConnected => InLobby || Connected; + + #endregion + /// /// Tries to guess if we can skip recycling the server/client pair. /// @@ -114,4 +130,4 @@ public sealed class PoolSettings && Map == nextSettings.Map && InLobby == nextSettings.InLobby; } -} \ No newline at end of file +} From b266c9b545522c8598c744d820d58bdd0da5f866 Mon Sep 17 00:00:00 2001 From: Plykiya <58439124+Plykiya@users.noreply.github.com> Date: Thu, 8 Aug 2024 22:32:41 -0700 Subject: [PATCH 037/174] Create Generic DamageOnInteract/Attacked Comps/Systems (#30244) * Everything but the submodule * stuff I forgot * heat * missed lights * behonky * LocId * I guess it was a skill issue? * predicted audio * It works with lights now * Borg equality * Gorilla gauntlet grants protection from anomaly returned damage when attacking it * woops, there we go * NONE * Use DamageModifierSets, remove Behonker damage * Reviews dealt with --------- Co-authored-by: plykiya --- .../GloveHeatResistanceComponent.cs | 12 --- .../Light/Components/PoweredLightComponent.cs | 4 - .../Light/EntitySystems/PoweredLightSystem.cs | 45 ++------- .../Anomaly/Components/AnomalyComponent.cs | 14 --- Content.Shared/Anomaly/SharedAnomalySystem.cs | 26 ----- .../Components/DamageOnAttackedComponent.cs | 47 +++++++++ .../DamageOnAttackedProtectionComponent.cs | 29 ++++++ .../Components/DamageOnInteractComponent.cs | 47 +++++++++ .../DamageOnInteractProtectionComponent.cs | 29 ++++++ .../Damage/Systems/DamageOnAttackedSystem.cs | 99 +++++++++++++++++++ .../Damage/Systems/DamageOnInteractSystem.cs | 85 ++++++++++++++++ .../Inventory/InventorySystem.Slots.cs | 6 +- .../Clothing/Hands/base_clothinghands.yml | 4 + .../Entities/Clothing/Hands/colored.yml | 7 -- .../Entities/Clothing/Hands/gloves.yml | 22 +++-- .../OuterClothing/base_clothingouter.yml | 10 ++ .../Mobs/Cyborgs/base_borg_chassis.yml | 4 + .../Entities/Mobs/NPCs/behonker.yml | 6 -- .../Objects/Specific/Research/anomaly.yml | 7 ++ .../Entities/Objects/Weapons/Melee/sword.yml | 5 +- .../Structures/Lighting/base_lighting.yml | 96 +++++++++++------- .../Structures/Lighting/ground_lighting.yml | 24 +++-- .../Structures/Lighting/strobe_lighting.yml | 8 +- .../Structures/Specific/Anomaly/anomalies.yml | 54 ++++++---- .../Structures/Wallmounts/service_light.yml | 2 + 25 files changed, 507 insertions(+), 185 deletions(-) delete mode 100644 Content.Server/Clothing/Components/GloveHeatResistanceComponent.cs create mode 100644 Content.Shared/Damage/Components/DamageOnAttackedComponent.cs create mode 100644 Content.Shared/Damage/Components/DamageOnAttackedProtectionComponent.cs create mode 100644 Content.Shared/Damage/Components/DamageOnInteractComponent.cs create mode 100644 Content.Shared/Damage/Components/DamageOnInteractProtectionComponent.cs create mode 100644 Content.Shared/Damage/Systems/DamageOnAttackedSystem.cs create mode 100644 Content.Shared/Damage/Systems/DamageOnInteractSystem.cs diff --git a/Content.Server/Clothing/Components/GloveHeatResistanceComponent.cs b/Content.Server/Clothing/Components/GloveHeatResistanceComponent.cs deleted file mode 100644 index 29a3b901a7..0000000000 --- a/Content.Server/Clothing/Components/GloveHeatResistanceComponent.cs +++ /dev/null @@ -1,12 +0,0 @@ -namespace Content.Server.Clothing.Components; - -/// -/// TODO this needs removed somehow. -/// Handles 'heat resistance' for gloves touching bulbs and that's it, ick. -/// -[RegisterComponent] -public sealed partial class GloveHeatResistanceComponent : Component -{ - [DataField("heatResistance")] - public int HeatResistance = 323; -} diff --git a/Content.Server/Light/Components/PoweredLightComponent.cs b/Content.Server/Light/Components/PoweredLightComponent.cs index 489a49eec2..1a6f610516 100644 --- a/Content.Server/Light/Components/PoweredLightComponent.cs +++ b/Content.Server/Light/Components/PoweredLightComponent.cs @@ -30,10 +30,6 @@ namespace Content.Server.Light.Components [DataField("on")] public bool On = true; - [DataField("damage", required: true)] - [ViewVariables(VVAccess.ReadWrite)] - public DamageSpecifier Damage = default!; - [DataField("ignoreGhostsBoo")] public bool IgnoreGhostsBoo; diff --git a/Content.Server/Light/EntitySystems/PoweredLightSystem.cs b/Content.Server/Light/EntitySystems/PoweredLightSystem.cs index 8aa432c21e..33b7ce0782 100644 --- a/Content.Server/Light/EntitySystems/PoweredLightSystem.cs +++ b/Content.Server/Light/EntitySystems/PoweredLightSystem.cs @@ -1,5 +1,4 @@ using Content.Server.Administration.Logs; -using Content.Server.Clothing.Components; using Content.Server.DeviceLinking.Events; using Content.Server.DeviceLinking.Systems; using Content.Server.DeviceNetwork; @@ -24,6 +23,8 @@ using Robust.Shared.Containers; using Robust.Shared.Player; using Robust.Shared.Timing; using Robust.Shared.Audio.Systems; +using Content.Shared.Damage.Systems; +using Content.Shared.Damage.Components; namespace Content.Server.Light.EntitySystems { @@ -33,11 +34,8 @@ namespace Content.Server.Light.EntitySystems public sealed class PoweredLightSystem : EntitySystem { [Dependency] private readonly IGameTiming _gameTiming = default!; - [Dependency] private readonly DamageableSystem _damageableSystem = default!; [Dependency] private readonly SharedAmbientSoundSystem _ambientSystem = default!; [Dependency] private readonly LightBulbSystem _bulbSystem = default!; - [Dependency] private readonly SharedPopupSystem _popupSystem = default!; - [Dependency] private readonly IAdminLogManager _adminLogger= default!; [Dependency] private readonly SharedHandsSystem _handsSystem = default!; [Dependency] private readonly DeviceLinkSystem _signalSystem = default!; [Dependency] private readonly SharedContainerSystem _containerSystem = default!; @@ -45,7 +43,7 @@ namespace Content.Server.Light.EntitySystems [Dependency] private readonly SharedAudioSystem _audio = default!; [Dependency] private readonly PointLightSystem _pointLight = default!; [Dependency] private readonly SharedAppearanceSystem _appearance = default!; - [Dependency] private readonly InventorySystem _inventory = default!; + [Dependency] private readonly DamageOnInteractSystem _damageOnInteractSystem = default!; private static readonly TimeSpan ThunkDelay = TimeSpan.FromSeconds(2); public const string LightBulbContainer = "light_bulb"; @@ -106,40 +104,7 @@ namespace Content.Server.Light.EntitySystems if (bulbUid == null) return; - // check if it's possible to apply burn damage to user var userUid = args.User; - if (EntityManager.TryGetComponent(bulbUid.Value, out LightBulbComponent? lightBulb)) - { - // get users heat resistance - var res = int.MinValue; - if (_inventory.TryGetSlotEntity(userUid, "gloves", out var slotEntity) && - TryComp(slotEntity, out var gloves)) - { - res = gloves.HeatResistance; - } - - // check heat resistance against user - var burnedHand = light.CurrentLit && res < lightBulb.BurningTemperature; - if (burnedHand) - { - var damage = _damageableSystem.TryChangeDamage(userUid, light.Damage, origin: userUid); - - // If damage is null then the entity could not take heat damage so they did not get burned. - if (damage != null) - { - - var burnMsg = Loc.GetString("powered-light-component-burn-hand"); - _popupSystem.PopupEntity(burnMsg, uid, userUid); - _adminLogger.Add(LogType.Damaged, $"{ToPrettyString(args.User):user} burned their hand on {ToPrettyString(args.Target):target} and received {damage.GetTotal():damage} damage"); - _audio.PlayEntity(light.BurnHandSound, Filter.Pvs(uid), uid, true); - - args.Handled = true; - return; - } - } - } - - //removing a broken/burned bulb, so allow instant removal if(TryComp(bulbUid.Value, out var bulb) && bulb.State != LightBulbState.Normal) { @@ -435,6 +400,10 @@ namespace Content.Server.Light.EntitySystems if (softness != null) _pointLight.SetSoftness(uid, (float) softness, pointLight); } + + // light bulbs burn your hands! + if (TryComp(uid, out var damageOnInteractComp)) + _damageOnInteractSystem.SetIsDamageActiveTo((uid, damageOnInteractComp), value); } public void ToggleLight(EntityUid uid, PoweredLightComponent? light = null) diff --git a/Content.Shared/Anomaly/Components/AnomalyComponent.cs b/Content.Shared/Anomaly/Components/AnomalyComponent.cs index 88e942ec50..724dfd38d2 100644 --- a/Content.Shared/Anomaly/Components/AnomalyComponent.cs +++ b/Content.Shared/Anomaly/Components/AnomalyComponent.cs @@ -202,20 +202,6 @@ public sealed partial class AnomalyComponent : Component public float GrowingPointMultiplier = 1.5f; #endregion - /// - /// The amount of damage dealt when either a player touches the anomaly - /// directly or by hitting the anomaly. - /// - [DataField(required: true)] - public DamageSpecifier AnomalyContactDamage = default!; - - /// - /// The sound effect played when a player - /// burns themselves on an anomaly via contact. - /// - [DataField] - public SoundSpecifier AnomalyContactDamageSound = new SoundPathSpecifier("/Audio/Effects/lightburn.ogg"); - /// /// A prototype entity that appears when an anomaly supercrit collapse. /// diff --git a/Content.Shared/Anomaly/SharedAnomalySystem.cs b/Content.Shared/Anomaly/SharedAnomalySystem.cs index da1d31c6ff..c3d6591b72 100644 --- a/Content.Shared/Anomaly/SharedAnomalySystem.cs +++ b/Content.Shared/Anomaly/SharedAnomalySystem.cs @@ -30,7 +30,6 @@ public abstract class SharedAnomalySystem : EntitySystem [Dependency] private readonly INetManager _net = default!; [Dependency] protected readonly IRobustRandom Random = default!; [Dependency] protected readonly ISharedAdminLogManager AdminLog = default!; - [Dependency] private readonly DamageableSystem _damageable = default!; [Dependency] protected readonly SharedAudioSystem Audio = default!; [Dependency] protected readonly SharedAppearanceSystem Appearance = default!; [Dependency] private readonly SharedPhysicsSystem _physics = default!; @@ -42,26 +41,10 @@ public abstract class SharedAnomalySystem : EntitySystem { base.Initialize(); - SubscribeLocalEvent(OnInteractHand); - SubscribeLocalEvent(OnAttacked); SubscribeLocalEvent(OnAnomalyThrowStart); SubscribeLocalEvent(OnAnomalyThrowEnd); } - private void OnInteractHand(EntityUid uid, AnomalyComponent component, InteractHandEvent args) - { - DoAnomalyBurnDamage(uid, args.User, component); - args.Handled = true; - } - - private void OnAttacked(EntityUid uid, AnomalyComponent component, AttackedEvent args) - { - if (HasComp(args.Used)) - return; - - DoAnomalyBurnDamage(uid, args.User, component); - } - private void OnAnomalyThrowStart(Entity ent, ref MeleeThrowOnHitStartEvent args) { if (!TryComp(args.Used, out var corePowered) || !TryComp(ent, out var body)) @@ -75,15 +58,6 @@ public abstract class SharedAnomalySystem : EntitySystem _physics.SetBodyType(ent, BodyType.Static); } - public void DoAnomalyBurnDamage(EntityUid source, EntityUid target, AnomalyComponent component) - { - _damageable.TryChangeDamage(target, component.AnomalyContactDamage, true); - if (!Timing.IsFirstTimePredicted || _net.IsServer) - return; - Audio.PlayPvs(component.AnomalyContactDamageSound, source); - Popup.PopupEntity(Loc.GetString("anomaly-component-contact-damage"), target, target); - } - public void DoAnomalyPulse(EntityUid uid, AnomalyComponent? component = null) { if (!Resolve(uid, ref component)) diff --git a/Content.Shared/Damage/Components/DamageOnAttackedComponent.cs b/Content.Shared/Damage/Components/DamageOnAttackedComponent.cs new file mode 100644 index 0000000000..5f6bd7d997 --- /dev/null +++ b/Content.Shared/Damage/Components/DamageOnAttackedComponent.cs @@ -0,0 +1,47 @@ +using Robust.Shared.Audio; +using Robust.Shared.GameStates; + +namespace Content.Shared.Damage.Components; + + +/// +/// This component is added to entities that you want to damage the player +/// if the player interacts with it. For example, if a player tries touching +/// a hot light bulb or an anomaly. This damage can be cancelled if the user +/// has a component that protects them from this. +/// +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +public sealed partial class DamageOnAttackedComponent : Component +{ + /// + /// How much damage to apply to the person making contact + /// + [DataField(required: true), AutoNetworkedField] + public DamageSpecifier Damage = default!; + + /// + /// Whether the damage should be resisted by a person's armor values + /// and the + /// + [DataField] + public bool IgnoreResistances = false; + + /// + /// What kind of localized text should pop up when they interact with the entity + /// + [DataField] + public LocId? PopupText; + + /// + /// The sound that should be made when interacting with the entity + /// + [DataField] + public SoundSpecifier InteractSound = new SoundPathSpecifier("/Audio/Effects/lightburn.ogg"); + + /// + /// Generic boolean to toggle the damage application on and off + /// This is useful for things that can be toggled on or off, like a stovetop + /// + [DataField, AutoNetworkedField] + public bool IsDamageActive = true; +} diff --git a/Content.Shared/Damage/Components/DamageOnAttackedProtectionComponent.cs b/Content.Shared/Damage/Components/DamageOnAttackedProtectionComponent.cs new file mode 100644 index 0000000000..9581d20496 --- /dev/null +++ b/Content.Shared/Damage/Components/DamageOnAttackedProtectionComponent.cs @@ -0,0 +1,29 @@ +using Content.Shared.Inventory; +using Robust.Shared.GameStates; + +namespace Content.Shared.Damage.Components; + + +/// +/// This component is added to entities to protect them from being damaged +/// when attacking objects with the +/// If the entity has sufficient protection, the entity will take no damage. +/// +[RegisterComponent, NetworkedComponent] +public sealed partial class DamageOnAttackedProtectionComponent : Component, IClothingSlots +{ + /// + /// How much and what kind of damage to protect the user from + /// when interacting with something with + /// + [DataField(required: true)] + public DamageModifierSet DamageProtection = default!; + + /// + /// Only protects if the item is in the correct slot + /// i.e. having gloves in your pocket doesn't protect you, it has to be on your hands + /// Set slots to NONE if it works while you hold the item in your main hand + /// + [DataField] + public SlotFlags Slots { get; set; } = SlotFlags.WITHOUT_POCKET; +} diff --git a/Content.Shared/Damage/Components/DamageOnInteractComponent.cs b/Content.Shared/Damage/Components/DamageOnInteractComponent.cs new file mode 100644 index 0000000000..9487dec8ef --- /dev/null +++ b/Content.Shared/Damage/Components/DamageOnInteractComponent.cs @@ -0,0 +1,47 @@ +using Robust.Shared.Audio; +using Robust.Shared.GameStates; + +namespace Content.Shared.Damage.Components; + + +/// +/// This component is added to entities that you want to damage the player +/// if the player interacts with it. For example, if a player tries touching +/// a hot light bulb or an anomaly. This damage can be cancelled if the user +/// has a component that protects them from this. +/// +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +public sealed partial class DamageOnInteractComponent : Component +{ + /// + /// How much damage to apply to the person making contact + /// + [DataField(required: true), AutoNetworkedField] + public DamageSpecifier Damage = default!; + + /// + /// Whether the damage should be resisted by a person's armor values + /// and the + /// + [DataField] + public bool IgnoreResistances; + + /// + /// What kind of localized text should pop up when they interact with the entity + /// + [DataField] + public LocId? PopupText; + + /// + /// The sound that should be made when interacting with the entity + /// + [DataField] + public SoundSpecifier InteractSound = new SoundPathSpecifier("/Audio/Effects/lightburn.ogg"); + + /// + /// Generic boolean to toggle the damage application on and off + /// This is useful for things that can be toggled on or off, like a stovetop + /// + [DataField, AutoNetworkedField] + public bool IsDamageActive = true; +} diff --git a/Content.Shared/Damage/Components/DamageOnInteractProtectionComponent.cs b/Content.Shared/Damage/Components/DamageOnInteractProtectionComponent.cs new file mode 100644 index 0000000000..f57c3d22c1 --- /dev/null +++ b/Content.Shared/Damage/Components/DamageOnInteractProtectionComponent.cs @@ -0,0 +1,29 @@ +using Content.Shared.Inventory; +using Robust.Shared.GameStates; + +namespace Content.Shared.Damage.Components; + + +/// +/// This component is added to entities to protect them from being damaged +/// when interacting with objects with the +/// If the entity has sufficient protection, interaction with the object is not cancelled. +/// This allows the user to do things like remove a lightbulb. +/// +[RegisterComponent, NetworkedComponent] +public sealed partial class DamageOnInteractProtectionComponent : Component, IClothingSlots +{ + /// + /// How much and what kind of damage to protect the user from + /// when interacting with something with + /// + [DataField(required: true)] + public DamageModifierSet DamageProtection = default!; + + /// + /// Only protects if the item is in the correct slot + /// i.e. having gloves in your pocket doesn't protect you, it has to be on your hands + /// + [DataField] + public SlotFlags Slots { get; set; } = SlotFlags.GLOVES; +} diff --git a/Content.Shared/Damage/Systems/DamageOnAttackedSystem.cs b/Content.Shared/Damage/Systems/DamageOnAttackedSystem.cs new file mode 100644 index 0000000000..ab5866c5aa --- /dev/null +++ b/Content.Shared/Damage/Systems/DamageOnAttackedSystem.cs @@ -0,0 +1,99 @@ +using Content.Shared.Administration.Logs; +using Content.Shared.Damage.Components; +using Content.Shared.Database; +using Content.Shared.Hands.Components; +using Content.Shared.Hands.EntitySystems; +using Content.Shared.Inventory; +using Content.Shared.Popups; +using Content.Shared.Weapons.Melee.Events; +using Robust.Shared.Audio.Systems; +using Robust.Shared.Network; +using Robust.Shared.Timing; + +namespace Content.Shared.Damage.Systems; + +public sealed class DamageOnAttackedSystem : EntitySystem +{ + [Dependency] private readonly ISharedAdminLogManager _adminLogger = default!; + [Dependency] private readonly IGameTiming _gameTiming = default!; + [Dependency] private readonly INetManager _net = default!; + [Dependency] private readonly DamageableSystem _damageableSystem = default!; + [Dependency] private readonly SharedAudioSystem _audioSystem = default!; + [Dependency] private readonly SharedPopupSystem _popupSystem = default!; + [Dependency] private readonly InventorySystem _inventorySystem = default!; + [Dependency] private readonly SharedHandsSystem _handsSystem = default!; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnAttacked); + } + + /// + /// Damages the user that attacks the entity and potentially + /// plays a sound or pops up text in response + /// + /// The entity being hit + /// Contains the user that hit the entity + private void OnAttacked(Entity entity, ref AttackedEvent args) + { + if (!entity.Comp.IsDamageActive) + return; + + var totalDamage = entity.Comp.Damage; + + if (!entity.Comp.IgnoreResistances) + { + // try to get the damage on attacked protection component from something the entity has in their inventory + _inventorySystem.TryGetInventoryEntity(args.User, out var protectiveEntity); + + // if comp is null that means the user didn't have anything equipped that protected them + // let's check their hands to see if the thing they attacked with gives them protection, like the GORILLA gauntlet + if (protectiveEntity.Comp == null && TryComp(args.User, out var handsComp)) + { + if (_handsSystem.TryGetActiveItem((args.User, handsComp), out var itemInHand) && + TryComp(itemInHand, out var itemProtectComp) + && itemProtectComp.Slots == SlotFlags.NONE) + { + protectiveEntity = (itemInHand.Value, itemProtectComp); + } + } + + // if comp is null, that means both the inventory and hands had nothing to protect them + // let's check if the entity itself has the protective comp, like with borgs + if (protectiveEntity.Comp == null && + TryComp(args.User, out var protectiveComp)) + { + protectiveEntity = (args.User, protectiveComp); + } + + // if comp is NOT NULL that means they have damage protection! + if (protectiveEntity.Comp != null) + { + totalDamage = DamageSpecifier.ApplyModifierSet(totalDamage, protectiveEntity.Comp.DamageProtection); + } + } + + totalDamage = _damageableSystem.TryChangeDamage(args.User, totalDamage, entity.Comp.IgnoreResistances, origin: entity); + + if (totalDamage != null && totalDamage.AnyPositive()) + { + _adminLogger.Add(LogType.Damaged, $"{ToPrettyString(args.User):user} injured themselves by attacking {ToPrettyString(entity):target} and received {totalDamage.GetTotal():damage} damage"); + _audioSystem.PlayPredicted(entity.Comp.InteractSound, entity, args.User); + + if (entity.Comp.PopupText != null) + _popupSystem.PopupClient(Loc.GetString(entity.Comp.PopupText), args.User, args.User); + + } + } + + public void SetIsDamageActiveTo(Entity entity, bool mode) + { + if (entity.Comp.IsDamageActive == mode) + return; + + entity.Comp.IsDamageActive = mode; + Dirty(entity); + } +} diff --git a/Content.Shared/Damage/Systems/DamageOnInteractSystem.cs b/Content.Shared/Damage/Systems/DamageOnInteractSystem.cs new file mode 100644 index 0000000000..4b50a1fd0e --- /dev/null +++ b/Content.Shared/Damage/Systems/DamageOnInteractSystem.cs @@ -0,0 +1,85 @@ +using Content.Shared.Administration.Logs; +using Content.Shared.Damage.Components; +using Content.Shared.Database; +using Content.Shared.Interaction; +using Content.Shared.Inventory; +using Content.Shared.Popups; +using Robust.Shared.Audio.Systems; +using Robust.Shared.Network; +using Robust.Shared.Timing; + +namespace Content.Shared.Damage.Systems; + +public sealed class DamageOnInteractSystem : EntitySystem +{ + [Dependency] private readonly ISharedAdminLogManager _adminLogger = default!; + [Dependency] private readonly IGameTiming _gameTiming = default!; + [Dependency] private readonly INetManager _net = default!; + [Dependency] private readonly DamageableSystem _damageableSystem = default!; + [Dependency] private readonly SharedAudioSystem _audioSystem = default!; + [Dependency] private readonly SharedPopupSystem _popupSystem = default!; + [Dependency] private readonly InventorySystem _inventorySystem = default!; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnHandInteract); + } + + /// + /// Damages the user that interacts with the entity with an empty hand and + /// plays a sound or pops up text in response. If the user does not have + /// proper protection, the user will only be damaged and other interactions + /// will be cancelled. + /// + /// The entity being interacted with + /// Contains the user that interacted with the entity + private void OnHandInteract(Entity entity, ref InteractHandEvent args) + { + if (!entity.Comp.IsDamageActive) + return; + + var totalDamage = entity.Comp.Damage; + + if (!entity.Comp.IgnoreResistances) + { + // try to get damage on interact protection from either the inventory slots of the entity + _inventorySystem.TryGetInventoryEntity(args.User, out var protectiveEntity); + + // or checking the entity for the comp itself if the inventory didn't work + if (protectiveEntity.Comp == null && TryComp(args.User, out var protectiveComp)) + { + protectiveEntity = (args.User, protectiveComp); + } + + // if protectiveComp isn't null after all that, it means the user has protection, + // so let's calculate how much they resist + if (protectiveEntity.Comp != null) + { + totalDamage = DamageSpecifier.ApplyModifierSet(totalDamage, protectiveEntity.Comp.DamageProtection); + } + } + + totalDamage = _damageableSystem.TryChangeDamage(args.User, totalDamage, origin: args.Target); + + if (totalDamage != null && totalDamage.AnyPositive()) + { + args.Handled = true; + _adminLogger.Add(LogType.Damaged, $"{ToPrettyString(args.User):user} injured their hand by interacting with {ToPrettyString(args.Target):target} and received {totalDamage.GetTotal():damage} damage"); + _audioSystem.PlayPredicted(entity.Comp.InteractSound, args.Target, args.User); + + if (entity.Comp.PopupText != null) + _popupSystem.PopupClient(Loc.GetString(entity.Comp.PopupText), args.User, args.User); + } + } + + public void SetIsDamageActiveTo(Entity entity, bool mode) + { + if (entity.Comp.IsDamageActive == mode) + return; + + entity.Comp.IsDamageActive = mode; + Dirty(entity); + } +} diff --git a/Content.Shared/Inventory/InventorySystem.Slots.cs b/Content.Shared/Inventory/InventorySystem.Slots.cs index 228b788722..2522dd5d0a 100644 --- a/Content.Shared/Inventory/InventorySystem.Slots.cs +++ b/Content.Shared/Inventory/InventorySystem.Slots.cs @@ -30,7 +30,7 @@ public partial class InventorySystem : EntitySystem /// /// Tries to find an entity in the specified slot with the specified component. /// - public bool TryGetInventoryEntity(Entity entity, out EntityUid targetUid) + public bool TryGetInventoryEntity(Entity entity, out Entity target) where T : IComponent, IClothingSlots { if (TryGetContainerSlotEnumerator(entity.Owner, out var containerSlotEnumerator)) @@ -43,12 +43,12 @@ public partial class InventorySystem : EntitySystem if ((((IClothingSlots) required).Slots & slot.SlotFlags) == 0x0) continue; - targetUid = item; + target = (item, required); return true; } } - targetUid = EntityUid.Invalid; + target = EntityUid.Invalid; return false; } diff --git a/Resources/Prototypes/Entities/Clothing/Hands/base_clothinghands.yml b/Resources/Prototypes/Entities/Clothing/Hands/base_clothinghands.yml index 02cf0ab6f6..c1a53ccf6e 100644 --- a/Resources/Prototypes/Entities/Clothing/Hands/base_clothinghands.yml +++ b/Resources/Prototypes/Entities/Clothing/Hands/base_clothinghands.yml @@ -23,6 +23,10 @@ tags: - ClothMade - WhitelistChameleon + - type: DamageOnInteractProtection + damageProtection: + flatReductions: + Heat: 5 # the average lightbulb only does around four damage! - type: entity abstract: true diff --git a/Resources/Prototypes/Entities/Clothing/Hands/colored.yml b/Resources/Prototypes/Entities/Clothing/Hands/colored.yml index 0fa298b648..556442cee1 100644 --- a/Resources/Prototypes/Entities/Clothing/Hands/colored.yml +++ b/Resources/Prototypes/Entities/Clothing/Hands/colored.yml @@ -283,8 +283,6 @@ color: "#535353" - type: Clothing sprite: Clothing/Hands/Gloves/Color/black.rsi - - type: GloveHeatResistance - heatResistance: 1400 - type: Butcherable butcheringType: Knife spawned: @@ -305,8 +303,6 @@ sprite: Clothing/Hands/Gloves/Color/yellow.rsi - type: Clothing sprite: Clothing/Hands/Gloves/Color/yellow.rsi - - type: GloveHeatResistance - heatResistance: 1400 - type: Butcherable butcheringType: Knife spawned: @@ -323,9 +319,6 @@ name: budget insulated gloves description: These gloves are cheap knockoffs of the coveted ones - no way this can end badly. components: - - type: GloveHeatResistance - # can't take out lights using budgets - heatResistance: 0 - type: RandomInsulation # Why repeated numbers? So some numbers are more common, of course! list: diff --git a/Resources/Prototypes/Entities/Clothing/Hands/gloves.yml b/Resources/Prototypes/Entities/Clothing/Hands/gloves.yml index f1d9988465..53a165cd57 100644 --- a/Resources/Prototypes/Entities/Clothing/Hands/gloves.yml +++ b/Resources/Prototypes/Entities/Clothing/Hands/gloves.yml @@ -103,8 +103,6 @@ sprite: Clothing/Hands/Gloves/captain.rsi - type: Clothing sprite: Clothing/Hands/Gloves/captain.rsi - - type: GloveHeatResistance - heatResistance: 1400 - type: Insulated - type: Fiber fiberMaterial: fibers-durathread @@ -169,8 +167,6 @@ sprite: Clothing/Hands/Gloves/leather.rsi - type: Clothing sprite: Clothing/Hands/Gloves/leather.rsi - - type: GloveHeatResistance - heatResistance: 1400 - type: Fiber fiberMaterial: fibers-leather fiberColor: fibers-brown @@ -225,8 +221,6 @@ enum.ToggleVisuals.Layer: True: {state: icon-green} False: {state: icon} - - type: GloveHeatResistance - heatResistance: 1400 - type: Insulated - type: Fiber fiberMaterial: fibers-nanomachines @@ -270,8 +264,6 @@ sprite: Clothing/Hands/Gloves/combat.rsi - type: Clothing sprite: Clothing/Hands/Gloves/combat.rsi - - type: GloveHeatResistance - heatResistance: 1400 - type: Insulated - type: Fiber fiberMaterial: fibers-insulative @@ -287,8 +279,6 @@ sprite: Clothing/Hands/Gloves/tacticalmaidgloves.rsi - type: Clothing sprite: Clothing/Hands/Gloves/tacticalmaidgloves.rsi - - type: GloveHeatResistance - heatResistance: 1400 - type: Insulated - type: Fiber fiberColor: fibers-black @@ -324,6 +314,10 @@ - type: Fiber fiberMaterial: fibers-synthetic fiberColor: fibers-black + - type: DamageOnInteractProtection + damageProtection: + flatReductions: + Heat: 0 # no protection - type: entity parent: ClothingHandsBase @@ -338,6 +332,10 @@ - type: Fiber fiberMaterial: fibers-insulative fiberColor: fibers-yellow + - type: DamageOnInteractProtection + damageProtection: + flatReductions: + Heat: 0 # no protection - type: entity parent: ClothingHandsButcherable @@ -352,6 +350,10 @@ - type: Fiber fiberMaterial: fibers-insulative fiberColor: fibers-olive + - type: DamageOnInteractProtection + damageProtection: + flatReductions: + Heat: 0 # no protection - type: entity # Intentionally named after regular gloves, they're meant to be sneaky. diff --git a/Resources/Prototypes/Entities/Clothing/OuterClothing/base_clothingouter.yml b/Resources/Prototypes/Entities/Clothing/OuterClothing/base_clothingouter.yml index 7c264a596a..5df6adffec 100644 --- a/Resources/Prototypes/Entities/Clothing/OuterClothing/base_clothingouter.yml +++ b/Resources/Prototypes/Entities/Clothing/OuterClothing/base_clothingouter.yml @@ -136,6 +136,11 @@ - WhitelistChameleon - type: ClothingRequiredStepTriggerImmune slots: WITHOUT_POCKET + - type: DamageOnInteractProtection + damageProtection: + flatReductions: + Heat: 10 # the average lightbulb only does around four damage! + slots: OUTERCLOTHING - type: entity abstract: true @@ -156,6 +161,11 @@ size: Huge - type: ClothingRequiredStepTriggerImmune slots: WITHOUT_POCKET + - type: DamageOnInteractProtection + damageProtection: + flatReductions: + Heat: 10 # the average lightbulb only does around four damage! + slots: OUTERCLOTHING - type: entity parent: ClothingOuterBase diff --git a/Resources/Prototypes/Entities/Mobs/Cyborgs/base_borg_chassis.yml b/Resources/Prototypes/Entities/Mobs/Cyborgs/base_borg_chassis.yml index 0b1f200d4b..371c102eb0 100644 --- a/Resources/Prototypes/Entities/Mobs/Cyborgs/base_borg_chassis.yml +++ b/Resources/Prototypes/Entities/Mobs/Cyborgs/base_borg_chassis.yml @@ -230,6 +230,10 @@ - Cyborgs - Robotics - type: StepTriggerImmune + - type: DamageOnInteractProtection + damageProtection: + flatReductions: + Heat: 10 # capable of touching light bulbs and stoves without feeling pain! - type: entity abstract: true diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/behonker.yml b/Resources/Prototypes/Entities/Mobs/NPCs/behonker.yml index 6f9935d351..1db787a66d 100644 --- a/Resources/Prototypes/Entities/Mobs/NPCs/behonker.yml +++ b/Resources/Prototypes/Entities/Mobs/NPCs/behonker.yml @@ -110,9 +110,6 @@ collection: BananiumHorn params: volume: 5 - anomalyContactDamage: - types: - Radiation: 10 - type: Input context: "human" - type: Bloodstream @@ -158,9 +155,6 @@ suffix: "Ice" components: - type: Anomaly - anomalyContactDamage: - types: - Cold: 10 - type: ExplosionAnomaly supercriticalExplosion: Cryo explosionTotalIntensity: 1000 diff --git a/Resources/Prototypes/Entities/Objects/Specific/Research/anomaly.yml b/Resources/Prototypes/Entities/Objects/Specific/Research/anomaly.yml index 99f874406b..929f509710 100644 --- a/Resources/Prototypes/Entities/Objects/Specific/Research/anomaly.yml +++ b/Resources/Prototypes/Entities/Objects/Specific/Research/anomaly.yml @@ -147,3 +147,10 @@ - type: ContainerContainer containers: core_slot: !type:ContainerSlot + - type: DamageOnAttackedProtection + damageProtection: + flatReductions: + Heat: 100 + Cold: 100 + Radiation: 100 + slots: NONE diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Melee/sword.yml b/Resources/Prototypes/Entities/Objects/Weapons/Melee/sword.yml index 0bab2c828d..838cde619f 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Melee/sword.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Melee/sword.yml @@ -154,7 +154,7 @@ - type: DisarmMalus - type: entity - name: The Throngler + name: Throngler parent: BaseSword id: Throngler description: Why would you make this? @@ -180,3 +180,6 @@ size: Ginormous sprite: Objects/Weapons/Melee/Throngler-in-hand.rsi - type: DisarmMalus + - type: Grammar + attributes: + proper: true diff --git a/Resources/Prototypes/Entities/Structures/Lighting/base_lighting.yml b/Resources/Prototypes/Entities/Structures/Lighting/base_lighting.yml index 436eaa2697..f684ca3425 100644 --- a/Resources/Prototypes/Entities/Structures/Lighting/base_lighting.yml +++ b/Resources/Prototypes/Entities/Structures/Lighting/base_lighting.yml @@ -89,9 +89,6 @@ enabled: false - type: PoweredLight bulb: Tube - damage: - types: - Heat: 2 - type: ContainerContainer containers: light_bulb: !type:ContainerSlot @@ -117,6 +114,11 @@ on: base broken: broken burned: burned + - type: DamageOnInteract + damage: + types: + Heat: 2 + popupText: powered-light-component-burn-hand - type: entity id: Poweredlight @@ -130,15 +132,17 @@ enabled: true - type: PoweredLight hasLampOnSpawn: LightTube - damage: - types: - Heat: 2 - type: AmbientOnPowered - type: AmbientSound volume: -15 range: 2 sound: path: /Audio/Ambience/Objects/light_hum.ogg + - type: DamageOnInteract + damage: + types: + Heat: 2 + popupText: powered-light-component-burn-hand #LED lights - type: entity @@ -149,14 +153,16 @@ components: - type: PoweredLight hasLampOnSpawn: LedLightTube - damage: - types: - Heat: 1 #LEDs don't get as hot - type: PointLight radius: 15 energy: 1 softness: 0.9 color: "#EEEEFF" + - type: DamageOnInteract + damage: + types: + Heat: 1 # LEDs don't get as hot + popupText: powered-light-component-burn-hand - type: entity parent: AlwaysPoweredWallLight @@ -178,9 +184,11 @@ components: - type: PoweredLight hasLampOnSpawn: ExteriorLightTube + - type: DamageOnInteract damage: types: - Heat: 4 #brighter light gets hotter + Heat: 4 # brighter light gets hotter + popupText: powered-light-component-burn-hand - type: entity parent: AlwaysPoweredWallLight @@ -202,14 +210,16 @@ components: - type: PoweredLight hasLampOnSpawn: SodiumLightTube - damage: - types: - Heat: 2 - type: PointLight radius: 10 energy: 2.5 softness: 0.9 color: "#FFAF38" + - type: DamageOnInteract + damage: + types: + Heat: 2 + popupText: powered-light-component-burn-hand - type: entity parent: AlwaysPoweredWallLight @@ -289,9 +299,6 @@ light_bulb: !type:ContainerSlot - type: PoweredLight bulb: Bulb - damage: - types: - Heat: 2 - type: ApcPowerReceiver - type: ExtensionCableReceiver - type: DeviceNetwork @@ -312,6 +319,11 @@ - On - Off - Toggle + - type: DamageOnInteract + damage: + types: + Heat: 2 + popupText: powered-light-component-burn-hand - type: entity id: PoweredLEDSmallLight @@ -328,9 +340,11 @@ color: "#EEEEFF" - type: PoweredLight hasLampOnSpawn: LedLightBulb + - type: DamageOnInteract damage: types: Heat: 1 + popupText: powered-light-component-burn-hand - type: entity id: PoweredSmallLight @@ -343,9 +357,11 @@ enabled: true - type: PoweredLight hasLampOnSpawn: LightBulb + - type: DamageOnInteract damage: types: Heat: 2 + popupText: powered-light-component-burn-hand #Emergency Lights - type: entity @@ -398,14 +414,16 @@ components: - type: PoweredLight hasLampOnSpawn: LightTubeCrystalCyan - damage: - types: - Heat: 2 - type: PointLight radius: 8 energy: 3 softness: 0.5 color: "#47f8ff" + - type: DamageOnInteract + damage: + types: + Heat: 2 + popupText: powered-light-component-burn-hand - type: entity id: AlwaysPoweredlightCyan @@ -425,14 +443,16 @@ components: - type: PoweredLight hasLampOnSpawn: LightTubeCrystalBlue - damage: - types: - Heat: 2 - type: PointLight radius: 8 energy: 3 softness: 0.5 color: "#39a1ff" + - type: DamageOnInteract + damage: + types: + Heat: 2 + popupText: powered-light-component-burn-hand - type: entity id: AlwaysPoweredlightBlue @@ -452,14 +472,16 @@ components: - type: PoweredLight hasLampOnSpawn: LightTubeCrystalPink - damage: - types: - Heat: 2 - type: PointLight radius: 8 energy: 3 softness: 0.5 color: "#ff66cc" + - type: DamageOnInteract + damage: + types: + Heat: 2 + popupText: powered-light-component-burn-hand - type: entity id: AlwaysPoweredlightPink @@ -479,14 +501,16 @@ components: - type: PoweredLight hasLampOnSpawn: LightTubeCrystalOrange - damage: - types: - Heat: 2 - type: PointLight radius: 8 energy: 3 softness: 0.5 color: "#ff8227" + - type: DamageOnInteract + damage: + types: + Heat: 2 + popupText: powered-light-component-burn-hand - type: entity id: AlwaysPoweredlightOrange @@ -506,14 +530,16 @@ components: - type: PoweredLight hasLampOnSpawn: LightTubeCrystalRed - damage: - types: - Heat: 2 - type: PointLight radius: 8 energy: 3 softness: 0.5 color: "#fb4747" + - type: DamageOnInteract + damage: + types: + Heat: 2 + popupText: powered-light-component-burn-hand - type: entity id: AlwaysPoweredlightRed @@ -533,14 +559,16 @@ components: - type: PoweredLight hasLampOnSpawn: LightTubeCrystalGreen - damage: - types: - Heat: 2 - type: PointLight radius: 8 energy: 3 softness: 0.5 color: "#52ff39" + - type: DamageOnInteract + damage: + types: + Heat: 2 + popupText: powered-light-component-burn-hand - type: entity id: AlwaysPoweredlightGreen diff --git a/Resources/Prototypes/Entities/Structures/Lighting/ground_lighting.yml b/Resources/Prototypes/Entities/Structures/Lighting/ground_lighting.yml index 2afde4ef3f..0771cb71bc 100644 --- a/Resources/Prototypes/Entities/Structures/Lighting/ground_lighting.yml +++ b/Resources/Prototypes/Entities/Structures/Lighting/ground_lighting.yml @@ -77,9 +77,6 @@ enabled: false - type: PoweredLight bulb: Tube - damage: - types: - Heat: 2 - type: ContainerContainer containers: light_bulb: !type:ContainerSlot @@ -108,6 +105,11 @@ on: base broken: broken burned: burned + - type: DamageOnInteract + damage: + types: + Heat: 2 + popupText: powered-light-component-burn-hand - type: entity id: PoweredLightPostSmall @@ -122,9 +124,6 @@ enabled: true - type: PoweredLight hasLampOnSpawn: LightTube - damage: - types: - Heat: 2 - type: StaticPrice price: 25 - type: AmbientOnPowered @@ -133,6 +132,11 @@ range: 3 sound: path: /Audio/Ambience/Objects/light_hum.ogg + - type: DamageOnInteract + damage: + types: + Heat: 2 + popupText: powered-light-component-burn-hand - type: entity id: PoweredLEDLightPostSmall @@ -151,9 +155,6 @@ color: "#EEEEFF" - type: PoweredLight hasLampOnSpawn: LedLightTube - damage: - types: - Heat: 1 - type: StaticPrice price: 25 - type: AmbientOnPowered @@ -162,3 +163,8 @@ range: 3 sound: path: /Audio/Ambience/Objects/light_hum.ogg + - type: DamageOnInteract + damage: + types: + Heat: 1 + popupText: powered-light-component-burn-hand diff --git a/Resources/Prototypes/Entities/Structures/Lighting/strobe_lighting.yml b/Resources/Prototypes/Entities/Structures/Lighting/strobe_lighting.yml index 72f5439646..50e24eab73 100644 --- a/Resources/Prototypes/Entities/Structures/Lighting/strobe_lighting.yml +++ b/Resources/Prototypes/Entities/Structures/Lighting/strobe_lighting.yml @@ -87,9 +87,6 @@ - type: PoweredLight bulb: Bulb on: false - damage: - types: - Heat: 2 - type: ApcPowerReceiver - type: ExtensionCableReceiver - type: DeviceNetwork @@ -113,6 +110,11 @@ - type: Construction graph: LightFixture node: strobeLight + - type: DamageOnInteract + damage: + types: + Heat: 2 + popupText: powered-light-component-burn-hand - type: entity id: PoweredStrobeLightPolice diff --git a/Resources/Prototypes/Entities/Structures/Specific/Anomaly/anomalies.yml b/Resources/Prototypes/Entities/Structures/Specific/Anomaly/anomalies.yml index 8bca49c4e5..a16aaaabbb 100644 --- a/Resources/Prototypes/Entities/Structures/Specific/Anomaly/anomalies.yml +++ b/Resources/Prototypes/Entities/Structures/Specific/Anomaly/anomalies.yml @@ -9,9 +9,6 @@ collection: RadiationPulse params: volume: 5 - anomalyContactDamage: - types: - Radiation: 10 - type: AmbientSound range: 5 volume: -5 @@ -51,6 +48,15 @@ - type: SecretDataAnomaly randomStartSecretMin: 0 randomStartSecretMax: 2 + - type: DamageOnInteract + damage: + types: + Radiation: 10 + popupText: anomaly-component-contact-damage + - type: DamageOnAttacked + damage: + types: + Radiation: 10 - type: entity id: AnomalyPyroclastic @@ -99,6 +105,15 @@ - type: IgniteOnCollide fixtureId: fix1 fireStacks: 1 + - type: DamageOnInteract + damage: + types: + Heat: 10 + popupText: anomaly-component-contact-damage + - type: DamageOnAttacked + damage: + types: + Heat: 10 - type: entity id: AnomalyGravity @@ -294,9 +309,6 @@ collection: RadiationPulse params: volume: 5 - anomalyContactDamage: - types: - Radiation: 10 - type: entity id: AnomalyIce @@ -319,9 +331,6 @@ - type: Anomaly corePrototype: AnomalyCoreIce coreInertPrototype: AnomalyCoreIceInert - anomalyContactDamage: - types: - Cold: 10 - type: ExplosionAnomaly supercriticalExplosion: Cryo explosionTotalIntensity: 300 @@ -345,6 +354,15 @@ releasedGas: 8 # Frezon. Please replace if there is a better way to specify this releaseOnMaxSeverity: true spawnRadius: 0 + - type: DamageOnInteract + damage: + types: + Cold: 10 + popupText: anomaly-component-contact-damage + - type: DamageOnAttacked + damage: + types: + Cold: 10 - type: entity id: AnomalyRockBase @@ -609,9 +627,6 @@ coreInertPrototype: AnomalyCoreFloraInert minPulseLength: 60 maxPulseLength: 120 - anomalyContactDamage: - types: - Slash: 0 - type: TileSpawnAnomaly entries: - settings: @@ -715,9 +730,6 @@ coreInertPrototype: AnomalyCoreLiquidInert minPulseLength: 60 maxPulseLength: 120 - anomalyContactDamage: - types: - Slash: 1 - type: EntitySpawnAnomaly entries: - settings: @@ -829,9 +841,6 @@ coreInertPrototype: AnomalyCoreShadowInert minPulseLength: 60 maxPulseLength: 120 - anomalyContactDamage: - types: - Cold: 10 animationTime: 4 offset: "-0.1,0.1" - type: EntitySpawnAnomaly @@ -857,3 +866,12 @@ - type: Tag tags: - SpookyFog + - type: DamageOnInteract + damage: + types: + Cold: 10 + popupText: anomaly-component-contact-damage + - type: DamageOnAttacked + damage: + types: + Cold: 10 diff --git a/Resources/Prototypes/Entities/Structures/Wallmounts/service_light.yml b/Resources/Prototypes/Entities/Structures/Wallmounts/service_light.yml index b8aaa60c37..baadcb67db 100644 --- a/Resources/Prototypes/Entities/Structures/Wallmounts/service_light.yml +++ b/Resources/Prototypes/Entities/Structures/Wallmounts/service_light.yml @@ -24,6 +24,8 @@ bulb: Bulb on: false hasLampOnSpawn: ServiceLightBulb + - type: DamageOnInteract damage: types: Heat: 5 + popupText: powered-light-component-burn-hand From d1a60fafe78c4b3b8cf521601506b92840c2afe3 Mon Sep 17 00:00:00 2001 From: nikthechampiongr <32041239+nikthechampiongr@users.noreply.github.com> Date: Fri, 9 Aug 2024 08:33:25 +0300 Subject: [PATCH 038/174] Implement a playerpanel (#30238) * Basic structure for the player panel ui * Ensure basic functionality Player panel now receives and displays basic info * Make whitelistcommands accept user ids * Make PlayerPanel use GUIDs where possible * Add functionality to most playerpanel buttons * Implement remaining playerpanel features * Localize everything * Finish up * Put command arguments in quotes I am not sure if it's even possible to have something like a space in them considering they are guids and usernames but sure why not * Make playerpanel a verb * Add Logs button to player panel * Change Notesbutton text and make whitelistbutton a confirmtion button * Add freeze button that does not mute the player * Add sharedconnections counter to playerpanel * Make the playetime format clearer * Allow for copying of the a player's username * Do minor cleanup * Rearrange buttons * Fix unfreeze button not updating * Fix wrong localisation text * "Fix" the same role ban counting multiple times The way rolebans are stored is horrible. As such if you ban someone from a departmenrt or something role bans are individually placed for every role. The only way I found to distinguish them is the bantime. This is horrible but I do not want to rewrite how all the bans are stored right now. * Add Delete and Rejuvenate buttons to player panel By popular demand * Marginally improve ui * Add logs * review update * Fix verb * Fix double notes --------- Co-authored-by: metalgearsloth --- .../UI/PlayerPanel/PlayerPanel.xaml | 36 +++ .../UI/PlayerPanel/PlayerPanel.xaml.cs | 132 +++++++++++ .../UI/PlayerPanel/PlayerPanelEui.cs | 72 ++++++ .../Commands/PlayerPanelCommand.cs | 56 +++++ .../Administration/PlayerPanelEui.cs | 210 ++++++++++++++++++ .../Administration/Systems/AdminVerbSystem.cs | 9 + Content.Server/Whitelist/WhitelistCommands.cs | 4 +- .../Administration/PlayerPanelEuiState.cs | 54 +++++ .../en-US/administration/ui/actions.ftl | 1 + .../en-US/administration/ui/player-panel.ftl | 22 ++ .../Locale/en-US/connection-messages.ftl | 4 +- Resources/Locale/en-US/info/playerpanel.ftl | 7 + 12 files changed, 603 insertions(+), 4 deletions(-) create mode 100644 Content.Client/Administration/UI/PlayerPanel/PlayerPanel.xaml create mode 100644 Content.Client/Administration/UI/PlayerPanel/PlayerPanel.xaml.cs create mode 100644 Content.Client/Administration/UI/PlayerPanel/PlayerPanelEui.cs create mode 100644 Content.Server/Administration/Commands/PlayerPanelCommand.cs create mode 100644 Content.Server/Administration/PlayerPanelEui.cs create mode 100644 Content.Shared/Administration/PlayerPanelEuiState.cs create mode 100644 Resources/Locale/en-US/administration/ui/player-panel.ftl create mode 100644 Resources/Locale/en-US/info/playerpanel.ftl diff --git a/Content.Client/Administration/UI/PlayerPanel/PlayerPanel.xaml b/Content.Client/Administration/UI/PlayerPanel/PlayerPanel.xaml new file mode 100644 index 0000000000..8feec273b4 --- /dev/null +++ b/Content.Client/Administration/UI/PlayerPanel/PlayerPanel.xaml @@ -0,0 +1,36 @@ + + + + + + + + diff --git a/Content.Client/Silicons/Laws/SiliconLawEditUi/SiliconLawContainer.xaml.cs b/Content.Client/Silicons/Laws/SiliconLawEditUi/SiliconLawContainer.xaml.cs new file mode 100644 index 0000000000..2e44b820df --- /dev/null +++ b/Content.Client/Silicons/Laws/SiliconLawEditUi/SiliconLawContainer.xaml.cs @@ -0,0 +1,61 @@ +using Content.Shared.Silicons.Laws; +using Robust.Client.AutoGenerated; +using Robust.Client.UserInterface.Controls; +using Robust.Client.UserInterface.XAML; +using Robust.Shared.Utility; + +namespace Content.Client.Silicons.Laws.SiliconLawEditUi; + +[GenerateTypedNameReferences] +public sealed partial class SiliconLawContainer : BoxContainer +{ + public const string StyleClassSiliconLawPositionLabel = "SiliconLawPositionLabel"; + + public static readonly string CorruptedString = + Loc.GetString("ion-storm-law-scrambled-number", ("length", 5)); + + private SiliconLaw? _law; + + public event Action? MoveLawUp; + public event Action? MoveLawDown; + public event Action? DeleteAction; + + + public SiliconLawContainer() + { + RobustXamlLoader.Load(this); + + MoveUp.OnPressed += _ => MoveLawUp?.Invoke(_law!); + MoveDown.OnPressed += _ => MoveLawDown?.Invoke(_law!); + Corrupted.OnPressed += _ => + { + if (Corrupted.Pressed) + { + _law!.LawIdentifierOverride = CorruptedString; + } + else + { + _law!.LawIdentifierOverride = null; + } + }; + + LawContent.OnTextChanged += _ => _law!.LawString = Rope.Collapse(LawContent.TextRope).Trim(); + LawContent.Placeholder = new Rope.Leaf(Loc.GetString("silicon-law-ui-placeholder")); + Delete.OnPressed += _ => DeleteAction?.Invoke(_law!); + } + + public void SetLaw(SiliconLaw law) + { + _law = law; + LawContent.TextRope = new Rope.Leaf(Loc.GetString(law.LawString)); + PositionText.Text = law.Order.ToString(); + if (!string.IsNullOrEmpty(law.LawIdentifierOverride)) + { + Corrupted.Pressed = true; + } + else + { + Corrupted.Pressed = false; + } + } +} diff --git a/Content.Client/Silicons/Laws/SiliconLawEditUi/SiliconLawEui.cs b/Content.Client/Silicons/Laws/SiliconLawEditUi/SiliconLawEui.cs new file mode 100644 index 0000000000..a4d59d1f31 --- /dev/null +++ b/Content.Client/Silicons/Laws/SiliconLawEditUi/SiliconLawEui.cs @@ -0,0 +1,38 @@ +using Content.Client.Eui; +using Content.Shared.Eui; +using Content.Shared.Silicons.Laws; + +namespace Content.Client.Silicons.Laws.SiliconLawEditUi; + +public sealed class SiliconLawEui : BaseEui +{ + public readonly EntityManager _entityManager = default!; + + private SiliconLawUi _siliconLawUi; + private EntityUid _target; + + public SiliconLawEui() + { + _entityManager = IoCManager.Resolve(); + + _siliconLawUi = new SiliconLawUi(); + _siliconLawUi.OnClose += () => SendMessage(new CloseEuiMessage()); + _siliconLawUi.Save.OnPressed += _ => SendMessage(new SiliconLawsSaveMessage(_siliconLawUi.GetLaws(), _entityManager.GetNetEntity(_target))); + } + + public override void HandleState(EuiStateBase state) + { + if (state is not SiliconLawsEuiState s) + { + return; + } + + _target = _entityManager.GetEntity(s.Target); + _siliconLawUi.SetLaws(s.Laws); + } + + public override void Opened() + { + _siliconLawUi.OpenCentered(); + } +} diff --git a/Content.Client/Silicons/Laws/SiliconLawEditUi/SiliconLawUi.xaml b/Content.Client/Silicons/Laws/SiliconLawEditUi/SiliconLawUi.xaml new file mode 100644 index 0000000000..19dcbac620 --- /dev/null +++ b/Content.Client/Silicons/Laws/SiliconLawEditUi/SiliconLawUi.xaml @@ -0,0 +1,22 @@ + + + this shit does not layout properly unless I put the horizontal boxcontainer inside of a vertical one + ???? + + + + + + + + + + + + + diff --git a/Content.Client/Silicons/Laws/SiliconLawEditUi/SiliconLawUi.xaml.cs b/Content.Client/Silicons/Laws/SiliconLawEditUi/SiliconLawUi.xaml.cs new file mode 100644 index 0000000000..372961ea9a --- /dev/null +++ b/Content.Client/Silicons/Laws/SiliconLawEditUi/SiliconLawUi.xaml.cs @@ -0,0 +1,89 @@ +using System.Linq; +using Content.Client.UserInterface.Controls; +using Content.Shared.FixedPoint; +using Content.Shared.Silicons.Laws; +using Robust.Client.AutoGenerated; +using Robust.Client.UserInterface.XAML; + +namespace Content.Client.Silicons.Laws.SiliconLawEditUi; + +[GenerateTypedNameReferences] +public sealed partial class SiliconLawUi : FancyWindow +{ + private List _laws = new(); + + public SiliconLawUi() + { + RobustXamlLoader.Load(this); + NewLawButton.OnPressed += _ => AddNewLaw(); + } + + private void AddNewLaw() + { + var newLaw = new SiliconLaw(); + newLaw.Order = FixedPoint2.New(_laws.Count + 1); + _laws.Add(newLaw); + SetLaws(_laws); + } + + public void SetLaws(List sLaws) + { + _laws = sLaws; + LawContainer.RemoveAllChildren(); + foreach (var law in sLaws.OrderBy(l => l.Order)) + { + var lawControl = new SiliconLawContainer(); + lawControl.SetLaw(law); + lawControl.MoveLawDown += MoveLawDown; + lawControl.MoveLawUp += MoveLawUp; + lawControl.DeleteAction += DeleteLaw; + + LawContainer.AddChild(lawControl); + } + } + + public void DeleteLaw(SiliconLaw law) + { + _laws.Remove(law); + SetLaws(_laws); + } + + public void MoveLawDown(SiliconLaw law) + { + if (_laws.Count == 0) + { + return; + } + + var index = _laws.IndexOf(law); + if (index == -1) + { + return; + } + + _laws[index].Order += FixedPoint2.New(1); + SetLaws(_laws); + } + + public void MoveLawUp(SiliconLaw law) + { + if (_laws.Count == 0) + { + return; + } + + var index = _laws.IndexOf(law); + if (index == -1) + { + return; + } + + _laws[index].Order += FixedPoint2.New(-1); + SetLaws(_laws); + } + + public List GetLaws() + { + return _laws; + } +} diff --git a/Content.Client/Stylesheets/StyleNano.cs b/Content.Client/Stylesheets/StyleNano.cs index 0c04a55059..0bd75003a2 100644 --- a/Content.Client/Stylesheets/StyleNano.cs +++ b/Content.Client/Stylesheets/StyleNano.cs @@ -4,6 +4,7 @@ using Content.Client.ContextMenu.UI; using Content.Client.Examine; using Content.Client.PDA; using Content.Client.Resources; +using Content.Client.Silicons.Laws.SiliconLawEditUi; using Content.Client.UserInterface.Controls; using Content.Client.UserInterface.Controls.FancyTree; using Content.Client.Verbs.UI; @@ -1613,6 +1614,10 @@ namespace Content.Client.Stylesheets { BackgroundColor = FancyTreeSelectedRowColor, }), + + // Silicon law edit ui + Element