From 9e0397d60e2b331c8a0c9ff3a6ff998edab7f1c6 Mon Sep 17 00:00:00 2001 From: SlamBamActionman <83650252+SlamBamActionman@users.noreply.github.com> Date: Fri, 1 Aug 2025 13:46:59 +0200 Subject: [PATCH 001/340] Fix variantize command not respecting tile rotation (#39314) Oopsiedoodle --- Content.Server/Administration/Commands/VariantizeCommand.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Content.Server/Administration/Commands/VariantizeCommand.cs b/Content.Server/Administration/Commands/VariantizeCommand.cs index a75f72b1c7d..428207bde6d 100644 --- a/Content.Server/Administration/Commands/VariantizeCommand.cs +++ b/Content.Server/Administration/Commands/VariantizeCommand.cs @@ -44,7 +44,7 @@ public sealed class VariantizeCommand : IConsoleCommand foreach (var tile in mapsSystem.GetAllTiles(euid.Value, gridComp)) { var def = turfSystem.GetContentTileDefinition(tile); - var newTile = new Tile(tile.Tile.TypeId, tile.Tile.Flags, tileSystem.PickVariant(def)); + var newTile = new Tile(tile.Tile.TypeId, tile.Tile.Flags, tileSystem.PickVariant(def), tile.Tile.RotationMirroring); mapsSystem.SetTile(euid.Value, gridComp, tile.GridIndices, newTile); } } From f4b02e33c3ea439637d2c796b6b58563233c14bd Mon Sep 17 00:00:00 2001 From: Arcane-Waffle Date: Fri, 1 Aug 2025 16:58:32 +0500 Subject: [PATCH 002/340] Renames slugcat jelly-donuts to scurret jelly-donuts (#39308) * renames slugcat jelly-donuts to scurret jelly-donuts * renames slugcat jelly-donuts to scurret jelly-donuts * renames slugcat jelly-donuts to scurret jelly-donuts * missing end of file new line --------- Co-authored-by: Arcane-Waffle Co-authored-by: slarticodefast <161409025+slarticodefast@users.noreply.github.com> --- Resources/Migrations/migration.yml | 3 +++ .../Entities/Objects/Consumable/Food/Baked/donut.yml | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/Resources/Migrations/migration.yml b/Resources/Migrations/migration.yml index 081ae622343..214a6e4b466 100644 --- a/Resources/Migrations/migration.yml +++ b/Resources/Migrations/migration.yml @@ -653,6 +653,9 @@ BarSignWhiskeyEchoesAlignTile: BarSignWhiskeyEchoes # 2025-06-21 ClothingNeckHeadphones: ClothingMultipleHeadphones +# 2025-08-01 +FoodDonutJellySlugcat: FoodDonutJellyScurret + # 2025-10-01 SimpleXenoArtifact: ComplexXenoArtifact MediumXenoArtifact: ComplexXenoArtifact diff --git a/Resources/Prototypes/Entities/Objects/Consumable/Food/Baked/donut.yml b/Resources/Prototypes/Entities/Objects/Consumable/Food/Baked/donut.yml index 52ac7b2fe98..c13f52194fa 100644 --- a/Resources/Prototypes/Entities/Objects/Consumable/Food/Baked/donut.yml +++ b/Resources/Prototypes/Entities/Objects/Consumable/Food/Baked/donut.yml @@ -445,9 +445,9 @@ # Tastes like jelly-donut, fizzy tutti frutti. - type: entity - name: slugcat jelly-donut + name: scurret jelly-donut parent: FoodDonutBase - id: FoodDonutJellySlugcat + id: FoodDonutJellyScurret description: No holes in this donut in case a suspicious looking pole shows up. components: - type: Sprite From 0f3558b424d17b306998f4a31021ba5e67067255 Mon Sep 17 00:00:00 2001 From: Kyle Tyo <36606155+VerinSenpai@users.noreply.github.com> Date: Fri, 1 Aug 2025 13:40:15 -0400 Subject: [PATCH 003/340] Predict EmitterSystem ExamineEvent and GetVerbsEvent (#39318) * ididathing.exe * commit * cleanup --------- Co-authored-by: slarticodefast <161409025+slarticodefast@users.noreply.github.com> --- .../Singularity/Systems/EmitterSystem.cs | 2 + .../EntitySystems/EmitterSystem.cs | 47 -------------- .../Components/SharedEmitterComponent.cs | 38 ++++++------ .../EntitySystems/SharedEmitterSystem.cs | 62 ++++++++++++++++++- 4 files changed, 81 insertions(+), 68 deletions(-) diff --git a/Content.Client/Singularity/Systems/EmitterSystem.cs b/Content.Client/Singularity/Systems/EmitterSystem.cs index e9e08463404..b35c3297a17 100644 --- a/Content.Client/Singularity/Systems/EmitterSystem.cs +++ b/Content.Client/Singularity/Systems/EmitterSystem.cs @@ -12,6 +12,8 @@ public sealed class EmitterSystem : SharedEmitterSystem /// public override void Initialize() { + base.Initialize(); + SubscribeLocalEvent(OnAppearanceChange); } diff --git a/Content.Server/Singularity/EntitySystems/EmitterSystem.cs b/Content.Server/Singularity/EntitySystems/EmitterSystem.cs index 662df43e122..28d3eedd328 100644 --- a/Content.Server/Singularity/EntitySystems/EmitterSystem.cs +++ b/Content.Server/Singularity/EntitySystems/EmitterSystem.cs @@ -7,7 +7,6 @@ using Content.Server.Projectiles; using Content.Server.Weapons.Ranged.Systems; using Content.Shared.Database; using Content.Shared.DeviceLinking.Events; -using Content.Shared.Examine; using Content.Shared.Interaction; using Content.Shared.Lock; using Content.Shared.Popups; @@ -15,9 +14,7 @@ using Content.Shared.Power; using Content.Shared.Projectiles; using Content.Shared.Singularity.Components; using Content.Shared.Singularity.EntitySystems; -using Content.Shared.Verbs; using Content.Shared.Weapons.Ranged.Components; -using JetBrains.Annotations; using Robust.Shared.Map; using Robust.Shared.Physics; using Robust.Shared.Physics.Components; @@ -28,7 +25,6 @@ using Timer = Robust.Shared.Timing.Timer; namespace Content.Server.Singularity.EntitySystems { - [UsedImplicitly] public sealed class EmitterSystem : SharedEmitterSystem { [Dependency] private readonly IRobustRandom _random = default!; @@ -46,8 +42,6 @@ namespace Content.Server.Singularity.EntitySystems SubscribeLocalEvent(ReceivedChanged); SubscribeLocalEvent(OnApcChanged); SubscribeLocalEvent(OnActivate); - SubscribeLocalEvent>(OnGetVerb); - SubscribeLocalEvent(OnExamined); SubscribeLocalEvent(OnAnchorStateChanged); SubscribeLocalEvent(OnSignalReceived); } @@ -99,47 +93,6 @@ namespace Content.Server.Singularity.EntitySystems } } - private void OnGetVerb(EntityUid uid, EmitterComponent component, GetVerbsEvent args) - { - if (!args.CanAccess || !args.CanInteract || !args.CanComplexInteract || args.Hands == null) - return; - - if (TryComp(uid, out var lockComp) && lockComp.Locked) - return; - - if (component.SelectableTypes.Count < 2) - return; - - foreach (var type in component.SelectableTypes) - { - var proto = _prototype.Index(type); - - var v = new Verb - { - Priority = 1, - Category = VerbCategory.SelectType, - Text = proto.Name, - Disabled = type == component.BoltType, - Impact = LogImpact.Medium, - DoContactInteraction = true, - Act = () => - { - component.BoltType = type; - _popup.PopupEntity(Loc.GetString("emitter-component-type-set", ("type", proto.Name)), uid); - } - }; - args.Verbs.Add(v); - } - } - - private void OnExamined(EntityUid uid, EmitterComponent component, ExaminedEvent args) - { - if (component.SelectableTypes.Count < 2) - return; - var proto = _prototype.Index(component.BoltType); - args.PushMarkup(Loc.GetString("emitter-component-current-type", ("type", proto.Name))); - } - private void ReceivedChanged( EntityUid uid, EmitterComponent component, diff --git a/Content.Shared/Singularity/Components/SharedEmitterComponent.cs b/Content.Shared/Singularity/Components/SharedEmitterComponent.cs index dce2f92d0c7..d1817579689 100644 --- a/Content.Shared/Singularity/Components/SharedEmitterComponent.cs +++ b/Content.Shared/Singularity/Components/SharedEmitterComponent.cs @@ -3,12 +3,10 @@ using Content.Shared.DeviceLinking; using Robust.Shared.GameStates; using Robust.Shared.Prototypes; using Robust.Shared.Serialization; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.Dictionary; namespace Content.Shared.Singularity.Components; -[RegisterComponent, NetworkedComponent] +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] public sealed partial class EmitterComponent : Component { public CancellationTokenSource? TimerCancel; @@ -27,8 +25,8 @@ public sealed partial class EmitterComponent : Component /// /// The entity that is spawned when the emitter fires. /// - [DataField("boltType", customTypeSerializer: typeof(PrototypeIdSerializer))] - public string BoltType = "EmitterBolt"; + [DataField, AutoNetworkedField] + public EntProtoId BoltType = "EmitterBolt"; [DataField] public List SelectableTypes = new(); @@ -36,68 +34,68 @@ public sealed partial class EmitterComponent : Component /// /// The current amount of power being used. /// - [DataField("powerUseActive")] + [DataField] public int PowerUseActive = 600; /// /// The amount of shots that are fired in a single "burst" /// - [DataField("fireBurstSize")] + [DataField] public int FireBurstSize = 3; /// /// The time between each shot during a burst. /// - [DataField("fireInterval")] + [DataField] public TimeSpan FireInterval = TimeSpan.FromSeconds(2); /// /// The current minimum delay between bursts. /// - [DataField("fireBurstDelayMin")] + [DataField] public TimeSpan FireBurstDelayMin = TimeSpan.FromSeconds(4); /// /// The current maximum delay between bursts. /// - [DataField("fireBurstDelayMax")] + [DataField] public TimeSpan FireBurstDelayMax = TimeSpan.FromSeconds(10); /// /// The visual state that is set when the emitter is turned on /// - [DataField("onState")] + [DataField] public string? OnState = "beam"; /// /// The visual state that is set when the emitter doesn't have enough power. /// - [DataField("underpoweredState")] + [DataField] public string? UnderpoweredState = "underpowered"; /// /// Signal port that turns on the emitter. /// - [DataField("onPort", customTypeSerializer: typeof(PrototypeIdSerializer))] - public string OnPort = "On"; + [DataField] + public ProtoId OnPort = "On"; /// /// Signal port that turns off the emitter. /// - [DataField("offPort", customTypeSerializer: typeof(PrototypeIdSerializer))] - public string OffPort = "Off"; + [DataField] + public ProtoId OffPort = "Off"; /// /// Signal port that toggles the emitter on or off. /// - [DataField("togglePort", customTypeSerializer: typeof(PrototypeIdSerializer))] - public string TogglePort = "Toggle"; + [DataField] + public ProtoId TogglePort = "Toggle"; /// /// Map of signal ports to entity prototype IDs of the entity that will be fired. /// - [DataField("setTypePorts", customTypeSerializer: typeof(PrototypeIdDictionarySerializer))] - public Dictionary SetTypePorts = new(); + [DataField] + public Dictionary, EntProtoId> SetTypePorts = new(); } [NetSerializable, Serializable] diff --git a/Content.Shared/Singularity/EntitySystems/SharedEmitterSystem.cs b/Content.Shared/Singularity/EntitySystems/SharedEmitterSystem.cs index bba66299886..9ef7dcfbdb2 100644 --- a/Content.Shared/Singularity/EntitySystems/SharedEmitterSystem.cs +++ b/Content.Shared/Singularity/EntitySystems/SharedEmitterSystem.cs @@ -1,6 +1,66 @@ -namespace Content.Shared.Singularity.EntitySystems; +using Content.Shared.Database; +using Content.Shared.Examine; +using Content.Shared.Lock; +using Content.Shared.Popups; +using Content.Shared.Singularity.Components; +using Content.Shared.Verbs; +using Robust.Shared.Prototypes; + +namespace Content.Shared.Singularity.EntitySystems; public abstract class SharedEmitterSystem : EntitySystem { + [Dependency] private readonly IPrototypeManager _prototype = default!; + [Dependency] private readonly SharedPopupSystem _popup = default!; + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnExamined); + SubscribeLocalEvent>(OnGetVerb); + } + + private void OnGetVerb(Entity ent, ref GetVerbsEvent args) + { + if (!args.CanAccess || !args.CanInteract || !args.CanComplexInteract || args.Hands == null) + return; + + if (TryComp(ent.Owner, out var lockComp) && lockComp.Locked) + return; + + if (ent.Comp.SelectableTypes.Count < 2) + return; + + foreach (var type in ent.Comp.SelectableTypes) + { + var proto = _prototype.Index(type); + + var v = new Verb + { + Priority = 1, + Category = VerbCategory.SelectType, + Text = proto.Name, + Disabled = type == ent.Comp.BoltType, + Impact = LogImpact.Medium, + DoContactInteraction = true, + Act = () => + { + ent.Comp.BoltType = type; + Dirty(ent); + _popup.PopupClient(Loc.GetString("emitter-component-type-set", ("type", proto.Name)), ent.Owner); + }, + }; + args.Verbs.Add(v); + } + } + + private void OnExamined(Entity ent, ref ExaminedEvent args) + { + if (ent.Comp.SelectableTypes.Count < 2) + return; + + var proto = _prototype.Index(ent.Comp.BoltType); + args.PushMarkup(Loc.GetString("emitter-component-current-type", ("type", proto.Name))); + } } From 7210699f8bb093d192cf054b45f6d8b1ff14cae9 Mon Sep 17 00:00:00 2001 From: Perry Fraser Date: Fri, 1 Aug 2025 17:48:40 -0400 Subject: [PATCH 004/340] Fix tabletop grids rarely spawning on top of another (#39327) * fix: fix off-by-one for tabletop map positions Ulam spirals start at 1, not 0. * fix: make the ulam spiral a ulam spiral --- Content.Server/Tabletop/TabletopSystem.Map.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Content.Server/Tabletop/TabletopSystem.Map.cs b/Content.Server/Tabletop/TabletopSystem.Map.cs index 5e116d81ef6..89563ec6bf0 100644 --- a/Content.Server/Tabletop/TabletopSystem.Map.cs +++ b/Content.Server/Tabletop/TabletopSystem.Map.cs @@ -37,7 +37,7 @@ namespace Content.Server.Tabletop /// private Vector2 GetNextTabletopPosition() { - return UlamSpiral(_tabletops++) * TabletopSeparation; + return UlamSpiral(++_tabletops) * TabletopSeparation; } /// @@ -62,11 +62,11 @@ namespace Content.Server.Tabletop /// /// Algorithm for mapping scalars to 2D positions in the same pattern as an Ulam Spiral. /// - /// Scalar to map to a 2D position. + /// Scalar to map to a 2D position. Must be greater than or equal to 1. /// The mapped 2D position for the scalar. private Vector2i UlamSpiral(int n) { - var k = (int)MathF.Ceiling(MathF.Sqrt(n) - 1) / 2; + var k = (int)MathF.Ceiling((MathF.Sqrt(n) - 1) / 2); var t = 2 * k + 1; var m = (int)MathF.Pow(t, 2); t--; From 2b995b6be403cbaeef87f7b17b6d45a91b3c9af4 Mon Sep 17 00:00:00 2001 From: Kyle Tyo <36606155+VerinSenpai@users.noreply.github.com> Date: Fri, 1 Aug 2025 15:38:39 -0400 Subject: [PATCH 005/340] Predict ExamineEvent for CryoPodSystem. (#39322) commit --- Content.Server/Medical/CryoPodSystem.cs | 17 -------------- .../Medical/Cryogenics/SharedCryoPodSystem.cs | 22 +++++++++++++++++++ 2 files changed, 22 insertions(+), 17 deletions(-) diff --git a/Content.Server/Medical/CryoPodSystem.cs b/Content.Server/Medical/CryoPodSystem.cs index 361f05d6dd8..c335024258c 100644 --- a/Content.Server/Medical/CryoPodSystem.cs +++ b/Content.Server/Medical/CryoPodSystem.cs @@ -68,7 +68,6 @@ public sealed partial class CryoPodSystem : SharedCryoPodSystem SubscribeLocalEvent(OnCryoPodUpdateAtmosphere); SubscribeLocalEvent(HandleDragDropOn); SubscribeLocalEvent(OnInteractUsing); - SubscribeLocalEvent(OnExamined); SubscribeLocalEvent(OnPowerChanged); SubscribeLocalEvent(OnGasAnalyzed); SubscribeLocalEvent(OnActivateUIAttempt); @@ -219,22 +218,6 @@ public sealed partial class CryoPodSystem : SharedCryoPodSystem args.Handled = _toolSystem.UseTool(args.Used, args.User, entity.Owner, entity.Comp.PryDelay, PryingQuality, new CryoPodPryFinished()); } - private void OnExamined(Entity entity, ref ExaminedEvent args) - { - var container = _itemSlotsSystem.GetItemOrNull(entity.Owner, entity.Comp.SolutionContainerName); - if (args.IsInDetailsRange && container != null && _solutionContainerSystem.TryGetFitsInDispenser(container.Value, out _, out var containerSolution)) - { - using (args.PushGroup(nameof(CryoPodComponent))) - { - args.PushMarkup(Loc.GetString("cryo-pod-examine", ("beaker", Name(container.Value)))); - if (containerSolution.Volume == 0) - { - args.PushMarkup(Loc.GetString("cryo-pod-empty-beaker")); - } - } - } - } - private void OnPowerChanged(Entity entity, ref PowerChangedEvent args) { // Needed to avoid adding/removing components on a deleted entity diff --git a/Content.Shared/Medical/Cryogenics/SharedCryoPodSystem.cs b/Content.Shared/Medical/Cryogenics/SharedCryoPodSystem.cs index 8d7eb05cd91..f45ecc09342 100644 --- a/Content.Shared/Medical/Cryogenics/SharedCryoPodSystem.cs +++ b/Content.Shared/Medical/Cryogenics/SharedCryoPodSystem.cs @@ -1,9 +1,12 @@ using Content.Shared.Administration.Logs; using Content.Shared.Body.Components; +using Content.Shared.Chemistry.EntitySystems; +using Content.Shared.Containers.ItemSlots; using Content.Shared.Database; using Content.Shared.DoAfter; using Content.Shared.DragDrop; using Content.Shared.Emag.Systems; +using Content.Shared.Examine; using Content.Shared.Mobs.Components; using Content.Shared.Mobs.Systems; using Content.Shared.Popups; @@ -20,10 +23,12 @@ public abstract partial class SharedCryoPodSystem: EntitySystem [Dependency] private readonly SharedAppearanceSystem _appearanceSystem = default!; [Dependency] private readonly StandingStateSystem _standingStateSystem = default!; [Dependency] private readonly EmagSystem _emag = default!; + [Dependency] private readonly ItemSlotsSystem _itemSlotsSystem = default!; [Dependency] private readonly MobStateSystem _mobStateSystem = default!; [Dependency] private readonly SharedPopupSystem _popupSystem = default!; [Dependency] private readonly SharedContainerSystem _containerSystem = default!; [Dependency] private readonly SharedPointLightSystem _light = default!; + [Dependency] private readonly SharedSolutionContainerSystem _solutionContainerSystem = default!; [Dependency] private readonly ISharedAdminLogManager _adminLogger = default!; public override void Initialize() @@ -31,9 +36,26 @@ public abstract partial class SharedCryoPodSystem: EntitySystem base.Initialize(); SubscribeLocalEvent(OnCryoPodCanDropOn); + SubscribeLocalEvent(OnExamined); InitializeInsideCryoPod(); } + private void OnExamined(Entity entity, ref ExaminedEvent args) + { + var container = _itemSlotsSystem.GetItemOrNull(entity.Owner, entity.Comp.SolutionContainerName); + if (args.IsInDetailsRange && container != null && _solutionContainerSystem.TryGetFitsInDispenser(container.Value, out _, out var containerSolution)) + { + using (args.PushGroup(nameof(CryoPodComponent))) + { + args.PushMarkup(Loc.GetString("cryo-pod-examine", ("beaker", Name(container.Value)))); + if (containerSolution.Volume == 0) + { + args.PushMarkup(Loc.GetString("cryo-pod-empty-beaker")); + } + } + } + } + private void OnCryoPodCanDropOn(EntityUid uid, CryoPodComponent component, ref CanDropTargetEvent args) { if (args.Handled) From dce074ec24ccdd4a744268cfdecd9ed19d2c4d23 Mon Sep 17 00:00:00 2001 From: Krosus777 <38509947+Krosus777@users.noreply.github.com> Date: Sat, 2 Aug 2025 17:14:16 +0200 Subject: [PATCH 006/340] HumanoidCharacterProfileFix (#39333) --- Content.Shared/Preferences/HumanoidCharacterProfile.cs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/Content.Shared/Preferences/HumanoidCharacterProfile.cs b/Content.Shared/Preferences/HumanoidCharacterProfile.cs index 74f933f7ac0..acf943c149f 100644 --- a/Content.Shared/Preferences/HumanoidCharacterProfile.cs +++ b/Content.Shared/Preferences/HumanoidCharacterProfile.cs @@ -758,10 +758,17 @@ namespace Content.Shared.Preferences var namingSystem = IoCManager.Resolve().GetEntitySystem(); return namingSystem.GetName(species, gender); } + public bool Equals(HumanoidCharacterProfile? other) + { + if (other is null) + return false; + + return ReferenceEquals(this, other) || MemberwiseEquals(other); + } public override bool Equals(object? obj) { - return ReferenceEquals(this, obj) || obj is HumanoidCharacterProfile other && Equals(other); + return obj is HumanoidCharacterProfile other && Equals(other); } public override int GetHashCode() From aeea786127f6eb9ec8e60f87f10a737be3ab4647 Mon Sep 17 00:00:00 2001 From: Pieter-Jan Briers Date: Sat, 2 Aug 2025 17:23:44 +0200 Subject: [PATCH 007/340] Fix StoreTests EventBus usage (#38489) Fix split off from #37349 to avoid needing to sync the content/engine PRs. --- Content.IntegrationTests/Tests/StoreTests.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Content.IntegrationTests/Tests/StoreTests.cs b/Content.IntegrationTests/Tests/StoreTests.cs index 1f7d357bc05..cbbd163bec9 100644 --- a/Content.IntegrationTests/Tests/StoreTests.cs +++ b/Content.IntegrationTests/Tests/StoreTests.cs @@ -122,7 +122,7 @@ public sealed class StoreTests var buyMsg = new StoreBuyListingMessage(discountedListingItem.ID){Actor = human}; - server.EntMan.EventBus.RaiseComponentEvent(pda, storeComponent, buyMsg); + server.EntMan.EventBus.RaiseLocalEvent(pda, buyMsg); var newBalance = storeComponent.Balance[UplinkSystem.TelecrystalCurrencyPrototype]; Assert.That(newBalance.Value, Is.EqualTo((originalBalance - plainDiscountedCost).Value), "Expected to have balance reduced by discounted cost"); @@ -135,7 +135,7 @@ public sealed class StoreTests Assert.That(costAfterBuy.Value, Is.EqualTo(prototypeCost.Value), "Expected cost after discount refund to be equal to prototype cost."); var refundMsg = new StoreRequestRefundMessage { Actor = human }; - server.EntMan.EventBus.RaiseComponentEvent(pda, storeComponent, refundMsg); + server.EntMan.EventBus.RaiseLocalEvent(pda, refundMsg); // get refreshed item after refund re-generated items discountedListingItem = storeComponent.FullListingsCatalog.First(x => x.ID == itemId); From a97f3dbb1f5bb4e8c9c1a2cbcd31faa7de853e0e Mon Sep 17 00:00:00 2001 From: Pieter-Jan Briers Date: Sat, 2 Aug 2025 22:20:17 +0200 Subject: [PATCH 008/340] Fix horizontal space men in replays (#39338) * Fix horizontal space men in replays Visualizer should not bail if data unavailable. * Update Content.Client/Rotation/RotationVisualizerSystem.cs --------- Co-authored-by: slarticodefast <161409025+slarticodefast@users.noreply.github.com> --- Content.Client/Rotation/RotationVisualizerSystem.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Content.Client/Rotation/RotationVisualizerSystem.cs b/Content.Client/Rotation/RotationVisualizerSystem.cs index 8dbcf973201..b5be4d0b179 100644 --- a/Content.Client/Rotation/RotationVisualizerSystem.cs +++ b/Content.Client/Rotation/RotationVisualizerSystem.cs @@ -24,7 +24,7 @@ public sealed class RotationVisualizerSystem : SharedRotationVisualsSystem return; if (!_appearance.TryGetData(uid, RotationVisuals.RotationState, out var state, args.Component)) - return; + state = RotationState.Vertical; switch (state) { From f59810ab283311e535901113c61c1307011d07af Mon Sep 17 00:00:00 2001 From: DrSmugleaf <10968691+DrSmugleaf@users.noreply.github.com> Date: Sat, 2 Aug 2025 15:59:48 -0700 Subject: [PATCH 009/340] Fix ActionsSystem.IsCooldownActive always returning false if curTime is null (#39329) --- Content.Shared/Actions/SharedActionsSystem.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/Content.Shared/Actions/SharedActionsSystem.cs b/Content.Shared/Actions/SharedActionsSystem.cs index 39a75beea16..705c69b5f47 100644 --- a/Content.Shared/Actions/SharedActionsSystem.cs +++ b/Content.Shared/Actions/SharedActionsSystem.cs @@ -1022,6 +1022,7 @@ public abstract class SharedActionsSystem : EntitySystem public bool IsCooldownActive(ActionComponent action, TimeSpan? curTime = null) { // TODO: Check for charge recovery timer + curTime ??= GameTiming.CurTime; return action.Cooldown.HasValue && action.Cooldown.Value.End > curTime; } From 23b9e50d84b48d7ae42a9deff9a284e1920cbefd Mon Sep 17 00:00:00 2001 From: Pieter-Jan Briers Date: Sun, 3 Aug 2025 01:02:40 +0200 Subject: [PATCH 010/340] Make dirt non-compressible (#39220) This sets the new rsic: false flag in dirt.rsi. One of the interior PNGs is directly accessed by a tile definition, which would otherwise cause a game startup failure with the new packaging improvements: https://github.com/space-wizards/RobustToolbox/commit/c4dff678a9511190da2e6217992852d5e1df7985 --- Resources/Textures/Tiles/Planet/dirt.rsi/meta.json | 1 + 1 file changed, 1 insertion(+) diff --git a/Resources/Textures/Tiles/Planet/dirt.rsi/meta.json b/Resources/Textures/Tiles/Planet/dirt.rsi/meta.json index 57ea3f50a51..dc93307bc3f 100644 --- a/Resources/Textures/Tiles/Planet/dirt.rsi/meta.json +++ b/Resources/Textures/Tiles/Planet/dirt.rsi/meta.json @@ -6,6 +6,7 @@ "x": 32, "y": 32 }, + "rsic": false, "states": [ { "name": "dirt" From 312e28055f246579ee17d02421aba867c122e24b Mon Sep 17 00:00:00 2001 From: slarticodefast <161409025+slarticodefast@users.noreply.github.com> Date: Sun, 3 Aug 2025 01:07:32 +0200 Subject: [PATCH 011/340] Predict anomaly synchronizer (#39321) * predict anomaly synchronizer * pvs * lambda * Update Resources/Locale/en-US/anomaly/anomaly.ftl --------- Co-authored-by: Pieter-Jan Briers --- .../Anomaly/AnomalySynchronizerSystem.cs | 140 ++++++++++-------- .../AnomalySynchronizerComponent.cs | 31 ++-- Resources/Locale/en-US/anomaly/anomaly.ftl | 6 +- 3 files changed, 101 insertions(+), 76 deletions(-) rename {Content.Server => Content.Shared}/Anomaly/AnomalySynchronizerSystem.cs (59%) rename {Content.Server => Content.Shared}/Anomaly/Components/AnomalySynchronizerComponent.cs (66%) diff --git a/Content.Server/Anomaly/AnomalySynchronizerSystem.cs b/Content.Shared/Anomaly/AnomalySynchronizerSystem.cs similarity index 59% rename from Content.Server/Anomaly/AnomalySynchronizerSystem.cs rename to Content.Shared/Anomaly/AnomalySynchronizerSystem.cs index 67c0eeb2661..5de209c70ef 100644 --- a/Content.Server/Anomaly/AnomalySynchronizerSystem.cs +++ b/Content.Shared/Anomaly/AnomalySynchronizerSystem.cs @@ -1,33 +1,30 @@ using System.Linq; -using System.Numerics; -using Content.Server.Anomaly.Components; -using Content.Server.DeviceLinking.Systems; -using Content.Server.Power.Components; -using Content.Server.Power.EntitySystems; using Content.Shared.Anomaly.Components; +using Content.Shared.DeviceLinking; using Content.Shared.Examine; using Content.Shared.Interaction; using Content.Shared.Popups; using Content.Shared.Power; -using Robust.Shared.Audio.Systems; +using Content.Shared.Power.EntitySystems; using Content.Shared.Verbs; +using Robust.Shared.Audio.Systems; using Robust.Shared.Timing; -namespace Content.Server.Anomaly; +namespace Content.Shared.Anomaly; /// -/// a device that allows you to translate anomaly activity into multitool signals. +/// A device that allows you to translate anomaly activity into multitool signals. /// public sealed partial class AnomalySynchronizerSystem : EntitySystem { - [Dependency] private readonly AnomalySystem _anomaly = default!; - [Dependency] private readonly SharedAudioSystem _audio = default!; [Dependency] private readonly EntityLookupSystem _entityLookup = default!; - [Dependency] private readonly DeviceLinkSystem _signal = default!; - [Dependency] private readonly SharedTransformSystem _transform = default!; - [Dependency] private readonly SharedPopupSystem _popup = default!; - [Dependency] private readonly PowerReceiverSystem _power = default!; [Dependency] private readonly IGameTiming _timing = default!; + [Dependency] private readonly SharedAnomalySystem _anomaly = default!; + [Dependency] private readonly SharedAudioSystem _audio = default!; + [Dependency] private readonly SharedDeviceLinkSystem _deviceLink = default!; + [Dependency] private readonly SharedPopupSystem _popup = default!; + [Dependency] private readonly SharedPowerReceiverSystem _power = default!; + [Dependency] private readonly SharedTransformSystem _transform = default!; public override void Initialize() { @@ -47,27 +44,41 @@ public sealed partial class AnomalySynchronizerSystem : EntitySystem { base.Update(frameTime); + var curTime = _timing.CurTime; var query = EntityQueryEnumerator(); - while (query.MoveNext(out var uid, out var sync, out var xform)) + while (query.MoveNext(out var uid, out var sync, out var synchronizerTransform)) { - if (sync.ConnectedAnomaly is null) + if (sync.ConnectedAnomaly == null) continue; - if (_timing.CurTime < sync.NextCheckTime) + if (curTime < sync.NextCheckTime) continue; + sync.NextCheckTime += sync.CheckFrequency; + Dirty(uid, sync); - if (Transform(sync.ConnectedAnomaly.Value).MapUid != Transform(uid).MapUid) + if (TerminatingOrDeleted(sync.ConnectedAnomaly)) { - DisconnectFromAnomaly((uid, sync), sync.ConnectedAnomaly.Value); + DisconnectFromAnomaly((uid, sync)); continue; } - if (!xform.Coordinates.TryDistance(EntityManager, Transform(sync.ConnectedAnomaly.Value).Coordinates, out var distance)) + // Use TryComp instead of Transform(uid) to take care of cases where the anomaly is out of + // PVS range on the client, but the synchronizer isn't. + if (!TryComp(sync.ConnectedAnomaly.Value, out TransformComponent? anomalyTransform)) + continue; + + if (anomalyTransform.MapUid != synchronizerTransform.MapUid) + { + DisconnectFromAnomaly((uid, sync)); + continue; + } + + if (!synchronizerTransform.Coordinates.TryDistance(EntityManager, anomalyTransform.Coordinates, out var distance)) continue; if (distance > sync.AttachRange) - DisconnectFromAnomaly((uid, sync), sync.ConnectedAnomaly.Value); + DisconnectFromAnomaly((uid, sync)); } } @@ -76,11 +87,9 @@ public sealed partial class AnomalySynchronizerSystem : EntitySystem /// public bool TryAttachNearbyAnomaly(Entity ent, EntityUid? user = null) { - if (!_power.IsPowered(ent)) + if (!_power.IsPowered(ent.Owner)) { - if (user is not null) - _popup.PopupEntity(Loc.GetString("base-computer-ui-component-not-powered", ("machine", ent)), ent, user.Value); - + _popup.PopupClient(Loc.GetString("base-computer-ui-component-not-powered", ("machine", ent)), ent, user); return false; } @@ -89,13 +98,11 @@ public sealed partial class AnomalySynchronizerSystem : EntitySystem if (anomaly.Owner is { Valid: false }) // no anomaly in range { - if (user is not null) - _popup.PopupEntity(Loc.GetString("anomaly-sync-no-anomaly"), ent, user.Value); - + _popup.PopupClient(Loc.GetString("anomaly-sync-no-anomaly"), ent, user); return false; } - ConnectToAnomaly(ent, anomaly); + ConnectToAnomaly(ent, anomaly, user); return true; } @@ -104,10 +111,10 @@ public sealed partial class AnomalySynchronizerSystem : EntitySystem if (args.Powered) return; - if (ent.Comp.ConnectedAnomaly is null) + if (ent.Comp.ConnectedAnomaly == null) return; - DisconnectFromAnomaly(ent, ent.Comp.ConnectedAnomaly.Value); + DisconnectFromAnomaly(ent); } private void OnExamined(Entity ent, ref ExaminedEvent args) @@ -117,19 +124,29 @@ public sealed partial class AnomalySynchronizerSystem : EntitySystem private void OnGetInteractionVerbs(Entity ent, ref GetVerbsEvent args) { - if (!args.CanAccess || !args.CanInteract || args.Hands is null || ent.Comp.ConnectedAnomaly.HasValue) + if (!args.CanAccess || !args.CanInteract || args.Hands == null) return; var user = args.User; - args.Verbs.Add(new() + + if (ent.Comp.ConnectedAnomaly == null) { - Act = () => + args.Verbs.Add(new() { - TryAttachNearbyAnomaly(ent, user); - }, - Message = Loc.GetString("anomaly-sync-connect-verb-message", ("machine", ent)), - Text = Loc.GetString("anomaly-sync-connect-verb-text"), - }); + Act = () => TryAttachNearbyAnomaly(ent, user), + Message = Loc.GetString("anomaly-sync-connect-verb-message", ("machine", ent)), + Text = Loc.GetString("anomaly-sync-connect-verb-text"), + }); + } + else + { + args.Verbs.Add(new() + { + Act = () => DisconnectFromAnomaly(ent, user), + Message = Loc.GetString("anomaly-sync-disconnect-verb-message", ("machine", ent)), + Text = Loc.GetString("anomaly-sync-disconnect-verb-text"), + }); + } } private void OnInteractHand(Entity ent, ref InteractHandEvent args) @@ -137,12 +154,13 @@ public sealed partial class AnomalySynchronizerSystem : EntitySystem TryAttachNearbyAnomaly(ent, args.User); } - private void ConnectToAnomaly(Entity ent, Entity anomaly) + private void ConnectToAnomaly(Entity ent, Entity anomaly, EntityUid? user = null) { if (ent.Comp.ConnectedAnomaly == anomaly) return; ent.Comp.ConnectedAnomaly = anomaly; + Dirty(ent); //move the anomaly to the center of the synchronizer, for aesthetics. var targetXform = _transform.GetWorldPosition(ent); _transform.SetWorldPosition(anomaly, targetXform); @@ -150,27 +168,27 @@ public sealed partial class AnomalySynchronizerSystem : EntitySystem if (ent.Comp.PulseOnConnect && !anomaly.Comp.CannotRandomPulse) // imp - added cannotrandompulse _anomaly.DoAnomalyPulse(anomaly, anomaly); - _popup.PopupEntity(Loc.GetString("anomaly-sync-connected"), ent, PopupType.Medium); - _audio.PlayPvs(ent.Comp.ConnectedSound, ent); + _popup.PopupPredicted(Loc.GetString("anomaly-sync-connected"), ent, user, PopupType.Medium); + _audio.PlayPredicted(ent.Comp.ConnectedSound, ent, user); } //TODO: disconnection from the anomaly should also be triggered if the anomaly is far away from the synchronizer. //Currently only bluespace anomaly can do this, but for some reason it is the only one that cannot be connected to the synchronizer. - private void DisconnectFromAnomaly(Entity ent, EntityUid other) + private void DisconnectFromAnomaly(Entity ent, EntityUid? user = null) { if (ent.Comp.ConnectedAnomaly == null) return; - if (TryComp(other, out var anomaly)) + if (ent.Comp.PulseOnDisconnect && TryComp(ent.Comp.ConnectedAnomaly, out var anomaly) && !anomaly.CannotRandomPulse) // imp - added cannotrandompulse { - if (ent.Comp.PulseOnDisconnect && !anomaly.CannotRandomPulse) // imp - added cannotrandompulse - _anomaly.DoAnomalyPulse(ent.Comp.ConnectedAnomaly.Value, anomaly); + _anomaly.DoAnomalyPulse(ent.Comp.ConnectedAnomaly.Value, anomaly); } - _popup.PopupEntity(Loc.GetString("anomaly-sync-disconnected"), ent, PopupType.Large); - _audio.PlayPvs(ent.Comp.ConnectedSound, ent); + _popup.PopupPredicted(Loc.GetString("anomaly-sync-disconnected"), ent, user, PopupType.Large); + _audio.PlayPredicted(ent.Comp.DisconnectedSound, ent, user); ent.Comp.ConnectedAnomaly = null; + Dirty(ent); } private void OnAnomalyPulse(ref AnomalyPulseEvent args) @@ -184,19 +202,19 @@ public sealed partial class AnomalySynchronizerSystem : EntitySystem if (!_power.IsPowered(uid)) continue; - _signal.InvokePort(uid, component.PulsePort); + _deviceLink.InvokePort(uid, component.PulsePort); } } private void OnAnomalySeverityChanged(ref AnomalySeverityChangedEvent args) { var query = EntityQueryEnumerator(); - while (query.MoveNext(out var ent, out var component)) + while (query.MoveNext(out var uid, out var component)) { if (args.Anomaly != component.ConnectedAnomaly) continue; - if (!_power.IsPowered(ent)) + if (!_power.IsPowered(uid)) continue; //The superscritical port is invoked not at the AnomalySupercriticalEvent, @@ -204,34 +222,34 @@ public sealed partial class AnomalySynchronizerSystem : EntitySystem //ATTENTION! the console command supercriticalanomaly does not work here, //as it forcefully causes growth to start without increasing severity. if (args.Severity >= 1) - _signal.InvokePort(ent, component.SupercritPort); + _deviceLink.InvokePort(uid, component.SupercritPort); } } private void OnAnomalyStabilityChanged(ref AnomalyStabilityChangedEvent args) { - Entity anomaly = (args.Anomaly, Comp(args.Anomaly)); + var anomaly = Comp(args.Anomaly); var query = EntityQueryEnumerator(); - while (query.MoveNext(out var ent, out var component)) + while (query.MoveNext(out var uid, out var sync)) { - if (component.ConnectedAnomaly != anomaly) + if (sync.ConnectedAnomaly != args.Anomaly) continue; - if (!_power.IsPowered(ent)) + if (!_power.IsPowered(uid)) continue; - if (args.Stability < anomaly.Comp.DecayThreshold) + if (args.Stability < anomaly.DecayThreshold) { - _signal.InvokePort(ent, component.DecayingPort); + _deviceLink.InvokePort(uid, sync.DecayingPort); } - else if (args.Stability > anomaly.Comp.GrowthThreshold) + else if (args.Stability > anomaly.GrowthThreshold) { - _signal.InvokePort(ent, component.GrowingPort); + _deviceLink.InvokePort(uid, sync.GrowingPort); } else { - _signal.InvokePort(ent, component.StabilizePort); + _deviceLink.InvokePort(uid, sync.StabilizePort); } } } diff --git a/Content.Server/Anomaly/Components/AnomalySynchronizerComponent.cs b/Content.Shared/Anomaly/Components/AnomalySynchronizerComponent.cs similarity index 66% rename from Content.Server/Anomaly/Components/AnomalySynchronizerComponent.cs rename to Content.Shared/Anomaly/Components/AnomalySynchronizerComponent.cs index 3127f091e55..7e605ba1505 100644 --- a/Content.Server/Anomaly/Components/AnomalySynchronizerComponent.cs +++ b/Content.Shared/Anomaly/Components/AnomalySynchronizerComponent.cs @@ -1,46 +1,51 @@ using Content.Shared.DeviceLinking; using Robust.Shared.Audio; +using Robust.Shared.GameStates; using Robust.Shared.Prototypes; +using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom; -namespace Content.Server.Anomaly.Components; +namespace Content.Shared.Anomaly.Components; /// -/// a device that allows you to translate anomaly activity into multitool signals. +/// A device that allows you to translate anomaly activity into multitool signals. /// -[RegisterComponent, AutoGenerateComponentPause, Access(typeof(AnomalySynchronizerSystem))] +[RegisterComponent, NetworkedComponent] +[AutoGenerateComponentState, AutoGenerateComponentPause] +[Access(typeof(AnomalySynchronizerSystem))] public sealed partial class AnomalySynchronizerComponent : Component { /// /// The uid of the anomaly to which the synchronizer is connected. /// - [DataField, ViewVariables(VVAccess.ReadWrite)] + [DataField, AutoNetworkedField] public EntityUid? ConnectedAnomaly; /// /// Should the anomaly pulse when connected to the synchronizer? /// - [DataField] + [DataField, AutoNetworkedField] public bool PulseOnConnect = true; /// /// Should the anomaly pulse when disconnected from synchronizer? /// - [DataField] + [DataField, AutoNetworkedField] public bool PulseOnDisconnect = false; /// - /// minimum distance from the synchronizer to the anomaly to be attached + /// Minimum distance from the synchronizer to the anomaly to be attached. /// - [DataField] + [DataField, AutoNetworkedField] public float AttachRange = 0.4f; /// - /// Periodicheski checks to see if the anomaly has moved to disconnect it. + /// Periodically checks to see if the anomaly has moved to disconnect it. /// - [DataField] + [DataField, AutoNetworkedField] public TimeSpan CheckFrequency = TimeSpan.FromSeconds(1f); - [DataField, AutoPausedField] + [DataField(customTypeSerializer: typeof(TimeOffsetSerializer))] + [AutoNetworkedField, AutoPausedField] public TimeSpan NextCheckTime = TimeSpan.Zero; [DataField] @@ -58,9 +63,9 @@ public sealed partial class AnomalySynchronizerComponent : Component [DataField] public ProtoId SupercritPort = "Supercritical"; - [DataField, ViewVariables(VVAccess.ReadWrite)] + [DataField] public SoundSpecifier ConnectedSound = new SoundPathSpecifier("/Audio/Machines/anomaly_sync_connect.ogg"); - [DataField, ViewVariables(VVAccess.ReadWrite)] + [DataField] public SoundSpecifier DisconnectedSound = new SoundPathSpecifier("/Audio/Machines/anomaly_sync_connect.ogg"); } diff --git a/Resources/Locale/en-US/anomaly/anomaly.ftl b/Resources/Locale/en-US/anomaly/anomaly.ftl index c8d099777d4..77608da435a 100644 --- a/Resources/Locale/en-US/anomaly/anomaly.ftl +++ b/Resources/Locale/en-US/anomaly/anomaly.ftl @@ -54,6 +54,8 @@ anomaly-sync-examine-connected = It is [color=darkgreen]attached[/color] to an a anomaly-sync-examine-not-connected = It is [color=darkred]not attached[/color] to an anomaly. anomaly-sync-connect-verb-text = Attach anomaly anomaly-sync-connect-verb-message = Attach a nearby anomaly to {THE($machine)}. +anomaly-sync-disconnect-verb-text = Detach anomaly +anomaly-sync-disconnect-verb-message = Detach the connected anomaly from {THE($machine)}. anomaly-generator-ui-title = Anomaly Generator anomaly-generator-fuel-display = Fuel: @@ -78,7 +80,7 @@ anomaly-generator-flavor-right = v1.1 anomaly-behavior-unknown = [color=red]ERROR. Cannot be read.[/color] anomaly-behavior-title = behavior deviation analysis: -anomaly-behavior-point =[color=gold]Anomaly produces {$mod}% of the points[/color] +anomaly-behavior-point = [color=gold]Anomaly produces {$mod}% of the points[/color] anomaly-behavior-safe = [color=forestgreen]The anomaly is extremely stable. Extremely rare pulsations.[/color] anomaly-behavior-slow = [color=forestgreen]The frequency of pulsations is much less frequent.[/color] @@ -94,4 +96,4 @@ anomaly-behavior-secret = Interference detected. Some data cannot be read anomaly-behavior-inconstancy = [color=crimson]Impermanence has been detected. Particle types can change over time.[/color] anomaly-behavior-fast = [color=crimson]The pulsation frequency is strongly increased.[/color] anomaly-behavior-strenght = [color=crimson]The pulsation power is significantly increased.[/color] -anomaly-behavior-moving = [color=crimson]Coordinate instability was detected.[/color] \ No newline at end of file +anomaly-behavior-moving = [color=crimson]Coordinate instability was detected.[/color] From 95839dd94280f053f697823f0c774de9abac4508 Mon Sep 17 00:00:00 2001 From: Hannah Giovanna Dawson Date: Sat, 2 Aug 2025 18:31:46 +0100 Subject: [PATCH 012/340] Don't purge note buffer when starting/switching MIDI songs (#39335) Stop stuck notes on remote when changing MIDI song --- Content.Client/Instruments/InstrumentSystem.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/Content.Client/Instruments/InstrumentSystem.cs b/Content.Client/Instruments/InstrumentSystem.cs index d861f4163b0..c01845bb133 100644 --- a/Content.Client/Instruments/InstrumentSystem.cs +++ b/Content.Client/Instruments/InstrumentSystem.cs @@ -294,7 +294,6 @@ public sealed partial class InstrumentSystem : SharedInstrumentSystem SetMaster(uid, null); TrySetChannels(uid, data); - instrument.MidiEventBuffer.Clear(); instrument.Renderer.OnMidiEvent += instrument.MidiEventBuffer.Add; return true; } From 8fa3b9af4cc9223d1a58fe3433a7bab7d8a95c93 Mon Sep 17 00:00:00 2001 From: Hannah Giovanna Dawson Date: Sat, 2 Aug 2025 19:35:09 +0100 Subject: [PATCH 013/340] Berry Delight (#38881) * Berry delight * Uncook the YAML * Move stuff in meal_recipes * BERRY DELIGHT IS INEVITABLE --- .../Locale/en-US/flavors/flavor-profiles.ftl | 1 + .../Random/Food_Drinks/food_baked_single.yml | 1 + .../Random/Food_Drinks/food_baked_whole.yml | 1 + .../Objects/Consumable/Food/Baked/cake.yml | 85 ++++++++++++++++++ Resources/Prototypes/Flavors/flavors.yml | 4 + .../Recipes/Cooking/meal_recipes.yml | 12 +++ .../Food/Baked/cake.rsi/berry_delight.png | Bin 0 -> 872 bytes .../Baked/cake.rsi/berry_delight_slice.png | Bin 0 -> 642 bytes .../Consumable/Food/Baked/cake.rsi/meta.json | 8 +- 9 files changed, 111 insertions(+), 1 deletion(-) create mode 100644 Resources/Textures/Objects/Consumable/Food/Baked/cake.rsi/berry_delight.png create mode 100644 Resources/Textures/Objects/Consumable/Food/Baked/cake.rsi/berry_delight_slice.png diff --git a/Resources/Locale/en-US/flavors/flavor-profiles.ftl b/Resources/Locale/en-US/flavors/flavor-profiles.ftl index 3e7a2797ab0..b8db233e358 100644 --- a/Resources/Locale/en-US/flavors/flavor-profiles.ftl +++ b/Resources/Locale/en-US/flavors/flavor-profiles.ftl @@ -54,6 +54,7 @@ flavor-base-terrible = terrible flavor-base-mindful = mindful flavor-base-chewy = chewy flavor-base-trashy = trashy +flavor-base-motivating = motivating # Complex flavors. Put a flavor here when you want something that's more # specific. diff --git a/Resources/Prototypes/Entities/Markers/Spawners/Random/Food_Drinks/food_baked_single.yml b/Resources/Prototypes/Entities/Markers/Spawners/Random/Food_Drinks/food_baked_single.yml index 40e6f83b25b..5b31a640a70 100644 --- a/Resources/Prototypes/Entities/Markers/Spawners/Random/Food_Drinks/food_baked_single.yml +++ b/Resources/Prototypes/Entities/Markers/Spawners/Random/Food_Drinks/food_baked_single.yml @@ -42,6 +42,7 @@ - FoodCakeChristmasSlice - FoodCakeVanillaSlice - FoodCakeBirthdaySlice + - FoodCakeBerryDelightSlice - FoodCakeCottonSlice - FoodBakedMuffin - FoodBakedMuffinBerry diff --git a/Resources/Prototypes/Entities/Markers/Spawners/Random/Food_Drinks/food_baked_whole.yml b/Resources/Prototypes/Entities/Markers/Spawners/Random/Food_Drinks/food_baked_whole.yml index 69d61cbb329..329f1f73ccd 100644 --- a/Resources/Prototypes/Entities/Markers/Spawners/Random/Food_Drinks/food_baked_whole.yml +++ b/Resources/Prototypes/Entities/Markers/Spawners/Random/Food_Drinks/food_baked_whole.yml @@ -37,6 +37,7 @@ - FoodCakeChristmas - FoodCakeBirthday - FoodCakeVanilla + - FoodCakeBerryDelight - FoodCakeCotton - FoodPieApple - FoodPieBaklava diff --git a/Resources/Prototypes/Entities/Objects/Consumable/Food/Baked/cake.yml b/Resources/Prototypes/Entities/Objects/Consumable/Food/Baked/cake.yml index fcd23e1b794..9462404f282 100644 --- a/Resources/Prototypes/Entities/Objects/Consumable/Food/Baked/cake.yml +++ b/Resources/Prototypes/Entities/Objects/Consumable/Food/Baked/cake.yml @@ -1253,3 +1253,88 @@ Quantity: 2 - type: Item heldPrefix: cotton-slice + +# Motivating + +- type: entity + name: berry delight + parent: FoodCakeBase + id: FoodCakeBerryDelight + description: This is a cake that is approaching. + components: + - type: Sprite + state: berry_delight + - type: FlavorProfile + flavors: + - sweet + - berry + - motivating + - type: SolutionContainerManager + solutions: + food: + maxVol: 55 + reagents: + - ReagentId: Nutriment + Quantity: 40 + - ReagentId: Vitamin + Quantity: 10 + - ReagentId: Milk + Quantity: 10 + - type: SliceableFood + slice: FoodCakeBerryDelightSlice + - type: Tag + tags: + - Cake + - Fruit + - type: Item + inhandVisuals: + left: + - state: plain-inhand-left + - state: alpha-filling-inhand-left + color: red + right: + - state: plain-inhand-right + - state: alpha-filling-inhand-right + color: red + +- type: entity + name: berry delight slice + parent: FoodCakeSliceBase + id: FoodCakeBerryDelightSlice + description: Put a fork in, your hunger in isolation. + components: + - type: Sprite + state: berry_delight_slice + - type: FlavorProfile + flavors: + - sweet + - berry + - motivating + - type: SolutionContainerManager + solutions: + food: + maxVol: 12 + reagents: + - ReagentId: Nutriment + Quantity: 8 + - ReagentId: Vitamin + Quantity: 2 + - ReagentId: Milk + Quantity: 2 + - type: Tag + tags: + - Cake + - Fruit + - Slice + - type: Item + inhandVisuals: + left: + - state: alpha-slice-inhand-left + color: white + - state: alpha-slice-filling-inhand-left + color: red + right: + - state: alpha-slice-inhand-right + color: white + - state: alpha-slice-filling-inhand-right + color: red diff --git a/Resources/Prototypes/Flavors/flavors.yml b/Resources/Prototypes/Flavors/flavors.yml index d789ccbdf90..c944096fa8a 100644 --- a/Resources/Prototypes/Flavors/flavors.yml +++ b/Resources/Prototypes/Flavors/flavors.yml @@ -1475,3 +1475,7 @@ flavorType: Base description: flavor-base-trashy +- type: flavor + id: motivating + flavorType: Base + description: flavor-base-motivating diff --git a/Resources/Prototypes/Recipes/Cooking/meal_recipes.yml b/Resources/Prototypes/Recipes/Cooking/meal_recipes.yml index baf3e7011c9..7e3cca3fa4b 100644 --- a/Resources/Prototypes/Recipes/Cooking/meal_recipes.yml +++ b/Resources/Prototypes/Recipes/Cooking/meal_recipes.yml @@ -1700,6 +1700,18 @@ FoodSnackRaisins: 1 OrganAnimalHeart: 1 +- type: microwaveMealRecipe + id: RecipeBerryDelight + name: berry delight recipe + result: FoodCakeBerryDelight + time: 5 + group: Cake + solids: + FoodCakePlain: 1 + FoodBerries: 5 + reagents: + Milk: 10 + - type: microwaveMealRecipe id: RecipeBreadDog name: bread dog recipe diff --git a/Resources/Textures/Objects/Consumable/Food/Baked/cake.rsi/berry_delight.png b/Resources/Textures/Objects/Consumable/Food/Baked/cake.rsi/berry_delight.png new file mode 100644 index 0000000000000000000000000000000000000000..765507a014b75bf99849c259621f2fee87bfb270 GIT binary patch literal 872 zcmV-u1DE`XP)Px&B1uF+R9J=Wl`&`=R~*KF@8sMSS&`FNAP;WZV!Bkx)}&LG8$88=ltPyTXDf7R zA%)Nmt&1U0Xdp`q*_t{-!4QZ=+Qh>(X>2GicnQ{GM4;_pfz=?(obA)S_d1;QtUH|? zhYsza4+Qu0{_p+1_q})TV4#5p`i~`Eruff4YP!3fot(m7tn}2qc533t^B!851Sa7f z`HL0Pepy339sQvB{0IPBTg@2UYu0f`iZL@CWilCrun5C;Uo+N=;Q9PWDt!CuWDlG~ zG60q(ux%ULwo@6#z+rKx!B@VRGw|)Jld%LcnGCjVn*;!~*86P{V+|!iok2o?Wn~D0 zJ(P;-hkpANfD?dwW6{8K`_C)aPjNaipVkVcG+IZ$q08pO@c8EaRpH^{4 z4z?|~x`Ycb6Safgmg&1Y?XsZ`n6Z2L{Wr$-)ENhW4Moh%zflMJ``R8;XB?(0HN)-s z7~P(l&>ITIET}x)<7~-cY=5KPyL~i69pG5kHPC5y!&43PGn1SsX)dYC(`dCD3a;I+ y9sP5BnAY!ou0Q+u2Rhr7RKHaYG|)i*YyAUx^p~N9+-08t0000Px%JV``BR9J=Wl|e{TaU91#K9`OV6}D``$mkH#sXE9uI>dqwAtGcHL>R^noy87L z4`J<)bql-*VaFC8szZn&YvC&I7L~fq)N)VT+_Lwk`~N$b(<0(OGwAR>@Zj-&|KIQX zeZT+j{~lOaSXk@=;d+N$YCIyt^$wXyFUU-KL8|6zyCLqc*}vobzcTQv_~yNw>ixF{ zGU)}mT|C!$`lq;=7s|D4r3lX^r;2;KUA*ef2mr4`2k-$5eBNCHo5I!Ad$$r_J_Df2 zbE^2v=f8*XCdgxZnX&<;m5YmU2~b&4`Nws0^E#rXjkO0u96Rn&s;$%kUC#pGbpAeW z8U?bsRlcqo#8wt*GV>~BL3IdSw}SvAk|`3&6uO=*UI1lU0ev}xJb#haiRX-VUs5)p z)PWC?w-7mtbI=38>V;Qmj~*6HeKSl9a}7H%KmSEpT-iXx+kp9Wf}^oXY6dd^O#4sb z4>x09-#8d^ff%l_VeVgUre`dnJcUYI(9#=10QrI>Cj^m|6m|Am;_c&1#wMBW7{`>7 znRrT7w}?^)X5u>Mq9X_?(AqQ(0#9xRX^c)`b4c8K?#N16MfQP{F=(5E9I5cejez%6SpG%B}H_ zCA~eWA0mJ*pIa^qaQv8>bty^9G8`Jjrt^3YRnWf!13PB0uU(#S)yYn;TXy-}rT5;# c!s377JJ)XLH#R&t@&Et;07*qoM6N<$f)h<7g#Z8m literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Consumable/Food/Baked/cake.rsi/meta.json b/Resources/Textures/Objects/Consumable/Food/Baked/cake.rsi/meta.json index e00bbdeeea1..c8d773339d6 100644 --- a/Resources/Textures/Objects/Consumable/Food/Baked/cake.rsi/meta.json +++ b/Resources/Textures/Objects/Consumable/Food/Baked/cake.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation and modified by Swept at https://github.com/tgstation/tgstation/commit/40d75cc340c63582fb66ce15bf75a36115f6bdaa, inhands by mubururu_ (github), cotton cake sprites by DispenserG0inUp", + "copyright": "Taken from tgstation and modified by Swept at https://github.com/tgstation/tgstation/commit/40d75cc340c63582fb66ce15bf75a36115f6bdaa, inhands by mubururu_ (github), cotton cake sprites by DispenserG0inUp, berry delighht sprites by FairlySadPanda (Github)", "size": { "x": 32, "y": 32 @@ -330,6 +330,12 @@ { "name": "cotton-slice-inhand-right", "directions": 4 + }, + { + "name": "berry_delight" + }, + { + "name": "berry_delight_slice" } ] } From 7642a65ff7f6812f20af26fb4794e5b25f9abcfd Mon Sep 17 00:00:00 2001 From: Token <56667933+TokenStyle@users.noreply.github.com> Date: Sun, 3 Aug 2025 05:27:49 +0500 Subject: [PATCH 014/340] parrotMemory is onGetVerbs now in shared (#39341) * parrotMemory is onGetVerbs now in shared * code review * code review popup on client rename parrotMemoryComponent * code rev create client system * forgot usings * is server now --- .../Animals/Systems/ParrotMemorySystem.cs | 5 ++ .../Animals/Systems/ParrotMemorySystem.cs | 32 ++----------- .../Components/ParrotMemoryComponent.cs | 26 +++++----- .../Systems/SharedParrotMemorySystem.cs | 48 +++++++++++++++++++ 4 files changed, 71 insertions(+), 40 deletions(-) create mode 100644 Content.Client/Animals/Systems/ParrotMemorySystem.cs rename {Content.Server => Content.Shared}/Animals/Components/ParrotMemoryComponent.cs (67%) create mode 100644 Content.Shared/Animals/Systems/SharedParrotMemorySystem.cs diff --git a/Content.Client/Animals/Systems/ParrotMemorySystem.cs b/Content.Client/Animals/Systems/ParrotMemorySystem.cs new file mode 100644 index 00000000000..cdf62a4eae5 --- /dev/null +++ b/Content.Client/Animals/Systems/ParrotMemorySystem.cs @@ -0,0 +1,5 @@ +using Content.Shared.Animals.Systems; + +namespace Content.Client.Animals.Systems; + +public sealed class ParrotMemorySystem : SharedParrotMemorySystem; diff --git a/Content.Server/Animals/Systems/ParrotMemorySystem.cs b/Content.Server/Animals/Systems/ParrotMemorySystem.cs index eb3429821c2..56843094a1a 100644 --- a/Content.Server/Animals/Systems/ParrotMemorySystem.cs +++ b/Content.Server/Animals/Systems/ParrotMemorySystem.cs @@ -8,10 +8,10 @@ using Content.Server.Radio; using Content.Server.Speech; using Content.Server.Speech.Components; using Content.Server.Vocalization.Systems; +using Content.Shared.Animals.Components; +using Content.Shared.Animals.Systems; using Content.Shared.Database; using Content.Shared.Mobs.Systems; -using Content.Shared.Popups; -using Content.Shared.Verbs; using Content.Shared.Whitelist; using Robust.Shared.Network; using Robust.Shared.Random; @@ -25,7 +25,7 @@ namespace Content.Server.Animals.Systems; /// (radiovocalizer) and stores them in a list. When an entity with a VocalizerComponent attempts to vocalize, this will /// try to set the message from memory. /// -public sealed partial class ParrotMemorySystem : EntitySystem +public sealed partial class ParrotMemorySystem : SharedParrotMemorySystem { [Dependency] private readonly EntityWhitelistSystem _whitelist = default!; [Dependency] private readonly IAdminLogManager _adminLogger = default!; @@ -42,8 +42,6 @@ public sealed partial class ParrotMemorySystem : EntitySystem SubscribeLocalEvent(OnErase); - SubscribeLocalEvent>(OnGetVerbs); - SubscribeLocalEvent(ListenerOnMapInit); SubscribeLocalEvent(OnListen); @@ -57,30 +55,6 @@ public sealed partial class ParrotMemorySystem : EntitySystem DeletePlayerMessages(args.PlayerNetUserId); } - private void OnGetVerbs(Entity entity, ref GetVerbsEvent args) - { - var user = args.User; - - // limit this to admins - if (!_admin.IsAdmin(user)) - return; - - // simple verb that just clears the memory list - var clearMemoryVerb = new Verb() - { - Text = Loc.GetString("parrot-verb-clear-memory"), - Category = VerbCategory.Admin, - Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/AdminActions/clear-parrot.png")), - Act = () => - { - entity.Comp.SpeechMemories.Clear(); - _popup.PopupEntity(Loc.GetString("parrot-popup-memory-cleared"), entity, user, PopupType.Medium); - }, - }; - - args.Verbs.Add(clearMemoryVerb); - } - private void ListenerOnMapInit(Entity entity, ref MapInitEvent args) { // If an entity has a ParrotListenerComponent it really ought to have an ActiveListenerComponent diff --git a/Content.Server/Animals/Components/ParrotMemoryComponent.cs b/Content.Shared/Animals/Components/ParrotMemoryComponent.cs similarity index 67% rename from Content.Server/Animals/Components/ParrotMemoryComponent.cs rename to Content.Shared/Animals/Components/ParrotMemoryComponent.cs index 69908a0a9ec..e1c5ba8ed91 100644 --- a/Content.Server/Animals/Components/ParrotMemoryComponent.cs +++ b/Content.Shared/Animals/Components/ParrotMemoryComponent.cs @@ -1,57 +1,61 @@ +using Content.Shared.Animals.Systems; +using Robust.Shared.GameStates; using Robust.Shared.Network; +using Robust.Shared.Serialization; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom; -namespace Content.Server.Animals.Components; +namespace Content.Shared.Animals.Components; /// -/// Makes an entity able to memorize chat/radio messages +/// Makes an entity able to memorize chat/radio messages. /// -[RegisterComponent] +[RegisterComponent, NetworkedComponent] [AutoGenerateComponentPause] public sealed partial class ParrotMemoryComponent : Component { /// - /// List of SpeechMemory records this entity has learned + /// List of SpeechMemory records this entity has learned. /// [DataField] - public List SpeechMemories = []; + public List SpeechMemories = new(); /// - /// The % chance an entity with this component learns a phrase when learning is off cooldown + /// The % chance an entity with this component learns a phrase when learning is off cooldown. /// [DataField] public float LearnChance = 0.6f; /// - /// Time after which another attempt can be made at learning a phrase + /// Time after which another attempt can be made at learning a phrase. /// [DataField] public TimeSpan LearnCooldown = TimeSpan.FromMinutes(1); /// - /// Next time at which the parrot can attempt to learn something + /// Next time at which the parrot can attempt to learn something. /// [DataField(customTypeSerializer: typeof(TimeOffsetSerializer))] [AutoPausedField] public TimeSpan NextLearnInterval = TimeSpan.Zero; /// - /// The number of speech entries that are remembered + /// The number of speech entries that are remembered. /// [DataField] public int MaxSpeechMemory = 50; /// - /// Minimum length of a speech entry + /// Minimum length of a speech entry. /// [DataField] public int MinEntryLength = 4; /// - /// Maximum length of a speech entry + /// Maximum length of a speech entry. /// [DataField] public int MaxEntryLength = 50; } +[Serializable, NetSerializable] public record struct SpeechMemory(NetUserId? NetUserId, string Message); diff --git a/Content.Shared/Animals/Systems/SharedParrotMemorySystem.cs b/Content.Shared/Animals/Systems/SharedParrotMemorySystem.cs new file mode 100644 index 00000000000..fb8e3309ea2 --- /dev/null +++ b/Content.Shared/Animals/Systems/SharedParrotMemorySystem.cs @@ -0,0 +1,48 @@ +using Content.Shared.Administration.Managers; +using Content.Shared.Animals.Components; +using Content.Shared.Popups; +using Content.Shared.Verbs; +using Robust.Shared.Network; +using Robust.Shared.Utility; + +namespace Content.Shared.Animals.Systems; + +public abstract class SharedParrotMemorySystem : EntitySystem +{ + [Dependency] private readonly SharedPopupSystem _popup = default!; + [Dependency] private readonly ISharedAdminManager _admin = default!; + [Dependency] private readonly INetManager _net = default!; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent>(OnGetVerbs); + } + + private void OnGetVerbs(Entity entity, ref GetVerbsEvent args) + { + var user = args.User; + + // limit this to admins + if (!_admin.IsAdmin(user)) + return; + + // simple verb that just clears the memory list + var clearMemoryVerb = new Verb() + { + Text = Loc.GetString("parrot-verb-clear-memory"), + Category = VerbCategory.Admin, + Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/AdminActions/clear-parrot.png")), + Act = () => + { + _popup.PopupClient(Loc.GetString("parrot-popup-memory-cleared"), entity.Owner, user); + + if (_net.IsServer) + entity.Comp.SpeechMemories.Clear(); + }, + }; + + args.Verbs.Add(clearMemoryVerb); + } +} From b878cabc23749dec7fcc73989a3fccb8432409ce Mon Sep 17 00:00:00 2001 From: DrSmugleaf <10968691+DrSmugleaf@users.noreply.github.com> Date: Sat, 2 Aug 2025 17:34:36 -0700 Subject: [PATCH 015/340] Fix rotate verbs not being predicted (#38165) * Fix rotate verbs not being predicted * fixes --------- Co-authored-by: slarticodefast <161409025+slarticodefast@users.noreply.github.com> --- .../Rotatable/FlippableComponent.cs | 15 -- Content.Server/Rotatable/RotatableSystem.cs | 197 ---------------- .../Rotatable/FlippableComponent.cs | 17 ++ .../Rotatable/RotatableComponent.cs | 47 ++-- Content.Shared/Rotatable/RotatableSystem.cs | 213 ++++++++++++++++++ .../components/rotatable-component.ftl | 3 + 6 files changed, 257 insertions(+), 235 deletions(-) delete mode 100644 Content.Server/Rotatable/FlippableComponent.cs delete mode 100644 Content.Server/Rotatable/RotatableSystem.cs create mode 100644 Content.Shared/Rotatable/FlippableComponent.cs create mode 100644 Content.Shared/Rotatable/RotatableSystem.cs diff --git a/Content.Server/Rotatable/FlippableComponent.cs b/Content.Server/Rotatable/FlippableComponent.cs deleted file mode 100644 index 98eb0f6d5c6..00000000000 --- a/Content.Server/Rotatable/FlippableComponent.cs +++ /dev/null @@ -1,15 +0,0 @@ -using Robust.Shared.Prototypes; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; - -namespace Content.Server.Rotatable -{ - [RegisterComponent] - public sealed partial class FlippableComponent : Component - { - /// - /// Entity to replace this entity with when the current one is 'flipped'. - /// - [DataField("mirrorEntity", required: true, customTypeSerializer: typeof(PrototypeIdSerializer))] - public string MirrorEntity = default!; - } -} diff --git a/Content.Server/Rotatable/RotatableSystem.cs b/Content.Server/Rotatable/RotatableSystem.cs deleted file mode 100644 index 5190b0e92e2..00000000000 --- a/Content.Server/Rotatable/RotatableSystem.cs +++ /dev/null @@ -1,197 +0,0 @@ -using Content.Server.Popups; -using Content.Shared.ActionBlocker; -using Content.Shared.Input; -using Content.Shared.Interaction; -using Content.Shared.Rotatable; -using Content.Shared.Verbs; -using Robust.Shared.Input.Binding; -using Robust.Shared.Map; -using Robust.Shared.Player; -using Robust.Shared.Physics; -using Robust.Shared.Physics.Components; -using Robust.Shared.Utility; - -namespace Content.Server.Rotatable -{ - /// - /// Handles verbs for the and components. - /// - public sealed class RotatableSystem : EntitySystem - { - [Dependency] private readonly PopupSystem _popup = default!; - [Dependency] private readonly ActionBlockerSystem _actionBlocker = default!; - [Dependency] private readonly SharedInteractionSystem _interaction = default!; - [Dependency] private readonly SharedTransformSystem _transform = default!; - - public override void Initialize() - { - SubscribeLocalEvent>(AddFlipVerb); - SubscribeLocalEvent>(AddRotateVerbs); - - CommandBinds.Builder - .Bind(ContentKeyFunctions.RotateObjectClockwise, new PointerInputCmdHandler(HandleRotateObjectClockwise)) - .Bind(ContentKeyFunctions.RotateObjectCounterclockwise, new PointerInputCmdHandler(HandleRotateObjectCounterclockwise)) - .Bind(ContentKeyFunctions.FlipObject, new PointerInputCmdHandler(HandleFlipObject)) - .Register(); - } - - private void AddFlipVerb(EntityUid uid, FlippableComponent component, GetVerbsEvent args) - { - if (!args.CanAccess - || !args.CanInteract - || !args.CanComplexInteract) - return; - - // Check if the object is anchored. - if (TryComp(uid, out PhysicsComponent? physics) && physics.BodyType == BodyType.Static) - return; - - Verb verb = new() - { - Act = () => Flip(uid, component), - Text = Loc.GetString("flippable-verb-get-data-text"), - Category = VerbCategory.Rotate, - Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/VerbIcons/flip.svg.192dpi.png")), - Priority = -3, // show flip last - DoContactInteraction = true - }; - args.Verbs.Add(verb); - } - - private void AddRotateVerbs(EntityUid uid, RotatableComponent component, GetVerbsEvent args) - { - if (!args.CanAccess - || !args.CanInteract - || !args.CanComplexInteract - || Transform(uid).NoLocalRotation) // Good ol prototype inheritance, eh? - return; - - // Check if the object is anchored, and whether we are still allowed to rotate it. - if (!component.RotateWhileAnchored && - TryComp(uid, out PhysicsComponent? physics) && - physics.BodyType == BodyType.Static) - return; - - Verb resetRotation = new() - { - DoContactInteraction = true, - Act = () => Comp(uid).LocalRotation = Angle.Zero, - Category = VerbCategory.Rotate, - Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/VerbIcons/refresh.svg.192dpi.png")), - Text = "Reset", - Priority = -2, // show CCW, then CW, then reset - CloseMenu = false, - }; - args.Verbs.Add(resetRotation); - - // rotate clockwise - Verb rotateCW = new() - { - Act = () => Comp(uid).LocalRotation -= component.Increment, - Category = VerbCategory.Rotate, - Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/VerbIcons/rotate_cw.svg.192dpi.png")), - Priority = -1, - CloseMenu = false, // allow for easy double rotations. - }; - args.Verbs.Add(rotateCW); - - // rotate counter-clockwise - Verb rotateCCW = new() - { - Act = () => Comp(uid).LocalRotation += component.Increment, - Category = VerbCategory.Rotate, - Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/VerbIcons/rotate_ccw.svg.192dpi.png")), - Priority = 0, - CloseMenu = false, // allow for easy double rotations. - }; - args.Verbs.Add(rotateCCW); - } - - /// - /// Replace a flippable entity with it's flipped / mirror-symmetric entity. - /// - public void Flip(EntityUid uid, FlippableComponent component) - { - var oldTransform = Comp(uid); - var entity = Spawn(component.MirrorEntity, oldTransform.Coordinates); - var newTransform = Comp(entity); - newTransform.LocalRotation = oldTransform.LocalRotation; - _transform.Unanchor(entity, newTransform); - Del(uid); - } - - public bool HandleRotateObjectClockwise(ICommonSession? playerSession, EntityCoordinates coordinates, EntityUid entity) - { - if (playerSession?.AttachedEntity is not { Valid: true } player || !Exists(player)) - return false; - - if (!TryComp(entity, out var rotatableComp)) - return false; - - if (!_actionBlocker.CanInteract(player, entity) - || !_actionBlocker.CanComplexInteract(player) - || !_interaction.InRangeAndAccessible(player, entity)) - return false; - - // Check if the object is anchored, and whether we are still allowed to rotate it. - if (!rotatableComp.RotateWhileAnchored && TryComp(entity, out PhysicsComponent? physics) && - physics.BodyType == BodyType.Static) - { - _popup.PopupEntity(Loc.GetString("rotatable-component-try-rotate-stuck"), entity, player); - return false; - } - - Transform(entity).LocalRotation -= rotatableComp.Increment; - return true; - } - - public bool HandleRotateObjectCounterclockwise(ICommonSession? playerSession, EntityCoordinates coordinates, EntityUid entity) - { - if (playerSession?.AttachedEntity is not { Valid: true } player || !Exists(player)) - return false; - - if (!TryComp(entity, out var rotatableComp)) - return false; - - if (!_actionBlocker.CanInteract(player, entity) - || !_actionBlocker.CanComplexInteract(player) - || !_interaction.InRangeAndAccessible(player, entity)) - return false; - - // Check if the object is anchored, and whether we are still allowed to rotate it. - if (!rotatableComp.RotateWhileAnchored && TryComp(entity, out PhysicsComponent? physics) && - physics.BodyType == BodyType.Static) - { - _popup.PopupEntity(Loc.GetString("rotatable-component-try-rotate-stuck"), entity, player); - return false; - } - - Transform(entity).LocalRotation += rotatableComp.Increment; - return true; - } - - public bool HandleFlipObject(ICommonSession? playerSession, EntityCoordinates coordinates, EntityUid entity) - { - if (playerSession?.AttachedEntity is not { Valid: true } player || !Exists(player)) - return false; - - if (!TryComp(entity, out var flippableComp)) - return false; - - if (!_actionBlocker.CanInteract(player, entity) - || !_actionBlocker.CanComplexInteract(player) - || !_interaction.InRangeAndAccessible(player, entity)) - return false; - - // Check if the object is anchored. - if (TryComp(entity, out PhysicsComponent? physics) && physics.BodyType == BodyType.Static) - { - _popup.PopupEntity(Loc.GetString("flippable-component-try-flip-is-stuck"), entity, player); - return false; - } - - Flip(entity, flippableComp); - return true; - } - } -} diff --git a/Content.Shared/Rotatable/FlippableComponent.cs b/Content.Shared/Rotatable/FlippableComponent.cs new file mode 100644 index 00000000000..fdc8c15c8a5 --- /dev/null +++ b/Content.Shared/Rotatable/FlippableComponent.cs @@ -0,0 +1,17 @@ +using Robust.Shared.GameStates; +using Robust.Shared.Prototypes; + +namespace Content.Shared.Rotatable; + +/// +/// Allows an entity to be flipped (mirrored) by using a verb. +/// +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +public sealed partial class FlippableComponent : Component +{ + /// + /// Entity to replace this entity with when the current one is 'flipped'. + /// + [DataField(required: true), AutoNetworkedField] + public EntProtoId MirrorEntity = default!; +} diff --git a/Content.Shared/Rotatable/RotatableComponent.cs b/Content.Shared/Rotatable/RotatableComponent.cs index b008c281602..336c484d8c0 100644 --- a/Content.Shared/Rotatable/RotatableComponent.cs +++ b/Content.Shared/Rotatable/RotatableComponent.cs @@ -1,27 +1,28 @@ -namespace Content.Shared.Rotatable +using Robust.Shared.GameStates; + +namespace Content.Shared.Rotatable; + +/// +/// Allows an entity to be rotated by using a verb. +/// +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +public sealed partial class RotatableComponent : Component { - [RegisterComponent] - public sealed partial class RotatableComponent : Component - { - /// - /// If true, this entity can be rotated even while anchored. - /// - [ViewVariables(VVAccess.ReadWrite)] - [DataField("rotateWhileAnchored")] - public bool RotateWhileAnchored { get; private set; } + /// + /// If true, this entity can be rotated even while anchored. + /// + [DataField, AutoNetworkedField] + public bool RotateWhileAnchored; - /// - /// If true, will rotate entity in players direction when pulled - /// - [ViewVariables(VVAccess.ReadWrite)] - [DataField("rotateWhilePulling")] - public bool RotateWhilePulling { get; private set; } = true; + /// + /// If true, will rotate entity in players direction when pulled + /// + [DataField, AutoNetworkedField] + public bool RotateWhilePulling = true; - /// - /// The angular value to change when using the rotate verbs. - /// - [ViewVariables(VVAccess.ReadWrite)] - [DataField("increment")] - public Angle Increment { get; private set; } = Angle.FromDegrees(90); - } + /// + /// The angular value to change when using the rotate verbs. + /// + [DataField, AutoNetworkedField] + public Angle Increment = Angle.FromDegrees(90); } diff --git a/Content.Shared/Rotatable/RotatableSystem.cs b/Content.Shared/Rotatable/RotatableSystem.cs new file mode 100644 index 00000000000..94d9206247a --- /dev/null +++ b/Content.Shared/Rotatable/RotatableSystem.cs @@ -0,0 +1,213 @@ +using Content.Shared.ActionBlocker; +using Content.Shared.Input; +using Content.Shared.Interaction; +using Content.Shared.Popups; +using Content.Shared.Verbs; +using Robust.Shared.Input.Binding; +using Robust.Shared.Map; +using Robust.Shared.Physics; +using Robust.Shared.Physics.Components; +using Robust.Shared.Player; +using Robust.Shared.Utility; + +namespace Content.Shared.Rotatable; + +/// +/// Handles verbs for the and components. +/// +public sealed class RotatableSystem : EntitySystem +{ + [Dependency] private readonly ActionBlockerSystem _actionBlocker = default!; + [Dependency] private readonly SharedInteractionSystem _interaction = default!; + [Dependency] private readonly SharedPopupSystem _popup = default!; + [Dependency] private readonly SharedTransformSystem _transform = default!; + + public override void Initialize() + { + SubscribeLocalEvent>(AddFlipVerb); + SubscribeLocalEvent>(AddRotateVerbs); + + CommandBinds.Builder + .Bind(ContentKeyFunctions.RotateObjectClockwise, new PointerInputCmdHandler(HandleRotateObjectClockwise)) + .Bind(ContentKeyFunctions.RotateObjectCounterclockwise, new PointerInputCmdHandler(HandleRotateObjectCounterclockwise)) + .Bind(ContentKeyFunctions.FlipObject, new PointerInputCmdHandler(HandleFlipObject)) + .Register(); + } + + private void AddFlipVerb(EntityUid uid, FlippableComponent component, GetVerbsEvent args) + { + if (!args.CanAccess + || !args.CanInteract + || !args.CanComplexInteract) + return; + + // Check if the object is anchored. + if (TryComp(uid, out var physics) && physics.BodyType == BodyType.Static) + return; + + Verb verb = new() + { + Act = () => Flip(uid, component), + Text = Loc.GetString("flippable-verb-get-data-text"), + Category = VerbCategory.Rotate, + Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/VerbIcons/flip.svg.192dpi.png")), + Priority = -3, // show flip last + DoContactInteraction = true + }; + args.Verbs.Add(verb); + } + + private void AddRotateVerbs(EntityUid uid, RotatableComponent component, GetVerbsEvent args) + { + if (!args.CanAccess + || !args.CanInteract + || !args.CanComplexInteract + || Transform(uid).NoLocalRotation) // Good ol prototype inheritance, eh? + return; + + // Check if the object is anchored, and whether we are still allowed to rotate it. + if (!component.RotateWhileAnchored && + TryComp(uid, out var physics) && + physics.BodyType == BodyType.Static) + return; + + Verb resetRotation = new() + { + DoContactInteraction = true, + Act = () => ResetRotation(uid), + Category = VerbCategory.Rotate, + Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/VerbIcons/refresh.svg.192dpi.png")), + Text = Loc.GetString("rotate-reset-verb-get-data-text"), + Priority = -2, // show CCW, then CW, then reset + CloseMenu = false, + }; + args.Verbs.Add(resetRotation); + + // rotate clockwise + Verb rotateCW = new() + { + Act = () => Rotate(uid, -component.Increment), + Category = VerbCategory.Rotate, + Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/VerbIcons/rotate_cw.svg.192dpi.png")), + Text = Loc.GetString("rotate-verb-get-data-text"), + Priority = -1, + CloseMenu = false, // allow for easy double rotations. + }; + args.Verbs.Add(rotateCW); + + // rotate counter-clockwise + Verb rotateCCW = new() + { + Act = () => Rotate(uid, component.Increment), + Category = VerbCategory.Rotate, + Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/VerbIcons/rotate_ccw.svg.192dpi.png")), + Text = Loc.GetString("rotate-counter-verb-get-data-text"), + Priority = 0, + CloseMenu = false, // allow for easy double rotations. + }; + args.Verbs.Add(rotateCCW); + } + + /// + /// Replace a flippable entity with it's flipped / mirror-symmetric entity. + /// + public void Flip(EntityUid uid, FlippableComponent component) + { + var oldTransform = Comp(uid); + var entity = PredictedSpawnAtPosition(component.MirrorEntity, oldTransform.Coordinates); + var newTransform = Comp(entity); + _transform.SetLocalRotation(entity, oldTransform.LocalRotation); + _transform.Unanchor(entity, newTransform); + PredictedDel(uid); + } + + private bool HandleRotateObjectClockwise(ICommonSession? playerSession, EntityCoordinates coordinates, EntityUid entity) + { + if (playerSession?.AttachedEntity is not { Valid: true } player || !Exists(player)) + return false; + + if (!TryComp(entity, out var rotatableComp)) + return false; + + if (!_actionBlocker.CanInteract(player, entity) + || !_actionBlocker.CanComplexInteract(player) + || !_interaction.InRangeAndAccessible(player, entity)) + return false; + + // Check if the object is anchored, and whether we are still allowed to rotate it. + if (!rotatableComp.RotateWhileAnchored && TryComp(entity, out var physics) && + physics.BodyType == BodyType.Static) + { + _popup.PopupClient(Loc.GetString("rotatable-component-try-rotate-stuck"), entity, player); + return false; + } + + Rotate(entity, -rotatableComp.Increment); + return false; + } + + private bool HandleRotateObjectCounterclockwise(ICommonSession? playerSession, EntityCoordinates coordinates, EntityUid entity) + { + if (playerSession?.AttachedEntity is not { Valid: true } player || !Exists(player)) + return false; + + if (!TryComp(entity, out var rotatableComp)) + return false; + + if (!_actionBlocker.CanInteract(player, entity) + || !_actionBlocker.CanComplexInteract(player) + || !_interaction.InRangeAndAccessible(player, entity)) + return false; + + // Check if the object is anchored, and whether we are still allowed to rotate it. + if (!rotatableComp.RotateWhileAnchored && TryComp(entity, out var physics) && + physics.BodyType == BodyType.Static) + { + _popup.PopupClient(Loc.GetString("rotatable-component-try-rotate-stuck"), entity, player); + return false; + } + + Rotate(entity, rotatableComp.Increment); + return false; + } + + private bool HandleFlipObject(ICommonSession? playerSession, EntityCoordinates coordinates, EntityUid entity) + { + if (playerSession?.AttachedEntity is not { Valid: true } player || !Exists(player)) + return false; + + if (!TryComp(entity, out var flippableComp)) + return false; + + if (!_actionBlocker.CanInteract(player, entity) + || !_actionBlocker.CanComplexInteract(player) + || !_interaction.InRangeAndAccessible(player, entity)) + return false; + + // Check if the object is anchored. + if (TryComp(entity, out var physics) && physics.BodyType == BodyType.Static) + { + _popup.PopupClient(Loc.GetString("flippable-component-try-flip-is-stuck"), entity, player); + return false; + } + + Flip(entity, flippableComp); + return false; + } + + private void Rotate(Entity ent, Angle angle) + { + if (!Resolve(ent, ref ent.Comp, false)) + return; + + _transform.SetLocalRotation(ent.Owner, ent.Comp.LocalRotation + angle); + } + + private void ResetRotation(Entity ent) + { + if (!Resolve(ent, ref ent.Comp, false)) + return; + + _transform.SetLocalRotation(ent.Owner, Angle.Zero); + } +} diff --git a/Resources/Locale/en-US/rotation/components/rotatable-component.ftl b/Resources/Locale/en-US/rotation/components/rotatable-component.ftl index bc23e488fb7..18d8d55bdd1 100644 --- a/Resources/Locale/en-US/rotation/components/rotatable-component.ftl +++ b/Resources/Locale/en-US/rotation/components/rotatable-component.ftl @@ -6,3 +6,6 @@ rotate-verb-get-data-text = Rotate clockwise # RotateCounterVerb rotate-counter-verb-get-data-text = Rotate counter-clockwise + +# ResetVerb +rotate-reset-verb-get-data-text = Reset From 86459666d849bae3d532871bf5837372eb39a3aa Mon Sep 17 00:00:00 2001 From: Tiniest Shark Date: Sun, 3 Aug 2025 06:58:34 -0400 Subject: [PATCH 016/340] Hardsuit helmet text fix + CBurn Vox Fix (#39345) * text fix and vox helm fix * oop one line --- .../Prototypes/Entities/Clothing/Head/hardsuit-helmets.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Resources/Prototypes/Entities/Clothing/Head/hardsuit-helmets.yml b/Resources/Prototypes/Entities/Clothing/Head/hardsuit-helmets.yml index 1a779979aa8..8384fe8863e 100644 --- a/Resources/Prototypes/Entities/Clothing/Head/hardsuit-helmets.yml +++ b/Resources/Prototypes/Entities/Clothing/Head/hardsuit-helmets.yml @@ -238,6 +238,7 @@ - CorgiWearable - WhitelistChameleon +#Goliath Hardsuit - type: entity parent: [ ClothingHeadHardsuitBase, ClothingHeadSuitWithLightBase ] id: ClothingHeadHelmetHardsuitGoliath @@ -291,6 +292,7 @@ - CorgiWearable - WhitelistChameleon +#Maxim Hardsuit - type: entity parent: ClothingHeadHardsuitBase id: ClothingHeadHelmetHardsuitMaxim @@ -964,6 +966,10 @@ - state: equipped-head - state: equipped-head-unshaded shader: unshaded + head-vox: + - state: equipped-head-vox + - state: equipped-head-unshaded-vox + shader: unshaded - type: PointLight color: orange - type: PressureProtection From 6359249608e31b6d80e2a30eb53a65c4204fcb42 Mon Sep 17 00:00:00 2001 From: Zeneganto Date: Sun, 3 Aug 2025 21:15:25 +1000 Subject: [PATCH 017/340] Localize Refund Button (#39346) * Localize Refund Button * Requested changes --- Content.Client/Store/Ui/StoreMenu.xaml | 2 +- Resources/Locale/en-US/store/store.ftl | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/Content.Client/Store/Ui/StoreMenu.xaml b/Content.Client/Store/Ui/StoreMenu.xaml index 843c9dc0296..1ee86a5a68f 100644 --- a/Content.Client/Store/Ui/StoreMenu.xaml +++ b/Content.Client/Store/Ui/StoreMenu.xaml @@ -21,7 +21,7 @@ Name="RefundButton" MinWidth="64" HorizontalAlignment="Right" - Text="Refund" /> + Text="{Loc 'store-ui-refund-text'}" /> diff --git a/Resources/Locale/en-US/store/store.ftl b/Resources/Locale/en-US/store/store.ftl index a0b349e6a2a..6fce1bcaa09 100644 --- a/Resources/Locale/en-US/store/store.ftl +++ b/Resources/Locale/en-US/store/store.ftl @@ -1,5 +1,6 @@ store-ui-default-title = Store store-ui-default-withdraw-text = Withdraw +store-ui-refund-text = Refund store-ui-balance-display = {$currency}: {$amount} store-ui-price-display = {$amount} {$currency} store-ui-discount-display-with-currency = {$amount} off on {$currency} From c85c0fdca2e430cf5253c299f6c4000bc96a6b79 Mon Sep 17 00:00:00 2001 From: qwerltaz <69696513+qwerltaz@users.noreply.github.com> Date: Sun, 3 Aug 2025 19:12:02 +0200 Subject: [PATCH 018/340] Make wallmount screen, telescreen, and signal timer destructible (#39340) * make wallmount screen destructible * louder * fix indent * fix indent --- .../WallmountMachines/Monitors/telescreens.yml | 11 +++++++++++ .../Wallmounts/WallmountMachines/screen.yml | 11 +++++++++++ .../Structures/Wallmounts/WallmountMachines/timer.yml | 11 +++++++++++ 3 files changed, 33 insertions(+) diff --git a/Resources/Prototypes/Entities/Structures/Wallmounts/WallmountMachines/Monitors/telescreens.yml b/Resources/Prototypes/Entities/Structures/Wallmounts/WallmountMachines/Monitors/telescreens.yml index fd2ba1d072a..ed585aa1851 100644 --- a/Resources/Prototypes/Entities/Structures/Wallmounts/WallmountMachines/Monitors/telescreens.yml +++ b/Resources/Prototypes/Entities/Structures/Wallmounts/WallmountMachines/Monitors/telescreens.yml @@ -12,6 +12,17 @@ state: telescreen_frame - map: ["computerLayerScreen"] state: telescreen + - type: Destructible + thresholds: + - trigger: + !type:DamageTrigger + damage: 200 + behaviors: + - !type:DoActsBehavior + acts: [ "Destruction" ] + - !type:PlaySoundBehavior + sound: + collection: MetalGlassBreak - type: Construction graph: WallmountTelescreen node: Telescreen diff --git a/Resources/Prototypes/Entities/Structures/Wallmounts/WallmountMachines/screen.yml b/Resources/Prototypes/Entities/Structures/Wallmounts/WallmountMachines/screen.yml index bb794e8ac08..94244d3d99a 100644 --- a/Resources/Prototypes/Entities/Structures/Wallmounts/WallmountMachines/screen.yml +++ b/Resources/Prototypes/Entities/Structures/Wallmounts/WallmountMachines/screen.yml @@ -14,6 +14,17 @@ sprite: Structures/Wallmounts/screen.rsi state: screen noRot: true + - type: Destructible + thresholds: + - trigger: + !type:DamageTrigger + damage: 200 + behaviors: + - !type:DoActsBehavior + acts: [ "Destruction" ] + - !type:PlaySoundBehavior + sound: + collection: MetalGlassBreak - type: ApcPowerReceiver powerLoad: 100 - type: ExtensionCableReceiver diff --git a/Resources/Prototypes/Entities/Structures/Wallmounts/WallmountMachines/timer.yml b/Resources/Prototypes/Entities/Structures/Wallmounts/WallmountMachines/timer.yml index 3db7f690afc..7f0b1d6ba1f 100644 --- a/Resources/Prototypes/Entities/Structures/Wallmounts/WallmountMachines/timer.yml +++ b/Resources/Prototypes/Entities/Structures/Wallmounts/WallmountMachines/timer.yml @@ -12,6 +12,17 @@ sprite: Structures/Wallmounts/switch.rsi state: on - type: Appearance + - type: Destructible + thresholds: + - trigger: + !type:DamageTrigger + damage: 200 + behaviors: + - !type:DoActsBehavior + acts: [ "Destruction" ] + - !type:PlaySoundBehavior + sound: + collection: MetalGlassBreak - type: Rotatable - type: SignalTimer canEditLabel: false From 2d14cd4cc085e459c8af4994fd7793db790ba96d Mon Sep 17 00:00:00 2001 From: slarticodefast <161409025+slarticodefast@users.noreply.github.com> Date: Sun, 3 Aug 2025 21:20:37 +0200 Subject: [PATCH 019/340] Trigger Refactor (#39034) --- .../Explosion/SmokeOnTriggerSystem.cs | 7 - .../Explosion/TriggerOnProximityComponent.cs | 7 - Content.Client/Explosion/TriggerSystem.cs | 10 - Content.Client/HotPotato/HotPotatoSystem.cs | 6 +- .../TimerTriggerVisualizerComponent.cs | 12 +- .../ProximityTriggerAnimationSystem.cs} | 13 +- .../Systems/ReleaseGasOnTriggerSystem.cs | 5 + .../TimerTriggerVisualizerSystem.cs | 20 +- .../Tests/Payload/ModularGrenadeTests.cs | 17 +- .../AlertLevelChangeOnTriggerComponent.cs | 33 -- .../Animals/Systems/ParrotMemorySystem.cs | 4 +- .../Chat/SpeakOnTriggerComponent.cs | 17 - Content.Server/Chat/SuicideSystem.cs | 3 + Content.Server/Chat/Systems/ChatSystem.cs | 5 - .../Systems/DamageUserOnTriggerSystem.cs | 51 -- .../Defusable/Systems/DefusableSystem.cs | 35 +- .../Destructible/DestructibleSystem.cs | 7 +- .../Behaviors/TimerStartBehavior.cs | 2 +- .../Thresholds/Behaviors/TriggerBehavior.cs | 12 +- .../DeviceLinking/Systems/DeviceLinkSystem.cs | 2 + .../DeviceLinking/Systems/MemoryCellSystem.cs | 1 - .../DeviceLinking/Systems/SignallerSystem.cs | 15 - .../Electrocution/ElectrocutionSystem.cs | 6 +- Content.Server/Emp/EmpOnTriggerComponent.cs | 36 -- Content.Server/Emp/EmpSystem.cs | 23 +- .../ActiveTriggerOnTimedCollideComponent.cs | 4 - .../Components/AutomatedTimerComponent.cs | 9 - .../OnTrigger/AnchorOnTriggerComponent.cs | 13 - .../OnTrigger/DeleteOnTriggerComponent.cs | 11 - .../OnTrigger/GibOnTriggerComponent.cs | 16 - .../OnTrigger/SoundOnTriggerComponent.cs | 17 - .../OnTrigger/TwoStageTriggerComponent.cs | 34 -- .../Components/ProjectileGrenadeComponent.cs | 6 + .../Components/ShockOnTriggerComponent.cs | 37 -- .../Components/SpawnOnTriggerComponent.cs | 24 - .../Components/TimerStartOnSignalComponent.cs | 15 - .../Components/TriggerOnActivateComponent.cs | 7 - .../Components/TriggerOnCollideComponent.cs | 20 - .../TriggerOnMobstateChangeComponent.cs | 24 - .../Components/TriggerOnProximityComponent.cs | 93 ---- .../Components/TriggerOnSignalComponent.cs | 15 - .../Components/TriggerOnSlipComponent.cs | 6 - .../Components/TriggerOnSpawnComponent.cs | 9 - .../TriggerOnStepTriggerComponent.cs | 10 - .../TriggerOnTimedCollideComponent.cs | 18 - .../Components/TriggerOnUseComponent.cs | 7 - .../Components/TriggerOnVoiceComponent.cs | 28 -- .../Components/TriggerWhenEmptyComponent.cs | 9 - .../Components/TriggerWhitelistComponent.cs | 23 - .../EntitySystems/ProjectileGrenadeSystem.cs | 4 + .../ReleaseGasOnTriggerSystem.cs | 79 ---- .../RepulseAttractOnTriggerSystem.cs | 29 -- .../EntitySystems/ScatteringGrenadeSystem.cs | 16 +- .../EntitySystems/SmokeOnTriggerSystem.cs | 57 --- .../EntitySystems/TriggerSystem.OnUse.cs | 170 ------- .../EntitySystems/TriggerSystem.Proximity.cs | 154 ------ .../EntitySystems/TriggerSystem.Signal.cs | 43 -- .../TriggerSystem.TimedCollide.cs | 59 --- .../EntitySystems/TriggerSystem.Voice.cs | 154 ------ .../Explosion/EntitySystems/TriggerSystem.cs | 447 ------------------ .../EntitySystems/TwoStageTriggerSystem.cs | 64 --- .../GhostKickUserOnTriggerComponent.cs | 7 - .../GhostKick/GhostKickUserOnTriggerSystem.cs | 26 - Content.Server/Holopad/HolopadSystem.cs | 4 +- Content.Server/HotPotato/HotPotatoSystem.cs | 58 +-- .../IgniteOnTriggerComponent.cs | 30 -- Content.Server/LandMines/LandMineSystem.cs | 23 +- Content.Server/Mousetrap/MousetrapSystem.cs | 84 ---- .../Ninja/Systems/SpiderChargeSystem.cs | 5 +- .../Nutrition/EntitySystems/CreamPieSystem.cs | 14 +- .../Payload/EntitySystems/PayloadSystem.cs | 11 +- .../Components/PolymorphOnTriggerComponent.cs | 18 - .../Systems/PolymorphSystem.Trigger.cs | 41 -- .../Polymorph/Systems/PolymorphSystem.cs | 3 - .../Radio/EntitySystems/RadioDeviceSystem.cs | 5 +- .../Silicons/Borgs/BorgSystem.Transponder.cs | 2 +- Content.Server/Silicons/Borgs/BorgSystem.cs | 2 +- .../Components/EmitSoundOnTriggerComponent.cs | 13 - Content.Server/Sound/EmitSoundSystem.cs | 10 - .../Components/ActiveListenerComponent.cs | 13 - .../EntitySystems/BlockListeningSystem.cs | 1 + .../Speech/EntitySystems/ListeningSystem.cs | 3 +- .../SurveillanceCameraMicrophoneSystem.cs | 4 +- Content.Server/Telephone/TelephoneSystem.cs | 3 +- .../AlertLevelChangeOnTriggerSystem.cs | 11 +- .../Systems/GhostKickUserOnTriggerSystem.cs | 38 ++ .../Systems}/IgniteOnTriggerSystem.cs | 25 +- .../Systems/PolymorphOnTriggerSystem.cs | 51 ++ .../Trigger/Systems/RattleOnTriggerSystem.cs | 53 +++ .../Systems/ReleaseGasOnTriggerSystem.cs | 48 ++ .../Trigger/Systems/SmokeOnTriggerSystem.cs | 68 +++ .../Systems/SpeakOnTriggerSystem.cs | 38 +- .../VoiceTrigger/StorageVoiceControlSystem.cs | 1 + .../XAETriggerExplosivesComponent.cs | 4 +- Content.Shared/Chat/SharedChatSystem.cs | 5 + .../DamageUserOnTriggerComponent.cs | 19 - Content.Shared/Emp/SharedEmpSystem.cs | 12 + .../Components/ActiveTimerTriggerComponent.cs | 21 - .../OnTrigger/ExplodeOnTriggerComponent.cs | 11 - .../Components/OnUseTimerTriggerComponent.cs | 66 --- .../Components/ScatteringGrenadeComponent.cs | 6 + .../SharedTriggerOnProximityComponent.cs | 9 - .../SharedReleaseGasOnTriggerSystem.cs | 5 - .../SharedRepulseAttractOnTriggerSystem.cs | 3 - .../SharedSmokeOnTriggerSystem.cs | 5 - .../EntitySystems/SharedTriggerSystem.cs | 6 - .../Components/FlashOnTriggerComponent.cs | 18 - .../HotPotato/ActiveHotPotatoComponent.cs | 2 +- .../HotPotato/HotPotatoComponent.cs | 3 +- .../HotPotato/SharedHotPotatoSystem.cs | 65 ++- .../Implants/Components/RattleComponent.cs | 21 - .../TriggerImplantActionComponent.cs | 12 - .../Implants/SharedSubdermalImplantSystem.cs | 7 +- .../Components/ItemToggleComponent.cs | 20 +- .../Item/ItemToggle/ItemToggleSystem.cs | 42 +- .../Mousetrap/MousetrapComponent.cs | 22 +- Content.Shared/Mousetrap/MousetrapSystem.cs | 47 ++ Content.Shared/Mousetrap/MousetrapVisuals.cs | 11 - .../Ninja/Components/SpiderChargeComponent.cs | 14 +- .../Components/PayloadTriggerComponent.cs | 9 +- .../Rootable/SharedRootableSystem.cs | 7 +- .../Components/ActiveListenerComponent.cs | 17 + .../Speech/ListenEvent.cs | 2 +- .../Sticky/Components/StickyComponent.cs | 2 +- Content.Shared/Timing/UseDelaySystem.cs | 2 +- .../Components/ActiveTimerTriggerComponent.cs | 10 + .../ActiveTwoStageTriggerComponent.cs | 10 + .../BaseTriggerConditionComponent.cs | 15 + .../ToggleTriggerConditionComponent.cs | 34 ++ .../UseDelayTriggerConditionComponent.cs | 20 + .../WhitelistTriggerConditionComponent.cs | 24 + .../AddComponentsOnTriggerComponent.cs | 37 ++ .../AlertLevelChangeOnTriggerComponent.cs | 34 ++ .../Effects/AnchorOnTriggerComponent.cs | 34 ++ .../Effects/BaseXOnTriggerComponent.cs | 22 + .../Effects/DamageOnTriggerComponent.cs | 32 ++ .../Effects/DeleteOnTriggerComponent.cs | 10 + .../Effects/EmitSoundOnTriggerComponent.cs | 31 ++ .../Effects/EmpOnTriggerComponent.cs | 41 ++ .../Effects/ExplodeOnTriggerComponent.cs | 14 + .../Effects/FlashOnTriggerComponent.cs | 29 ++ .../Effects/GhostKickOnTriggerComponent.cs | 19 + .../Effects/GibOnTriggerComponent.cs | 17 + .../Effects/IgniteOnTriggerComponent.cs | 27 ++ .../Effects/ItemToggleOnTriggerComponent.cs | 37 ++ .../Effects/PolymorphOnTriggerComponent.cs | 19 + .../Effects/RattleOnTriggerComponent.cs | 30 ++ .../Effects}/ReleaseGasOnTriggerComponent.cs | 8 +- .../RepulseAttractOnTriggerComponent.cs} | 24 +- .../Effects/ShockOnTriggerComponent.cs | 34 ++ .../Effects/SignalOnTriggerComponent.cs | 18 + .../Effects}/SmokeOnTriggerComponent.cs | 22 +- .../Effects/SpawnOnTriggerComponent.cs | 31 ++ .../Effects/SpeakOnTriggerComponent.cs | 26 + .../Effects/UseDelayOnTriggerComponent.cs | 26 + .../Components/RandomTimerTriggerComponent.cs | 12 +- .../Components/TimerTriggerComponent.cs | 109 +++++ .../ActiveTriggerOnTimedCollideComponent.cs | 6 + .../Triggers/BaseTriggerOnXComponent.cs | 16 + .../Triggers}/RepeatingTriggerComponent.cs | 17 +- .../Triggers/TriggerOnActivateComponent.cs | 17 + .../TriggerOnActivateImplantComponent.cs | 10 + .../Triggers/TriggerOnCollideComponent.cs | 23 + .../TriggerOnEmptyGunshotComponent.cs | 10 + .../TriggerOnMobstateChangeComponent.cs | 35 ++ .../Triggers/TriggerOnProximityComponent.cs | 91 ++++ .../Triggers/TriggerOnSignalComponent.cs | 19 + .../Triggers/TriggerOnSlipComponent.cs | 10 + .../Triggers/TriggerOnSpawnComponent.cs | 10 + .../Triggers/TriggerOnStepTriggerComponent.cs | 14 + .../Triggers/TriggerOnStuckComponent.cs | 11 + .../TriggerOnTimedCollideComponent.cs | 26 + .../Triggers/TriggerOnUseComponent.cs | 10 + .../Components/Triggers/TriggerOnVerb.cs | 20 + .../Triggers/TriggerOnVoiceComponent.cs | 47 ++ .../Components/TwoStageTriggerComponent.cs | 58 +++ .../Systems/AddComponentsOnTriggerSystem.cs | 33 ++ .../Trigger/Systems/DamageOnTriggerSystem.cs | 40 ++ .../Systems/EmitSoundOnTriggerSystem.cs | 55 +++ .../Trigger/Systems/EmpOnTriggerSystem.cs | 31 ++ .../Trigger/Systems/ExplodeOnTriggerSystem.cs | 30 ++ .../Trigger/Systems/FlashOnTriggerSystem.cs | 30 ++ .../Trigger/Systems/GibOnTriggerSystem.cs | 40 ++ .../Systems/RepulseAttractOnTriggerSystem.cs | 34 ++ .../SharedReleaseGasOnTriggerSystem.cs | 36 ++ .../Trigger/Systems/ShockOnTriggerSystem.cs | 44 ++ .../Systems/TriggerOnActivateImplantSystem.cs | 22 + .../Systems/TriggerOnEmptyGunshotSystem.cs | 20 + .../Systems/TriggerOnMobstateChangeSystem.cs | 57 +-- .../Trigger/Systems/TriggerOnSlipSystem.cs | 21 + .../Trigger/Systems/TriggerOnStuckSystem.cs | 21 + .../Trigger/Systems/TriggerOnVerbSystem.cs | 31 ++ .../Trigger/Systems/TriggerSystem.Collide.cs | 73 +++ .../Systems/TriggerSystem.Condition.cs | 57 +++ .../Systems/TriggerSystem.Interaction.cs | 96 ++++ .../Systems/TriggerSystem.Proximity.cs | 138 ++++++ .../Trigger/Systems/TriggerSystem.Signal.cs | 44 ++ .../Trigger/Systems/TriggerSystem.Spawn.cs | 70 +++ .../Trigger/Systems/TriggerSystem.Timer.cs | 179 +++++++ .../Trigger/Systems/TriggerSystem.Voice.cs | 160 +++++++ .../Trigger/Systems/TriggerSystem.cs | 186 ++++++++ .../Trigger/Systems/TwoStageTriggerSystem.cs | 51 ++ Content.Shared/Trigger/TriggerEvent.cs | 33 ++ Content.Shared/Trigger/TriggerVisuals.cs | 47 +- Content.Shared/Trigger/VoiceTriggeredEvent.cs | 10 + .../Ranged/Events/OnEmptyGunShotEvent.cs | 2 +- .../Weapons/Ranged/Systems/SharedGunSystem.cs | 2 +- .../en-US/machine-linking/receiver_ports.ftl | 7 +- .../machine-linking/transmitter_ports.ftl | 7 +- .../en-US/triggers/ghost-kick-on-trigger.ftl | 1 + .../Locale/en-US/triggers/timer-trigger.ftl | 10 + .../triggers/toggle-trigger-condition.ftl | 7 + .../Locale/en-US/triggers/trigger-on-verb.ftl | 2 + .../en-US/triggers/trigger-on-voice.ftl | 12 + .../en-US/weapons/grenades/timer-trigger.ftl | 16 - .../en-US/weapons/grenades/voice-trigger.ftl | 12 - .../Maps/Shuttles/ShuttleEvent/quark.yml | 6 +- .../Prototypes/DeviceLinking/sink_ports.yml | 4 +- .../Prototypes/DeviceLinking/source_ports.yml | 6 + .../Entities/Clothing/Back/backpacks.yml | 2 +- .../Entities/Effects/admin_triggers.yml | 28 +- .../Mobs/Cyborgs/base_borg_chassis.yml | 5 +- .../Prototypes/Entities/Mobs/NPCs/animals.yml | 5 +- .../Entities/Mobs/NPCs/elemental.yml | 5 - .../Objects/Consumable/Food/Baked/pie.yml | 2 +- .../Objects/Devices/Electronics/igniter.yml | 5 + .../Objects/Devices/Electronics/signaller.yml | 6 +- .../Objects/Devices/Electronics/triggers.yml | 22 +- .../Objects/Devices/desynchronizer.yml | 1 + .../Entities/Objects/Devices/mousetrap.yml | 35 +- .../Entities/Objects/Devices/payload.yml | 1 + .../Entities/Objects/Fun/bike_horn.yml | 1 + .../Prototypes/Entities/Objects/Fun/dice.yml | 3 +- .../Entities/Objects/Fun/figurines.yml | 2 + .../Prototypes/Entities/Objects/Fun/toys.yml | 2 +- .../Entities/Objects/Materials/shards.yml | 13 +- .../Entities/Objects/Misc/land_mine.yml | 3 +- .../Objects/Misc/subdermal_implants.yml | 113 +++-- .../Objects/Specific/Janitorial/janitor.yml | 15 +- .../Objects/Specific/Janitorial/soap.yml | 5 +- .../Objects/Weapons/Bombs/firebomb.yml | 5 +- .../Entities/Objects/Weapons/Bombs/funny.yml | 9 +- .../Entities/Objects/Weapons/Bombs/pen.yml | 7 +- .../Objects/Weapons/Bombs/pipebomb.yml | 5 +- .../Objects/Weapons/Bombs/plastic.yml | 48 +- .../Entities/Objects/Weapons/Bombs/spider.yml | 9 +- .../Weapons/Guns/Projectiles/magic.yml | 23 +- .../Weapons/Guns/Projectiles/projectiles.yml | 6 +- .../Guns/Turrets/turrets_ballistic.yml | 4 +- .../Objects/Weapons/Throwable/grenades.yml | 123 ++++- .../Weapons/Throwable/projectile_grenades.yml | 21 +- .../Weapons/Throwable/scattering_grenades.yml | 18 +- .../Entities/Objects/Weapons/security.yml | 1 + .../Entities/Structures/Machines/bombs.yml | 6 +- .../Entities/Structures/Walls/asteroid.yml | 5 +- .../ServerInfo/Guidebook/Security/Defusal.xml | 2 +- 256 files changed, 4044 insertions(+), 2899 deletions(-) delete mode 100644 Content.Client/Explosion/SmokeOnTriggerSystem.cs delete mode 100644 Content.Client/Explosion/TriggerOnProximityComponent.cs delete mode 100644 Content.Client/Explosion/TriggerSystem.cs rename Content.Client/Trigger/{ => Components}/TimerTriggerVisualizerComponent.cs (84%) rename Content.Client/{Explosion/TriggerSystem.Proximity.cs => Trigger/Systems/ProximityTriggerAnimationSystem.cs} (91%) create mode 100644 Content.Client/Trigger/Systems/ReleaseGasOnTriggerSystem.cs rename Content.Client/Trigger/{ => Systems}/TimerTriggerVisualizerSystem.cs (80%) delete mode 100644 Content.Server/AlertLevel/AlertLevelChangeOnTriggerComponent.cs delete mode 100644 Content.Server/Chat/SpeakOnTriggerComponent.cs delete mode 100644 Content.Server/Damage/Systems/DamageUserOnTriggerSystem.cs delete mode 100644 Content.Server/Emp/EmpOnTriggerComponent.cs delete mode 100644 Content.Server/Explosion/Components/ActiveTriggerOnTimedCollideComponent.cs delete mode 100644 Content.Server/Explosion/Components/AutomatedTimerComponent.cs delete mode 100644 Content.Server/Explosion/Components/OnTrigger/AnchorOnTriggerComponent.cs delete mode 100644 Content.Server/Explosion/Components/OnTrigger/DeleteOnTriggerComponent.cs delete mode 100644 Content.Server/Explosion/Components/OnTrigger/GibOnTriggerComponent.cs delete mode 100644 Content.Server/Explosion/Components/OnTrigger/SoundOnTriggerComponent.cs delete mode 100644 Content.Server/Explosion/Components/OnTrigger/TwoStageTriggerComponent.cs delete mode 100644 Content.Server/Explosion/Components/ShockOnTriggerComponent.cs delete mode 100644 Content.Server/Explosion/Components/SpawnOnTriggerComponent.cs delete mode 100644 Content.Server/Explosion/Components/TimerStartOnSignalComponent.cs delete mode 100644 Content.Server/Explosion/Components/TriggerOnActivateComponent.cs delete mode 100644 Content.Server/Explosion/Components/TriggerOnCollideComponent.cs delete mode 100644 Content.Server/Explosion/Components/TriggerOnMobstateChangeComponent.cs delete mode 100644 Content.Server/Explosion/Components/TriggerOnProximityComponent.cs delete mode 100644 Content.Server/Explosion/Components/TriggerOnSignalComponent.cs delete mode 100644 Content.Server/Explosion/Components/TriggerOnSlipComponent.cs delete mode 100644 Content.Server/Explosion/Components/TriggerOnSpawnComponent.cs delete mode 100644 Content.Server/Explosion/Components/TriggerOnStepTriggerComponent.cs delete mode 100644 Content.Server/Explosion/Components/TriggerOnTimedCollideComponent.cs delete mode 100644 Content.Server/Explosion/Components/TriggerOnUseComponent.cs delete mode 100644 Content.Server/Explosion/Components/TriggerOnVoiceComponent.cs delete mode 100644 Content.Server/Explosion/Components/TriggerWhenEmptyComponent.cs delete mode 100644 Content.Server/Explosion/Components/TriggerWhitelistComponent.cs delete mode 100644 Content.Server/Explosion/EntitySystems/ReleaseGasOnTriggerSystem.cs delete mode 100644 Content.Server/Explosion/EntitySystems/RepulseAttractOnTriggerSystem.cs delete mode 100644 Content.Server/Explosion/EntitySystems/SmokeOnTriggerSystem.cs delete mode 100644 Content.Server/Explosion/EntitySystems/TriggerSystem.OnUse.cs delete mode 100644 Content.Server/Explosion/EntitySystems/TriggerSystem.Proximity.cs delete mode 100644 Content.Server/Explosion/EntitySystems/TriggerSystem.Signal.cs delete mode 100644 Content.Server/Explosion/EntitySystems/TriggerSystem.TimedCollide.cs delete mode 100644 Content.Server/Explosion/EntitySystems/TriggerSystem.Voice.cs delete mode 100644 Content.Server/Explosion/EntitySystems/TriggerSystem.cs delete mode 100644 Content.Server/Explosion/EntitySystems/TwoStageTriggerSystem.cs delete mode 100644 Content.Server/GhostKick/GhostKickUserOnTriggerComponent.cs delete mode 100644 Content.Server/GhostKick/GhostKickUserOnTriggerSystem.cs delete mode 100644 Content.Server/IgnitionSource/IgniteOnTriggerComponent.cs delete mode 100644 Content.Server/Mousetrap/MousetrapSystem.cs delete mode 100644 Content.Server/Polymorph/Components/PolymorphOnTriggerComponent.cs delete mode 100644 Content.Server/Polymorph/Systems/PolymorphSystem.Trigger.cs delete mode 100644 Content.Server/Sound/Components/EmitSoundOnTriggerComponent.cs delete mode 100644 Content.Server/Speech/Components/ActiveListenerComponent.cs rename Content.Server/{AlertLevel => Trigger}/Systems/AlertLevelChangeOnTriggerSystem.cs (74%) create mode 100644 Content.Server/Trigger/Systems/GhostKickUserOnTriggerSystem.cs rename Content.Server/{IgnitionSource => Trigger/Systems}/IgniteOnTriggerSystem.cs (66%) create mode 100644 Content.Server/Trigger/Systems/PolymorphOnTriggerSystem.cs create mode 100644 Content.Server/Trigger/Systems/RattleOnTriggerSystem.cs create mode 100644 Content.Server/Trigger/Systems/ReleaseGasOnTriggerSystem.cs create mode 100644 Content.Server/Trigger/Systems/SmokeOnTriggerSystem.cs rename Content.Server/{Chat => Trigger}/Systems/SpeakOnTriggerSystem.cs (53%) delete mode 100644 Content.Shared/Damage/Components/DamageUserOnTriggerComponent.cs delete mode 100644 Content.Shared/Explosion/Components/ActiveTimerTriggerComponent.cs delete mode 100644 Content.Shared/Explosion/Components/OnTrigger/ExplodeOnTriggerComponent.cs delete mode 100644 Content.Shared/Explosion/Components/OnUseTimerTriggerComponent.cs delete mode 100644 Content.Shared/Explosion/Components/SharedTriggerOnProximityComponent.cs delete mode 100644 Content.Shared/Explosion/EntitySystems/SharedReleaseGasOnTriggerSystem.cs delete mode 100644 Content.Shared/Explosion/EntitySystems/SharedRepulseAttractOnTriggerSystem.cs delete mode 100644 Content.Shared/Explosion/EntitySystems/SharedSmokeOnTriggerSystem.cs delete mode 100644 Content.Shared/Explosion/EntitySystems/SharedTriggerSystem.cs delete mode 100644 Content.Shared/Flash/Components/FlashOnTriggerComponent.cs delete mode 100644 Content.Shared/Implants/Components/RattleComponent.cs delete mode 100644 Content.Shared/Implants/Components/TriggerImplantActionComponent.cs create mode 100644 Content.Shared/Mousetrap/MousetrapSystem.cs delete mode 100644 Content.Shared/Mousetrap/MousetrapVisuals.cs create mode 100644 Content.Shared/Speech/Components/ActiveListenerComponent.cs rename {Content.Server => Content.Shared}/Speech/ListenEvent.cs (93%) create mode 100644 Content.Shared/Trigger/Components/ActiveTimerTriggerComponent.cs create mode 100644 Content.Shared/Trigger/Components/ActiveTwoStageTriggerComponent.cs create mode 100644 Content.Shared/Trigger/Components/Conditions/BaseTriggerConditionComponent.cs create mode 100644 Content.Shared/Trigger/Components/Conditions/ToggleTriggerConditionComponent.cs create mode 100644 Content.Shared/Trigger/Components/Conditions/UseDelayTriggerConditionComponent.cs create mode 100644 Content.Shared/Trigger/Components/Conditions/WhitelistTriggerConditionComponent.cs create mode 100644 Content.Shared/Trigger/Components/Effects/AddComponentsOnTriggerComponent.cs create mode 100644 Content.Shared/Trigger/Components/Effects/AlertLevelChangeOnTriggerComponent.cs create mode 100644 Content.Shared/Trigger/Components/Effects/AnchorOnTriggerComponent.cs create mode 100644 Content.Shared/Trigger/Components/Effects/BaseXOnTriggerComponent.cs create mode 100644 Content.Shared/Trigger/Components/Effects/DamageOnTriggerComponent.cs create mode 100644 Content.Shared/Trigger/Components/Effects/DeleteOnTriggerComponent.cs create mode 100644 Content.Shared/Trigger/Components/Effects/EmitSoundOnTriggerComponent.cs create mode 100644 Content.Shared/Trigger/Components/Effects/EmpOnTriggerComponent.cs create mode 100644 Content.Shared/Trigger/Components/Effects/ExplodeOnTriggerComponent.cs create mode 100644 Content.Shared/Trigger/Components/Effects/FlashOnTriggerComponent.cs create mode 100644 Content.Shared/Trigger/Components/Effects/GhostKickOnTriggerComponent.cs create mode 100644 Content.Shared/Trigger/Components/Effects/GibOnTriggerComponent.cs create mode 100644 Content.Shared/Trigger/Components/Effects/IgniteOnTriggerComponent.cs create mode 100644 Content.Shared/Trigger/Components/Effects/ItemToggleOnTriggerComponent.cs create mode 100644 Content.Shared/Trigger/Components/Effects/PolymorphOnTriggerComponent.cs create mode 100644 Content.Shared/Trigger/Components/Effects/RattleOnTriggerComponent.cs rename Content.Shared/{Explosion/Components/OnTrigger => Trigger/Components/Effects}/ReleaseGasOnTriggerComponent.cs (90%) rename Content.Shared/{Explosion/Components/OnTrigger/SharedRepulseAttractOnTriggerComponent.cs => Trigger/Components/Effects/RepulseAttractOnTriggerComponent.cs} (57%) create mode 100644 Content.Shared/Trigger/Components/Effects/ShockOnTriggerComponent.cs create mode 100644 Content.Shared/Trigger/Components/Effects/SignalOnTriggerComponent.cs rename Content.Shared/{Explosion/Components/OnTrigger => Trigger/Components/Effects}/SmokeOnTriggerComponent.cs (59%) create mode 100644 Content.Shared/Trigger/Components/Effects/SpawnOnTriggerComponent.cs create mode 100644 Content.Shared/Trigger/Components/Effects/SpeakOnTriggerComponent.cs create mode 100644 Content.Shared/Trigger/Components/Effects/UseDelayOnTriggerComponent.cs rename {Content.Server/Explosion => Content.Shared/Trigger}/Components/RandomTimerTriggerComponent.cs (50%) create mode 100644 Content.Shared/Trigger/Components/TimerTriggerComponent.cs create mode 100644 Content.Shared/Trigger/Components/Triggers/ActiveTriggerOnTimedCollideComponent.cs create mode 100644 Content.Shared/Trigger/Components/Triggers/BaseTriggerOnXComponent.cs rename {Content.Server/Explosion/Components => Content.Shared/Trigger/Components/Triggers}/RepeatingTriggerComponent.cs (56%) create mode 100644 Content.Shared/Trigger/Components/Triggers/TriggerOnActivateComponent.cs create mode 100644 Content.Shared/Trigger/Components/Triggers/TriggerOnActivateImplantComponent.cs create mode 100644 Content.Shared/Trigger/Components/Triggers/TriggerOnCollideComponent.cs create mode 100644 Content.Shared/Trigger/Components/Triggers/TriggerOnEmptyGunshotComponent.cs create mode 100644 Content.Shared/Trigger/Components/Triggers/TriggerOnMobstateChangeComponent.cs create mode 100644 Content.Shared/Trigger/Components/Triggers/TriggerOnProximityComponent.cs create mode 100644 Content.Shared/Trigger/Components/Triggers/TriggerOnSignalComponent.cs create mode 100644 Content.Shared/Trigger/Components/Triggers/TriggerOnSlipComponent.cs create mode 100644 Content.Shared/Trigger/Components/Triggers/TriggerOnSpawnComponent.cs create mode 100644 Content.Shared/Trigger/Components/Triggers/TriggerOnStepTriggerComponent.cs create mode 100644 Content.Shared/Trigger/Components/Triggers/TriggerOnStuckComponent.cs create mode 100644 Content.Shared/Trigger/Components/Triggers/TriggerOnTimedCollideComponent.cs create mode 100644 Content.Shared/Trigger/Components/Triggers/TriggerOnUseComponent.cs create mode 100644 Content.Shared/Trigger/Components/Triggers/TriggerOnVerb.cs create mode 100644 Content.Shared/Trigger/Components/Triggers/TriggerOnVoiceComponent.cs create mode 100644 Content.Shared/Trigger/Components/TwoStageTriggerComponent.cs create mode 100644 Content.Shared/Trigger/Systems/AddComponentsOnTriggerSystem.cs create mode 100644 Content.Shared/Trigger/Systems/DamageOnTriggerSystem.cs create mode 100644 Content.Shared/Trigger/Systems/EmitSoundOnTriggerSystem.cs create mode 100644 Content.Shared/Trigger/Systems/EmpOnTriggerSystem.cs create mode 100644 Content.Shared/Trigger/Systems/ExplodeOnTriggerSystem.cs create mode 100644 Content.Shared/Trigger/Systems/FlashOnTriggerSystem.cs create mode 100644 Content.Shared/Trigger/Systems/GibOnTriggerSystem.cs create mode 100644 Content.Shared/Trigger/Systems/RepulseAttractOnTriggerSystem.cs create mode 100644 Content.Shared/Trigger/Systems/SharedReleaseGasOnTriggerSystem.cs create mode 100644 Content.Shared/Trigger/Systems/ShockOnTriggerSystem.cs create mode 100644 Content.Shared/Trigger/Systems/TriggerOnActivateImplantSystem.cs create mode 100644 Content.Shared/Trigger/Systems/TriggerOnEmptyGunshotSystem.cs rename Content.Server/Explosion/EntitySystems/TriggerSystem.Mobstate.cs => Content.Shared/Trigger/Systems/TriggerOnMobstateChangeSystem.cs (56%) create mode 100644 Content.Shared/Trigger/Systems/TriggerOnSlipSystem.cs create mode 100644 Content.Shared/Trigger/Systems/TriggerOnStuckSystem.cs create mode 100644 Content.Shared/Trigger/Systems/TriggerOnVerbSystem.cs create mode 100644 Content.Shared/Trigger/Systems/TriggerSystem.Collide.cs create mode 100644 Content.Shared/Trigger/Systems/TriggerSystem.Condition.cs create mode 100644 Content.Shared/Trigger/Systems/TriggerSystem.Interaction.cs create mode 100644 Content.Shared/Trigger/Systems/TriggerSystem.Proximity.cs create mode 100644 Content.Shared/Trigger/Systems/TriggerSystem.Signal.cs create mode 100644 Content.Shared/Trigger/Systems/TriggerSystem.Spawn.cs create mode 100644 Content.Shared/Trigger/Systems/TriggerSystem.Timer.cs create mode 100644 Content.Shared/Trigger/Systems/TriggerSystem.Voice.cs create mode 100644 Content.Shared/Trigger/Systems/TriggerSystem.cs create mode 100644 Content.Shared/Trigger/Systems/TwoStageTriggerSystem.cs create mode 100644 Content.Shared/Trigger/TriggerEvent.cs create mode 100644 Content.Shared/Trigger/VoiceTriggeredEvent.cs create mode 100644 Resources/Locale/en-US/triggers/ghost-kick-on-trigger.ftl create mode 100644 Resources/Locale/en-US/triggers/timer-trigger.ftl create mode 100644 Resources/Locale/en-US/triggers/toggle-trigger-condition.ftl create mode 100644 Resources/Locale/en-US/triggers/trigger-on-verb.ftl create mode 100644 Resources/Locale/en-US/triggers/trigger-on-voice.ftl delete mode 100644 Resources/Locale/en-US/weapons/grenades/timer-trigger.ftl delete mode 100644 Resources/Locale/en-US/weapons/grenades/voice-trigger.ftl diff --git a/Content.Client/Explosion/SmokeOnTriggerSystem.cs b/Content.Client/Explosion/SmokeOnTriggerSystem.cs deleted file mode 100644 index cac255e1ba9..00000000000 --- a/Content.Client/Explosion/SmokeOnTriggerSystem.cs +++ /dev/null @@ -1,7 +0,0 @@ -using Content.Shared.Explosion.EntitySystems; - -namespace Content.Client.Explosion; - -public sealed class SmokeOnTriggerSystem : SharedSmokeOnTriggerSystem -{ -} \ No newline at end of file diff --git a/Content.Client/Explosion/TriggerOnProximityComponent.cs b/Content.Client/Explosion/TriggerOnProximityComponent.cs deleted file mode 100644 index 5fa9bbfd237..00000000000 --- a/Content.Client/Explosion/TriggerOnProximityComponent.cs +++ /dev/null @@ -1,7 +0,0 @@ -using Content.Shared.Explosion; -using Content.Shared.Explosion.Components; - -namespace Content.Client.Explosion; - -[RegisterComponent, Access(typeof(TriggerSystem))] -public sealed partial class TriggerOnProximityComponent : SharedTriggerOnProximityComponent {} diff --git a/Content.Client/Explosion/TriggerSystem.cs b/Content.Client/Explosion/TriggerSystem.cs deleted file mode 100644 index e18569a18e7..00000000000 --- a/Content.Client/Explosion/TriggerSystem.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace Content.Client.Explosion; - -public sealed partial class TriggerSystem : EntitySystem -{ - public override void Initialize() - { - base.Initialize(); - InitializeProximity(); - } -} diff --git a/Content.Client/HotPotato/HotPotatoSystem.cs b/Content.Client/HotPotato/HotPotatoSystem.cs index 028a3b70d9f..a1495ab9945 100644 --- a/Content.Client/HotPotato/HotPotatoSystem.cs +++ b/Content.Client/HotPotato/HotPotatoSystem.cs @@ -1,5 +1,6 @@ using Content.Shared.HotPotato; using Robust.Shared.Random; +using Robust.Shared.Prototypes; using Robust.Shared.Timing; namespace Content.Client.HotPotato; @@ -10,6 +11,9 @@ public sealed class HotPotatoSystem : SharedHotPotatoSystem [Dependency] private readonly IRobustRandom _random = default!; [Dependency] private readonly SharedTransformSystem _transform = default!; + private readonly EntProtoId _hotPotatoEffectId = "HotPotatoEffect"; + + // TODO: particle system public override void Update(float frameTime) { base.Update(frameTime); @@ -23,7 +27,7 @@ public sealed class HotPotatoSystem : SharedHotPotatoSystem if (_timing.CurTime < comp.TargetTime) continue; comp.TargetTime = _timing.CurTime + TimeSpan.FromSeconds(comp.EffectCooldown); - Spawn("HotPotatoEffect", _transform.GetMapCoordinates(uid).Offset(_random.NextVector2(0.25f))); + Spawn(_hotPotatoEffectId, _transform.GetMapCoordinates(uid).Offset(_random.NextVector2(0.25f))); } } } diff --git a/Content.Client/Trigger/TimerTriggerVisualizerComponent.cs b/Content.Client/Trigger/Components/TimerTriggerVisualizerComponent.cs similarity index 84% rename from Content.Client/Trigger/TimerTriggerVisualizerComponent.cs rename to Content.Client/Trigger/Components/TimerTriggerVisualizerComponent.cs index 0e5a74b83b1..0cb89edd895 100644 --- a/Content.Client/Trigger/TimerTriggerVisualizerComponent.cs +++ b/Content.Client/Trigger/Components/TimerTriggerVisualizerComponent.cs @@ -1,7 +1,8 @@ +using Content.Client.Trigger.Systems; using Robust.Client.Animations; using Robust.Shared.Audio; -namespace Content.Client.Trigger; +namespace Content.Client.Trigger.Components; [RegisterComponent] [Access(typeof(TimerTriggerVisualizerSystem))] @@ -16,28 +17,27 @@ public sealed partial class TimerTriggerVisualsComponent : Component /// /// The RSI state used while the device has not been primed. /// - [DataField("unprimedSprite")] - [ViewVariables(VVAccess.ReadWrite)] + [DataField] public string UnprimedSprite = "icon"; /// /// The RSI state used when the device is primed. /// Not VVWrite-able because it's only used at component init to construct the priming animation. /// - [DataField("primingSprite")] + [DataField] public string PrimingSprite = "primed"; /// /// The sound played when the device is primed. /// Not VVWrite-able because it's only used at component init to construct the priming animation. /// - [DataField("primingSound")] + [DataField, ViewVariables] public SoundSpecifier? PrimingSound; /// /// The actual priming animation. /// Constructed at component init from the sprite and sound. /// - [ViewVariables(VVAccess.ReadWrite)] + [ViewVariables] public Animation PrimingAnimation = default!; } diff --git a/Content.Client/Explosion/TriggerSystem.Proximity.cs b/Content.Client/Trigger/Systems/ProximityTriggerAnimationSystem.cs similarity index 91% rename from Content.Client/Explosion/TriggerSystem.Proximity.cs rename to Content.Client/Trigger/Systems/ProximityTriggerAnimationSystem.cs index 03e74369714..79543995051 100644 --- a/Content.Client/Explosion/TriggerSystem.Proximity.cs +++ b/Content.Client/Trigger/Systems/ProximityTriggerAnimationSystem.cs @@ -1,11 +1,12 @@ using Content.Shared.Trigger; +using Content.Shared.Trigger.Components.Triggers; using Robust.Client.Animations; using Robust.Client.GameObjects; using Robust.Shared.Animations; -namespace Content.Client.Explosion; +namespace Content.Client.Trigger.Systems; -public sealed partial class TriggerSystem +public sealed class ProximityTriggerAnimationSystem : EntitySystem { [Dependency] private readonly AnimationPlayerSystem _player = default!; [Dependency] private readonly SharedAppearanceSystem _appearance = default!; @@ -18,7 +19,7 @@ public sealed partial class TriggerSystem private const string AnimKey = "proximity"; - private static readonly Animation _flasherAnimation = new Animation + private static readonly Animation FlasherAnimation = new Animation { Length = TimeSpan.FromSeconds(0.6f), AnimationTracks = { @@ -42,8 +43,10 @@ public sealed partial class TriggerSystem } }; - private void InitializeProximity() + public override void Initialize() { + base.Initialize(); + SubscribeLocalEvent(OnProximityInit); SubscribeLocalEvent(OnProxAppChange); SubscribeLocalEvent(OnProxAnimation); @@ -94,7 +97,7 @@ public sealed partial class TriggerSystem break; case ProximityTriggerVisuals.Active: if (_player.HasRunningAnimation(uid, player, AnimKey)) return; - _player.Play((uid, player), _flasherAnimation, AnimKey); + _player.Play((uid, player), FlasherAnimation, AnimKey); break; case ProximityTriggerVisuals.Off: default: diff --git a/Content.Client/Trigger/Systems/ReleaseGasOnTriggerSystem.cs b/Content.Client/Trigger/Systems/ReleaseGasOnTriggerSystem.cs new file mode 100644 index 00000000000..a183282ddea --- /dev/null +++ b/Content.Client/Trigger/Systems/ReleaseGasOnTriggerSystem.cs @@ -0,0 +1,5 @@ +using Content.Shared.Trigger.Systems; + +namespace Content.Client.Trigger.Systems; + +public sealed class ReleaseGasOnTriggerSystem : SharedReleaseGasOnTriggerSystem; diff --git a/Content.Client/Trigger/TimerTriggerVisualizerSystem.cs b/Content.Client/Trigger/Systems/TimerTriggerVisualizerSystem.cs similarity index 80% rename from Content.Client/Trigger/TimerTriggerVisualizerSystem.cs rename to Content.Client/Trigger/Systems/TimerTriggerVisualizerSystem.cs index b3d85f2017a..7c977c75897 100644 --- a/Content.Client/Trigger/TimerTriggerVisualizerSystem.cs +++ b/Content.Client/Trigger/Systems/TimerTriggerVisualizerSystem.cs @@ -1,11 +1,10 @@ +using Content.Client.Trigger.Components; using Content.Shared.Trigger; using Robust.Client.Animations; using Robust.Client.GameObjects; -using Robust.Shared.Audio; using Robust.Shared.Audio.Systems; -using Robust.Shared.GameObjects; -namespace Content.Client.Trigger; +namespace Content.Client.Trigger.Systems; public sealed class TimerTriggerVisualizerSystem : VisualizerSystem { @@ -17,25 +16,26 @@ public sealed class TimerTriggerVisualizerSystem : VisualizerSystem(OnComponentInit); } - private void OnComponentInit(EntityUid uid, TimerTriggerVisualsComponent comp, ComponentInit args) + private void OnComponentInit(Entity ent, ref ComponentInit args) { - comp.PrimingAnimation = new Animation + ent.Comp.PrimingAnimation = new Animation { Length = TimeSpan.MaxValue, AnimationTracks = { - new AnimationTrackSpriteFlick() { + new AnimationTrackSpriteFlick() + { LayerKey = TriggerVisualLayers.Base, - KeyFrames = { new AnimationTrackSpriteFlick.KeyFrame(comp.PrimingSprite, 0f) } + KeyFrames = { new AnimationTrackSpriteFlick.KeyFrame(ent.Comp.PrimingSprite, 0f) } } }, }; - if (comp.PrimingSound != null) + if (ent.Comp.PrimingSound != null) { - comp.PrimingAnimation.AnimationTracks.Add( + ent.Comp.PrimingAnimation.AnimationTracks.Add( new AnimationTrackPlaySound() { - KeyFrames = { new AnimationTrackPlaySound.KeyFrame(_audioSystem.ResolveSound(comp.PrimingSound), 0) } + KeyFrames = { new AnimationTrackPlaySound.KeyFrame(_audioSystem.ResolveSound(ent.Comp.PrimingSound), 0) } } ); } diff --git a/Content.IntegrationTests/Tests/Payload/ModularGrenadeTests.cs b/Content.IntegrationTests/Tests/Payload/ModularGrenadeTests.cs index 4db79373d38..f5a15295fd6 100644 --- a/Content.IntegrationTests/Tests/Payload/ModularGrenadeTests.cs +++ b/Content.IntegrationTests/Tests/Payload/ModularGrenadeTests.cs @@ -1,6 +1,6 @@ using Content.IntegrationTests.Tests.Interaction; -using Content.Server.Explosion.Components; -using Content.Shared.Explosion.Components; +using Content.Shared.Trigger.Components; +using Content.Shared.Trigger.Systems; using Robust.Shared.Containers; using Robust.Shared.GameObjects; @@ -25,19 +25,19 @@ public sealed class ModularGrenadeTests : InteractionTest await InteractUsing(Cable); // Insert & remove trigger - AssertComp(false); + AssertComp(false); await InteractUsing(Trigger); - AssertComp(); + AssertComp(); await FindEntity(Trigger, LookupFlags.Uncontained, shouldSucceed: false); await InteractUsing(Pry); - AssertComp(false); + AssertComp(false); // Trigger was dropped to floor, not deleted. await FindEntity(Trigger, LookupFlags.Uncontained); // Re-insert await InteractUsing(Trigger); - AssertComp(); + AssertComp(); // Insert & remove payload. await InteractUsing(Payload); @@ -56,13 +56,14 @@ public sealed class ModularGrenadeTests : InteractionTest await Pickup(); AssertComp(false); await UseInHand(); + AssertComp(true); // So uhhh grenades in hands don't destroy themselves when exploding. Maybe that will be fixed eventually. await Drop(); // Wait until grenade explodes - var timer = Comp(); - while (timer.TimeRemaining >= 0) + var triggerSys = SEntMan.System(); + while (Target != null && triggerSys.GetRemainingTime(SEntMan.GetEntity(Target.Value))?.TotalSeconds >= 0.0) { await RunTicks(10); } diff --git a/Content.Server/AlertLevel/AlertLevelChangeOnTriggerComponent.cs b/Content.Server/AlertLevel/AlertLevelChangeOnTriggerComponent.cs deleted file mode 100644 index aa6c5ba2bd1..00000000000 --- a/Content.Server/AlertLevel/AlertLevelChangeOnTriggerComponent.cs +++ /dev/null @@ -1,33 +0,0 @@ -using Content.Server.AlertLevel.Systems; - -namespace Content.Server.AlertLevel; -/// -/// This component is for changing the alert level of the station when triggered. -/// -[RegisterComponent, Access(typeof(AlertLevelChangeOnTriggerSystem))] -public sealed partial class AlertLevelChangeOnTriggerComponent : Component -{ - /// - ///The alert level to change to when triggered. - /// - [DataField] - public string Level = "blue"; - - /// - ///Whether to play the sound when the alert level changes. - /// - [DataField] - public bool PlaySound = true; - - /// - ///Whether to say the announcement when the alert level changes. - /// - [DataField] - public bool Announce = true; - - /// - ///Force the alert change. This applies if the alert level is not selectable or not. - /// - [DataField] - public bool Force = false; -} diff --git a/Content.Server/Animals/Systems/ParrotMemorySystem.cs b/Content.Server/Animals/Systems/ParrotMemorySystem.cs index 56843094a1a..a88957913f5 100644 --- a/Content.Server/Animals/Systems/ParrotMemorySystem.cs +++ b/Content.Server/Animals/Systems/ParrotMemorySystem.cs @@ -5,13 +5,13 @@ using Content.Server.Animals.Components; using Content.Server.Mind; using Content.Server.Popups; using Content.Server.Radio; -using Content.Server.Speech; -using Content.Server.Speech.Components; using Content.Server.Vocalization.Systems; using Content.Shared.Animals.Components; using Content.Shared.Animals.Systems; using Content.Shared.Database; using Content.Shared.Mobs.Systems; +using Content.Shared.Speech; +using Content.Shared.Speech.Components; using Content.Shared.Whitelist; using Robust.Shared.Network; using Robust.Shared.Random; diff --git a/Content.Server/Chat/SpeakOnTriggerComponent.cs b/Content.Server/Chat/SpeakOnTriggerComponent.cs deleted file mode 100644 index d879cbf1bf0..00000000000 --- a/Content.Server/Chat/SpeakOnTriggerComponent.cs +++ /dev/null @@ -1,17 +0,0 @@ -using Content.Shared.Dataset; -using Robust.Shared.Prototypes; - -namespace Content.Server.Chat; - -/// -/// Makes the entity speak when triggered. If the item has UseDelay component, the system will respect that cooldown. -/// -[RegisterComponent] -public sealed partial class SpeakOnTriggerComponent : Component -{ - /// - /// The identifier for the dataset prototype containing messages to be spoken by this entity. - /// - [DataField(required: true)] - public ProtoId Pack = string.Empty; -} diff --git a/Content.Server/Chat/SuicideSystem.cs b/Content.Server/Chat/SuicideSystem.cs index ce07c63048e..9d85cb05c01 100644 --- a/Content.Server/Chat/SuicideSystem.cs +++ b/Content.Server/Chat/SuicideSystem.cs @@ -71,6 +71,9 @@ public sealed class SuicideSystem : EntitySystem return false; // DeltaV - Prevent Suicide. We allow the event to go out anyways in case anything relies on the event for a message or whatever. + // TODO: fix this + // This is a handled event, but the result is never used + // It looks like TriggerOnMobstateChange is supposed to prevent you from suiciding var suicideEvent = new SuicideEvent(victim); RaiseLocalEvent(victim, suicideEvent); diff --git a/Content.Server/Chat/Systems/ChatSystem.cs b/Content.Server/Chat/Systems/ChatSystem.cs index 8306d5abb23..9ded783990c 100644 --- a/Content.Server/Chat/Systems/ChatSystem.cs +++ b/Content.Server/Chat/Systems/ChatSystem.cs @@ -69,11 +69,6 @@ public sealed partial class ChatSystem : SharedChatSystem //Nyano - Summary: pulls in the nyano chat system for psionics. [Dependency] private readonly NyanoChatSystem _nyanoChatSystem = default!; - public const int VoiceRange = 10; // how far voice goes in world units - public const int WhisperClearRange = 2; // how far whisper goes while still being understandable, in world units - public const int WhisperMuffledRange = 5; // how far whisper goes at all, in world units - public const string DefaultAnnouncementSound = "/Audio/Announcements/announce.ogg"; - private bool _loocEnabled = true; private bool _deadLoocEnabled; private bool _critLoocEnabled; diff --git a/Content.Server/Damage/Systems/DamageUserOnTriggerSystem.cs b/Content.Server/Damage/Systems/DamageUserOnTriggerSystem.cs deleted file mode 100644 index 6c910f9dc3b..00000000000 --- a/Content.Server/Damage/Systems/DamageUserOnTriggerSystem.cs +++ /dev/null @@ -1,51 +0,0 @@ -using Content.Server.Damage.Components; -using Content.Server.Explosion.EntitySystems; -using Content.Shared.Damage; -using Content.Shared.Damage.Components; - -namespace Content.Server.Damage.Systems; - -// System for damage that occurs on specific trigger, towards the user.. -public sealed class DamageUserOnTriggerSystem : EntitySystem -{ - [Dependency] private readonly DamageableSystem _damageableSystem = default!; - - public override void Initialize() - { - SubscribeLocalEvent(OnTrigger); - } - - private void OnTrigger(EntityUid uid, DamageUserOnTriggerComponent component, TriggerEvent args) - { - if (args.User is null) - return; - - args.Handled |= OnDamageTrigger(uid, args.User.Value, component); - } - - private bool OnDamageTrigger(EntityUid source, EntityUid target, DamageUserOnTriggerComponent? component = null) - { - if (!Resolve(source, ref component)) - { - return false; - } - - var damage = new DamageSpecifier(component.Damage); - var ev = new BeforeDamageUserOnTriggerEvent(damage, target); - RaiseLocalEvent(source, ev); - - return _damageableSystem.TryChangeDamage(target, ev.Damage, component.IgnoreResistances, origin: source, targetPart: component.TargetPart) is not null; // Shitmed Change - } -} - -public sealed class BeforeDamageUserOnTriggerEvent : EntityEventArgs -{ - public DamageSpecifier Damage { get; set; } - public EntityUid Tripper { get; } - - public BeforeDamageUserOnTriggerEvent(DamageSpecifier damage, EntityUid target) - { - Damage = damage; - Tripper = target; - } -} diff --git a/Content.Server/Defusable/Systems/DefusableSystem.cs b/Content.Server/Defusable/Systems/DefusableSystem.cs index 1e9caece945..5c589d21311 100644 --- a/Content.Server/Defusable/Systems/DefusableSystem.cs +++ b/Content.Server/Defusable/Systems/DefusableSystem.cs @@ -1,5 +1,4 @@ using Content.Server.Defusable.Components; -using Content.Server.Explosion.Components; using Content.Server.Explosion.EntitySystems; using Content.Server.Popups; using Content.Server.Wires; @@ -8,13 +7,13 @@ using Content.Shared.Construction.Components; using Content.Shared.Database; using Content.Shared.Defusable; using Content.Shared.Examine; -using Content.Shared.Explosion.Components; -using Content.Shared.Explosion.Components.OnTrigger; using Content.Shared.Popups; +using Content.Shared.Trigger.Components; +using Content.Shared.Trigger.Components.Effects; +using Content.Shared.Trigger.Systems; using Content.Shared.Verbs; using Content.Shared.Wires; using Robust.Server.GameObjects; -using Robust.Shared.Audio; using Robust.Shared.Audio.Systems; namespace Content.Server.Defusable.Systems; @@ -74,12 +73,13 @@ public sealed class DefusableSystem : SharedDefusableSystem { args.PushMarkup(Loc.GetString("defusable-examine-defused", ("name", uid))); } - else if (comp.Activated && TryComp(uid, out var activeComp)) + else if (comp.Activated) { - if (comp.DisplayTime) + var remaining = _trigger.GetRemainingTime(uid); + if (comp.DisplayTime && remaining != null) { args.PushMarkup(Loc.GetString("defusable-examine-live", ("name", uid), - ("time", MathF.Floor(activeComp.TimeRemaining)))); + ("time", Math.Floor(remaining.Value.TotalSeconds)))); } else { @@ -139,16 +139,9 @@ public sealed class DefusableSystem : SharedDefusableSystem SetActivated(comp, true); _popup.PopupEntity(Loc.GetString("defusable-popup-begun", ("name", uid)), uid); - if (TryComp(uid, out var timerTrigger)) + if (TryComp(uid, out var timerTrigger)) { - _trigger.HandleTimerTrigger( - uid, - user, - timerTrigger.Delay, - timerTrigger.BeepInterval, - timerTrigger.InitialBeepDelay, - timerTrigger.BeepSound - ); + _trigger.ActivateTimerTrigger((uid, timerTrigger)); } RaiseLocalEvent(uid, new BombArmedEvent(uid)); @@ -168,7 +161,7 @@ public sealed class DefusableSystem : SharedDefusableSystem RaiseLocalEvent(uid, new BombDetonatedEvent(uid)); - _explosion.TriggerExplosive(uid, user:detonator); + _explosion.TriggerExplosive(uid, user: detonator); QueueDel(uid); _appearance.SetData(uid, DefusableVisuals.Active, comp.Activated); @@ -188,7 +181,7 @@ public sealed class DefusableSystem : SharedDefusableSystem { SetUsable(comp, false); RemComp(uid); - RemComp(uid); + RemComp(uid); } RemComp(uid); @@ -246,7 +239,7 @@ public sealed class DefusableSystem : SharedDefusableSystem if (comp is not { Activated: true, DelayWireUsed: false }) return; - _trigger.TryDelay(wire.Owner, 30f); + _trigger.TryDelay(wire.Owner, TimeSpan.FromSeconds(30)); _popup.PopupEntity(Loc.GetString("defusable-popup-wire-chirp", ("name", wire.Owner)), wire.Owner); comp.DelayWireUsed = true; } @@ -268,7 +261,7 @@ public sealed class DefusableSystem : SharedDefusableSystem if (comp is { Activated: true, ProceedWireUsed: false }) { comp.ProceedWireUsed = true; - _trigger.TryDelay(wire.Owner, -15f); + _trigger.TryDelay(wire.Owner, TimeSpan.FromSeconds(-15)); } _popup.PopupEntity(Loc.GetString("defusable-popup-wire-proceed-pulse", ("name", wire.Owner)), wire.Owner); @@ -298,7 +291,7 @@ public sealed class DefusableSystem : SharedDefusableSystem { if (!comp.ActivatedWireUsed) { - _trigger.TryDelay(wire.Owner, 30f); + _trigger.TryDelay(wire.Owner, TimeSpan.FromSeconds(30)); _popup.PopupEntity(Loc.GetString("defusable-popup-wire-chirp", ("name", wire.Owner)), wire.Owner); comp.ActivatedWireUsed = true; } diff --git a/Content.Server/Destructible/DestructibleSystem.cs b/Content.Server/Destructible/DestructibleSystem.cs index 82d5ffcb9ac..b4a79c6830b 100644 --- a/Content.Server/Destructible/DestructibleSystem.cs +++ b/Content.Server/Destructible/DestructibleSystem.cs @@ -1,4 +1,5 @@ using System.Diagnostics.CodeAnalysis; +using System.Linq; using Content.Server.Administration.Logs; using Content.Server.Atmos.EntitySystems; using Content.Server.Body.Systems; @@ -14,15 +15,13 @@ using Content.Shared.Damage; using Content.Shared.Database; using Content.Shared.Destructible; using Content.Shared.FixedPoint; +using Content.Shared.Humanoid; +using Content.Shared.Trigger.Systems; using JetBrains.Annotations; using Robust.Server.Audio; -using Robust.Server.GameObjects; using Robust.Shared.Containers; using Robust.Shared.Prototypes; using Robust.Shared.Random; -using System.Linq; -using Content.Shared.Humanoid; -using Robust.Shared.Player; namespace Content.Server.Destructible { diff --git a/Content.Server/Destructible/Thresholds/Behaviors/TimerStartBehavior.cs b/Content.Server/Destructible/Thresholds/Behaviors/TimerStartBehavior.cs index 97a5f8b7ef5..cf337ac76a7 100644 --- a/Content.Server/Destructible/Thresholds/Behaviors/TimerStartBehavior.cs +++ b/Content.Server/Destructible/Thresholds/Behaviors/TimerStartBehavior.cs @@ -5,6 +5,6 @@ public sealed partial class TimerStartBehavior : IThresholdBehavior { public void Execute(EntityUid owner, DestructibleSystem system, EntityUid? cause = null) { - system.TriggerSystem.StartTimer(owner, cause); + system.TriggerSystem.ActivateTimerTrigger(owner, cause); } } diff --git a/Content.Server/Destructible/Thresholds/Behaviors/TriggerBehavior.cs b/Content.Server/Destructible/Thresholds/Behaviors/TriggerBehavior.cs index 03bdb8ff696..66da79063cc 100644 --- a/Content.Server/Destructible/Thresholds/Behaviors/TriggerBehavior.cs +++ b/Content.Server/Destructible/Thresholds/Behaviors/TriggerBehavior.cs @@ -1,10 +1,18 @@ -namespace Content.Server.Destructible.Thresholds.Behaviors; +using Content.Shared.Trigger.Systems; + +namespace Content.Server.Destructible.Thresholds.Behaviors; [DataDefinition] public sealed partial class TriggerBehavior : IThresholdBehavior { + /// + /// The trigger key to use when triggering. + /// + [DataField] + public string? KeyOut { get; set; } = TriggerSystem.DefaultTriggerKey; + public void Execute(EntityUid owner, DestructibleSystem system, EntityUid? cause = null) { - system.TriggerSystem.Trigger(owner, cause); + system.TriggerSystem.Trigger(owner, cause, KeyOut); } } diff --git a/Content.Server/DeviceLinking/Systems/DeviceLinkSystem.cs b/Content.Server/DeviceLinking/Systems/DeviceLinkSystem.cs index d957f0171e7..ff20ac4d8d8 100644 --- a/Content.Server/DeviceLinking/Systems/DeviceLinkSystem.cs +++ b/Content.Server/DeviceLinking/Systems/DeviceLinkSystem.cs @@ -1,4 +1,6 @@ using Content.Server.DeviceLinking.Components; +using Content.Server.DeviceNetwork; +using Content.Server.DeviceNetwork.Components; using Content.Server.DeviceNetwork.Systems; using Content.Shared.DeviceLinking; using Content.Shared.DeviceLinking.Events; diff --git a/Content.Server/DeviceLinking/Systems/MemoryCellSystem.cs b/Content.Server/DeviceLinking/Systems/MemoryCellSystem.cs index 45e4d217507..7743a97d72d 100644 --- a/Content.Server/DeviceLinking/Systems/MemoryCellSystem.cs +++ b/Content.Server/DeviceLinking/Systems/MemoryCellSystem.cs @@ -1,5 +1,4 @@ using Content.Server.DeviceLinking.Components; -using Content.Server.DeviceNetwork; using Content.Shared.DeviceLinking; using Content.Shared.DeviceLinking.Events; using Content.Shared.DeviceNetwork; diff --git a/Content.Server/DeviceLinking/Systems/SignallerSystem.cs b/Content.Server/DeviceLinking/Systems/SignallerSystem.cs index a5091508ed7..7d684d1cd59 100644 --- a/Content.Server/DeviceLinking/Systems/SignallerSystem.cs +++ b/Content.Server/DeviceLinking/Systems/SignallerSystem.cs @@ -1,6 +1,5 @@ using Content.Server.Administration.Logs; using Content.Server.DeviceLinking.Components; -using Content.Server.Explosion.EntitySystems; using Content.Shared.Database; using Content.Shared.Interaction.Events; using Content.Shared.Timing; @@ -10,7 +9,6 @@ namespace Content.Server.DeviceLinking.Systems; public sealed class SignallerSystem : EntitySystem { [Dependency] private readonly DeviceLinkSystem _link = default!; - [Dependency] private readonly UseDelaySystem _useDelay = default!; [Dependency] private readonly IAdminLogManager _adminLogger = default!; public override void Initialize() @@ -19,7 +17,6 @@ public sealed class SignallerSystem : EntitySystem SubscribeLocalEvent(OnInit); SubscribeLocalEvent(OnUseInHand); - SubscribeLocalEvent(OnTrigger); } private void OnInit(EntityUid uid, SignallerComponent component, ComponentInit args) @@ -36,16 +33,4 @@ public sealed class SignallerSystem : EntitySystem _link.InvokePort(uid, component.Port); args.Handled = true; } - - private void OnTrigger(EntityUid uid, SignallerComponent component, TriggerEvent args) - { - if (!TryComp(uid, out UseDelayComponent? useDelay) - // if on cooldown, do nothing - // and set cooldown to prevent clocks - || !_useDelay.TryResetDelay((uid, useDelay), true)) - return; - - _link.InvokePort(uid, component.Port); - args.Handled = true; - } } diff --git a/Content.Server/Electrocution/ElectrocutionSystem.cs b/Content.Server/Electrocution/ElectrocutionSystem.cs index 77f9b295d93..bebe20eaefb 100644 --- a/Content.Server/Electrocution/ElectrocutionSystem.cs +++ b/Content.Server/Electrocution/ElectrocutionSystem.cs @@ -59,7 +59,7 @@ public sealed class ElectrocutionSystem : SharedElectrocutionSystem [Dependency] private readonly MetaDataSystem _metaData = default!; [Dependency] private readonly TurfSystem _turf = default!; - private static readonly ProtoId StatusEffectKey = "Electrocution"; + private static readonly ProtoId StatusKeyIn = "Electrocution"; private static readonly ProtoId DamageType = "Shock"; private static readonly ProtoId WindowTag = "Window"; @@ -387,12 +387,12 @@ public sealed class ElectrocutionSystem : SharedElectrocutionSystem } if (!Resolve(uid, ref statusEffects, false) || - !_statusEffects.CanApplyEffect(uid, StatusEffectKey, statusEffects)) + !_statusEffects.CanApplyEffect(uid, StatusKeyIn, statusEffects)) { return false; } - if (!_statusEffects.TryAddStatusEffect(uid, StatusEffectKey, time, refresh, statusEffects)) + if (!_statusEffects.TryAddStatusEffect(uid, StatusKeyIn, time, refresh, statusEffects)) return false; var shouldStun = siemensCoefficient > 0.5f; diff --git a/Content.Server/Emp/EmpOnTriggerComponent.cs b/Content.Server/Emp/EmpOnTriggerComponent.cs deleted file mode 100644 index e7e30f4e54d..00000000000 --- a/Content.Server/Emp/EmpOnTriggerComponent.cs +++ /dev/null @@ -1,36 +0,0 @@ -using Content.Shared.Damage; // DeltaV - EMP damage - -namespace Content.Server.Emp; - -/// -/// Upon being triggered will EMP area around it. -/// -[RegisterComponent] -[Access(typeof(EmpSystem))] -public sealed partial class EmpOnTriggerComponent : Component -{ - [DataField("range"), ViewVariables(VVAccess.ReadWrite)] - public float Range = 1.0f; - - /// - /// How much energy will be consumed per battery in range - /// - [DataField("energyConsumption"), ViewVariables(VVAccess.ReadWrite)] - public float EnergyConsumption; - - /// - /// How long it disables targets in seconds - /// - [DataField("disableDuration"), ViewVariables(VVAccess.ReadWrite)] - public float DisableDuration = 60f; - - /// - /// DeltaV - The damage dealt to silicons instead of draining their power cells - /// - [DataField] - public DamageSpecifier Damage = new() { - DamageDict = new() { - { "Ion", 130 } // Most EMP sources should pretty much oneshot silicons. This would kill an IPC and completely disable a borg for a minute. - } - }; -} diff --git a/Content.Server/Emp/EmpSystem.cs b/Content.Server/Emp/EmpSystem.cs index a5c7835a69c..99be8a1c6e8 100644 --- a/Content.Server/Emp/EmpSystem.cs +++ b/Content.Server/Emp/EmpSystem.cs @@ -27,7 +27,6 @@ public sealed class EmpSystem : SharedEmpSystem { base.Initialize(); SubscribeLocalEvent(OnExamine); - SubscribeLocalEvent(HandleEmpTrigger); SubscribeLocalEvent(OnRadioSendAttempt); SubscribeLocalEvent(OnRadioReceiveAttempt); @@ -35,6 +34,19 @@ public sealed class EmpSystem : SharedEmpSystem SubscribeLocalEvent(OnCameraSetActive); } + /// + /// DeltaV - Triggers an EMP pulse at the given location, by first raising an , then a raising on all entities in range. + /// Shim for Upstream EmpPulse method. + /// + /// The location to trigger the EMP pulse at. + /// The range of the EMP pulse. + /// The amount of energy consumed by the EMP pulse. + /// The duration of the EMP effects. + public override void EmpPulse(MapCoordinates coordinates, float range, float energyConsumption, float duration) + { + this.EmpPulse(coordinates, range, energyConsumption, duration, null); + } + /// /// Triggers an EMP pulse at the given location, by first raising an , then a raising on all entities in range. /// @@ -45,7 +57,8 @@ public sealed class EmpSystem : SharedEmpSystem /// DeltaV - the damage dealt by the EMP to silicons instead of draining their power cells. public void EmpPulse(MapCoordinates coordinates, float range, float energyConsumption, float duration, DamageSpecifier? damage = null) { - if (damage == null) damage = new() {DamageDict = new() {{"Ion", 80}}}; // DeltaV - EMP damage + // TODO: AUM - Slightly refactor this + if (damage == null) damage = new() { DamageDict = new() { { "Ion", 80 } } }; // DeltaV - EMP damage foreach (var uid in _lookup.GetEntitiesInRange(coordinates, range)) { TryEmpEffects(uid, energyConsumption, duration, damage); @@ -103,7 +116,7 @@ public sealed class EmpSystem : SharedEmpSystem /// DeltaV - the damage dealt by the EMP to silicons instead of draining their power cells. public void DoEmpEffects(EntityUid uid, float energyConsumption, float duration, DamageSpecifier? damage = null) { - if (damage == null) damage = new() {DamageDict = new() {{"Ion", 80}}}; // DeltaV - EMP damage + if (damage == null) damage = new() { DamageDict = new() { { "Ion", 80 } } }; // DeltaV - EMP damage var ev = new EmpPulseEvent(energyConsumption, false, false, TimeSpan.FromSeconds(duration)); RaiseLocalEvent(uid, ref ev); if (ev.Affected) @@ -138,11 +151,13 @@ public sealed class EmpSystem : SharedEmpSystem args.PushMarkup(Loc.GetString("emp-disabled-comp-on-examine")); } + /* Removed in Trigger Refactor private void HandleEmpTrigger(EntityUid uid, EmpOnTriggerComponent comp, TriggerEvent args) { EmpPulse(_transform.GetMapCoordinates(uid), comp.Range, comp.EnergyConsumption, comp.DisableDuration, comp.Damage); // DeltaV - EMP damage args.Handled = true; } + */ private void OnRadioSendAttempt(EntityUid uid, EmpDisabledComponent component, ref RadioSendAttemptEvent args) { @@ -170,7 +185,7 @@ public sealed class EmpSystem : SharedEmpSystem /// public sealed partial class EmpAttemptEvent(DamageSpecifier? damage = null) : CancellableEntityEventArgs // DeltaV - EMP damage { - public DamageSpecifier? Damage = (damage == null) ? new() {DamageDict = new() {{"Ion", 80}}} : damage; // DeltaV - EMP damage; + public DamageSpecifier? Damage = (damage == null) ? new() { DamageDict = new() { {"Ion", 80 } } } : damage; // DeltaV - EMP damage; } [ByRefEvent] diff --git a/Content.Server/Explosion/Components/ActiveTriggerOnTimedCollideComponent.cs b/Content.Server/Explosion/Components/ActiveTriggerOnTimedCollideComponent.cs deleted file mode 100644 index 9d8073413c1..00000000000 --- a/Content.Server/Explosion/Components/ActiveTriggerOnTimedCollideComponent.cs +++ /dev/null @@ -1,4 +0,0 @@ -namespace Content.Server.Explosion.Components; - -[RegisterComponent] -public sealed partial class ActiveTriggerOnTimedCollideComponent : Component { } diff --git a/Content.Server/Explosion/Components/AutomatedTimerComponent.cs b/Content.Server/Explosion/Components/AutomatedTimerComponent.cs deleted file mode 100644 index c01aeb91e55..00000000000 --- a/Content.Server/Explosion/Components/AutomatedTimerComponent.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Content.Server.Explosion.Components; - -/// -/// Disallows starting the timer by hand, must be stuck or triggered by a system using StartTimer. -/// -[RegisterComponent] -public sealed partial class AutomatedTimerComponent : Component -{ -} diff --git a/Content.Server/Explosion/Components/OnTrigger/AnchorOnTriggerComponent.cs b/Content.Server/Explosion/Components/OnTrigger/AnchorOnTriggerComponent.cs deleted file mode 100644 index d83b57c188c..00000000000 --- a/Content.Server/Explosion/Components/OnTrigger/AnchorOnTriggerComponent.cs +++ /dev/null @@ -1,13 +0,0 @@ -using Content.Server.Explosion.EntitySystems; - -namespace Content.Server.Explosion.Components; - -/// -/// Will anchor the attached entity upon a . -/// -[RegisterComponent] -public sealed partial class AnchorOnTriggerComponent : Component -{ - [DataField("removeOnTrigger")] - public bool RemoveOnTrigger = true; -} diff --git a/Content.Server/Explosion/Components/OnTrigger/DeleteOnTriggerComponent.cs b/Content.Server/Explosion/Components/OnTrigger/DeleteOnTriggerComponent.cs deleted file mode 100644 index 9846cad84ba..00000000000 --- a/Content.Server/Explosion/Components/OnTrigger/DeleteOnTriggerComponent.cs +++ /dev/null @@ -1,11 +0,0 @@ -using Content.Server.Explosion.EntitySystems; - -namespace Content.Server.Explosion.Components; - -/// -/// Will delete the attached entity upon a . -/// -[RegisterComponent] -public sealed partial class DeleteOnTriggerComponent : Component -{ -} diff --git a/Content.Server/Explosion/Components/OnTrigger/GibOnTriggerComponent.cs b/Content.Server/Explosion/Components/OnTrigger/GibOnTriggerComponent.cs deleted file mode 100644 index da584676593..00000000000 --- a/Content.Server/Explosion/Components/OnTrigger/GibOnTriggerComponent.cs +++ /dev/null @@ -1,16 +0,0 @@ -namespace Content.Server.Explosion.Components; - -/// -/// Gibs on trigger, self explanatory. -/// Also in case of an implant using this, gibs the implant user instead. -/// -[RegisterComponent] -public sealed partial class GibOnTriggerComponent : Component -{ - /// - /// Should gibbing also delete the owners items? - /// - [ViewVariables(VVAccess.ReadWrite)] - [DataField("deleteItems")] - public bool DeleteItems = false; -} diff --git a/Content.Server/Explosion/Components/OnTrigger/SoundOnTriggerComponent.cs b/Content.Server/Explosion/Components/OnTrigger/SoundOnTriggerComponent.cs deleted file mode 100644 index 7f9f16a2274..00000000000 --- a/Content.Server/Explosion/Components/OnTrigger/SoundOnTriggerComponent.cs +++ /dev/null @@ -1,17 +0,0 @@ -using Content.Server.Explosion.EntitySystems; -using Robust.Shared.Audio; - -namespace Content.Server.Explosion.Components; - -/// -/// Will play sound from the attached entity upon a . -/// -[RegisterComponent] -public sealed partial class SoundOnTriggerComponent : Component -{ - [DataField("removeOnTrigger")] - public bool RemoveOnTrigger = true; - - [DataField("sound")] - public SoundSpecifier? Sound = new SoundPathSpecifier("/Audio/Effects/Grenades/supermatter_start.ogg"); -} diff --git a/Content.Server/Explosion/Components/OnTrigger/TwoStageTriggerComponent.cs b/Content.Server/Explosion/Components/OnTrigger/TwoStageTriggerComponent.cs deleted file mode 100644 index a63d6fcf66f..00000000000 --- a/Content.Server/Explosion/Components/OnTrigger/TwoStageTriggerComponent.cs +++ /dev/null @@ -1,34 +0,0 @@ -using Robust.Shared.Prototypes; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom; - -namespace Content.Server.Explosion.Components.OnTrigger; - -/// -/// After being triggered applies the specified components and runs triggers again. -/// -[RegisterComponent, AutoGenerateComponentPause] -public sealed partial class TwoStageTriggerComponent : Component -{ - /// - /// How long it takes for the second stage to be triggered. - /// - [ViewVariables(VVAccess.ReadWrite)] - [DataField("triggerDelay")] - public TimeSpan TriggerDelay = TimeSpan.FromSeconds(10); - - /// - /// This list of components that will be added for the second trigger. - /// - [DataField("components", required: true)] - public ComponentRegistry SecondStageComponents = new(); - - [DataField("nextTriggerTime", customTypeSerializer: typeof(TimeOffsetSerializer))] - [AutoPausedField] - public TimeSpan? NextTriggerTime; - - [DataField("triggered")] - public bool Triggered = false; - - [DataField("ComponentsIsLoaded")] - public bool ComponentsIsLoaded = false; -} diff --git a/Content.Server/Explosion/Components/ProjectileGrenadeComponent.cs b/Content.Server/Explosion/Components/ProjectileGrenadeComponent.cs index 58d687e0258..20a73b46b52 100644 --- a/Content.Server/Explosion/Components/ProjectileGrenadeComponent.cs +++ b/Content.Server/Explosion/Components/ProjectileGrenadeComponent.cs @@ -45,4 +45,10 @@ public sealed partial class ProjectileGrenadeComponent : Component /// [DataField] public float MaxVelocity = 6f; + + /// + /// The trigger key that will activate the grenade. + /// + [DataField] + public string TriggerKey = "timer"; } diff --git a/Content.Server/Explosion/Components/ShockOnTriggerComponent.cs b/Content.Server/Explosion/Components/ShockOnTriggerComponent.cs deleted file mode 100644 index a553cc047ac..00000000000 --- a/Content.Server/Explosion/Components/ShockOnTriggerComponent.cs +++ /dev/null @@ -1,37 +0,0 @@ -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom; -using Content.Server.Explosion.EntitySystems; - -namespace Content.Server.Explosion.Components; - -/// -/// A component that electrocutes an entity having this component when a trigger is triggered. -/// -[RegisterComponent, AutoGenerateComponentPause] -[Access(typeof(TriggerSystem))] -public sealed partial class ShockOnTriggerComponent : Component -{ - /// - /// The force of an electric shock when the trigger is triggered. - /// - [DataField] - public int Damage = 5; - - /// - /// Duration of electric shock when the trigger is triggered. - /// - [DataField] - public TimeSpan Duration = TimeSpan.FromSeconds(2); - - /// - /// The minimum delay between repeating triggers. - /// - [DataField] - public TimeSpan Cooldown = TimeSpan.FromSeconds(4); - - /// - /// When can the trigger run again? - /// - [DataField(customTypeSerializer: typeof(TimeOffsetSerializer))] - [AutoPausedField] - public TimeSpan NextTrigger = TimeSpan.Zero; -} diff --git a/Content.Server/Explosion/Components/SpawnOnTriggerComponent.cs b/Content.Server/Explosion/Components/SpawnOnTriggerComponent.cs deleted file mode 100644 index c28ec7faeb8..00000000000 --- a/Content.Server/Explosion/Components/SpawnOnTriggerComponent.cs +++ /dev/null @@ -1,24 +0,0 @@ -using Content.Server.Explosion.EntitySystems; -using Robust.Shared.Prototypes; - -namespace Content.Server.Explosion.Components; - -/// -/// Spawns a protoype when triggered. -/// -[RegisterComponent, Access(typeof(TriggerSystem))] -public sealed partial class SpawnOnTriggerComponent : Component -{ - /// - /// The prototype to spawn. - /// - [DataField(required: true)] - public EntProtoId Proto = string.Empty; - - /// - /// Use MapCoordinates for spawning? - /// Set to true if you don't want the new entity parented to the spawner. - /// - [DataField] - public bool mapCoords; -} diff --git a/Content.Server/Explosion/Components/TimerStartOnSignalComponent.cs b/Content.Server/Explosion/Components/TimerStartOnSignalComponent.cs deleted file mode 100644 index 9adc6dab871..00000000000 --- a/Content.Server/Explosion/Components/TimerStartOnSignalComponent.cs +++ /dev/null @@ -1,15 +0,0 @@ -using Content.Shared.DeviceLinking; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; - -namespace Content.Server.Explosion.Components -{ - /// - /// Sends a trigger when signal is received. - /// - [RegisterComponent] - public sealed partial class TimerStartOnSignalComponent : Component - { - [DataField("port", customTypeSerializer: typeof(PrototypeIdSerializer))] - public string Port = "Timer"; - } -} diff --git a/Content.Server/Explosion/Components/TriggerOnActivateComponent.cs b/Content.Server/Explosion/Components/TriggerOnActivateComponent.cs deleted file mode 100644 index 1531c7425ea..00000000000 --- a/Content.Server/Explosion/Components/TriggerOnActivateComponent.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace Content.Server.Explosion.Components; - -/// -/// Triggers on click. -/// -[RegisterComponent] -public sealed partial class TriggerOnActivateComponent : Component { } diff --git a/Content.Server/Explosion/Components/TriggerOnCollideComponent.cs b/Content.Server/Explosion/Components/TriggerOnCollideComponent.cs deleted file mode 100644 index 28c2ed8c34c..00000000000 --- a/Content.Server/Explosion/Components/TriggerOnCollideComponent.cs +++ /dev/null @@ -1,20 +0,0 @@ -namespace Content.Server.Explosion.Components; - -/// -/// Triggers when colliding with another entity. -/// -[RegisterComponent] -public sealed partial class TriggerOnCollideComponent : Component -{ - /// - /// The fixture with which to collide. - /// - [DataField(required: true)] - public string FixtureID = string.Empty; - - /// - /// Doesn't trigger if the other colliding fixture is nonhard. - /// - [DataField] - public bool IgnoreOtherNonHard = true; -} diff --git a/Content.Server/Explosion/Components/TriggerOnMobstateChangeComponent.cs b/Content.Server/Explosion/Components/TriggerOnMobstateChangeComponent.cs deleted file mode 100644 index a6cdda247c3..00000000000 --- a/Content.Server/Explosion/Components/TriggerOnMobstateChangeComponent.cs +++ /dev/null @@ -1,24 +0,0 @@ -using Content.Shared.Mobs; - -namespace Content.Server.Explosion.Components; - -/// -/// Use where you want something to trigger on mobstate change -/// -[RegisterComponent] -public sealed partial class TriggerOnMobstateChangeComponent : Component -{ - /// - /// What state should trigger this? - /// - [ViewVariables] - [DataField("mobState", required: true)] - public List MobState = new(); - - /// - /// If true, prevents suicide attempts for the trigger to prevent cheese. - /// - [ViewVariables] - [DataField("preventSuicide")] - public bool PreventSuicide = false; -} diff --git a/Content.Server/Explosion/Components/TriggerOnProximityComponent.cs b/Content.Server/Explosion/Components/TriggerOnProximityComponent.cs deleted file mode 100644 index 4f3fb4754e9..00000000000 --- a/Content.Server/Explosion/Components/TriggerOnProximityComponent.cs +++ /dev/null @@ -1,93 +0,0 @@ -using Content.Server.Explosion.EntitySystems; -using Content.Shared.Explosion; -using Content.Shared.Explosion.Components; -using Content.Shared.Physics; -using Robust.Shared.Physics.Collision.Shapes; -using Robust.Shared.Physics.Components; -using Robust.Shared.Physics.Dynamics; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom; - -namespace Content.Server.Explosion.Components -{ - - /// - /// Raises a whenever an entity collides with a fixture attached to the owner of this component. - /// - [RegisterComponent, AutoGenerateComponentPause] - public sealed partial class TriggerOnProximityComponent : SharedTriggerOnProximityComponent - { - public const string FixtureID = "trigger-on-proximity-fixture"; - - [ViewVariables] - public readonly Dictionary Colliding = new(); - - /// - /// What is the shape of the proximity fixture? - /// - [ViewVariables] - [DataField("shape")] - public IPhysShape Shape = new PhysShapeCircle(2f); - - /// - /// How long the the proximity trigger animation plays for. - /// - [ViewVariables(VVAccess.ReadWrite)] - [DataField("animationDuration")] - public TimeSpan AnimationDuration = TimeSpan.FromSeconds(0.6f); - - /// - /// Whether the entity needs to be anchored for the proximity to work. - /// - [ViewVariables(VVAccess.ReadWrite)] - [DataField("requiresAnchored")] - public bool RequiresAnchored = true; - - [ViewVariables(VVAccess.ReadWrite)] - [DataField("enabled")] - public bool Enabled = true; - - /// - /// The minimum delay between repeating triggers. - /// - [ViewVariables(VVAccess.ReadWrite)] - [DataField("cooldown")] - public TimeSpan Cooldown = TimeSpan.FromSeconds(5); - - /// - /// When can the trigger run again? - /// - [ViewVariables(VVAccess.ReadWrite)] - [DataField("nextTrigger", customTypeSerializer: typeof(TimeOffsetSerializer))] - [AutoPausedField] - public TimeSpan NextTrigger = TimeSpan.Zero; - - /// - /// When will the visual state be updated again after activation? - /// - [ViewVariables(VVAccess.ReadWrite)] - [DataField("nextVisualUpdate", customTypeSerializer: typeof(TimeOffsetSerializer))] - [AutoPausedField] - public TimeSpan NextVisualUpdate = TimeSpan.Zero; - - /// - /// What speed should the other object be moving at to trigger the proximity fixture? - /// - [ViewVariables(VVAccess.ReadWrite)] - [DataField("triggerSpeed")] - public float TriggerSpeed = 3.5f; - - /// - /// If this proximity is triggered should we continually repeat it? - /// - [ViewVariables(VVAccess.ReadWrite)] - [DataField("repeating")] - public bool Repeating = true; - - /// - /// What layer is the trigger fixture on? - /// - [ViewVariables] - [DataField("layer", customTypeSerializer: typeof(FlagSerializer))] - public int Layer = (int) (CollisionGroup.MidImpassable | CollisionGroup.LowImpassable | CollisionGroup.HighImpassable); - } -} diff --git a/Content.Server/Explosion/Components/TriggerOnSignalComponent.cs b/Content.Server/Explosion/Components/TriggerOnSignalComponent.cs deleted file mode 100644 index fb7495612c7..00000000000 --- a/Content.Server/Explosion/Components/TriggerOnSignalComponent.cs +++ /dev/null @@ -1,15 +0,0 @@ -using Content.Shared.DeviceLinking; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; - -namespace Content.Server.Explosion.Components -{ - /// - /// Sends a trigger when signal is received. - /// - [RegisterComponent] - public sealed partial class TriggerOnSignalComponent : Component - { - [DataField("port", customTypeSerializer: typeof(PrototypeIdSerializer))] - public string Port = "Trigger"; - } -} diff --git a/Content.Server/Explosion/Components/TriggerOnSlipComponent.cs b/Content.Server/Explosion/Components/TriggerOnSlipComponent.cs deleted file mode 100644 index 16632b9b72b..00000000000 --- a/Content.Server/Explosion/Components/TriggerOnSlipComponent.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace Content.Server.Explosion.Components; - -[RegisterComponent] -public sealed partial class TriggerOnSlipComponent : Component -{ -} diff --git a/Content.Server/Explosion/Components/TriggerOnSpawnComponent.cs b/Content.Server/Explosion/Components/TriggerOnSpawnComponent.cs deleted file mode 100644 index 704ff410cd7..00000000000 --- a/Content.Server/Explosion/Components/TriggerOnSpawnComponent.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Content.Server.Explosion.Components; - -/// -/// calls the trigger when the object is initialized -/// -[RegisterComponent] -public sealed partial class TriggerOnSpawnComponent : Component -{ -} diff --git a/Content.Server/Explosion/Components/TriggerOnStepTriggerComponent.cs b/Content.Server/Explosion/Components/TriggerOnStepTriggerComponent.cs deleted file mode 100644 index 49e99ff7858..00000000000 --- a/Content.Server/Explosion/Components/TriggerOnStepTriggerComponent.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace Content.Server.Explosion.Components; - -/// -/// This is used for entities that want the more generic 'trigger' behavior after a step trigger occurs. -/// Not done by default, since it's not useful for everything and might cause weird behavior. But it is useful for a lot of stuff like mousetraps. -/// -[RegisterComponent] -public sealed partial class TriggerOnStepTriggerComponent : Component -{ -} diff --git a/Content.Server/Explosion/Components/TriggerOnTimedCollideComponent.cs b/Content.Server/Explosion/Components/TriggerOnTimedCollideComponent.cs deleted file mode 100644 index d53bcbcc5db..00000000000 --- a/Content.Server/Explosion/Components/TriggerOnTimedCollideComponent.cs +++ /dev/null @@ -1,18 +0,0 @@ -namespace Content.Server.Explosion.Components; - -/// -/// Triggers when the entity is overlapped for the specified duration. -/// -[RegisterComponent] -public sealed partial class TriggerOnTimedCollideComponent : Component -{ - [ViewVariables(VVAccess.ReadWrite)] - [DataField("threshold")] - public float Threshold; - - /// - /// A collection of entities that are colliding with this, and their own unique accumulator. - /// - [ViewVariables] - public readonly Dictionary Colliding = new(); -} diff --git a/Content.Server/Explosion/Components/TriggerOnUseComponent.cs b/Content.Server/Explosion/Components/TriggerOnUseComponent.cs deleted file mode 100644 index 2b44d2fbac4..00000000000 --- a/Content.Server/Explosion/Components/TriggerOnUseComponent.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace Content.Server.Explosion.Components; - -/// -/// Triggers on use in hand. -/// -[RegisterComponent] -public sealed partial class TriggerOnUseComponent : Component { } diff --git a/Content.Server/Explosion/Components/TriggerOnVoiceComponent.cs b/Content.Server/Explosion/Components/TriggerOnVoiceComponent.cs deleted file mode 100644 index 7d07f496d04..00000000000 --- a/Content.Server/Explosion/Components/TriggerOnVoiceComponent.cs +++ /dev/null @@ -1,28 +0,0 @@ -namespace Content.Server.Explosion.Components -{ - /// - /// Sends a trigger when the keyphrase is heard - /// - [RegisterComponent] - public sealed partial class TriggerOnVoiceComponent : Component - { - public bool IsListening => IsRecording || !string.IsNullOrWhiteSpace(KeyPhrase); - - [ViewVariables(VVAccess.ReadWrite)] - [DataField("keyPhrase")] - public string? KeyPhrase; - - [ViewVariables(VVAccess.ReadWrite)] - [DataField("listenRange")] - public int ListenRange { get; private set; } = 4; - - [DataField("isRecording")] - public bool IsRecording = false; - - [DataField("minLength")] - public int MinLength = 3; - - [DataField("maxLength")] - public int MaxLength = 50; - } -} diff --git a/Content.Server/Explosion/Components/TriggerWhenEmptyComponent.cs b/Content.Server/Explosion/Components/TriggerWhenEmptyComponent.cs deleted file mode 100644 index ad39b9c5153..00000000000 --- a/Content.Server/Explosion/Components/TriggerWhenEmptyComponent.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Content.Server.Explosion.Components; - -/// -/// Triggers a gun when attempting to shoot while it's empty -/// -[RegisterComponent] -public sealed partial class TriggerWhenEmptyComponent : Component -{ -} diff --git a/Content.Server/Explosion/Components/TriggerWhitelistComponent.cs b/Content.Server/Explosion/Components/TriggerWhitelistComponent.cs deleted file mode 100644 index 80becf17ccd..00000000000 --- a/Content.Server/Explosion/Components/TriggerWhitelistComponent.cs +++ /dev/null @@ -1,23 +0,0 @@ -using Content.Shared.Whitelist; - -namespace Content.Server.Explosion.Components; - -/// -/// Checks if the user of a Trigger satisfies a whitelist and blacklist condition. -/// Cancels the trigger otherwise. -/// -[RegisterComponent] -public sealed partial class TriggerWhitelistComponent : Component -{ - /// - /// Whitelist for what entites can cause this trigger. - /// - [DataField] - public EntityWhitelist? Whitelist; - - /// - /// Blacklist for what entites can cause this trigger. - /// - [DataField] - public EntityWhitelist? Blacklist; -} diff --git a/Content.Server/Explosion/EntitySystems/ProjectileGrenadeSystem.cs b/Content.Server/Explosion/EntitySystems/ProjectileGrenadeSystem.cs index e10a91463d7..26642bb6ec8 100644 --- a/Content.Server/Explosion/EntitySystems/ProjectileGrenadeSystem.cs +++ b/Content.Server/Explosion/EntitySystems/ProjectileGrenadeSystem.cs @@ -1,6 +1,7 @@ using Content.Server.Explosion.Components; using Content.Server.Weapons.Ranged.Systems; using Content.Shared.Weapons.Ranged.Components; // Imp +using Content.Shared.Trigger; using Robust.Server.GameObjects; using Robust.Shared.Containers; using Robust.Shared.Map; @@ -46,6 +47,9 @@ public sealed class ProjectileGrenadeSystem : EntitySystem /// private void OnFragTrigger(Entity entity, ref TriggerEvent args) { + if (args.Key != entity.Comp.TriggerKey) + return; + FragmentIntoProjectiles(entity.Owner, entity.Comp); args.Handled = true; } diff --git a/Content.Server/Explosion/EntitySystems/ReleaseGasOnTriggerSystem.cs b/Content.Server/Explosion/EntitySystems/ReleaseGasOnTriggerSystem.cs deleted file mode 100644 index ae3f84f8439..00000000000 --- a/Content.Server/Explosion/EntitySystems/ReleaseGasOnTriggerSystem.cs +++ /dev/null @@ -1,79 +0,0 @@ -using Content.Server.Atmos.EntitySystems; -using Content.Shared.Explosion.Components.OnTrigger; -using Content.Shared.Explosion.EntitySystems; -using Robust.Shared.Timing; - -namespace Content.Server.Explosion.EntitySystems; - -/// -/// Releases a gas mixture to the atmosphere when triggered. -/// Can also release gas over a set timespan to prevent trolling people -/// with the instant-wall-of-pressure-inator. -/// -public sealed partial class ReleaseGasOnTriggerSystem : SharedReleaseGasOnTriggerSystem -{ - [Dependency] private readonly SharedAppearanceSystem _appearance = default!; - [Dependency] private readonly AtmosphereSystem _atmosphereSystem = default!; - [Dependency] private readonly IGameTiming _timing = default!; - - public override void Initialize() - { - base.Initialize(); - - SubscribeLocalEvent(OnTrigger); - } - - /// - /// Shrimply sets the component to active when triggered, allowing it to release over time. - /// - private void OnTrigger(Entity ent, ref TriggerEvent args) - { - ent.Comp.Active = true; - ent.Comp.NextReleaseTime = _timing.CurTime; - ent.Comp.StartingTotalMoles = ent.Comp.Air.TotalMoles; - UpdateAppearance(ent.Owner, true); - } - - public override void Update(float frameTime) - { - base.Update(frameTime); - - var curTime = _timing.CurTime; - var query = EntityQueryEnumerator(); - - while (query.MoveNext(out var uid, out var comp)) - { - if (!comp.Active || comp.NextReleaseTime > curTime) - continue; - - var giverGasMix = comp.Air.Remove(comp.StartingTotalMoles * comp.RemoveFraction); - var environment = _atmosphereSystem.GetContainingMixture(uid, false, true); - - if (environment == null) - { - UpdateAppearance(uid, false); - RemCompDeferred(uid); - continue; - } - - _atmosphereSystem.Merge(environment, giverGasMix); - comp.NextReleaseTime += comp.ReleaseInterval; - - if (comp.PressureLimit != 0 && environment.Pressure >= comp.PressureLimit || - comp.Air.TotalMoles <= 0) - { - UpdateAppearance(uid, false); - RemCompDeferred(uid); - continue; - } - } - } - - private void UpdateAppearance(Entity entity, bool state) - { - if (!Resolve(entity, ref entity.Comp, false)) - return; - - _appearance.SetData(entity, ReleaseGasOnTriggerVisuals.Key, state); - } -} diff --git a/Content.Server/Explosion/EntitySystems/RepulseAttractOnTriggerSystem.cs b/Content.Server/Explosion/EntitySystems/RepulseAttractOnTriggerSystem.cs deleted file mode 100644 index 9e595c5d9e5..00000000000 --- a/Content.Server/Explosion/EntitySystems/RepulseAttractOnTriggerSystem.cs +++ /dev/null @@ -1,29 +0,0 @@ -using Content.Shared.Explosion.Components.OnTrigger; -using Content.Shared.Explosion.EntitySystems; -using Content.Shared.RepulseAttract; -using Content.Shared.Timing; - -namespace Content.Server.Explosion.EntitySystems; - -public sealed class RepulseAttractOnTriggerSystem : SharedRepulseAttractOnTriggerSystem -{ - [Dependency] private readonly RepulseAttractSystem _repulse = default!; - [Dependency] private readonly SharedTransformSystem _transform = default!; - [Dependency] private readonly UseDelaySystem _delay = default!; - - public override void Initialize() - { - base.Initialize(); - - SubscribeLocalEvent(OnTrigger); - } - - private void OnTrigger(Entity ent, ref TriggerEvent args) - { - if (_delay.IsDelayed(ent.Owner)) - return; - - var position = _transform.GetMapCoordinates(ent); - _repulse.TryRepulseAttract(position, args.User, ent.Comp.Speed, ent.Comp.Range, ent.Comp.Whitelist, ent.Comp.CollisionMask); - } -} diff --git a/Content.Server/Explosion/EntitySystems/ScatteringGrenadeSystem.cs b/Content.Server/Explosion/EntitySystems/ScatteringGrenadeSystem.cs index 2657ba34494..5f7df28beb2 100644 --- a/Content.Server/Explosion/EntitySystems/ScatteringGrenadeSystem.cs +++ b/Content.Server/Explosion/EntitySystems/ScatteringGrenadeSystem.cs @@ -1,5 +1,8 @@ using Content.Shared.Explosion.Components; using Content.Shared.Throwing; +using Content.Shared.Trigger; +using Content.Shared.Trigger.Systems; +using Content.Shared.Trigger.Components; using Robust.Server.GameObjects; using Robust.Shared.Containers; using Robust.Shared.Map; @@ -15,6 +18,7 @@ public sealed class ScatteringGrenadeSystem : SharedScatteringGrenadeSystem [Dependency] private readonly IRobustRandom _random = default!; [Dependency] private readonly ThrowingSystem _throwingSystem = default!; [Dependency] private readonly TransformSystem _transformSystem = default!; + [Dependency] private readonly TriggerSystem _trigger = default!; public override void Initialize() { @@ -30,6 +34,9 @@ public sealed class ScatteringGrenadeSystem : SharedScatteringGrenadeSystem /// private void OnScatteringTrigger(Entity entity, ref TriggerEvent args) { + if (args.Key != entity.Comp.TriggerKey) + return; + entity.Comp.IsTriggered = true; args.Handled = true; } @@ -76,13 +83,12 @@ public sealed class ScatteringGrenadeSystem : SharedScatteringGrenadeSystem _throwingSystem.TryThrow(contentUid, direction, component.Velocity); - if (component.TriggerContents) + if (component.TriggerContents && TryComp(contentUid, out var contentTimer)) { additionalIntervalDelay += _random.NextFloat(component.IntervalBetweenTriggersMin, component.IntervalBetweenTriggersMax); - var contentTimer = EnsureComp(contentUid); - contentTimer.TimeRemaining = component.DelayBeforeTriggerContents + additionalIntervalDelay; - var ev = new ActiveTimerTriggerEvent(contentUid, uid); - RaiseLocalEvent(contentUid, ref ev); + + _trigger.SetDelay((contentUid, contentTimer), TimeSpan.FromSeconds(component.DelayBeforeTriggerContents + additionalIntervalDelay)); + _trigger.ActivateTimerTrigger((contentUid, contentTimer)); } } diff --git a/Content.Server/Explosion/EntitySystems/SmokeOnTriggerSystem.cs b/Content.Server/Explosion/EntitySystems/SmokeOnTriggerSystem.cs deleted file mode 100644 index 19335d3446c..00000000000 --- a/Content.Server/Explosion/EntitySystems/SmokeOnTriggerSystem.cs +++ /dev/null @@ -1,57 +0,0 @@ -using Content.Shared.Explosion.Components; -using Content.Shared.Explosion.EntitySystems; -using Content.Server.Fluids.EntitySystems; -using Content.Server.Spreader; -using Content.Shared.Chemistry.Components; -using Content.Shared.Coordinates.Helpers; -using Content.Shared.Maps; -using Robust.Server.GameObjects; -using Robust.Shared.Map; - -namespace Content.Server.Explosion.EntitySystems; - -/// -/// Handles creating smoke when is triggered. -/// -public sealed class SmokeOnTriggerSystem : SharedSmokeOnTriggerSystem -{ - [Dependency] private readonly IMapManager _mapMan = default!; - [Dependency] private readonly SharedMapSystem _map = default!; - [Dependency] private readonly SmokeSystem _smoke = default!; - [Dependency] private readonly TransformSystem _transform = default!; - [Dependency] private readonly SpreaderSystem _spreader = default!; - [Dependency] private readonly TurfSystem _turf = default!; - - public override void Initialize() - { - base.Initialize(); - - SubscribeLocalEvent(OnTrigger); - } - - private void OnTrigger(EntityUid uid, SmokeOnTriggerComponent comp, TriggerEvent args) - { - var xform = Transform(uid); - var mapCoords = _transform.GetMapCoordinates(uid, xform); - if (!_mapMan.TryFindGridAt(mapCoords, out var gridUid, out var grid) || - !_map.TryGetTileRef(gridUid, grid, xform.Coordinates, out var tileRef) || - tileRef.Tile.IsEmpty) - { - return; - } - - if (_spreader.RequiresFloorToSpread(comp.SmokePrototype.ToString()) && _turf.IsSpace(tileRef)) - return; - - var coords = _map.MapToGrid(gridUid, mapCoords); - var ent = Spawn(comp.SmokePrototype, coords.SnapToGrid()); - if (!TryComp(ent, out var smoke)) - { - Log.Error($"Smoke prototype {comp.SmokePrototype} was missing SmokeComponent"); - Del(ent); - return; - } - - _smoke.StartSmoke(ent, comp.Solution, comp.Duration, comp.SpreadAmount, smoke); - } -} diff --git a/Content.Server/Explosion/EntitySystems/TriggerSystem.OnUse.cs b/Content.Server/Explosion/EntitySystems/TriggerSystem.OnUse.cs deleted file mode 100644 index d06e9fa1c2d..00000000000 --- a/Content.Server/Explosion/EntitySystems/TriggerSystem.OnUse.cs +++ /dev/null @@ -1,170 +0,0 @@ -using Content.Server.Explosion.Components; -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; - -public sealed partial class TriggerSystem -{ - [Dependency] private readonly SharedPopupSystem _popupSystem = default!; - - private void InitializeOnUse() - { - SubscribeLocalEvent(OnTimerUse); - SubscribeLocalEvent(OnExamined); - SubscribeLocalEvent>(OnGetAltVerbs); - SubscribeLocalEvent(OnStuck); - SubscribeLocalEvent(OnRandomTimerTriggerMapInit); - } - - private void OnStuck(EntityUid uid, OnUseTimerTriggerComponent component, ref EntityStuckEvent args) - { - if (!component.StartOnStick) - return; - - StartTimer((uid, component), args.User); - } - - private void OnExamined(EntityUid uid, OnUseTimerTriggerComponent component, ExaminedEvent args) - { - if (args.IsInDetailsRange && component.Examinable) - args.PushText(Loc.GetString("examine-trigger-timer", ("time", component.Delay))); - } - - /// - /// Add an alt-click interaction that cycles through delays. - /// - private void OnGetAltVerbs(EntityUid uid, OnUseTimerTriggerComponent component, GetVerbsEvent args) - { - if (!args.CanInteract || !args.CanAccess || args.Hands == null) - return; - - if (component.UseVerbInstead) - { - args.Verbs.Add(new AlternativeVerb() - { - Text = Loc.GetString("verb-start-detonation"), - Act = () => StartTimer((uid, component), args.User), - Priority = 2 - }); - } - - if (component.AllowToggleStartOnStick) - { - args.Verbs.Add(new AlternativeVerb() - { - Text = Loc.GetString("verb-toggle-start-on-stick"), - Act = () => ToggleStartOnStick(uid, args.User, component) - }); - } - - if (component.DelayOptions == null || component.DelayOptions.Count == 1) - return; - - args.Verbs.Add(new AlternativeVerb() - { - Category = TimerOptions, - Text = Loc.GetString("verb-trigger-timer-cycle"), - Act = () => CycleDelay(component, args.User), - Priority = 1 - }); - - foreach (var option in component.DelayOptions) - { - if (MathHelper.CloseTo(option, component.Delay)) - { - args.Verbs.Add(new AlternativeVerb() - { - Category = TimerOptions, - Text = Loc.GetString("verb-trigger-timer-set-current", ("time", option)), - Disabled = true, - Priority = (int) (-100 * option) - }); - continue; - } - - args.Verbs.Add(new AlternativeVerb() - { - Category = TimerOptions, - Text = Loc.GetString("verb-trigger-timer-set", ("time", option)), - Priority = (int) (-100 * option), - - Act = () => - { - component.Delay = option; - _popupSystem.PopupEntity(Loc.GetString("popup-trigger-timer-set", ("time", option)), args.User, args.User); - }, - }); - } - } - - private void OnRandomTimerTriggerMapInit(Entity ent, ref MapInitEvent args) - { - var (_, comp) = ent; - - if (!TryComp(ent, out var timerTriggerComp)) - return; - - timerTriggerComp.Delay = _random.NextFloat(comp.Min, comp.Max); - } - - private void CycleDelay(OnUseTimerTriggerComponent component, EntityUid user) - { - if (component.DelayOptions == null || component.DelayOptions.Count == 1) - return; - - // This is somewhat inefficient, but its good enough. This is run rarely, and the lists should be short. - - component.DelayOptions.Sort(); - - if (component.DelayOptions[^1] <= component.Delay) - { - component.Delay = component.DelayOptions[0]; - _popupSystem.PopupEntity(Loc.GetString("popup-trigger-timer-set", ("time", component.Delay)), user, user); - return; - } - - foreach (var option in component.DelayOptions) - { - if (option > component.Delay) - { - component.Delay = option; - _popupSystem.PopupEntity(Loc.GetString("popup-trigger-timer-set", ("time", option)), user, user); - return; - } - } - } - - private void ToggleStartOnStick(EntityUid grenade, EntityUid user, OnUseTimerTriggerComponent comp) - { - if (comp.StartOnStick) - { - comp.StartOnStick = false; - _popupSystem.PopupEntity(Loc.GetString("popup-start-on-stick-off"), grenade, user); - } - else - { - comp.StartOnStick = true; - _popupSystem.PopupEntity(Loc.GetString("popup-start-on-stick-on"), grenade, user); - } - } - - private void OnTimerUse(EntityUid uid, OnUseTimerTriggerComponent component, UseInHandEvent args) - { - if (args.Handled || HasComp(uid) || component.UseVerbInstead) - return; - - if (component.DoPopup) - _popupSystem.PopupEntity(Loc.GetString("trigger-activated", ("device", uid)), args.User, args.User); - - StartTimer((uid, component), args.User); - - args.Handled = true; - } - - public static VerbCategory TimerOptions = new("verb-categories-timer", "/Textures/Interface/VerbIcons/clock.svg.192dpi.png"); -} diff --git a/Content.Server/Explosion/EntitySystems/TriggerSystem.Proximity.cs b/Content.Server/Explosion/EntitySystems/TriggerSystem.Proximity.cs deleted file mode 100644 index 426bade10e9..00000000000 --- a/Content.Server/Explosion/EntitySystems/TriggerSystem.Proximity.cs +++ /dev/null @@ -1,154 +0,0 @@ -using Content.Server.Explosion.Components; -using Content.Shared.Trigger; -using Robust.Shared.Physics.Components; -using Robust.Shared.Physics.Events; -using Robust.Shared.Utility; -using Robust.Shared.Timing; - -namespace Content.Server.Explosion.EntitySystems; - -public sealed partial class TriggerSystem -{ - [Dependency] private readonly IGameTiming _timing = default!; - [Dependency] private readonly SharedAppearanceSystem _appearance = default!; - - private void InitializeProximity() - { - SubscribeLocalEvent(OnProximityStartCollide); - SubscribeLocalEvent(OnProximityEndCollide); - SubscribeLocalEvent(OnMapInit); - SubscribeLocalEvent(OnProximityShutdown); - // Shouldn't need re-anchoring. - SubscribeLocalEvent(OnProximityAnchor); - } - - private void OnProximityAnchor(EntityUid uid, TriggerOnProximityComponent component, ref AnchorStateChangedEvent args) - { - component.Enabled = !component.RequiresAnchored || - args.Anchored; - - SetProximityAppearance(uid, component); - - if (!component.Enabled) - { - component.Colliding.Clear(); - } - // Re-check for contacts as we cleared them. - else if (TryComp(uid, out var body)) - { - _broadphase.RegenerateContacts((uid, body)); - } - } - - private void OnProximityShutdown(EntityUid uid, TriggerOnProximityComponent component, ComponentShutdown args) - { - component.Colliding.Clear(); - } - - private void OnMapInit(EntityUid uid, TriggerOnProximityComponent component, MapInitEvent args) - { - component.Enabled = !component.RequiresAnchored || - Transform(uid).Anchored; - - SetProximityAppearance(uid, component); - - if (!TryComp(uid, out var body)) - return; - - _fixtures.TryCreateFixture( - uid, - component.Shape, - TriggerOnProximityComponent.FixtureID, - hard: false, - body: body, - collisionLayer: component.Layer); - } - - private void OnProximityStartCollide(EntityUid uid, TriggerOnProximityComponent component, ref StartCollideEvent args) - { - if (args.OurFixtureId != TriggerOnProximityComponent.FixtureID) - return; - - component.Colliding[args.OtherEntity] = args.OtherBody; - } - - private static void OnProximityEndCollide(EntityUid uid, TriggerOnProximityComponent component, ref EndCollideEvent args) - { - if (args.OurFixtureId != TriggerOnProximityComponent.FixtureID) - return; - - component.Colliding.Remove(args.OtherEntity); - } - - private void SetProximityAppearance(EntityUid uid, TriggerOnProximityComponent component) - { - if (TryComp(uid, out AppearanceComponent? appearance)) - { - _appearance.SetData(uid, ProximityTriggerVisualState.State, component.Enabled ? ProximityTriggerVisuals.Inactive : ProximityTriggerVisuals.Off, appearance); - } - } - - private void Activate(EntityUid uid, EntityUid user, TriggerOnProximityComponent component) - { - DebugTools.Assert(component.Enabled); - - var curTime = _timing.CurTime; - - if (!component.Repeating) - { - component.Enabled = false; - component.Colliding.Clear(); - } - else - { - component.NextTrigger = curTime + component.Cooldown; - } - - // Queue a visual update for when the animation is complete. - component.NextVisualUpdate = curTime + component.AnimationDuration; - - if (TryComp(uid, out AppearanceComponent? appearance)) - { - _appearance.SetData(uid, ProximityTriggerVisualState.State, ProximityTriggerVisuals.Active, appearance); - } - - Trigger(uid, user); - } - - private void UpdateProximity() - { - var curTime = _timing.CurTime; - - var query = EntityQueryEnumerator(); - while (query.MoveNext(out var uid, out var trigger)) - { - if (curTime >= trigger.NextVisualUpdate) - { - // Update the visual state once the animation is done. - trigger.NextVisualUpdate = TimeSpan.MaxValue; - SetProximityAppearance(uid, trigger); - } - - if (!trigger.Enabled) - continue; - - if (curTime < trigger.NextTrigger) - // The trigger's on cooldown. - continue; - - // Check for anything colliding and moving fast enough. - foreach (var (collidingUid, colliding) in trigger.Colliding) - { - if (Deleted(collidingUid)) - continue; - - if (colliding.LinearVelocity.Length() < trigger.TriggerSpeed) - continue; - - // Trigger! - Activate(uid, collidingUid, trigger); - break; - } - } - } -} diff --git a/Content.Server/Explosion/EntitySystems/TriggerSystem.Signal.cs b/Content.Server/Explosion/EntitySystems/TriggerSystem.Signal.cs deleted file mode 100644 index 99e8c97d53a..00000000000 --- a/Content.Server/Explosion/EntitySystems/TriggerSystem.Signal.cs +++ /dev/null @@ -1,43 +0,0 @@ -using Content.Server.DeviceLinking.Systems; -using Content.Server.Explosion.Components; -using Content.Shared.DeviceLinking.Events; - -namespace Content.Server.Explosion.EntitySystems -{ - public sealed partial class TriggerSystem - { - [Dependency] private readonly DeviceLinkSystem _signalSystem = default!; - private void InitializeSignal() - { - SubscribeLocalEvent(OnSignalReceived); - SubscribeLocalEvent(OnInit); - - SubscribeLocalEvent(OnTimerSignalReceived); - SubscribeLocalEvent(OnTimerSignalInit); - } - - private void OnSignalReceived(EntityUid uid, TriggerOnSignalComponent component, ref SignalReceivedEvent args) - { - if (args.Port != component.Port) - return; - - Trigger(uid, args.Trigger); - } - private void OnInit(EntityUid uid, TriggerOnSignalComponent component, ComponentInit args) - { - _signalSystem.EnsureSinkPorts(uid, component.Port); - } - - private void OnTimerSignalReceived(EntityUid uid, TimerStartOnSignalComponent component, ref SignalReceivedEvent args) - { - if (args.Port != component.Port) - return; - - StartTimer(uid, args.Trigger); - } - private void OnTimerSignalInit(EntityUid uid, TimerStartOnSignalComponent component, ComponentInit args) - { - _signalSystem.EnsureSinkPorts(uid, component.Port); - } - } -} diff --git a/Content.Server/Explosion/EntitySystems/TriggerSystem.TimedCollide.cs b/Content.Server/Explosion/EntitySystems/TriggerSystem.TimedCollide.cs deleted file mode 100644 index ea10b7c69b3..00000000000 --- a/Content.Server/Explosion/EntitySystems/TriggerSystem.TimedCollide.cs +++ /dev/null @@ -1,59 +0,0 @@ -using System.Linq; -using Content.Server.Explosion.Components; -using Content.Server.Explosion.EntitySystems; -using Robust.Shared.Physics.Dynamics; -using Robust.Shared.Physics.Events; - -namespace Content.Server.Explosion.EntitySystems; - -public sealed partial class TriggerSystem -{ - private void InitializeTimedCollide() - { - SubscribeLocalEvent(OnTimerCollide); - SubscribeLocalEvent(OnTimerEndCollide); - SubscribeLocalEvent(OnComponentRemove); - } - - private void OnTimerCollide(EntityUid uid, TriggerOnTimedCollideComponent component, ref StartCollideEvent args) - { - //Ensures the entity trigger will have an active component - EnsureComp(uid); - var otherUID = args.OtherEntity; - if (component.Colliding.ContainsKey(otherUID)) - return; - component.Colliding.Add(otherUID, 0); - } - - private void OnTimerEndCollide(EntityUid uid, TriggerOnTimedCollideComponent component, ref EndCollideEvent args) - { - var otherUID = args.OtherEntity; - component.Colliding.Remove(otherUID); - - if (component.Colliding.Count == 0 && HasComp(uid)) - RemComp(uid); - } - - private void OnComponentRemove(EntityUid uid, TriggerOnTimedCollideComponent component, ComponentRemove args) - { - if (HasComp(uid)) - RemComp(uid); - } - - private void UpdateTimedCollide(float frameTime) - { - var query = EntityQueryEnumerator(); - while (query.MoveNext(out var uid, out _, out var triggerOnTimedCollide)) - { - foreach (var (collidingEntity, collidingTimer) in triggerOnTimedCollide.Colliding) - { - triggerOnTimedCollide.Colliding[collidingEntity] += frameTime; - if (collidingTimer > triggerOnTimedCollide.Threshold) - { - RaiseLocalEvent(uid, new TriggerEvent(uid, collidingEntity), true); - triggerOnTimedCollide.Colliding[collidingEntity] -= triggerOnTimedCollide.Threshold; - } - } - } - } -} diff --git a/Content.Server/Explosion/EntitySystems/TriggerSystem.Voice.cs b/Content.Server/Explosion/EntitySystems/TriggerSystem.Voice.cs deleted file mode 100644 index a96508e37cb..00000000000 --- a/Content.Server/Explosion/EntitySystems/TriggerSystem.Voice.cs +++ /dev/null @@ -1,154 +0,0 @@ -using Content.Server.Explosion.Components; -using Content.Server.Speech; -using Content.Server.Speech.Components; -using Content.Shared.Database; -using Content.Shared.Examine; -using Content.Shared.Verbs; - -namespace Content.Server.Explosion.EntitySystems -{ - public sealed partial class TriggerSystem - { - private void InitializeVoice() - { - SubscribeLocalEvent(OnVoiceInit); - SubscribeLocalEvent(OnVoiceExamine); - SubscribeLocalEvent>(OnVoiceGetAltVerbs); - SubscribeLocalEvent(OnListen); - } - - private void OnVoiceInit(EntityUid uid, TriggerOnVoiceComponent component, ComponentInit args) - { - if (component.IsListening) - EnsureComp(uid).Range = component.ListenRange; - else - RemCompDeferred(uid); - } - - private void OnListen(Entity ent, ref ListenEvent args) - { - var component = ent.Comp; - var message = args.Message.Trim(); - - if (component.IsRecording) - { - var ev = new ListenAttemptEvent(args.Source); - RaiseLocalEvent(ent, ev); - - if (ev.Cancelled) - return; - - if (message.Length >= component.MinLength && message.Length <= component.MaxLength) - FinishRecording(ent, args.Source, args.Message); - else if (message.Length > component.MaxLength) - _popupSystem.PopupEntity(Loc.GetString("popup-trigger-voice-record-failed-too-long"), ent); - else if (message.Length < component.MinLength) - _popupSystem.PopupEntity(Loc.GetString("popup-trigger-voice-record-failed-too-short"), ent); - - return; - } - - if (!string.IsNullOrWhiteSpace(component.KeyPhrase) && message.IndexOf(component.KeyPhrase, StringComparison.InvariantCultureIgnoreCase) is var index and >= 0 ) - { - _adminLogger.Add(LogType.Trigger, LogImpact.Medium, - $"A voice-trigger on {ToPrettyString(ent):entity} was triggered by {ToPrettyString(args.Source):speaker} speaking the key-phrase {component.KeyPhrase}."); - Trigger(ent, args.Source); - - var messageWithoutPhrase = message.Remove(index, component.KeyPhrase.Length).Trim(); - - var voice = new VoiceTriggeredEvent(args.Source, message, messageWithoutPhrase); - RaiseLocalEvent(ent, ref voice); - } - } - - private void OnVoiceGetAltVerbs(Entity ent, ref GetVerbsEvent args) - { - if (!args.CanInteract || !args.CanAccess) - return; - - var component = ent.Comp; - - var @event = args; - args.Verbs.Add(new AlternativeVerb() - { - Text = Loc.GetString(component.IsRecording ? "verb-trigger-voice-stop" : "verb-trigger-voice-record"), - Act = () => - { - if (component.IsRecording) - StopRecording(ent); - else - StartRecording(ent, @event.User); - }, - Priority = 1 - }); - - if (string.IsNullOrWhiteSpace(component.KeyPhrase)) - return; - - args.Verbs.Add(new AlternativeVerb() - { - Text = Loc.GetString("verb-trigger-voice-clear"), - Act = () => - { - component.KeyPhrase = null; - component.IsRecording = false; - RemComp(ent); - } - }); - } - - public void StartRecording(Entity ent, EntityUid user) - { - var component = ent.Comp; - component.IsRecording = true; - EnsureComp(ent).Range = component.ListenRange; - - _adminLogger.Add(LogType.Trigger, LogImpact.Low, - $"A voice-trigger on {ToPrettyString(ent):entity} has started recording. User: {ToPrettyString(user):user}"); - - _popupSystem.PopupEntity(Loc.GetString("popup-trigger-voice-start-recording"), ent); - } - - public void StopRecording(Entity ent) - { - var component = ent.Comp; - component.IsRecording = false; - if (string.IsNullOrWhiteSpace(component.KeyPhrase)) - RemComp(ent); - - _popupSystem.PopupEntity(Loc.GetString("popup-trigger-voice-stop-recording"), ent); - } - - public void FinishRecording(Entity ent, EntityUid source, string message) - { - var component = ent.Comp; - component.KeyPhrase = message; - component.IsRecording = false; - - _adminLogger.Add(LogType.Trigger, LogImpact.Low, - $"A voice-trigger on {ToPrettyString(ent):entity} has recorded a new keyphrase: '{component.KeyPhrase}'. Recorded from {ToPrettyString(source):speaker}"); - - _popupSystem.PopupEntity(Loc.GetString("popup-trigger-voice-recorded", ("keyphrase", component.KeyPhrase!)), ent); - } - - private void OnVoiceExamine(EntityUid uid, TriggerOnVoiceComponent component, ExaminedEvent args) - { - if (args.IsInDetailsRange) - { - args.PushText(string.IsNullOrWhiteSpace(component.KeyPhrase) - ? Loc.GetString("trigger-voice-uninitialized") - : Loc.GetString("examine-trigger-voice", ("keyphrase", component.KeyPhrase))); - } - } - } -} - - -/// -/// Raised when a voice trigger is activated, containing the message that triggered it. -/// -/// The EntityUid of the entity sending the message -/// The contents of the message -/// The message without the phrase that triggered it. -[ByRefEvent] -public readonly record struct VoiceTriggeredEvent(EntityUid Source, string Message, string MessageWithoutPhrase); diff --git a/Content.Server/Explosion/EntitySystems/TriggerSystem.cs b/Content.Server/Explosion/EntitySystems/TriggerSystem.cs deleted file mode 100644 index 7be83252fc6..00000000000 --- a/Content.Server/Explosion/EntitySystems/TriggerSystem.cs +++ /dev/null @@ -1,447 +0,0 @@ -using Content.Server.Administration.Logs; -using Content.Server.Body.Systems; -using Content.Server.Explosion.Components; -using Content.Shared.Flash; -using Content.Server.Electrocution; -using Content.Server.Pinpointer; -using Content.Shared.Chemistry.EntitySystems; -using Content.Shared.Flash.Components; -using Content.Server.Radio.EntitySystems; -using Content.Shared.Chemistry.Components; -using Content.Shared.Chemistry.Components.SolutionManager; -using Content.Shared.Database; -using Content.Shared.Explosion.Components; -using Content.Shared.Explosion.Components.OnTrigger; -using Content.Shared.Implants.Components; -using Content.Shared.Interaction; -using Content.Shared.Interaction.Events; -using Content.Shared.Inventory; -using Content.Shared.Mobs; -using Content.Shared.Mobs.Components; -using Content.Shared.Payload.Components; -using Content.Shared.Radio; -using Content.Shared.Slippery; -using Content.Shared.StepTrigger.Systems; -using Content.Shared.Trigger; -using Content.Shared.Weapons.Ranged.Events; -using Content.Shared.Whitelist; -using JetBrains.Annotations; -using Robust.Shared.Audio; -using Robust.Shared.Audio.Systems; -using Robust.Shared.Containers; -using Robust.Shared.Physics.Events; -using Robust.Shared.Physics.Systems; -using Robust.Shared.Prototypes; -using Robust.Shared.Random; -using Robust.Shared.Utility; - -namespace Content.Server.Explosion.EntitySystems -{ - /// - /// Raised whenever something is Triggered on the entity. - /// - public sealed class TriggerEvent : HandledEntityEventArgs - { - public EntityUid Triggered { get; } - public EntityUid? User { get; } - - public TriggerEvent(EntityUid triggered, EntityUid? user = null) - { - Triggered = triggered; - User = user; - } - } - - /// - /// Raised before a trigger is activated. - /// - [ByRefEvent] - public record struct BeforeTriggerEvent(EntityUid Triggered, EntityUid? User, bool Cancelled = false); - - /// - /// Raised when timer trigger becomes active. - /// - [ByRefEvent] - public readonly record struct ActiveTimerTriggerEvent(EntityUid Triggered, EntityUid? User); - - [UsedImplicitly] - public sealed partial class TriggerSystem : EntitySystem - { - [Dependency] private readonly ExplosionSystem _explosions = default!; - [Dependency] private readonly FixtureSystem _fixtures = default!; - [Dependency] private readonly SharedFlashSystem _flashSystem = default!; - [Dependency] private readonly SharedBroadphaseSystem _broadphase = default!; - [Dependency] private readonly IAdminLogManager _adminLogger = default!; - [Dependency] private readonly SharedContainerSystem _container = default!; - [Dependency] private readonly BodySystem _body = default!; - [Dependency] private readonly SharedAudioSystem _audio = default!; - [Dependency] private readonly SharedTransformSystem _transformSystem = default!; - [Dependency] private readonly NavMapSystem _navMap = default!; - [Dependency] private readonly RadioSystem _radioSystem = default!; - [Dependency] private readonly IRobustRandom _random = default!; - [Dependency] private readonly IPrototypeManager _prototypeManager = default!; - [Dependency] private readonly SharedSolutionContainerSystem _solutionContainerSystem = default!; - [Dependency] private readonly InventorySystem _inventory = default!; - [Dependency] private readonly ElectrocutionSystem _electrocution = default!; - [Dependency] private readonly EntityWhitelistSystem _whitelist = default!; - - public override void Initialize() - { - base.Initialize(); - - InitializeProximity(); - InitializeOnUse(); - InitializeSignal(); - InitializeTimedCollide(); - InitializeVoice(); - InitializeMobstate(); - - SubscribeLocalEvent(OnSpawnTriggered); - SubscribeLocalEvent(OnTriggerCollide); - SubscribeLocalEvent(OnActivate); - SubscribeLocalEvent(OnUse); - SubscribeLocalEvent(OnImplantTrigger); - SubscribeLocalEvent(OnStepTriggered); - SubscribeLocalEvent(OnSlipTriggered); - SubscribeLocalEvent(OnEmptyTriggered); - SubscribeLocalEvent(OnRepeatInit); - - SubscribeLocalEvent(OnSpawnTrigger); - SubscribeLocalEvent(HandleDeleteTrigger); - SubscribeLocalEvent(HandleExplodeTrigger); - SubscribeLocalEvent(HandleFlashTrigger); - SubscribeLocalEvent(HandleGibTrigger); - - SubscribeLocalEvent(OnAnchorTrigger); - SubscribeLocalEvent(OnSoundTrigger); - SubscribeLocalEvent(HandleShockTrigger); - SubscribeLocalEvent(HandleRattleTrigger); - - SubscribeLocalEvent(HandleWhitelist); - } - - private void HandleWhitelist(Entity ent, ref BeforeTriggerEvent args) - { - args.Cancelled = !_whitelist.CheckBoth(args.User, ent.Comp.Blacklist, ent.Comp.Whitelist); - } - - private void OnSoundTrigger(EntityUid uid, SoundOnTriggerComponent component, TriggerEvent args) - { - if (component.RemoveOnTrigger) // if the component gets removed when it's triggered - { - var xform = Transform(uid); - _audio.PlayPvs(component.Sound, xform.Coordinates); // play the sound at its last known coordinates - } - else // if the component doesn't get removed when triggered - { - _audio.PlayPvs(component.Sound, uid); // have the sound follow the entity itself - } - } - - private void HandleShockTrigger(Entity shockOnTrigger, ref TriggerEvent args) - { - if (!_container.TryGetContainingContainer(shockOnTrigger.Owner, out var container)) - return; - - var containerEnt = container.Owner; - var curTime = _timing.CurTime; - - if (curTime < shockOnTrigger.Comp.NextTrigger) - { - // The trigger's on cooldown. - return; - } - - _electrocution.TryDoElectrocution(containerEnt, null, shockOnTrigger.Comp.Damage, shockOnTrigger.Comp.Duration, true, ignoreInsulation: true); - shockOnTrigger.Comp.NextTrigger = curTime + shockOnTrigger.Comp.Cooldown; - } - - private void OnAnchorTrigger(EntityUid uid, AnchorOnTriggerComponent component, TriggerEvent args) - { - var xform = Transform(uid); - - if (xform.Anchored) - return; - - _transformSystem.AnchorEntity(uid, xform); - - if (component.RemoveOnTrigger) - RemCompDeferred(uid); - } - - private void OnSpawnTrigger(Entity ent, ref TriggerEvent args) - { - var xform = Transform(ent); - - if (ent.Comp.mapCoords) - { - var mapCoords = _transformSystem.GetMapCoordinates(ent, xform); - Spawn(ent.Comp.Proto, mapCoords); - } - else - { - var coords = xform.Coordinates; - if (!coords.IsValid(EntityManager)) - return; - Spawn(ent.Comp.Proto, coords); - - } - } - - private void HandleExplodeTrigger(EntityUid uid, ExplodeOnTriggerComponent component, TriggerEvent args) - { - _explosions.TriggerExplosive(uid, user: args.User); - args.Handled = true; - } - - private void HandleFlashTrigger(EntityUid uid, FlashOnTriggerComponent component, TriggerEvent args) - { - _flashSystem.FlashArea(uid, args.User, component.Range, component.Duration, probability: component.Probability); - args.Handled = true; - } - - private void HandleDeleteTrigger(EntityUid uid, DeleteOnTriggerComponent component, TriggerEvent args) - { - QueueDel(uid); - args.Handled = true; - } - - private void HandleGibTrigger(EntityUid uid, GibOnTriggerComponent component, TriggerEvent args) - { - if (!TryComp(uid, out TransformComponent? xform)) - return; - _body.GibBody(xform.ParentUid, true); - args.Handled = true; - } - - - private void HandleRattleTrigger(EntityUid uid, RattleComponent component, TriggerEvent args) - { - if (!TryComp(uid, out var implanted)) - return; - - if (implanted.ImplantedEntity == null) - return; - - // Gets location of the implant - var position = _transformSystem.GetMapCoordinates(Transform(uid)).Position; // DeltaV - var posText = FormattedMessage.RemoveMarkupOrThrow(_navMap.GetNearestBeaconString(uid) + $" ({(int)position[0]}, {(int)position[1]})"); // DeltaV modified, adds the GPS coordinates on the message. - var critMessage = Loc.GetString(component.CritMessage, ("user", implanted.ImplantedEntity.Value), ("position", posText)); - var deathMessage = Loc.GetString(component.DeathMessage, ("user", implanted.ImplantedEntity.Value), ("position", posText)); - - if (!TryComp(implanted.ImplantedEntity, out var mobstate)) - return; - - // Sends a message to the radio channel specified by the implant - if (mobstate.CurrentState == MobState.Critical) - _radioSystem.SendRadioMessage(uid, critMessage, _prototypeManager.Index(component.RadioChannel), uid); - if (mobstate.CurrentState == MobState.Dead) - _radioSystem.SendRadioMessage(uid, deathMessage, _prototypeManager.Index(component.RadioChannel), uid); - - args.Handled = true; - } - - private void OnTriggerCollide(EntityUid uid, TriggerOnCollideComponent component, ref StartCollideEvent args) - { - if (args.OurFixtureId == component.FixtureID && (!component.IgnoreOtherNonHard || args.OtherFixture.Hard)) - Trigger(uid, args.OtherEntity); - } - - private void OnSpawnTriggered(EntityUid uid, TriggerOnSpawnComponent component, MapInitEvent args) - { - Trigger(uid); - } - - private void OnActivate(EntityUid uid, TriggerOnActivateComponent component, ActivateInWorldEvent args) - { - if (args.Handled || !args.Complex) - return; - - Trigger(uid, args.User); - args.Handled = true; - } - - private void OnUse(Entity ent, ref UseInHandEvent args) - { - if (args.Handled) - return; - - Trigger(ent.Owner, args.User); - args.Handled = true; - } - - private void OnImplantTrigger(EntityUid uid, TriggerImplantActionComponent component, ActivateImplantEvent args) - { - args.Handled = Trigger(uid); - } - - private void OnStepTriggered(EntityUid uid, TriggerOnStepTriggerComponent component, ref StepTriggeredOffEvent args) - { - Trigger(uid, args.Tripper); - } - - private void OnSlipTriggered(EntityUid uid, TriggerOnSlipComponent component, ref SlipEvent args) - { - Trigger(uid, args.Slipped); - } - - private void OnEmptyTriggered(EntityUid uid, TriggerWhenEmptyComponent component, ref OnEmptyGunShotEvent args) - { - Trigger(uid, args.EmptyGun); - } - - private void OnRepeatInit(Entity ent, ref MapInitEvent args) - { - ent.Comp.NextTrigger = _timing.CurTime + ent.Comp.Delay; - } - - public bool Trigger(EntityUid trigger, EntityUid? user = null) - { - var beforeTriggerEvent = new BeforeTriggerEvent(trigger, user); - RaiseLocalEvent(trigger, ref beforeTriggerEvent); - if (beforeTriggerEvent.Cancelled) - return false; - - var triggerEvent = new TriggerEvent(trigger, user); - EntityManager.EventBus.RaiseLocalEvent(trigger, triggerEvent, true); - return triggerEvent.Handled; - } - - public void TryDelay(EntityUid uid, float amount, ActiveTimerTriggerComponent? comp = null) - { - if (!Resolve(uid, ref comp, false)) - return; - - comp.TimeRemaining += amount; - } - - /// - /// Start the timer for triggering the device. - /// - public void StartTimer(Entity ent, EntityUid? user) - { - if (!Resolve(ent, ref ent.Comp, false)) - return; - - var comp = ent.Comp; - HandleTimerTrigger(ent, user, comp.Delay, comp.BeepInterval, comp.InitialBeepDelay, comp.BeepSound); - } - - public void HandleTimerTrigger(EntityUid uid, EntityUid? user, float delay, float beepInterval, float? initialBeepDelay, SoundSpecifier? beepSound) - { - if (delay <= 0) - { - RemComp(uid); - Trigger(uid, user); - return; - } - - if (HasComp(uid)) - return; - - if (user != null) - { - // Check if entity is bomb/mod. grenade/etc - if (_container.TryGetContainer(uid, "payload", out BaseContainer? container) && - container.ContainedEntities.Count > 0 && - TryComp(container.ContainedEntities[0], out ChemicalPayloadComponent? chemicalPayloadComponent)) - { - // If a beaker is missing, the entity won't explode, so no reason to log it - if (chemicalPayloadComponent?.BeakerSlotA.Item is not { } beakerA || - chemicalPayloadComponent?.BeakerSlotB.Item is not { } beakerB || - !TryComp(beakerA, out SolutionContainerManagerComponent? containerA) || - !TryComp(beakerB, out SolutionContainerManagerComponent? containerB) || - !TryComp(beakerA, out FitsInDispenserComponent? fitsA) || - !TryComp(beakerB, out FitsInDispenserComponent? fitsB) || - !_solutionContainerSystem.TryGetSolution((beakerA, containerA), fitsA.Solution, out _, out var solutionA) || - !_solutionContainerSystem.TryGetSolution((beakerB, containerB), fitsB.Solution, out _, out var solutionB)) - return; - - _adminLogger.Add(LogType.Trigger, - $"{ToPrettyString(user.Value):user} started a {delay} second timer trigger on entity {ToPrettyString(uid):timer}, which contains {SharedSolutionContainerSystem.ToPrettyString(solutionA)} in one beaker and {SharedSolutionContainerSystem.ToPrettyString(solutionB)} in the other."); - } - else - { - _adminLogger.Add(LogType.Trigger, - $"{ToPrettyString(user.Value):user} started a {delay} second timer trigger on entity {ToPrettyString(uid):timer}"); - } - - } - else - { - _adminLogger.Add(LogType.Trigger, - $"{delay} second timer trigger started on entity {ToPrettyString(uid):timer}"); - } - - var active = AddComp(uid); - active.TimeRemaining = delay; - active.User = user; - active.BeepSound = beepSound; - active.BeepInterval = beepInterval; - active.TimeUntilBeep = initialBeepDelay == null ? active.BeepInterval : initialBeepDelay.Value; - - var ev = new ActiveTimerTriggerEvent(uid, user); - RaiseLocalEvent(uid, ref ev); - - if (TryComp(uid, out var appearance)) - _appearance.SetData(uid, TriggerVisuals.VisualState, TriggerVisualState.Primed, appearance); - } - - public override void Update(float frameTime) - { - base.Update(frameTime); - - UpdateProximity(); - UpdateTimer(frameTime); - UpdateTimedCollide(frameTime); - UpdateRepeat(); - } - - private void UpdateTimer(float frameTime) - { - HashSet toRemove = new(); - var query = EntityQueryEnumerator(); - while (query.MoveNext(out var uid, out var timer)) - { - timer.TimeRemaining -= frameTime; - timer.TimeUntilBeep -= frameTime; - - if (timer.TimeRemaining <= 0) - { - Trigger(uid, timer.User); - toRemove.Add(uid); - continue; - } - - if (timer.BeepSound == null || timer.TimeUntilBeep > 0) - continue; - - timer.TimeUntilBeep += timer.BeepInterval; - _audio.PlayPvs(timer.BeepSound, uid, timer.BeepSound.Params); - } - - foreach (var uid in toRemove) - { - RemComp(uid); - - // In case this is a re-usable grenade, un-prime it. - if (TryComp(uid, out var appearance)) - _appearance.SetData(uid, TriggerVisuals.VisualState, TriggerVisualState.Unprimed, appearance); - } - } - - private void UpdateRepeat() - { - var now = _timing.CurTime; - var query = EntityQueryEnumerator(); - while (query.MoveNext(out var uid, out var comp)) - { - if (comp.NextTrigger > now) - continue; - - comp.NextTrigger = now + comp.Delay; - Trigger(uid); - } - } - } -} diff --git a/Content.Server/Explosion/EntitySystems/TwoStageTriggerSystem.cs b/Content.Server/Explosion/EntitySystems/TwoStageTriggerSystem.cs deleted file mode 100644 index 8488fd14bbd..00000000000 --- a/Content.Server/Explosion/EntitySystems/TwoStageTriggerSystem.cs +++ /dev/null @@ -1,64 +0,0 @@ -using Robust.Shared.Timing; -using Robust.Shared.Serialization.Manager; -using Content.Server.Explosion.Components.OnTrigger; - -namespace Content.Server.Explosion.EntitySystems; - -public sealed class TwoStageTriggerSystem : EntitySystem -{ - [Dependency] private readonly IGameTiming _timing = default!; - [Dependency] private readonly ISerializationManager _serializationManager = default!; - [Dependency] private readonly TriggerSystem _triggerSystem = default!; - - public override void Initialize() - { - base.Initialize(); - SubscribeLocalEvent(OnTrigger); - } - - private void OnTrigger(EntityUid uid, TwoStageTriggerComponent component, TriggerEvent args) - { - if (component.Triggered) - return; - - component.Triggered = true; - component.NextTriggerTime = _timing.CurTime + component.TriggerDelay; - } - - private void LoadComponents(EntityUid uid, TwoStageTriggerComponent component) - { - foreach (var (name, entry) in component.SecondStageComponents) - { - var comp = (Component) Factory.GetComponent(name); - var temp = (object)comp; - - if (EntityManager.TryGetComponent(uid, entry.Component.GetType(), out var c)) - RemComp(uid, c); - - _serializationManager.CopyTo(entry.Component, ref temp); - AddComp(uid, comp); - } - component.ComponentsIsLoaded = true; - } - - public override void Update(float frameTime) - { - base.Update(frameTime); - - var enumerator = EntityQueryEnumerator(); - while (enumerator.MoveNext(out var uid, out var component)) - { - if (!component.Triggered) - continue; - - if (!component.ComponentsIsLoaded) - LoadComponents(uid, component); - - if (_timing.CurTime < component.NextTriggerTime) - continue; - - component.NextTriggerTime = null; - _triggerSystem.Trigger(uid); - } - } -} diff --git a/Content.Server/GhostKick/GhostKickUserOnTriggerComponent.cs b/Content.Server/GhostKick/GhostKickUserOnTriggerComponent.cs deleted file mode 100644 index 11fb0156a40..00000000000 --- a/Content.Server/GhostKick/GhostKickUserOnTriggerComponent.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace Content.Server.GhostKick; - -[RegisterComponent] -public sealed partial class GhostKickUserOnTriggerComponent : Component -{ - -} diff --git a/Content.Server/GhostKick/GhostKickUserOnTriggerSystem.cs b/Content.Server/GhostKick/GhostKickUserOnTriggerSystem.cs deleted file mode 100644 index 2a5d9065fae..00000000000 --- a/Content.Server/GhostKick/GhostKickUserOnTriggerSystem.cs +++ /dev/null @@ -1,26 +0,0 @@ -using Content.Server.Explosion.EntitySystems; -using Robust.Shared.Player; - -namespace Content.Server.GhostKick; - -public sealed class GhostKickUserOnTriggerSystem : EntitySystem -{ - [Dependency] private readonly GhostKickManager _ghostKickManager = default!; - - public override void Initialize() - { - SubscribeLocalEvent(HandleMineTriggered); - } - - private void HandleMineTriggered(EntityUid uid, GhostKickUserOnTriggerComponent userOnTriggerComponent, TriggerEvent args) - { - if (!TryComp(args.User, out ActorComponent? actor)) - return; - - _ghostKickManager.DoDisconnect( - actor.PlayerSession.Channel, - "Tripped over a kick mine, crashed through the fourth wall"); - - args.Handled = true; - } -} diff --git a/Content.Server/Holopad/HolopadSystem.cs b/Content.Server/Holopad/HolopadSystem.cs index f2bd0e05adf..884fb3ae711 100644 --- a/Content.Server/Holopad/HolopadSystem.cs +++ b/Content.Server/Holopad/HolopadSystem.cs @@ -1,7 +1,6 @@ using Content.Server.Chat.Systems; using Content.Server.Popups; using Content.Server.Power.EntitySystems; -using Content.Server.Speech.Components; using Content.Server.Telephone; using Content.Shared.Access.Systems; using Content.Shared.Audio; @@ -12,6 +11,7 @@ using Content.Shared.Labels.Components; using Content.Shared.Power; using Content.Shared.Silicons.StationAi; using Content.Shared.Speech; +using Content.Shared.Speech.Components; using Content.Shared.Telephone; using Content.Shared.UserInterface; using Content.Shared.Verbs; @@ -560,7 +560,7 @@ public sealed class HolopadSystem : SharedHolopadSystem entity.Comp.User = (user.Value, holopadUser); } - // Add the new user to PVS and sync their appearance with any + // Add the new user to PVS and sync their appearance with any // holopads connected to the one they are using _pvs.AddGlobalOverride(user.Value); SyncHolopadHologramAppearanceWithTarget(entity, entity.Comp.User); diff --git a/Content.Server/HotPotato/HotPotatoSystem.cs b/Content.Server/HotPotato/HotPotatoSystem.cs index 8ca33fb8cd1..554fe098b0f 100644 --- a/Content.Server/HotPotato/HotPotatoSystem.cs +++ b/Content.Server/HotPotato/HotPotatoSystem.cs @@ -1,61 +1,5 @@ -using Content.Server.Audio; -using Content.Server.Explosion.EntitySystems; -using Content.Shared.Damage.Systems; -using Content.Shared.Hands.Components; -using Content.Shared.Hands.EntitySystems; using Content.Shared.HotPotato; -using Content.Shared.Popups; -using Content.Shared.Weapons.Melee.Events; namespace Content.Server.HotPotato; -public sealed class HotPotatoSystem : SharedHotPotatoSystem -{ - [Dependency] private readonly SharedHandsSystem _hands = default!; - [Dependency] private readonly SharedPopupSystem _popup = default!; - [Dependency] private readonly AmbientSoundSystem _ambientSound = default!; - [Dependency] private readonly DamageOnHoldingSystem _damageOnHolding = default!; - - public override void Initialize() - { - base.Initialize(); - SubscribeLocalEvent(OnActiveTimer); - SubscribeLocalEvent(OnMeleeHit); - } - - private void OnActiveTimer(EntityUid uid, HotPotatoComponent comp, ref ActiveTimerTriggerEvent args) - { - EnsureComp(uid); - comp.CanTransfer = false; - _ambientSound.SetAmbience(uid, true); - _damageOnHolding.SetEnabled(uid, true); - Dirty(uid, comp); - } - - private void OnMeleeHit(EntityUid uid, HotPotatoComponent comp, MeleeHitEvent args) - { - if (!HasComp(uid)) - return; - - comp.CanTransfer = true; - foreach (var hitEntity in args.HitEntities) - { - if (!TryComp(hitEntity, out var hands)) - continue; - - if (!_hands.IsHolding((hitEntity, hands), uid, out _) && _hands.TryForcePickupAnyHand(hitEntity, uid, handsComp: hands)) - { - _popup.PopupEntity(Loc.GetString("hot-potato-passed", - ("from", args.User), ("to", hitEntity)), uid, PopupType.Medium); - break; - } - - _popup.PopupEntity(Loc.GetString("hot-potato-failed", - ("to", hitEntity)), uid, PopupType.Medium); - - break; - } - comp.CanTransfer = false; - Dirty(uid, comp); - } -} +public sealed class HotPotatoSystem : SharedHotPotatoSystem; diff --git a/Content.Server/IgnitionSource/IgniteOnTriggerComponent.cs b/Content.Server/IgnitionSource/IgniteOnTriggerComponent.cs deleted file mode 100644 index 939198c45e0..00000000000 --- a/Content.Server/IgnitionSource/IgniteOnTriggerComponent.cs +++ /dev/null @@ -1,30 +0,0 @@ -using Robust.Shared.Audio; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom; - -namespace Content.Server.IgnitionSource; - -/// -/// Ignites for a certain length of time when triggered. -/// Requires along with triggering components. -/// -[RegisterComponent, Access(typeof(IgniteOnTriggerSystem))] -public sealed partial class IgniteOnTriggerComponent : Component -{ - /// - /// Once ignited, the time it will unignite at. - /// - [DataField(customTypeSerializer: typeof(TimeOffsetSerializer)), ViewVariables(VVAccess.ReadWrite)] - public TimeSpan IgnitedUntil = TimeSpan.Zero; - - /// - /// How long the ignition source is active for after triggering. - /// - [DataField, ViewVariables(VVAccess.ReadWrite)] - public TimeSpan IgnitedTime = TimeSpan.FromSeconds(0.5); - - /// - /// Sound to play when igniting. - /// - [DataField] - public SoundSpecifier IgniteSound = new SoundCollectionSpecifier("WelderOn"); -} diff --git a/Content.Server/LandMines/LandMineSystem.cs b/Content.Server/LandMines/LandMineSystem.cs index 57d25ef8ab7..fdea8e9c652 100644 --- a/Content.Server/LandMines/LandMineSystem.cs +++ b/Content.Server/LandMines/LandMineSystem.cs @@ -1,9 +1,9 @@ -using Content.Server.Explosion.EntitySystems; using Content.Shared.Armable; using Content.Shared.Item.ItemToggle.Components; using Content.Shared.LandMines; using Content.Shared.Popups; using Content.Shared.StepTrigger.Systems; +using Content.Shared.Trigger.Systems; using Robust.Shared.Audio.Systems; namespace Content.Server.LandMines; @@ -28,15 +28,15 @@ public sealed class LandMineSystem : EntitySystem /// private void HandleStepOnTriggered(EntityUid uid, LandMineComponent component, ref StepTriggeredOnEvent args) { - if (!string.IsNullOrEmpty(component.TriggerText)) - { - _popupSystem.PopupCoordinates( - Loc.GetString(component.TriggerText, ("mine", uid)), - Transform(uid).Coordinates, - args.Tripper, - PopupType.LargeCaution); - } - _audioSystem.PlayPvs(component.Sound, uid); + if (!string.IsNullOrEmpty(component.TriggerText)) + { + _popupSystem.PopupCoordinates( + Loc.GetString(component.TriggerText, ("mine", uid)), + Transform(uid).Coordinates, + args.Tripper, + PopupType.LargeCaution); + } + _audioSystem.PlayPvs(component.Sound, uid); } /// @@ -44,7 +44,8 @@ public sealed class LandMineSystem : EntitySystem /// private void HandleStepOffTriggered(EntityUid uid, LandMineComponent component, ref StepTriggeredOffEvent args) { - _trigger.Trigger(uid, args.Tripper); + // TODO: Adjust to the new trigger system + _trigger.Trigger(uid, args.Tripper, TriggerSystem.DefaultTriggerKey); } /// diff --git a/Content.Server/Mousetrap/MousetrapSystem.cs b/Content.Server/Mousetrap/MousetrapSystem.cs deleted file mode 100644 index ebcef0d645d..00000000000 --- a/Content.Server/Mousetrap/MousetrapSystem.cs +++ /dev/null @@ -1,84 +0,0 @@ -using Content.Server.Damage.Systems; -using Content.Server.Explosion.EntitySystems; -using Content.Server.Popups; -using Content.Shared.Abilities; -using Content.Shared.Interaction.Events; -using Content.Shared.Inventory; -using Content.Shared.Mousetrap; -using Content.Shared.StepTrigger; -using Content.Shared.StepTrigger.Systems; -using Robust.Server.GameObjects; -using Robust.Shared.Physics.Components; -using Robust.Shared.Player; - -namespace Content.Server.Mousetrap; - -public sealed class MousetrapSystem : EntitySystem -{ - [Dependency] private readonly PopupSystem _popupSystem = default!; - [Dependency] private readonly SharedAppearanceSystem _appearance = default!; - - public override void Initialize() - { - SubscribeLocalEvent(OnUseInHand); - SubscribeLocalEvent(BeforeDamageOnTrigger); - SubscribeLocalEvent(OnStepTriggerAttempt); - SubscribeLocalEvent(OnTrigger); - } - - private void OnUseInHand(EntityUid uid, MousetrapComponent component, UseInHandEvent args) - { - if (args.Handled) - return; - - component.IsActive = !component.IsActive; - _popupSystem.PopupEntity(component.IsActive - ? Loc.GetString("mousetrap-on-activate") - : Loc.GetString("mousetrap-on-deactivate"), - uid, - args.User); - - UpdateVisuals(uid); - - args.Handled = true; - } - - private void OnStepTriggerAttempt(EntityUid uid, MousetrapComponent component, ref StepTriggerAttemptEvent args) - { - // DeltaV: Entities with this component always trigger mouse traps, even if wearing shoes - if (HasComp(args.Tripper)) - args.Cancelled = false; - - args.Continue |= component.IsActive; - } - - private void BeforeDamageOnTrigger(EntityUid uid, MousetrapComponent component, BeforeDamageUserOnTriggerEvent args) - { - if (TryComp(args.Tripper, out PhysicsComponent? physics) && physics.Mass != 0) - { - // The idea here is inverse, - // Small - big damage, - // Large - small damage - // yes i punched numbers into a calculator until the graph looked right - var scaledDamage = -50 * Math.Atan(physics.Mass - component.MassBalance) + (25 * Math.PI); - args.Damage *= scaledDamage; - } - } - - private void OnTrigger(EntityUid uid, MousetrapComponent component, TriggerEvent args) - { - component.IsActive = false; - UpdateVisuals(uid); - } - - private void UpdateVisuals(EntityUid uid, MousetrapComponent? mousetrap = null, AppearanceComponent? appearance = null) - { - if (!Resolve(uid, ref mousetrap, ref appearance, false)) - { - return; - } - - _appearance.SetData(uid, MousetrapVisuals.Visual, - mousetrap.IsActive ? MousetrapVisuals.Armed : MousetrapVisuals.Unarmed, appearance); - } -} diff --git a/Content.Server/Ninja/Systems/SpiderChargeSystem.cs b/Content.Server/Ninja/Systems/SpiderChargeSystem.cs index 6594d7883bc..c08576a5ceb 100644 --- a/Content.Server/Ninja/Systems/SpiderChargeSystem.cs +++ b/Content.Server/Ninja/Systems/SpiderChargeSystem.cs @@ -1,4 +1,3 @@ -using Content.Server.Explosion.EntitySystems; using Content.Server.Mind; using Content.Server.Objectives.Components; using Content.Server.Popups; @@ -7,6 +6,7 @@ using Content.Shared.Ninja.Components; using Content.Shared.Ninja.Systems; using Content.Shared.Roles; using Content.Shared.Sticky; +using Content.Shared.Trigger; namespace Content.Server.Ninja.Systems; @@ -80,6 +80,9 @@ public sealed class SpiderChargeSystem : SharedSpiderChargeSystem /// private void OnExplode(EntityUid uid, SpiderChargeComponent comp, TriggerEvent args) { + if (args.Key != comp.TriggerKey) + return; + if (!TryComp(comp.Planter, out var ninja)) return; diff --git a/Content.Server/Nutrition/EntitySystems/CreamPieSystem.cs b/Content.Server/Nutrition/EntitySystems/CreamPieSystem.cs index 5c0aca1578f..e85393e6f7a 100644 --- a/Content.Server/Nutrition/EntitySystems/CreamPieSystem.cs +++ b/Content.Server/Nutrition/EntitySystems/CreamPieSystem.cs @@ -1,15 +1,15 @@ -using Content.Server.Explosion.EntitySystems; using Content.Server.Fluids.EntitySystems; using Content.Server.Nutrition.Components; using Content.Server.Popups; using Content.Shared.Containers.ItemSlots; -using Content.Shared.Explosion.Components; using Content.Shared.IdentityManagement; using Content.Shared.Nutrition; using Content.Shared.Nutrition.Components; using Content.Shared.Nutrition.EntitySystems; using Content.Shared.Rejuvenate; using Content.Shared.Throwing; +using Content.Shared.Trigger.Components; +using Content.Shared.Trigger.Systems; using Content.Shared.Chemistry.EntitySystems; using JetBrains.Annotations; using Robust.Shared.Audio; @@ -77,15 +77,9 @@ namespace Content.Server.Nutrition.EntitySystems { if (_itemSlots.TryEject(uid, itemSlot, user: null, out var item)) { - if (TryComp(item.Value, out var timerTrigger)) + if (TryComp(item.Value, out var timerTrigger)) { - _trigger.HandleTimerTrigger( - item.Value, - null, - timerTrigger.Delay, - timerTrigger.BeepInterval, - timerTrigger.InitialBeepDelay, - timerTrigger.BeepSound); + _trigger.ActivateTimerTrigger((item.Value, timerTrigger)); } } } diff --git a/Content.Server/Payload/EntitySystems/PayloadSystem.cs b/Content.Server/Payload/EntitySystems/PayloadSystem.cs index 18444bc590d..11e97c5b935 100644 --- a/Content.Server/Payload/EntitySystems/PayloadSystem.cs +++ b/Content.Server/Payload/EntitySystems/PayloadSystem.cs @@ -1,10 +1,10 @@ using Content.Server.Administration.Logs; -using Content.Server.Explosion.EntitySystems; using Content.Shared.Chemistry.Components; using Content.Shared.Database; using Content.Shared.Examine; using Content.Shared.Payload.Components; using Content.Shared.Tag; +using Content.Shared.Trigger; using Content.Shared.Chemistry.EntitySystems; using Robust.Shared.Containers; using Robust.Shared.Serialization.Manager; @@ -54,18 +54,22 @@ public sealed class PayloadSystem : EntitySystem private void OnCaseTriggered(EntityUid uid, PayloadCaseComponent component, TriggerEvent args) { + // TODO: Adjust to the new trigger system + if (!TryComp(uid, out ContainerManagerComponent? contMan)) return; // Pass trigger event onto all contained payloads. Payload capacity configurable by construction graphs. foreach (var ent in GetAllPayloads(uid, contMan)) { - RaiseLocalEvent(ent, args, false); + RaiseLocalEvent(ent, ref args, false); } } private void OnTriggerTriggered(EntityUid uid, PayloadTriggerComponent component, TriggerEvent args) { + // TODO: Adjust to the new trigger system + if (!component.Active) return; @@ -75,7 +79,7 @@ public sealed class PayloadSystem : EntitySystem // Ensure we don't enter a trigger-loop DebugTools.Assert(!_tagSystem.HasTag(uid, PayloadTag)); - RaiseLocalEvent(parent, args, false); + RaiseLocalEvent(parent, ref args); } private void OnEntityInserted(EntityUid uid, PayloadCaseComponent _, EntInsertedIntoContainerMessage args) @@ -146,6 +150,7 @@ public sealed class PayloadSystem : EntitySystem private void HandleChemicalPayloadTrigger(Entity entity, ref TriggerEvent args) { + // TODO: Adjust to the new trigger system if (entity.Comp.BeakerSlotA.Item is not EntityUid beakerA || entity.Comp.BeakerSlotB.Item is not EntityUid beakerB || !TryComp(beakerA, out FitsInDispenserComponent? compA) diff --git a/Content.Server/Polymorph/Components/PolymorphOnTriggerComponent.cs b/Content.Server/Polymorph/Components/PolymorphOnTriggerComponent.cs deleted file mode 100644 index a11b4f4d4c0..00000000000 --- a/Content.Server/Polymorph/Components/PolymorphOnTriggerComponent.cs +++ /dev/null @@ -1,18 +0,0 @@ -using Content.Shared.Polymorph; -using Robust.Shared.Prototypes; - -namespace Content.Server.Polymorph.Components; - -/// -/// Intended for use with the trigger system. -/// Polymorphs the user of the trigger. -/// -[RegisterComponent] -public sealed partial class PolymorphOnTriggerComponent : Component -{ - /// - /// Polymorph settings. - /// - [DataField(required: true)] - public ProtoId Polymorph; -} diff --git a/Content.Server/Polymorph/Systems/PolymorphSystem.Trigger.cs b/Content.Server/Polymorph/Systems/PolymorphSystem.Trigger.cs deleted file mode 100644 index 452b0603153..00000000000 --- a/Content.Server/Polymorph/Systems/PolymorphSystem.Trigger.cs +++ /dev/null @@ -1,41 +0,0 @@ -using Content.Shared.Polymorph; -using Content.Server.Polymorph.Components; -using Content.Server.Explosion.EntitySystems; -using Robust.Shared.Prototypes; - -namespace Content.Server.Polymorph.Systems; - -public sealed partial class PolymorphSystem -{ - /// - /// Need to do this so we don't get a collection enumeration error in physics by polymorphing - /// an entity we're colliding with in case of TriggerOnCollide. - /// Also makes sure other trigger effects don't activate in nullspace after we have polymorphed. - /// - private Queue<(EntityUid Ent, ProtoId Polymorph)> _queuedPolymorphUpdates = new(); - - private void InitializeTrigger() - { - SubscribeLocalEvent(OnTrigger); - } - - private void OnTrigger(Entity ent, ref TriggerEvent args) - { - if (args.User == null) - return; - - _queuedPolymorphUpdates.Enqueue((args.User.Value, ent.Comp.Polymorph)); - args.Handled = true; - } - - public void UpdateTrigger() - { - while (_queuedPolymorphUpdates.TryDequeue(out var data)) - { - if (TerminatingOrDeleted(data.Item1)) - continue; - - PolymorphEntity(data.Item1, data.Item2); - } - } -} diff --git a/Content.Server/Polymorph/Systems/PolymorphSystem.cs b/Content.Server/Polymorph/Systems/PolymorphSystem.cs index 5b54813d530..6203065ee89 100644 --- a/Content.Server/Polymorph/Systems/PolymorphSystem.cs +++ b/Content.Server/Polymorph/Systems/PolymorphSystem.cs @@ -63,7 +63,6 @@ public sealed partial class PolymorphSystem : EntitySystem SubscribeLocalEvent(OnDestruction); InitializeMap(); - InitializeTrigger(); } public override void Update(float frameTime) @@ -90,8 +89,6 @@ public sealed partial class PolymorphSystem : EntitySystem Revert((uid, comp)); } } - - UpdateTrigger(); } private void OnComponentStartup(Entity ent, ref ComponentStartup args) diff --git a/Content.Server/Radio/EntitySystems/RadioDeviceSystem.cs b/Content.Server/Radio/EntitySystems/RadioDeviceSystem.cs index 3829fc34d20..f052c460f50 100644 --- a/Content.Server/Radio/EntitySystems/RadioDeviceSystem.cs +++ b/Content.Server/Radio/EntitySystems/RadioDeviceSystem.cs @@ -2,15 +2,14 @@ using System.Linq; using Content.Server.Chat.Systems; using Content.Server.Interaction; using Content.Server.Popups; -using Content.Server.Power.Components; using Content.Server.Power.EntitySystems; using Content.Server.Radio.Components; -using Content.Server.Speech; -using Content.Server.Speech.Components; using Content.Shared.Examine; using Content.Shared.Interaction; using Content.Shared.Power; using Content.Shared.Radio; +using Content.Shared.Speech; +using Content.Shared.Speech.Components; using Content.Shared.Chat; using Content.Shared.Radio.Components; using Robust.Shared.Prototypes; diff --git a/Content.Server/Silicons/Borgs/BorgSystem.Transponder.cs b/Content.Server/Silicons/Borgs/BorgSystem.Transponder.cs index e950d3f2887..debed525f6e 100644 --- a/Content.Server/Silicons/Borgs/BorgSystem.Transponder.cs +++ b/Content.Server/Silicons/Borgs/BorgSystem.Transponder.cs @@ -119,7 +119,7 @@ public sealed partial class BorgSystem var message = Loc.GetString(ent.Comp.DestroyingPopup, ("name", Name(ent))); Popup.PopupEntity(message, ent); - _trigger.StartTimer(ent.Owner, user: null); + _trigger.ActivateTimerTrigger(ent.Owner); // prevent a shitter borg running into people RemComp(ent); diff --git a/Content.Server/Silicons/Borgs/BorgSystem.cs b/Content.Server/Silicons/Borgs/BorgSystem.cs index 821f8d9afb3..f2dd2f27a11 100644 --- a/Content.Server/Silicons/Borgs/BorgSystem.cs +++ b/Content.Server/Silicons/Borgs/BorgSystem.cs @@ -4,7 +4,6 @@ using Content.Server.Actions; using Content.Server.Administration.Logs; using Content.Server.Administration.Managers; using Content.Server.DeviceNetwork.Systems; -using Content.Server.Explosion.EntitySystems; using Content.Server.Hands.Systems; using Content.Server.PowerCell; using Content.Shared.Alert; @@ -25,6 +24,7 @@ using Content.Shared.Roles; using Content.Shared.Silicons.Borgs; using Content.Shared.Silicons.Borgs.Components; using Content.Shared.Throwing; +using Content.Shared.Trigger.Systems; using Content.Shared.Whitelist; using Content.Shared.Wires; using Robust.Server.GameObjects; diff --git a/Content.Server/Sound/Components/EmitSoundOnTriggerComponent.cs b/Content.Server/Sound/Components/EmitSoundOnTriggerComponent.cs deleted file mode 100644 index 53383519484..00000000000 --- a/Content.Server/Sound/Components/EmitSoundOnTriggerComponent.cs +++ /dev/null @@ -1,13 +0,0 @@ -using Content.Server.Explosion.EntitySystems; -using Content.Shared.Sound.Components; - -namespace Content.Server.Sound.Components -{ - /// - /// Whenever a is run play a sound in PVS range. - /// - [RegisterComponent] - public sealed partial class EmitSoundOnTriggerComponent : BaseEmitSoundComponent - { - } -} diff --git a/Content.Server/Sound/EmitSoundSystem.cs b/Content.Server/Sound/EmitSoundSystem.cs index 9d7e8496c3c..1720d67d024 100644 --- a/Content.Server/Sound/EmitSoundSystem.cs +++ b/Content.Server/Sound/EmitSoundSystem.cs @@ -1,6 +1,3 @@ -using Content.Server.Explosion.EntitySystems; -using Content.Server.Sound.Components; -using Content.Shared.UserInterface; using Content.Shared.Sound; using Content.Shared.Sound.Components; using Robust.Shared.Timing; @@ -38,16 +35,9 @@ public sealed class EmitSoundSystem : SharedEmitSoundSystem { base.Initialize(); - SubscribeLocalEvent(HandleEmitSoundOnTrigger); SubscribeLocalEvent(HandleSpamEmitSoundMapInit); } - private void HandleEmitSoundOnTrigger(EntityUid uid, EmitSoundOnTriggerComponent component, TriggerEvent args) - { - TryEmitSound(uid, component, args.User, false); - args.Handled = true; - } - private void HandleSpamEmitSoundMapInit(Entity entity, ref MapInitEvent args) { SpamEmitSoundReset(entity); diff --git a/Content.Server/Speech/Components/ActiveListenerComponent.cs b/Content.Server/Speech/Components/ActiveListenerComponent.cs deleted file mode 100644 index 4553fafa51d..00000000000 --- a/Content.Server/Speech/Components/ActiveListenerComponent.cs +++ /dev/null @@ -1,13 +0,0 @@ -using Content.Server.Chat.Systems; - -namespace Content.Server.Speech.Components; - -/// -/// This component is used to relay speech events to other systems. -/// -[RegisterComponent] -public sealed partial class ActiveListenerComponent : Component -{ - [DataField("range")] - public float Range = ChatSystem.VoiceRange; -} diff --git a/Content.Server/Speech/EntitySystems/BlockListeningSystem.cs b/Content.Server/Speech/EntitySystems/BlockListeningSystem.cs index a13eda1f733..6b098775125 100644 --- a/Content.Server/Speech/EntitySystems/BlockListeningSystem.cs +++ b/Content.Server/Speech/EntitySystems/BlockListeningSystem.cs @@ -1,4 +1,5 @@ using Content.Server.Speech.Components; +using Content.Shared.Speech; namespace Content.Server.Speech.EntitySystems; diff --git a/Content.Server/Speech/EntitySystems/ListeningSystem.cs b/Content.Server/Speech/EntitySystems/ListeningSystem.cs index ea3569e055c..17513d80e7a 100644 --- a/Content.Server/Speech/EntitySystems/ListeningSystem.cs +++ b/Content.Server/Speech/EntitySystems/ListeningSystem.cs @@ -1,5 +1,6 @@ using Content.Server.Chat.Systems; -using Content.Server.Speech.Components; +using Content.Shared.Speech; +using Content.Shared.Speech.Components; namespace Content.Server.Speech.EntitySystems; diff --git a/Content.Server/SurveillanceCamera/Systems/SurveillanceCameraMicrophoneSystem.cs b/Content.Server/SurveillanceCamera/Systems/SurveillanceCameraMicrophoneSystem.cs index 4deb5238a53..4029488159a 100644 --- a/Content.Server/SurveillanceCamera/Systems/SurveillanceCameraMicrophoneSystem.cs +++ b/Content.Server/SurveillanceCamera/Systems/SurveillanceCameraMicrophoneSystem.cs @@ -1,6 +1,6 @@ using Content.Server.Chat.Systems; -using Content.Server.Speech; -using Content.Server.Speech.Components; +using Content.Shared.Speech; +using Content.Shared.Speech.Components; using Content.Shared.Whitelist; using Robust.Shared.Player; using static Content.Server.Chat.Systems.ChatSystem; diff --git a/Content.Server/Telephone/TelephoneSystem.cs b/Content.Server/Telephone/TelephoneSystem.cs index 4c87707cc6b..46f45d12869 100644 --- a/Content.Server/Telephone/TelephoneSystem.cs +++ b/Content.Server/Telephone/TelephoneSystem.cs @@ -3,8 +3,6 @@ using Content.Server.Administration.Logs; using Content.Server.Chat.Systems; using Content.Server.Interaction; using Content.Server.Power.EntitySystems; -using Content.Server.Speech; -using Content.Server.Speech.Components; using Content.Shared.Chat; using Content.Shared.Database; using Content.Shared.Labels.Components; @@ -13,6 +11,7 @@ using Content.Shared.Power; using Content.Shared.Silicons.StationAi; using Content.Shared.Silicons.Borgs.Components; using Content.Shared.Speech; +using Content.Shared.Speech.Components; using Content.Shared.Telephone; using Robust.Server.GameObjects; using Robust.Shared.Audio.Systems; diff --git a/Content.Server/AlertLevel/Systems/AlertLevelChangeOnTriggerSystem.cs b/Content.Server/Trigger/Systems/AlertLevelChangeOnTriggerSystem.cs similarity index 74% rename from Content.Server/AlertLevel/Systems/AlertLevelChangeOnTriggerSystem.cs rename to Content.Server/Trigger/Systems/AlertLevelChangeOnTriggerSystem.cs index 0c9734b943e..1a3e49dd441 100644 --- a/Content.Server/AlertLevel/Systems/AlertLevelChangeOnTriggerSystem.cs +++ b/Content.Server/Trigger/Systems/AlertLevelChangeOnTriggerSystem.cs @@ -1,8 +1,9 @@ using Content.Server.AlertLevel; -using Content.Server.Explosion.EntitySystems; +using Content.Shared.Trigger; +using Content.Shared.Trigger.Components.Effects; using Content.Server.Station.Systems; -namespace Content.Server.AlertLevel.Systems; +namespace Content.Server.Trigger.Systems; public sealed class AlertLevelChangeOnTriggerSystem : EntitySystem { @@ -18,10 +19,14 @@ public sealed class AlertLevelChangeOnTriggerSystem : EntitySystem private void OnTrigger(Entity ent, ref TriggerEvent args) { + if (args.Key != null && !ent.Comp.KeysIn.Contains(args.Key)) + return; + var stationUid = _station.GetOwningStation(ent.Owner); - if (!stationUid.HasValue) + if (stationUid == null) return; _alertLevelSystem.SetLevel(stationUid.Value, ent.Comp.Level, ent.Comp.PlaySound, ent.Comp.Announce, ent.Comp.Force); + args.Handled = true; } } diff --git a/Content.Server/Trigger/Systems/GhostKickUserOnTriggerSystem.cs b/Content.Server/Trigger/Systems/GhostKickUserOnTriggerSystem.cs new file mode 100644 index 00000000000..0fae6ff1c51 --- /dev/null +++ b/Content.Server/Trigger/Systems/GhostKickUserOnTriggerSystem.cs @@ -0,0 +1,38 @@ +using Content.Shared.Trigger; +using Content.Shared.Trigger.Components.Effects; +using Content.Server.GhostKick; +using Robust.Shared.Player; + +namespace Content.Server.Trigger.Systems; + +public sealed class GhostKickUserOnTriggerSystem : EntitySystem +{ + [Dependency] private readonly GhostKickManager _ghostKickManager = default!; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnTrigger); + } + + private void OnTrigger(Entity ent, ref TriggerEvent args) + { + if (args.Key != null && !ent.Comp.KeysIn.Contains(args.Key)) + return; + + var target = ent.Comp.TargetUser ? args.User : ent.Owner; + + if (target == null) + return; + + if (!TryComp(target, out ActorComponent? actor)) + return; + + _ghostKickManager.DoDisconnect( + actor.PlayerSession.Channel, + Loc.GetString(ent.Comp.Reason)); + + args.Handled = true; + } +} diff --git a/Content.Server/IgnitionSource/IgniteOnTriggerSystem.cs b/Content.Server/Trigger/Systems/IgniteOnTriggerSystem.cs similarity index 66% rename from Content.Server/IgnitionSource/IgniteOnTriggerSystem.cs rename to Content.Server/Trigger/Systems/IgniteOnTriggerSystem.cs index 0e9dd566222..f4d88b774a1 100644 --- a/Content.Server/IgnitionSource/IgniteOnTriggerSystem.cs +++ b/Content.Server/Trigger/Systems/IgniteOnTriggerSystem.cs @@ -1,10 +1,9 @@ -using Content.Server.Explosion.EntitySystems; using Content.Shared.IgnitionSource; -using Content.Shared.Timing; -using Robust.Shared.Audio.Systems; +using Content.Shared.Trigger; +using Content.Shared.Trigger.Components.Effects; using Robust.Shared.Timing; -namespace Content.Server.IgnitionSource; +namespace Content.Server.Trigger.Systems; /// /// Handles igniting when triggered and stopping ignition after the delay. @@ -13,8 +12,6 @@ public sealed class IgniteOnTriggerSystem : EntitySystem { [Dependency] private readonly IGameTiming _timing = default!; [Dependency] private readonly SharedIgnitionSourceSystem _source = default!; - [Dependency] private readonly SharedAudioSystem _audio = default!; - [Dependency] private readonly UseDelaySystem _useDelay = default!; public override void Initialize() { @@ -23,6 +20,8 @@ public sealed class IgniteOnTriggerSystem : EntitySystem SubscribeLocalEvent(OnTrigger); } + // TODO: move this into ignition source component + // it already has an update loop public override void Update(float deltaTime) { base.Update(deltaTime); @@ -42,14 +41,18 @@ public sealed class IgniteOnTriggerSystem : EntitySystem private void OnTrigger(Entity ent, ref TriggerEvent args) { - // prevent spamming sound and ignition - if (!TryComp(ent.Owner, out UseDelayComponent? useDelay) || _useDelay.IsDelayed((ent.Owner, useDelay))) + if (args.Key != null && !ent.Comp.KeysIn.Contains(args.Key)) return; - _source.SetIgnited(ent.Owner); - _audio.PlayPvs(ent.Comp.IgniteSound, ent); + var target = ent.Comp.TargetUser ? args.User : ent.Owner; - _useDelay.TryResetDelay((ent.Owner, useDelay)); + if (target == null) + return; + + _source.SetIgnited(target.Value); ent.Comp.IgnitedUntil = _timing.CurTime + ent.Comp.IgnitedTime; + Dirty(ent); + + args.Handled = true; } } diff --git a/Content.Server/Trigger/Systems/PolymorphOnTriggerSystem.cs b/Content.Server/Trigger/Systems/PolymorphOnTriggerSystem.cs new file mode 100644 index 00000000000..8b4741b9ad3 --- /dev/null +++ b/Content.Server/Trigger/Systems/PolymorphOnTriggerSystem.cs @@ -0,0 +1,51 @@ +using Content.Server.Polymorph.Systems; +using Content.Shared.Polymorph; +using Content.Shared.Trigger; +using Content.Shared.Trigger.Components.Effects; +using Robust.Shared.Prototypes; + +namespace Content.Server.Trigger.Systems; + +public sealed partial class PolymorphOnTriggerSystem : EntitySystem +{ + [Dependency] private readonly PolymorphSystem _polymorph = default!; + + /// + /// Need to do this so we don't get a collection enumeration error in physics by polymorphing + /// an entity we're colliding with in case of TriggerOnCollide. + /// Also makes sure other trigger effects don't activate in nullspace after we have polymorphed. + /// + private Queue<(EntityUid Uid, ProtoId Polymorph)> _queuedPolymorphUpdates = new(); + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnTrigger); + } + + private void OnTrigger(Entity ent, ref TriggerEvent args) + { + if (args.Key != null && !ent.Comp.KeysIn.Contains(args.Key)) + return; + + var target = ent.Comp.TargetUser ? args.User : ent.Owner; + + if (target == null) + return; + + _queuedPolymorphUpdates.Enqueue((target.Value, ent.Comp.Polymorph)); + args.Handled = true; + } + + public override void Update(float frametime) + { + while (_queuedPolymorphUpdates.TryDequeue(out var data)) + { + if (TerminatingOrDeleted(data.Uid)) + continue; + + _polymorph.PolymorphEntity(data.Uid, data.Polymorph); + } + } +} diff --git a/Content.Server/Trigger/Systems/RattleOnTriggerSystem.cs b/Content.Server/Trigger/Systems/RattleOnTriggerSystem.cs new file mode 100644 index 00000000000..74e2d906b37 --- /dev/null +++ b/Content.Server/Trigger/Systems/RattleOnTriggerSystem.cs @@ -0,0 +1,53 @@ +using Content.Server.Radio.EntitySystems; +using Content.Server.Pinpointer; +using Content.Shared.Mobs.Components; +using Content.Shared.Trigger; +using Content.Shared.Trigger.Components.Effects; +using Robust.Shared.Prototypes; +using Robust.Shared.Utility; + +namespace Content.Server.Trigger.Systems; + +public sealed class RattleOnTriggerSystem : EntitySystem +{ + [Dependency] private readonly IPrototypeManager _prototypeManager = default!; + [Dependency] private readonly RadioSystem _radio = default!; + [Dependency] private readonly NavMapSystem _navMap = default!; + [Dependency] private readonly SharedTransformSystem _transform = default!; // DeltaV + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnTrigger); + } + + private void OnTrigger(Entity ent, ref TriggerEvent args) + { + if (args.Key != null && !ent.Comp.KeysIn.Contains(args.Key)) + return; + + var target = ent.Comp.TargetUser ? args.User : ent.Owner; + + if (target == null) + return; + + if (!TryComp(target.Value, out var mobstate)) + return; + + args.Handled = true; + + if (!ent.Comp.Messages.TryGetValue(mobstate.CurrentState, out var messageId)) + return; + + var position = _transform.GetMapCoordinates(Transform(target.Value)).Position; // DeltaV + + // Gets the location of the user + var posText = FormattedMessage.RemoveMarkupOrThrow(_navMap.GetNearestBeaconString(target.Value) + + $" ({(int)position[0]}, {(int)position[1]})"); // DeltaV - adds the GPS coordinates on the message. + + var message = Loc.GetString(messageId, ("user", target.Value), ("position", posText)); + // Sends a message to the radio channel specified by the implant + _radio.SendRadioMessage(ent.Owner, message, _prototypeManager.Index(ent.Comp.RadioChannel), ent.Owner); + } +} diff --git a/Content.Server/Trigger/Systems/ReleaseGasOnTriggerSystem.cs b/Content.Server/Trigger/Systems/ReleaseGasOnTriggerSystem.cs new file mode 100644 index 00000000000..a38ca2a7598 --- /dev/null +++ b/Content.Server/Trigger/Systems/ReleaseGasOnTriggerSystem.cs @@ -0,0 +1,48 @@ +using Content.Server.Atmos.EntitySystems; +using Content.Shared.Trigger.Components.Effects; +using Content.Shared.Trigger.Systems; +using Robust.Shared.Timing; + +namespace Content.Server.Trigger.Systems; + +public sealed class ReleaseGasOnTriggerSystem : SharedReleaseGasOnTriggerSystem +{ + [Dependency] private readonly AtmosphereSystem _atmosphereSystem = default!; + [Dependency] private readonly SharedAppearanceSystem _appearance = default!; + [Dependency] private readonly IGameTiming _timing = default!; + + + public override void Update(float frameTime) + { + base.Update(frameTime); + + var curTime = _timing.CurTime; + var query = EntityQueryEnumerator(); + + while (query.MoveNext(out var uid, out var comp)) + { + if (!comp.Active || comp.NextReleaseTime > curTime) + continue; + + var giverGasMix = comp.Air.Remove(comp.StartingTotalMoles * comp.RemoveFraction); + var environment = _atmosphereSystem.GetContainingMixture(uid, false, true); + + if (environment == null) + { + _appearance.SetData(uid, ReleaseGasOnTriggerVisuals.Key, false); + RemCompDeferred(uid); + continue; + } + + _atmosphereSystem.Merge(environment, giverGasMix); + comp.NextReleaseTime += comp.ReleaseInterval; + + if (comp.PressureLimit != 0 && environment.Pressure >= comp.PressureLimit || + comp.Air.TotalMoles <= 0) + { + _appearance.SetData(uid, ReleaseGasOnTriggerVisuals.Key, false); + RemCompDeferred(uid); + } + } + } +} diff --git a/Content.Server/Trigger/Systems/SmokeOnTriggerSystem.cs b/Content.Server/Trigger/Systems/SmokeOnTriggerSystem.cs new file mode 100644 index 00000000000..97799b9cc6c --- /dev/null +++ b/Content.Server/Trigger/Systems/SmokeOnTriggerSystem.cs @@ -0,0 +1,68 @@ +using Content.Server.Fluids.EntitySystems; +using Content.Server.Spreader; +using Content.Shared.Chemistry.Components; +using Content.Shared.Coordinates.Helpers; +using Content.Shared.Maps; +using Content.Shared.Trigger; +using Content.Shared.Trigger.Components.Effects; +using Robust.Server.GameObjects; +using Robust.Shared.Map; + +namespace Content.Server.Trigger.Systems; + +/// +/// Handles creating smoke when is triggered. +/// +public sealed class SmokeOnTriggerSystem : EntitySystem +{ + [Dependency] private readonly IMapManager _mapMan = default!; + [Dependency] private readonly MapSystem _map = default!; + [Dependency] private readonly SmokeSystem _smoke = default!; + [Dependency] private readonly TransformSystem _transform = default!; + [Dependency] private readonly SpreaderSystem _spreader = default!; + [Dependency] private readonly TurfSystem _turf = default!; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnTrigger); + } + + private void OnTrigger(Entity ent, ref TriggerEvent args) + { + if (args.Key != null && !ent.Comp.KeysIn.Contains(args.Key)) + return; + + var target = ent.Comp.TargetUser ? args.User : ent.Owner; + + if (target == null) + return; + + // TODO: move all of this into an API function in SmokeSystem + var xform = Transform(target.Value); + var mapCoords = _transform.GetMapCoordinates(target.Value, xform); + if (!_mapMan.TryFindGridAt(mapCoords, out var gridUid, out var gridComp) || + !_map.TryGetTileRef(gridUid, gridComp, xform.Coordinates, out var tileRef) || + tileRef.Tile.IsEmpty) + { + return; + } + + if (_spreader.RequiresFloorToSpread(ent.Comp.SmokePrototype.ToString()) && _turf.IsSpace(tileRef)) + return; + + var coords = _map.MapToGrid(gridUid, mapCoords); + var smoke = Spawn(ent.Comp.SmokePrototype, coords.SnapToGrid()); + if (!TryComp(smoke, out var smokeComp)) + { + Log.Error($"Smoke prototype {ent.Comp.SmokePrototype} was missing SmokeComponent"); + Del(smoke); + return; + } + + _smoke.StartSmoke(smoke, ent.Comp.Solution, (float)ent.Comp.Duration.TotalSeconds, ent.Comp.SpreadAmount, smokeComp); + + args.Handled = true; + } +} diff --git a/Content.Server/Chat/Systems/SpeakOnTriggerSystem.cs b/Content.Server/Trigger/Systems/SpeakOnTriggerSystem.cs similarity index 53% rename from Content.Server/Chat/Systems/SpeakOnTriggerSystem.cs rename to Content.Server/Trigger/Systems/SpeakOnTriggerSystem.cs index 28be6a53738..6da6f707c12 100644 --- a/Content.Server/Chat/Systems/SpeakOnTriggerSystem.cs +++ b/Content.Server/Trigger/Systems/SpeakOnTriggerSystem.cs @@ -1,13 +1,13 @@ -using Content.Server.Explosion.EntitySystems; -using Content.Shared.Timing; +using Content.Server.Chat.Systems; +using Content.Shared.Trigger; +using Content.Shared.Trigger.Components.Effects; using Robust.Shared.Prototypes; using Robust.Shared.Random; -namespace Content.Server.Chat.Systems; +namespace Content.Server.Trigger.Systems; public sealed class SpeakOnTriggerSystem : EntitySystem { - [Dependency] private readonly UseDelaySystem _useDelay = default!; [Dependency] private readonly IRobustRandom _random = default!; [Dependency] private readonly IPrototypeManager _prototypeManager = default!; [Dependency] private readonly ChatSystem _chat = default!; @@ -15,32 +15,34 @@ public sealed class SpeakOnTriggerSystem : EntitySystem public override void Initialize() { base.Initialize(); + SubscribeLocalEvent(OnTrigger); } private void OnTrigger(Entity ent, ref TriggerEvent args) { - TrySpeak(ent); - args.Handled = true; - } - - private void TrySpeak(Entity ent) - { - // If it doesn't have the use delay component, still send the message. - if (TryComp(ent.Owner, out var useDelay) && _useDelay.IsDelayed((ent.Owner, useDelay))) + if (args.Key != null && !ent.Comp.KeysIn.Contains(args.Key)) return; - if (!_prototypeManager.TryIndex(ent.Comp.Pack, out var messagePack)) + var target = ent.Comp.TargetUser ? args.User : ent.Owner; + + if (target == null) return; - var message = Loc.GetString(_random.Pick(messagePack.Values)); + string message; + if (ent.Comp.Text != null) + message = Loc.GetString(ent.Comp.Text); + else + { + if (!_prototypeManager.TryIndex(ent.Comp.Pack, out var messagePack)) + return; + message = Loc.GetString(_random.Pick(messagePack.Values)); + } // Chatcode moment: messages starting with "." are considered radio messages. // Prepending ">" forces the message to be spoken instead. // TODO chat refactor: remove this message = '>' + message; - _chat.TrySendInGameICMessage(ent.Owner, message, InGameICChatType.Speak, true); - - if (useDelay != null) - _useDelay.TryResetDelay((ent.Owner, useDelay)); + _chat.TrySendInGameICMessage(target.Value, message, InGameICChatType.Speak, true); + args.Handled = true; } } diff --git a/Content.Server/VoiceTrigger/StorageVoiceControlSystem.cs b/Content.Server/VoiceTrigger/StorageVoiceControlSystem.cs index 81bbd48a0df..ade861af981 100644 --- a/Content.Server/VoiceTrigger/StorageVoiceControlSystem.cs +++ b/Content.Server/VoiceTrigger/StorageVoiceControlSystem.cs @@ -5,6 +5,7 @@ using Content.Shared.Database; using Content.Shared.Inventory; using Content.Shared.Popups; using Content.Shared.Storage; +using Content.Shared.Trigger; using Robust.Server.Containers; namespace Content.Server.VoiceTrigger; diff --git a/Content.Server/Xenoarchaeology/Artifact/XAE/Components/XAETriggerExplosivesComponent.cs b/Content.Server/Xenoarchaeology/Artifact/XAE/Components/XAETriggerExplosivesComponent.cs index b9e23f036b9..faef4d5078b 100644 --- a/Content.Server/Xenoarchaeology/Artifact/XAE/Components/XAETriggerExplosivesComponent.cs +++ b/Content.Server/Xenoarchaeology/Artifact/XAE/Components/XAETriggerExplosivesComponent.cs @@ -1,9 +1,9 @@ -using Content.Shared.Explosion.Components.OnTrigger; +using Content.Shared.Explosion.Components; namespace Content.Server.Xenoarchaeology.Artifact.XAE.Components; /// -/// Activates 'trigger' for . +/// Activates to explode. /// [RegisterComponent, Access(typeof(XAETriggerExplosivesSystem))] public sealed partial class XAETriggerExplosivesComponent : Component; diff --git a/Content.Shared/Chat/SharedChatSystem.cs b/Content.Shared/Chat/SharedChatSystem.cs index 4b4694a89ef..f881a4f0210 100644 --- a/Content.Shared/Chat/SharedChatSystem.cs +++ b/Content.Shared/Chat/SharedChatSystem.cs @@ -25,6 +25,11 @@ public abstract class SharedChatSystem : EntitySystem public const char TelepathicPrefix = '='; //Nyano - Summary: Adds the telepathic channel's prefix. public const char DefaultChannelKey = 'h'; + public const int VoiceRange = 10; // how far voice goes in world units + public const int WhisperClearRange = 2; // how far whisper goes while still being understandable, in world units + public const int WhisperMuffledRange = 5; // how far whisper goes at all, in world units + public const string DefaultAnnouncementSound = "/Audio/Announcements/announce.ogg"; + public static readonly ProtoId CommonChannel = "Common"; public static readonly string DefaultChannelPrefix = $"{RadioChannelPrefix}{DefaultChannelKey}"; diff --git a/Content.Shared/Damage/Components/DamageUserOnTriggerComponent.cs b/Content.Shared/Damage/Components/DamageUserOnTriggerComponent.cs deleted file mode 100644 index 22dc39aabd6..00000000000 --- a/Content.Shared/Damage/Components/DamageUserOnTriggerComponent.cs +++ /dev/null @@ -1,19 +0,0 @@ -using Content.Shared.Damage; -using Content.Shared._Shitmed.Targeting; // Shitmed - -namespace Content.Server.Damage.Components; - -[RegisterComponent] -public sealed partial class DamageUserOnTriggerComponent : Component -{ - [DataField("ignoreResistances")] public bool IgnoreResistances; - - [DataField("damage", required: true)] - public DamageSpecifier Damage = default!; - - /// - /// Shitmed Change: Lets mousetraps, etc. target the feet. - /// - [DataField] - public TargetBodyPart? TargetPart = TargetBodyPart.Feet; -} diff --git a/Content.Shared/Emp/SharedEmpSystem.cs b/Content.Shared/Emp/SharedEmpSystem.cs index 6e4478bb6d5..72dc874935e 100644 --- a/Content.Shared/Emp/SharedEmpSystem.cs +++ b/Content.Shared/Emp/SharedEmpSystem.cs @@ -1,3 +1,4 @@ +using Robust.Shared.Map; using Robust.Shared.Timing; namespace Content.Shared.Emp; @@ -7,4 +8,15 @@ public abstract class SharedEmpSystem : EntitySystem [Dependency] protected readonly IGameTiming Timing = default!; protected const string EmpDisabledEffectPrototype = "EffectEmpDisabled"; + + /// + /// Triggers an EMP pulse at the given location, by first raising an , then a raising on all entities in range. + /// + /// The location to trigger the EMP pulse at. + /// The range of the EMP pulse. + /// The amount of energy consumed by the EMP pulse. + /// The duration of the EMP effects. + public virtual void EmpPulse(MapCoordinates coordinates, float range, float energyConsumption, float duration) + { + } } diff --git a/Content.Shared/Explosion/Components/ActiveTimerTriggerComponent.cs b/Content.Shared/Explosion/Components/ActiveTimerTriggerComponent.cs deleted file mode 100644 index 6d43abc9d9a..00000000000 --- a/Content.Shared/Explosion/Components/ActiveTimerTriggerComponent.cs +++ /dev/null @@ -1,21 +0,0 @@ -using Robust.Shared.Audio; -using Robust.Shared.GameStates; - -namespace Content.Shared.Explosion.Components; - -/// -/// Component for tracking active trigger timers. A timers can activated by some other component, e.g. . -/// -[RegisterComponent] -public sealed partial class ActiveTimerTriggerComponent : Component -{ - [DataField] public float TimeRemaining; - - [DataField] public EntityUid? User; - - [DataField] public float BeepInterval; - - [DataField] public float TimeUntilBeep; - - [DataField] public SoundSpecifier? BeepSound; -} diff --git a/Content.Shared/Explosion/Components/OnTrigger/ExplodeOnTriggerComponent.cs b/Content.Shared/Explosion/Components/OnTrigger/ExplodeOnTriggerComponent.cs deleted file mode 100644 index e14cd124640..00000000000 --- a/Content.Shared/Explosion/Components/OnTrigger/ExplodeOnTriggerComponent.cs +++ /dev/null @@ -1,11 +0,0 @@ -using Robust.Shared.GameStates; - -namespace Content.Shared.Explosion.Components.OnTrigger; - -/// -/// Explode using the entity's if Triggered. -/// -[RegisterComponent, NetworkedComponent] -public sealed partial class ExplodeOnTriggerComponent : Component -{ -} diff --git a/Content.Shared/Explosion/Components/OnUseTimerTriggerComponent.cs b/Content.Shared/Explosion/Components/OnUseTimerTriggerComponent.cs deleted file mode 100644 index 983b8a31ee6..00000000000 --- a/Content.Shared/Explosion/Components/OnUseTimerTriggerComponent.cs +++ /dev/null @@ -1,66 +0,0 @@ -using System.Linq; -using Content.Shared.Guidebook; -using Robust.Shared.Audio; -using Robust.Shared.GameStates; - -namespace Content.Shared.Explosion.Components -{ - [RegisterComponent, NetworkedComponent] - public sealed partial class OnUseTimerTriggerComponent : Component - { - [DataField] public float Delay = 1f; - - /// - /// If not null, a user can use verbs to configure the delay to one of these options. - /// - [DataField] public List? DelayOptions = null; - - /// - /// If not null, this timer will periodically play this sound while active. - /// - [DataField] public SoundSpecifier? BeepSound; - - /// - /// Time before beeping starts. Defaults to a single beep interval. If set to zero, will emit a beep immediately after use. - /// - [DataField] public float? InitialBeepDelay; - - [DataField] public float BeepInterval = 1; - - /// - /// Whether the timer should instead be activated through a verb in the right-click menu - /// - [DataField] public bool UseVerbInstead = false; - - /// - /// Should timer be started when it was stuck to another entity. - /// Used for C4 charges and similar behaviour. - /// - [DataField] public bool StartOnStick; - - /// - /// Allows changing the start-on-stick quality. - /// - [DataField("canToggleStartOnStick")] public bool AllowToggleStartOnStick; - - /// - /// Whether you can examine the item to see its timer or not. - /// - [DataField] public bool Examinable = true; - - /// - /// Whether or not to show the user a popup when starting the timer. - /// - [DataField] public bool DoPopup = true; - - #region GuidebookData - - [GuidebookData] - public float? ShortestDelayOption => DelayOptions?.Min(); - - [GuidebookData] - public float? LongestDelayOption => DelayOptions?.Max(); - - #endregion GuidebookData - } -} diff --git a/Content.Shared/Explosion/Components/ScatteringGrenadeComponent.cs b/Content.Shared/Explosion/Components/ScatteringGrenadeComponent.cs index 059ad189d11..1cab5d1a77b 100644 --- a/Content.Shared/Explosion/Components/ScatteringGrenadeComponent.cs +++ b/Content.Shared/Explosion/Components/ScatteringGrenadeComponent.cs @@ -112,4 +112,10 @@ public sealed partial class ScatteringGrenadeComponent : Component /// We need to store this because we are only allowed to spawn and trigger timed entities on the next available frame update /// public bool IsTriggered = false; + + /// + /// The trigger key that will activate the grenade. + /// + [DataField] + public string TriggerKey = "timer"; } diff --git a/Content.Shared/Explosion/Components/SharedTriggerOnProximityComponent.cs b/Content.Shared/Explosion/Components/SharedTriggerOnProximityComponent.cs deleted file mode 100644 index 02d11561049..00000000000 --- a/Content.Shared/Explosion/Components/SharedTriggerOnProximityComponent.cs +++ /dev/null @@ -1,9 +0,0 @@ -using Robust.Shared.GameStates; - -namespace Content.Shared.Explosion.Components; - -[NetworkedComponent] -public abstract partial class SharedTriggerOnProximityComponent : Component -{ - -} diff --git a/Content.Shared/Explosion/EntitySystems/SharedReleaseGasOnTriggerSystem.cs b/Content.Shared/Explosion/EntitySystems/SharedReleaseGasOnTriggerSystem.cs deleted file mode 100644 index 5027b04517c..00000000000 --- a/Content.Shared/Explosion/EntitySystems/SharedReleaseGasOnTriggerSystem.cs +++ /dev/null @@ -1,5 +0,0 @@ -namespace Content.Shared.Explosion.EntitySystems; - -public abstract partial class SharedReleaseGasOnTriggerSystem : EntitySystem; - -// I have dreams of Atmos in shared. diff --git a/Content.Shared/Explosion/EntitySystems/SharedRepulseAttractOnTriggerSystem.cs b/Content.Shared/Explosion/EntitySystems/SharedRepulseAttractOnTriggerSystem.cs deleted file mode 100644 index 386024fbeb6..00000000000 --- a/Content.Shared/Explosion/EntitySystems/SharedRepulseAttractOnTriggerSystem.cs +++ /dev/null @@ -1,3 +0,0 @@ -namespace Content.Shared.Explosion.EntitySystems; - -public abstract class SharedRepulseAttractOnTriggerSystem : EntitySystem; diff --git a/Content.Shared/Explosion/EntitySystems/SharedSmokeOnTriggerSystem.cs b/Content.Shared/Explosion/EntitySystems/SharedSmokeOnTriggerSystem.cs deleted file mode 100644 index b206dfa696c..00000000000 --- a/Content.Shared/Explosion/EntitySystems/SharedSmokeOnTriggerSystem.cs +++ /dev/null @@ -1,5 +0,0 @@ -namespace Content.Shared.Explosion.EntitySystems; - -public abstract class SharedSmokeOnTriggerSystem : EntitySystem -{ -} diff --git a/Content.Shared/Explosion/EntitySystems/SharedTriggerSystem.cs b/Content.Shared/Explosion/EntitySystems/SharedTriggerSystem.cs deleted file mode 100644 index cc5b3f6b748..00000000000 --- a/Content.Shared/Explosion/EntitySystems/SharedTriggerSystem.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace Content.Shared.Explosion.EntitySystems; - -public abstract class SharedTriggerSystem : EntitySystem -{ - -} \ No newline at end of file diff --git a/Content.Shared/Flash/Components/FlashOnTriggerComponent.cs b/Content.Shared/Flash/Components/FlashOnTriggerComponent.cs deleted file mode 100644 index e735b3784a6..00000000000 --- a/Content.Shared/Flash/Components/FlashOnTriggerComponent.cs +++ /dev/null @@ -1,18 +0,0 @@ -using Robust.Shared.GameStates; -namespace Content.Shared.Flash.Components; - -/// -/// Upon being triggered will flash in an area around it. -/// -[RegisterComponent, NetworkedComponent] -public sealed partial class FlashOnTriggerComponent : Component -{ - [DataField] - public float Range = 1.0f; - - [DataField] - public TimeSpan Duration = TimeSpan.FromSeconds(8); - - [DataField] - public float Probability = 1.0f; -} diff --git a/Content.Shared/HotPotato/ActiveHotPotatoComponent.cs b/Content.Shared/HotPotato/ActiveHotPotatoComponent.cs index 9bcd218335c..28dbb31324c 100644 --- a/Content.Shared/HotPotato/ActiveHotPotatoComponent.cs +++ b/Content.Shared/HotPotato/ActiveHotPotatoComponent.cs @@ -12,7 +12,7 @@ public sealed partial class ActiveHotPotatoComponent : Component /// /// Hot potato effect spawn cooldown in seconds /// - [DataField("effectCooldown"), ViewVariables(VVAccess.ReadWrite)] + [DataField] public float EffectCooldown = 0.3f; /// diff --git a/Content.Shared/HotPotato/HotPotatoComponent.cs b/Content.Shared/HotPotato/HotPotatoComponent.cs index f5b2e161890..b077e91e8f7 100644 --- a/Content.Shared/HotPotato/HotPotatoComponent.cs +++ b/Content.Shared/HotPotato/HotPotatoComponent.cs @@ -14,7 +14,6 @@ public sealed partial class HotPotatoComponent : Component /// /// If set to true entity can be removed by hitting entities if they have hands /// - [DataField("canTransfer"), ViewVariables(VVAccess.ReadWrite)] - [AutoNetworkedField] + [DataField, AutoNetworkedField] public bool CanTransfer = true; } diff --git a/Content.Shared/HotPotato/SharedHotPotatoSystem.cs b/Content.Shared/HotPotato/SharedHotPotatoSystem.cs index cd7a5d6da5c..6f2f498782d 100644 --- a/Content.Shared/HotPotato/SharedHotPotatoSystem.cs +++ b/Content.Shared/HotPotato/SharedHotPotatoSystem.cs @@ -1,18 +1,79 @@ +using Content.Shared.Audio; +using Content.Shared.Damage.Systems; +using Content.Shared.Hands.Components; +using Content.Shared.Hands.EntitySystems; +using Content.Shared.IdentityManagement; +using Content.Shared.Popups; +using Content.Shared.Trigger; +using Content.Shared.Weapons.Melee.Events; using Robust.Shared.Containers; +using Robust.Shared.Timing; namespace Content.Shared.HotPotato; public abstract class SharedHotPotatoSystem : EntitySystem { + [Dependency] private readonly SharedHandsSystem _hands = default!; + [Dependency] private readonly SharedPopupSystem _popup = default!; + [Dependency] private readonly SharedAmbientSoundSystem _ambientSound = default!; + [Dependency] private readonly DamageOnHoldingSystem _damageOnHolding = default!; + [Dependency] private readonly IGameTiming _timing = default!; + + public override void Initialize() { base.Initialize(); + SubscribeLocalEvent(OnRemoveAttempt); + SubscribeLocalEvent(OnActiveTimer); + SubscribeLocalEvent(OnMeleeHit); } - private void OnRemoveAttempt(EntityUid uid, HotPotatoComponent comp, ContainerGettingRemovedAttemptEvent args) + private void OnRemoveAttempt(Entity ent, ref ContainerGettingRemovedAttemptEvent args) { - if (!comp.CanTransfer) + if (!_timing.ApplyingState && !ent.Comp.CanTransfer) args.Cancel(); } + + private void OnActiveTimer(Entity ent, ref ActiveTimerTriggerEvent args) + { + EnsureComp(ent); + ent.Comp.CanTransfer = false; + _ambientSound.SetAmbience(ent.Owner, true); + _damageOnHolding.SetEnabled(ent.Owner, true); + Dirty(ent); + } + + private void OnMeleeHit(Entity ent, ref MeleeHitEvent args) + { + if (!HasComp(ent)) + return; + + ent.Comp.CanTransfer = true; + foreach (var hitEntity in args.HitEntities) + { + if (!TryComp(hitEntity, out var hands)) + continue; + + if (!_hands.IsHolding((hitEntity, hands), ent.Owner, out _) && _hands.TryForcePickupAnyHand(hitEntity, ent.Owner, handsComp: hands)) + { + _popup.PopupPredicted( + Loc.GetString("hot-potato-passed", ("from", Identity.Entity(args.User, EntityManager)), ("to", Identity.Entity(hitEntity, EntityManager))), + ent.Owner, + args.User, + PopupType.Medium); + break; + } + + _popup.PopupClient( + Loc.GetString("hot-potato-failed", ("to", Identity.Entity(hitEntity, EntityManager))), + ent.Owner, + args.User, + PopupType.Medium); + + break; + } + + ent.Comp.CanTransfer = false; + } } diff --git a/Content.Shared/Implants/Components/RattleComponent.cs b/Content.Shared/Implants/Components/RattleComponent.cs deleted file mode 100644 index 3ec63e8e15b..00000000000 --- a/Content.Shared/Implants/Components/RattleComponent.cs +++ /dev/null @@ -1,21 +0,0 @@ -using Content.Shared.Radio; -using Robust.Shared.GameStates; -using Robust.Shared.Prototypes; - -namespace Content.Shared.Implants.Components; - -[RegisterComponent, NetworkedComponent] -public sealed partial class RattleComponent : Component -{ - // The radio channel the message will be sent to - [DataField] - public ProtoId RadioChannel = "Syndicate"; - - // The message that the implant will send when crit - [DataField] - public LocId CritMessage = "deathrattle-implant-critical-message"; - - // The message that the implant will send when dead - [DataField] - public LocId DeathMessage = "deathrattle-implant-dead-message"; -} diff --git a/Content.Shared/Implants/Components/TriggerImplantActionComponent.cs b/Content.Shared/Implants/Components/TriggerImplantActionComponent.cs deleted file mode 100644 index 0f9856f2a4e..00000000000 --- a/Content.Shared/Implants/Components/TriggerImplantActionComponent.cs +++ /dev/null @@ -1,12 +0,0 @@ -using Robust.Shared.GameStates; - -namespace Content.Shared.Implants.Components; - -/// -/// Triggers implants when the action is pressed -/// -[RegisterComponent, NetworkedComponent] -public sealed partial class TriggerImplantActionComponent : Component -{ - -} diff --git a/Content.Shared/Implants/SharedSubdermalImplantSystem.cs b/Content.Shared/Implants/SharedSubdermalImplantSystem.cs index e95b00907fa..678bafaa794 100644 --- a/Content.Shared/Implants/SharedSubdermalImplantSystem.cs +++ b/Content.Shared/Implants/SharedSubdermalImplantSystem.cs @@ -184,7 +184,7 @@ public abstract class SharedSubdermalImplantSystem : EntitySystem if (!_container.TryGetContainer(uid, ImplanterComponent.ImplantSlotId, out var implantContainer)) return; - var relayEv = new ImplantRelayEvent(args); + var relayEv = new ImplantRelayEvent(args, uid); foreach (var implant in implantContainer.ContainedEntities) { if (args is HandledEntityEventArgs { Handled : true }) @@ -199,9 +199,12 @@ public sealed class ImplantRelayEvent where T : notnull { public readonly T Event; - public ImplantRelayEvent(T ev) + public readonly EntityUid ImplantedEntity; + + public ImplantRelayEvent(T ev, EntityUid implantedEntity) { Event = ev; + ImplantedEntity = implantedEntity; } } diff --git a/Content.Shared/Item/ItemToggle/Components/ItemToggleComponent.cs b/Content.Shared/Item/ItemToggle/Components/ItemToggleComponent.cs index 424bd12bb3f..6f6e55b5ef2 100644 --- a/Content.Shared/Item/ItemToggle/Components/ItemToggleComponent.cs +++ b/Content.Shared/Item/ItemToggle/Components/ItemToggleComponent.cs @@ -50,25 +50,37 @@ public sealed partial class ItemToggleComponent : Component /// /// /// If server-side systems affect the item's toggle, like charge/fuel systems, then the item is not predictable. /// - [ViewVariables(VVAccess.ReadWrite), DataField, AutoNetworkedField] + [DataField, AutoNetworkedField] public bool Predictable = true; /// /// The noise this item makes when it is toggled on. /// - [ViewVariables(VVAccess.ReadWrite), DataField, AutoNetworkedField] + [DataField, AutoNetworkedField] public SoundSpecifier? SoundActivate; /// /// The noise this item makes when it is toggled off. /// - [ViewVariables(VVAccess.ReadWrite), DataField, AutoNetworkedField] + [DataField, AutoNetworkedField] public SoundSpecifier? SoundDeactivate; + /// + /// The popup to show to someone activating this item. + /// + [DataField, AutoNetworkedField] + public LocId? PopupActivate; + + /// + /// The popup to show to someone deactivating this item. + /// + [DataField, AutoNetworkedField] + public LocId? PopupDeactivate; + /// /// The noise this item makes when it is toggled on. /// - [ViewVariables(VVAccess.ReadWrite), DataField, AutoNetworkedField] + [DataField, AutoNetworkedField] public SoundSpecifier? SoundFailToActivate; } diff --git a/Content.Shared/Item/ItemToggle/ItemToggleSystem.cs b/Content.Shared/Item/ItemToggle/ItemToggleSystem.cs index 8008ecf9e5b..ff31faaaa1a 100644 --- a/Content.Shared/Item/ItemToggle/ItemToggleSystem.cs +++ b/Content.Shared/Item/ItemToggle/ItemToggleSystem.cs @@ -117,30 +117,30 @@ public sealed class ItemToggleSystem : EntitySystem /// Sets its state to the opposite of what it is. /// /// Same as - public bool Toggle(Entity ent, EntityUid? user = null, bool predicted = true) + public bool Toggle(Entity ent, EntityUid? user = null, bool predicted = true, bool showPopup = true) { if (!_query.Resolve(ent, ref ent.Comp, false)) return false; - return TrySetActive(ent, !ent.Comp.Activated, user, predicted); + return TrySetActive(ent, !ent.Comp.Activated, user, predicted, showPopup); } /// /// Tries to set the activated bool from a value. /// /// false if the attempt fails for any reason - public bool TrySetActive(Entity ent, bool active, EntityUid? user = null, bool predicted = true) + public bool TrySetActive(Entity ent, bool active, EntityUid? user = null, bool predicted = true, bool showPopup = true) { if (active) - return TryActivate(ent, user, predicted: predicted); + return TryActivate(ent, user, predicted: predicted, showPopup); else - return TryDeactivate(ent, user, predicted: predicted); + return TryDeactivate(ent, user, predicted: predicted, showPopup); } /// /// Used when an item is attempting to be activated. It returns false if the attempt fails any reason, interrupting the activation. /// - public bool TryActivate(Entity ent, EntityUid? user = null, bool predicted = true) + public bool TryActivate(Entity ent, EntityUid? user = null, bool predicted = true, bool showPopup = true) { if (!_query.Resolve(ent, ref ent.Comp, false)) return false; @@ -169,7 +169,7 @@ public sealed class ItemToggleSystem : EntitySystem else _audio.PlayPvs(comp.SoundFailToActivate, uid); - if (attempt.Popup != null && user != null) + if (showPopup && attempt.Popup != null && user != null) { if (predicted) _popup.PopupClient(attempt.Popup, uid, user.Value); @@ -180,14 +180,14 @@ public sealed class ItemToggleSystem : EntitySystem return false; } - Activate((uid, comp), predicted, user); + Activate((uid, comp), predicted, user, showPopup); return true; } /// /// Used when an item is attempting to be deactivated. It returns false if the attempt fails any reason, interrupting the deactivation. /// - public bool TryDeactivate(Entity ent, EntityUid? user = null, bool predicted = true) + public bool TryDeactivate(Entity ent, EntityUid? user = null, bool predicted = true, bool showPopup = true) { if (!_query.Resolve(ent, ref ent.Comp, false)) return false; @@ -211,7 +211,7 @@ public sealed class ItemToggleSystem : EntitySystem if (attempt.Silent) return false; - if (attempt.Popup != null && user != null) + if (showPopup && attempt.Popup != null && user != null) { if (predicted) _popup.PopupClient(attempt.Popup, uid, user.Value); @@ -222,18 +222,26 @@ public sealed class ItemToggleSystem : EntitySystem return false; } - Deactivate((uid, comp), predicted, user); + Deactivate((uid, comp), predicted, user, showPopup); return true; } - private void Activate(Entity ent, bool predicted, EntityUid? user = null) + private void Activate(Entity ent, bool predicted, EntityUid? user = null, bool showPopup = true) { var (uid, comp) = ent; var soundToPlay = comp.SoundActivate; if (predicted) + { _audio.PlayPredicted(soundToPlay, uid, user); + if (showPopup && ent.Comp.PopupActivate != null && user != null) + _popup.PopupClient(Loc.GetString(ent.Comp.PopupActivate), user.Value, user.Value); + } else + { _audio.PlayPvs(soundToPlay, uid); + if (showPopup && ent.Comp.PopupActivate != null && user != null) + _popup.PopupEntity(Loc.GetString(ent.Comp.PopupActivate), user.Value, user.Value); + } comp.Activated = true; UpdateVisuals((uid, comp)); @@ -246,14 +254,22 @@ public sealed class ItemToggleSystem : EntitySystem /// /// Used to make the actual changes to the item's components on deactivation. /// - private void Deactivate(Entity ent, bool predicted, EntityUid? user = null) + private void Deactivate(Entity ent, bool predicted, EntityUid? user = null, bool showPopup = true) { var (uid, comp) = ent; var soundToPlay = comp.SoundDeactivate; if (predicted) + { _audio.PlayPredicted(soundToPlay, uid, user); + if (showPopup && ent.Comp.PopupDeactivate != null && user != null) + _popup.PopupClient(Loc.GetString(ent.Comp.PopupDeactivate), user.Value, user.Value); + } else + { _audio.PlayPvs(soundToPlay, uid); + if (showPopup && ent.Comp.PopupDeactivate != null && user != null) + _popup.PopupEntity(Loc.GetString(ent.Comp.PopupDeactivate), user.Value, user.Value); + } comp.Activated = false; UpdateVisuals((uid, comp)); diff --git a/Content.Shared/Mousetrap/MousetrapComponent.cs b/Content.Shared/Mousetrap/MousetrapComponent.cs index 6d7483802bd..4f48f00b3a9 100644 --- a/Content.Shared/Mousetrap/MousetrapComponent.cs +++ b/Content.Shared/Mousetrap/MousetrapComponent.cs @@ -2,20 +2,20 @@ using Robust.Shared.GameStates; namespace Content.Shared.Mousetrap; -[RegisterComponent, NetworkedComponent] +/// +/// Component inteded to be used for mouse traps. +/// Will stop step triggers from happening unless armed via +/// and will scale damage taken from +/// depending on mass. +/// +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] public sealed partial class MousetrapComponent : Component { - [ViewVariables] - [DataField("isActive")] - public bool IsActive = false; - /// - /// Set this to change where the - /// inflection point in the scaling - /// equation will occur. - /// The default is 10. + /// Set this to change where the + /// inflection point in the damage scaling + /// equation will occur. /// - [ViewVariables(VVAccess.ReadWrite)] - [DataField("massBalance")] + [DataField, AutoNetworkedField] public int MassBalance = 10; } diff --git a/Content.Shared/Mousetrap/MousetrapSystem.cs b/Content.Shared/Mousetrap/MousetrapSystem.cs new file mode 100644 index 00000000000..da95a37f528 --- /dev/null +++ b/Content.Shared/Mousetrap/MousetrapSystem.cs @@ -0,0 +1,47 @@ +using Content.Shared.Abilities; // DeltaV +using Content.Shared.Item.ItemToggle.Components; +using Content.Shared.Trigger.Systems; +using Content.Shared.StepTrigger.Systems; +using Robust.Shared.Physics.Components; + +namespace Content.Shared.Mousetrap; + +public sealed class MousetrapSystem : EntitySystem +{ + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(BeforeDamageOnTrigger); + SubscribeLocalEvent(OnStepTriggerAttempt); + } + + // only allow step triggers to trigger if the trap is armed + // TODO: refactor Steptriggers to get rid of this + // they should just use the new trigger conditions + private void OnStepTriggerAttempt(Entity ent, ref StepTriggerAttemptEvent args) + { + // DeltaV: Entities with this component always trigger mouse traps, even if wearing shoes + if (HasComp(args.Tripper)) + args.Cancelled = false; + + if (!TryComp(ent, out var toggle)) + return; + + args.Continue |= toggle.Activated; + } + + // scale the damage according to mass + private void BeforeDamageOnTrigger(Entity ent, ref BeforeDamageOnTriggerEvent args) + { + if (TryComp(args.Tripper, out PhysicsComponent? physics) && physics.Mass != 0) + { + // The idea here is inverse, + // Small - big damage, + // Large - small damage + // yes i punched numbers into a calculator until the graph looked right + var scaledDamage = -50 * Math.Atan(physics.Mass - ent.Comp.MassBalance) + 25 * Math.PI; + args.Damage *= scaledDamage; + } + } +} diff --git a/Content.Shared/Mousetrap/MousetrapVisuals.cs b/Content.Shared/Mousetrap/MousetrapVisuals.cs deleted file mode 100644 index 9685157aad6..00000000000 --- a/Content.Shared/Mousetrap/MousetrapVisuals.cs +++ /dev/null @@ -1,11 +0,0 @@ -using Robust.Shared.Serialization; - -namespace Content.Shared.Mousetrap; - -[Serializable, NetSerializable] -public enum MousetrapVisuals : byte -{ - Visual, - Armed, - Unarmed -} diff --git a/Content.Shared/Ninja/Components/SpiderChargeComponent.cs b/Content.Shared/Ninja/Components/SpiderChargeComponent.cs index 3ba4494cca4..75053011ffa 100644 --- a/Content.Shared/Ninja/Components/SpiderChargeComponent.cs +++ b/Content.Shared/Ninja/Components/SpiderChargeComponent.cs @@ -10,11 +10,21 @@ namespace Content.Shared.Ninja.Components; [RegisterComponent, NetworkedComponent, Access(typeof(SharedSpiderChargeSystem))] public sealed partial class SpiderChargeComponent : Component { - /// Range for planting within the target area + /// + /// Range for planting within the target area. + /// [DataField] public float Range = 10f; - /// The ninja that planted this charge + /// + /// The ninja that planted this charge. + /// [DataField] public EntityUid? Planter; + + /// + /// The trigger that will mark the objective as successful. + /// + [DataField] + public string TriggerKey = "timer"; } diff --git a/Content.Shared/Payload/Components/PayloadTriggerComponent.cs b/Content.Shared/Payload/Components/PayloadTriggerComponent.cs index b064e91198c..d07da4b24e0 100644 --- a/Content.Shared/Payload/Components/PayloadTriggerComponent.cs +++ b/Content.Shared/Payload/Components/PayloadTriggerComponent.cs @@ -1,4 +1,5 @@ -using Content.Shared.Explosion.Components; +using Content.Shared.Trigger.Components; +using Content.Shared.Trigger.Components.Triggers; using Robust.Shared.GameStates; using Robust.Shared.Prototypes; @@ -10,7 +11,7 @@ namespace Content.Shared.Payload.Components; /// /// This component performs two functions. Firstly, it will add or remove other components to some entity when this /// item is installed inside of it. This is intended for use with constructible grenades. For example, this allows -/// you to add things like , or . +/// you to add things like , or . /// This is required because otherwise you would have to forward arbitrary interaction directed at the casing /// through to the trigger, which would be quite complicated. Also proximity triggers don't really work inside of /// containers. @@ -29,7 +30,7 @@ public sealed partial class PayloadTriggerComponent : Component /// /// List of components to add or remove from an entity when this trigger is (un)installed. /// - [DataField("components", serverOnly:true, readOnly: true)] + [DataField(serverOnly: true, readOnly: true)] public ComponentRegistry? Components = null; /// @@ -41,6 +42,6 @@ public sealed partial class PayloadTriggerComponent : Component /// when removing the component, to ensure that removal of this trigger only removes the components that it was /// responsible for adding. /// - [DataField("grantedComponents", serverOnly: true)] + [DataField(serverOnly: true)] public HashSet GrantedComponents = new(); } diff --git a/Content.Shared/Rootable/SharedRootableSystem.cs b/Content.Shared/Rootable/SharedRootableSystem.cs index e969d7a05f4..a960b30b383 100644 --- a/Content.Shared/Rootable/SharedRootableSystem.cs +++ b/Content.Shared/Rootable/SharedRootableSystem.cs @@ -1,6 +1,4 @@ -using Content.Server.Damage.Components; -using Content.Shared.Damage.Components; -using Content.Shared.Actions; +using Content.Shared.Actions; using Content.Shared.Actions.Components; using Content.Shared.Alert; using Content.Shared.Coordinates; @@ -10,6 +8,7 @@ using Content.Shared.Mobs; using Content.Shared.Movement.Systems; using Content.Shared.Slippery; using Content.Shared.Toggleable; +using Content.Shared.Trigger.Components.Effects; using Robust.Shared.Audio.Systems; using Robust.Shared.Physics.Components; using Robust.Shared.Physics.Events; @@ -131,7 +130,7 @@ public abstract class SharedRootableSystem : EntitySystem if (!ent.Comp.Rooted) return; - if (args.SlipCausingEntity != null && HasComp(args.SlipCausingEntity)) + if (args.SlipCausingEntity != null && HasComp(args.SlipCausingEntity)) return; args.NoSlip = true; diff --git a/Content.Shared/Speech/Components/ActiveListenerComponent.cs b/Content.Shared/Speech/Components/ActiveListenerComponent.cs new file mode 100644 index 00000000000..fde108a8170 --- /dev/null +++ b/Content.Shared/Speech/Components/ActiveListenerComponent.cs @@ -0,0 +1,17 @@ +using Content.Shared.Chat; +using Robust.Shared.GameStates; + +namespace Content.Shared.Speech.Components; + +/// +/// This component is used to relay speech events to other systems. +/// +[RegisterComponent, NetworkedComponent] +public sealed partial class ActiveListenerComponent : Component +{ + /// + /// The range in which to listen to speech. + /// + [DataField] + public float Range = SharedChatSystem.VoiceRange; +} diff --git a/Content.Server/Speech/ListenEvent.cs b/Content.Shared/Speech/ListenEvent.cs similarity index 93% rename from Content.Server/Speech/ListenEvent.cs rename to Content.Shared/Speech/ListenEvent.cs index b67aa92f65f..8854bd99f42 100644 --- a/Content.Server/Speech/ListenEvent.cs +++ b/Content.Shared/Speech/ListenEvent.cs @@ -1,4 +1,4 @@ -namespace Content.Server.Speech; +namespace Content.Shared.Speech; public sealed class ListenEvent : EntityEventArgs { diff --git a/Content.Shared/Sticky/Components/StickyComponent.cs b/Content.Shared/Sticky/Components/StickyComponent.cs index 45130917548..a4007b0780c 100644 --- a/Content.Shared/Sticky/Components/StickyComponent.cs +++ b/Content.Shared/Sticky/Components/StickyComponent.cs @@ -1,5 +1,5 @@ using Content.Shared.Sticky.Systems; -using Content.Shared.Whitelist; +using Content.Shared.Whitelist; using Robust.Shared.GameStates; using Robust.Shared.Utility; diff --git a/Content.Shared/Timing/UseDelaySystem.cs b/Content.Shared/Timing/UseDelaySystem.cs index d02752e16b3..0950e8981de 100644 --- a/Content.Shared/Timing/UseDelaySystem.cs +++ b/Content.Shared/Timing/UseDelaySystem.cs @@ -9,7 +9,7 @@ public sealed class UseDelaySystem : EntitySystem [Dependency] private readonly IGameTiming _gameTiming = default!; [Dependency] private readonly MetaDataSystem _metadata = default!; - private const string DefaultId = "default"; + public const string DefaultId = "default"; public override void Initialize() { diff --git a/Content.Shared/Trigger/Components/ActiveTimerTriggerComponent.cs b/Content.Shared/Trigger/Components/ActiveTimerTriggerComponent.cs new file mode 100644 index 00000000000..d7da5cecdeb --- /dev/null +++ b/Content.Shared/Trigger/Components/ActiveTimerTriggerComponent.cs @@ -0,0 +1,10 @@ +using Robust.Shared.GameStates; + +namespace Content.Shared.Trigger.Components; + +/// +/// Component used for tracking active timers triggers. +/// Used internally for performance reasons. +/// +[RegisterComponent, NetworkedComponent] +public sealed partial class ActiveTimerTriggerComponent : Component; diff --git a/Content.Shared/Trigger/Components/ActiveTwoStageTriggerComponent.cs b/Content.Shared/Trigger/Components/ActiveTwoStageTriggerComponent.cs new file mode 100644 index 00000000000..bddbbd402e1 --- /dev/null +++ b/Content.Shared/Trigger/Components/ActiveTwoStageTriggerComponent.cs @@ -0,0 +1,10 @@ +using Robust.Shared.GameStates; + +namespace Content.Shared.Trigger.Components; + +/// +/// Component used for tracking active two-stage triggers. +/// Used internally for performance reasons. +/// +[RegisterComponent, NetworkedComponent] +public sealed partial class ActiveTwoStageTriggerComponent : Component; diff --git a/Content.Shared/Trigger/Components/Conditions/BaseTriggerConditionComponent.cs b/Content.Shared/Trigger/Components/Conditions/BaseTriggerConditionComponent.cs new file mode 100644 index 00000000000..7e77c99d93a --- /dev/null +++ b/Content.Shared/Trigger/Components/Conditions/BaseTriggerConditionComponent.cs @@ -0,0 +1,15 @@ +using Content.Shared.Trigger.Systems; + +namespace Content.Shared.Trigger.Components.Conditions; + +/// +/// Base class for components that add a condition to triggers. +/// +public abstract partial class BaseTriggerConditionComponent : Component +{ + /// + /// The keys that are checked for the condition. + /// + [DataField, AutoNetworkedField] + public HashSet Keys = new() { TriggerSystem.DefaultTriggerKey }; +} diff --git a/Content.Shared/Trigger/Components/Conditions/ToggleTriggerConditionComponent.cs b/Content.Shared/Trigger/Components/Conditions/ToggleTriggerConditionComponent.cs new file mode 100644 index 00000000000..478f06602dc --- /dev/null +++ b/Content.Shared/Trigger/Components/Conditions/ToggleTriggerConditionComponent.cs @@ -0,0 +1,34 @@ +using Robust.Shared.GameStates; + +namespace Content.Shared.Trigger.Components.Conditions; + +/// +/// Adds an alt verb that can be used to toggle a trigger. +/// +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +public sealed partial class ToggleTriggerConditionComponent : BaseTriggerConditionComponent +{ + /// + /// Is the component currently enabled? + /// + [DataField, AutoNetworkedField] + public bool Enabled = true; + + /// + /// The text of the toggle verb. + /// + [DataField, AutoNetworkedField] + public LocId ToggleVerb = "toggle-trigger-condition-default-verb"; + + /// + /// The popup to show when toggled on. + /// + [DataField, AutoNetworkedField] + public LocId ToggleOn = "toggle-trigger-condition-default-on"; + + /// + /// The popup to show when toggled off. + /// + [DataField, AutoNetworkedField] + public LocId ToggleOff = "toggle-trigger-condition-default-off"; +} diff --git a/Content.Shared/Trigger/Components/Conditions/UseDelayTriggerConditionComponent.cs b/Content.Shared/Trigger/Components/Conditions/UseDelayTriggerConditionComponent.cs new file mode 100644 index 00000000000..70a331227e4 --- /dev/null +++ b/Content.Shared/Trigger/Components/Conditions/UseDelayTriggerConditionComponent.cs @@ -0,0 +1,20 @@ +using Content.Shared.Timing; +using Robust.Shared.GameStates; + +namespace Content.Shared.Trigger.Components.Conditions; + +/// +/// Checks if the triggered entity has an active UseDelay. +/// +/// +/// TODO: Support specific UseDelay IDs for each trigger key. +/// +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +public sealed partial class UseDelayTriggerConditionComponent : BaseTriggerConditionComponent +{ + /// + /// Checks if the triggered entity has an active UseDelay. + /// + [DataField, AutoNetworkedField] + public string UseDelayId = UseDelaySystem.DefaultId; +} diff --git a/Content.Shared/Trigger/Components/Conditions/WhitelistTriggerConditionComponent.cs b/Content.Shared/Trigger/Components/Conditions/WhitelistTriggerConditionComponent.cs new file mode 100644 index 00000000000..a2779f79c6f --- /dev/null +++ b/Content.Shared/Trigger/Components/Conditions/WhitelistTriggerConditionComponent.cs @@ -0,0 +1,24 @@ +using Content.Shared.Whitelist; +using Robust.Shared.GameStates; + +namespace Content.Shared.Trigger.Components.Conditions; + +/// +/// Checks if the user of a trigger satisfies a whitelist and blacklist condition for the triggered entity or the one triggering it. +/// Cancels the trigger otherwise. +/// +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +public sealed partial class WhitelistTriggerConditionComponent : BaseTriggerConditionComponent +{ + /// + /// Whitelist for what entites can cause this trigger. + /// + [DataField, AutoNetworkedField] + public EntityWhitelist? UserWhitelist; + + /// + /// Blacklist for what entites can cause this trigger. + /// + [DataField, AutoNetworkedField] + public EntityWhitelist? UserBlacklist; +} diff --git a/Content.Shared/Trigger/Components/Effects/AddComponentsOnTriggerComponent.cs b/Content.Shared/Trigger/Components/Effects/AddComponentsOnTriggerComponent.cs new file mode 100644 index 00000000000..06f5258fbef --- /dev/null +++ b/Content.Shared/Trigger/Components/Effects/AddComponentsOnTriggerComponent.cs @@ -0,0 +1,37 @@ +using Robust.Shared.GameStates; +using Robust.Shared.Prototypes; + +namespace Content.Shared.Trigger.Components.Effects; + +/// +/// Adds the specified components when triggered. +/// If TargetUser is true they will be added to the user. +/// +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +public sealed partial class AddComponentsOnTriggerComponent : BaseXOnTriggerComponent +{ + /// + /// The list of components that will be added. + /// + [DataField(required: true)] + public ComponentRegistry Components = new(); + + /// + /// If this component has been triggered at least once already. + /// If this is true the components have been added. + /// + [DataField, AutoNetworkedField] + public bool Triggered = false; + + /// + /// If this effect can only be triggered once. + /// + [DataField, AutoNetworkedField] + public bool TriggerOnce = false; + + /// + /// Should components that already exist on the entity be overwritten? + /// + [DataField, AutoNetworkedField] + public bool RemoveExisting = false; +} diff --git a/Content.Shared/Trigger/Components/Effects/AlertLevelChangeOnTriggerComponent.cs b/Content.Shared/Trigger/Components/Effects/AlertLevelChangeOnTriggerComponent.cs new file mode 100644 index 00000000000..0d161344d8c --- /dev/null +++ b/Content.Shared/Trigger/Components/Effects/AlertLevelChangeOnTriggerComponent.cs @@ -0,0 +1,34 @@ +using Robust.Shared.GameStates; + +namespace Content.Shared.Trigger.Components.Effects; + +/// +/// Changes the alert level of the station when triggered. +/// +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +public sealed partial class AlertLevelChangeOnTriggerComponent : BaseXOnTriggerComponent +{ + /// + /// The alert level to change to when triggered. + /// + [DataField, AutoNetworkedField] + public string Level = "blue"; + + /// + /// Whether to play the sound when the alert level changes. + /// + [DataField, AutoNetworkedField] + public bool PlaySound = true; + + /// + /// Whether to say the announcement when the alert level changes. + /// + [DataField, AutoNetworkedField] + public bool Announce = true; + + /// + /// Force the alert change. This applies if the alert level is not selectable or not. + /// + [DataField, AutoNetworkedField] + public bool Force = false; +} diff --git a/Content.Shared/Trigger/Components/Effects/AnchorOnTriggerComponent.cs b/Content.Shared/Trigger/Components/Effects/AnchorOnTriggerComponent.cs new file mode 100644 index 00000000000..ed61876f156 --- /dev/null +++ b/Content.Shared/Trigger/Components/Effects/AnchorOnTriggerComponent.cs @@ -0,0 +1,34 @@ +using Robust.Shared.GameStates; + +namespace Content.Shared.Trigger.Components.Effects; + +/// +/// Will (un)anchor the entity when triggered. +/// If TargetUser is true they will be (un)anchored instead. +/// +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +public sealed partial class AnchorOnTriggerComponent : BaseXOnTriggerComponent +{ + /// + /// Anchor the entity on trigger if it is currently unanchored? + /// + [DataField, AutoNetworkedField] + public bool CanAnchor = true; + + /// + /// Unanchor the entity on trigger if it is currently anchored? + /// If both this and CanAnchor are true then the trigger will toggle between states. + /// + [DataField, AutoNetworkedField] + public bool CanUnanchor = false; + + /// + /// Removes this component when triggered so it can only be activated once. + /// + /// + /// TODO: Make this a generic thing for all triggers. + /// Or just add a RemoveComponentsOnTriggerComponent. + /// + [DataField, AutoNetworkedField] + public bool RemoveOnTrigger = true; +} diff --git a/Content.Shared/Trigger/Components/Effects/BaseXOnTriggerComponent.cs b/Content.Shared/Trigger/Components/Effects/BaseXOnTriggerComponent.cs new file mode 100644 index 00000000000..cf93ad6c4a9 --- /dev/null +++ b/Content.Shared/Trigger/Components/Effects/BaseXOnTriggerComponent.cs @@ -0,0 +1,22 @@ +using Content.Shared.Trigger.Systems; + +namespace Content.Shared.Trigger.Components.Effects; + +/// +/// Base class for components that do something when triggered. +/// +public abstract partial class BaseXOnTriggerComponent : Component +{ + /// + /// The keys that will activate the effect. + /// + [DataField, AutoNetworkedField] + public HashSet KeysIn = new() { TriggerSystem.DefaultTriggerKey }; + + /// + /// Set to true to make the user of the trigger the effect target. + /// Set to false to make the owner of this component the target. + /// + [DataField, AutoNetworkedField] + public bool TargetUser = false; +} diff --git a/Content.Shared/Trigger/Components/Effects/DamageOnTriggerComponent.cs b/Content.Shared/Trigger/Components/Effects/DamageOnTriggerComponent.cs new file mode 100644 index 00000000000..a418edc16f9 --- /dev/null +++ b/Content.Shared/Trigger/Components/Effects/DamageOnTriggerComponent.cs @@ -0,0 +1,32 @@ +using Content.Shared.Damage; +using Content.Shared._Shitmed.Targeting; // Shitmed +using Robust.Shared.GameStates; + +namespace Content.Shared.Trigger.Components.Effects; + +/// +/// Will damage an entity when triggered. +/// If TargetUser is true it the user will take damage instead. +/// +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +public sealed partial class DamageOnTriggerComponent : BaseXOnTriggerComponent +{ + /// + /// Should the damage ignore resistances? + /// + [DataField, AutoNetworkedField] + public bool IgnoreResistances; + + /// + /// The base damage amount that is dealt. + /// May be further modified by subscriptions. + /// + [DataField(required: true), AutoNetworkedField] + public DamageSpecifier Damage = default!; + + /// + /// Shitmed Change: Lets mousetraps, etc. target the feet. + /// + [DataField] + public TargetBodyPart? TargetPart = TargetBodyPart.Feet; +} diff --git a/Content.Shared/Trigger/Components/Effects/DeleteOnTriggerComponent.cs b/Content.Shared/Trigger/Components/Effects/DeleteOnTriggerComponent.cs new file mode 100644 index 00000000000..9d0a5b75176 --- /dev/null +++ b/Content.Shared/Trigger/Components/Effects/DeleteOnTriggerComponent.cs @@ -0,0 +1,10 @@ +using Robust.Shared.GameStates; + +namespace Content.Shared.Trigger.Components.Effects; + +/// +/// Will delete the entity when triggered. +/// If TargetUser is true it will delete them instead. +/// +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +public sealed partial class DeleteOnTriggerComponent : BaseXOnTriggerComponent; diff --git a/Content.Shared/Trigger/Components/Effects/EmitSoundOnTriggerComponent.cs b/Content.Shared/Trigger/Components/Effects/EmitSoundOnTriggerComponent.cs new file mode 100644 index 00000000000..f3870225e20 --- /dev/null +++ b/Content.Shared/Trigger/Components/Effects/EmitSoundOnTriggerComponent.cs @@ -0,0 +1,31 @@ +using Robust.Shared.Audio; +using Robust.Shared.GameStates; + +namespace Content.Shared.Trigger.Components.Effects; + +/// +/// Will play a sound in PVS range when triggered. +/// If TargetUser is true it will be played at their position. +/// +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +public sealed partial class EmitSoundOnTriggerComponent : BaseXOnTriggerComponent +{ + /// + /// The to play. + /// + [DataField(required: true), AutoNetworkedField] + public SoundSpecifier? Sound; + + /// + /// Play the sound at the position instead of parented to the source entity. + /// Useful if the entity is deleted after. + /// + [DataField, AutoNetworkedField] + public bool Positional; + + /// + /// Should this sound be predicted for the User? + /// + [DataField, AutoNetworkedField] + public bool Predicted; +} diff --git a/Content.Shared/Trigger/Components/Effects/EmpOnTriggerComponent.cs b/Content.Shared/Trigger/Components/Effects/EmpOnTriggerComponent.cs new file mode 100644 index 00000000000..2c4ff361878 --- /dev/null +++ b/Content.Shared/Trigger/Components/Effects/EmpOnTriggerComponent.cs @@ -0,0 +1,41 @@ +using Content.Shared.Damage; // DeltaV - EMP damage +using Robust.Shared.GameStates; + + +namespace Content.Shared.Trigger.Components.Effects; + +/// +/// Will cause an EMP at the entity's location when triggered. +/// If TargetUser is true then it will be spawned at their position. +/// +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +public sealed partial class EmpOnTriggerComponent : BaseXOnTriggerComponent +{ + /// + /// EMP range. + /// + [DataField, AutoNetworkedField] + public float Range = 1.0f; + + /// + /// How much energy (in Joules) will be consumed per battery in range. + /// + [DataField, AutoNetworkedField] + public float EnergyConsumption; + + /// + /// How long it disables targets. + /// + [DataField, AutoNetworkedField] + public TimeSpan DisableDuration = TimeSpan.FromSeconds(60); + + /// + /// DeltaV - The damage dealt to silicons instead of draining their power cells + /// + [DataField] + public DamageSpecifier Damage = new() { + DamageDict = new() { + { "Ion", 130 } // Most EMP sources should pretty much oneshot silicons. This would kill an IPC and completely disable a borg for a minute. + } + }; +} diff --git a/Content.Shared/Trigger/Components/Effects/ExplodeOnTriggerComponent.cs b/Content.Shared/Trigger/Components/Effects/ExplodeOnTriggerComponent.cs new file mode 100644 index 00000000000..2a1af40a2cd --- /dev/null +++ b/Content.Shared/Trigger/Components/Effects/ExplodeOnTriggerComponent.cs @@ -0,0 +1,14 @@ +using Robust.Shared.GameStates; + +namespace Content.Shared.Trigger.Components.Effects; + +/// +/// Will explode using the entity's when triggered. +/// TargetUser will only work of the user has ExplosiveComponent as well. +/// The User will be logged in the admin logs. +/// +/// +/// TODO: Allow this to work without an ExplosiveComponent on the user via QueueExplosion. +/// +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +public sealed partial class ExplodeOnTriggerComponent : BaseXOnTriggerComponent; diff --git a/Content.Shared/Trigger/Components/Effects/FlashOnTriggerComponent.cs b/Content.Shared/Trigger/Components/Effects/FlashOnTriggerComponent.cs new file mode 100644 index 00000000000..8b75417031f --- /dev/null +++ b/Content.Shared/Trigger/Components/Effects/FlashOnTriggerComponent.cs @@ -0,0 +1,29 @@ +using Robust.Shared.GameStates; + +namespace Content.Shared.Trigger.Components.Effects; + +/// +/// Will cause a flash in an area around the entity when triggered. +/// If TargetUser is true then their location will be used. +/// +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +public sealed partial class FlashOnTriggerComponent : BaseXOnTriggerComponent +{ + /// + /// The range in which to flash entities in. + /// + [DataField, AutoNetworkedField] + public float Range = 1.0f; + + /// + /// The duration of the status effect. + /// + [DataField, AutoNetworkedField] + public TimeSpan Duration = TimeSpan.FromSeconds(8); + + /// + /// The probability to apply the status effect. + /// + [DataField, AutoNetworkedField] + public float Probability = 1.0f; +} diff --git a/Content.Shared/Trigger/Components/Effects/GhostKickOnTriggerComponent.cs b/Content.Shared/Trigger/Components/Effects/GhostKickOnTriggerComponent.cs new file mode 100644 index 00000000000..16c1365c050 --- /dev/null +++ b/Content.Shared/Trigger/Components/Effects/GhostKickOnTriggerComponent.cs @@ -0,0 +1,19 @@ +using Robust.Shared.GameStates; + +namespace Content.Shared.Trigger.Components.Effects; + +/// +/// Will kick a player from the server as if their connection dropped if triggered. +/// Yes, really. Don't use this component. +/// If TargetUser is true then the user of the trigger will be kicked, otherwise the entity itself. +/// +/// +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +public sealed partial class GhostKickOnTriggerComponent : BaseXOnTriggerComponent +{ + /// + /// The reason that will be displayed in the server log when a player is kicked. + /// + [DataField, AutoNetworkedField] + public LocId Reason = "ghost-kick-on-trigger-default"; +} diff --git a/Content.Shared/Trigger/Components/Effects/GibOnTriggerComponent.cs b/Content.Shared/Trigger/Components/Effects/GibOnTriggerComponent.cs new file mode 100644 index 00000000000..b3475ac447e --- /dev/null +++ b/Content.Shared/Trigger/Components/Effects/GibOnTriggerComponent.cs @@ -0,0 +1,17 @@ +using Robust.Shared.GameStates; + +namespace Content.Shared.Trigger.Components.Effects; + +/// +/// Will gib the entity when triggered. +/// If TargetUser is true the user will be gibbed instead. +/// +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +public sealed partial class GibOnTriggerComponent : BaseXOnTriggerComponent +{ + /// + /// Should gibbing also delete the owners items? + /// + [DataField, AutoNetworkedField] + public bool DeleteItems = false; +} diff --git a/Content.Shared/Trigger/Components/Effects/IgniteOnTriggerComponent.cs b/Content.Shared/Trigger/Components/Effects/IgniteOnTriggerComponent.cs new file mode 100644 index 00000000000..36273ef1b21 --- /dev/null +++ b/Content.Shared/Trigger/Components/Effects/IgniteOnTriggerComponent.cs @@ -0,0 +1,27 @@ +using Robust.Shared.GameStates; +using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom; + +namespace Content.Shared.Trigger.Components.Effects; + +/// +/// Will ignite for a certain length of time when triggered. +/// Requires along with triggering components. +/// The if TargetUser is true they will be ignited instead (they need IgnitionSourceComponent as well). +/// +[RegisterComponent, NetworkedComponent] +[AutoGenerateComponentState, AutoGenerateComponentPause] +public sealed partial class IgniteOnTriggerComponent : BaseXOnTriggerComponent +{ + /// + /// Once ignited, the time it will unignite at. + /// + [DataField(customTypeSerializer: typeof(TimeOffsetSerializer))] + [AutoNetworkedField, AutoPausedField] + public TimeSpan IgnitedUntil = TimeSpan.Zero; + + /// + /// How long the ignition source is active for after triggering. + /// + [DataField, AutoNetworkedField] + public TimeSpan IgnitedTime = TimeSpan.FromSeconds(0.5); +} diff --git a/Content.Shared/Trigger/Components/Effects/ItemToggleOnTriggerComponent.cs b/Content.Shared/Trigger/Components/Effects/ItemToggleOnTriggerComponent.cs new file mode 100644 index 00000000000..4c5360f4d23 --- /dev/null +++ b/Content.Shared/Trigger/Components/Effects/ItemToggleOnTriggerComponent.cs @@ -0,0 +1,37 @@ +using Content.Shared.Item.ItemToggle.Components; +using Robust.Shared.GameStates; + +namespace Content.Shared.Trigger.Components.Effects; + +/// +/// Will toggle an item when triggered. Requires . +/// If TargetUser is true and they have that component they will be toggled instead. +/// +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +public sealed partial class ItemToggleOnTriggerComponent : BaseXOnTriggerComponent +{ + /// + /// Can the item be toggled on using the trigger? + /// + [DataField, AutoNetworkedField] + public bool CanActivate = true; + + /// + /// Can the item be toggled on using the trigger? + /// If both this and CanActivate are true then the trigger will toggle between states. + /// + [DataField, AutoNetworkedField] + public bool CanDeactivate = true; + + /// + /// Can the audio and popups be predicted? + /// + [DataField, AutoNetworkedField] + public bool Predicted = true; + + /// + /// Show a popup to the user when toggling the item? + /// + [DataField, AutoNetworkedField] + public bool ShowPopup = true; +} diff --git a/Content.Shared/Trigger/Components/Effects/PolymorphOnTriggerComponent.cs b/Content.Shared/Trigger/Components/Effects/PolymorphOnTriggerComponent.cs new file mode 100644 index 00000000000..3d2021e4256 --- /dev/null +++ b/Content.Shared/Trigger/Components/Effects/PolymorphOnTriggerComponent.cs @@ -0,0 +1,19 @@ +using Content.Shared.Polymorph; +using Robust.Shared.GameStates; +using Robust.Shared.Prototypes; + +namespace Content.Shared.Trigger.Components.Effects; + +/// +/// Polymorphs the enity when triggered. +/// If TargetUser is true it will polymorph the user instead. +/// +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +public sealed partial class PolymorphOnTriggerComponent : BaseXOnTriggerComponent +{ + /// + /// Polymorph settings. + /// + [DataField(required: true)] + public ProtoId Polymorph; +} diff --git a/Content.Shared/Trigger/Components/Effects/RattleOnTriggerComponent.cs b/Content.Shared/Trigger/Components/Effects/RattleOnTriggerComponent.cs new file mode 100644 index 00000000000..599a64339a1 --- /dev/null +++ b/Content.Shared/Trigger/Components/Effects/RattleOnTriggerComponent.cs @@ -0,0 +1,30 @@ +using Content.Shared.Mobs; +using Content.Shared.Radio; +using Robust.Shared.GameStates; +using Robust.Shared.Prototypes; + +namespace Content.Shared.Trigger.Components.Effects; + +/// +/// Sends an emergency message over coms when triggered giving information about the entity's mob status. +/// If TargetUser is true then the user's mob state will be used instead. +/// +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +public sealed partial class RattleOnTriggerComponent : BaseXOnTriggerComponent +{ + /// + /// The radio channel the message will be sent to. + /// + [DataField] + public ProtoId RadioChannel = "Syndicate"; + + /// + /// The message to be send depending on the target's current mob state. + /// + [DataField] + public Dictionary Messages = new() + { + {MobState.Critical, "deathrattle-implant-critical-message"}, + {MobState.Dead, "deathrattle-implant-dead-message"} + }; +} diff --git a/Content.Shared/Explosion/Components/OnTrigger/ReleaseGasOnTriggerComponent.cs b/Content.Shared/Trigger/Components/Effects/ReleaseGasOnTriggerComponent.cs similarity index 90% rename from Content.Shared/Explosion/Components/OnTrigger/ReleaseGasOnTriggerComponent.cs rename to Content.Shared/Trigger/Components/Effects/ReleaseGasOnTriggerComponent.cs index 28a5c5cf813..4edd5f83f44 100644 --- a/Content.Shared/Explosion/Components/OnTrigger/ReleaseGasOnTriggerComponent.cs +++ b/Content.Shared/Trigger/Components/Effects/ReleaseGasOnTriggerComponent.cs @@ -1,18 +1,16 @@ using Content.Shared.Atmos; -using Content.Shared.Explosion.EntitySystems; using Robust.Shared.GameStates; using Robust.Shared.Serialization; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom; -namespace Content.Shared.Explosion.Components.OnTrigger; +namespace Content.Shared.Trigger.Components.Effects; /// /// Contains a GasMixture that will release its contents to the atmosphere when triggered. /// [RegisterComponent, NetworkedComponent] -[AutoGenerateComponentPause] -[Access(typeof(SharedReleaseGasOnTriggerSystem))] -public sealed partial class ReleaseGasOnTriggerComponent : Component +[AutoGenerateComponentState, AutoGenerateComponentPause] +public sealed partial class ReleaseGasOnTriggerComponent : BaseXOnTriggerComponent { /// /// Whether this grenade is active and releasing gas. diff --git a/Content.Shared/Explosion/Components/OnTrigger/SharedRepulseAttractOnTriggerComponent.cs b/Content.Shared/Trigger/Components/Effects/RepulseAttractOnTriggerComponent.cs similarity index 57% rename from Content.Shared/Explosion/Components/OnTrigger/SharedRepulseAttractOnTriggerComponent.cs rename to Content.Shared/Trigger/Components/Effects/RepulseAttractOnTriggerComponent.cs index 43febff03bd..68af0bb544f 100644 --- a/Content.Shared/Explosion/Components/OnTrigger/SharedRepulseAttractOnTriggerComponent.cs +++ b/Content.Shared/Trigger/Components/Effects/RepulseAttractOnTriggerComponent.cs @@ -1,37 +1,39 @@ using Content.Shared.Physics; using Content.Shared.Whitelist; +using Robust.Shared.GameStates; -namespace Content.Shared.Explosion.Components.OnTrigger; +namespace Content.Shared.Trigger.Components.Effects; /// -/// Generates a gravity pulse/repulse using the RepulseAttractComponent when the entity is triggered +/// Generates a gravity pulse/repulse using the RepulseAttractComponent around the entity when triggered. +/// If TargetUser is true their location will be used instead. /// -[RegisterComponent] -public sealed partial class SharedRepulseAttractOnTriggerComponent : Component +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +public sealed partial class RepulseAttractOnTriggerComponent : BaseXOnTriggerComponent { /// /// How fast should the Repulsion/Attraction be? - /// A positive value will repulse objects, a negative value will attract + /// A positive value will repulse objects, a negative value will attract. /// - [DataField] - public float Speed; + [DataField, AutoNetworkedField] + public float Speed = 5.0f; /// /// How close do the entities need to be? /// - [DataField] - public float Range; + [DataField, AutoNetworkedField] + public float Range = 5.0f; /// /// What kind of entities should this effect apply to? /// - [DataField] + [DataField, AutoNetworkedField] public EntityWhitelist? Whitelist; /// /// What collision layers should be excluded? /// The default excludes ghost mobs, revenants, the AI camera etc. /// - [DataField] + [DataField, AutoNetworkedField] public CollisionGroup CollisionMask = CollisionGroup.GhostImpassable; } diff --git a/Content.Shared/Trigger/Components/Effects/ShockOnTriggerComponent.cs b/Content.Shared/Trigger/Components/Effects/ShockOnTriggerComponent.cs new file mode 100644 index 00000000000..e7da7a3801c --- /dev/null +++ b/Content.Shared/Trigger/Components/Effects/ShockOnTriggerComponent.cs @@ -0,0 +1,34 @@ +using Robust.Shared.GameStates; + +namespace Content.Shared.Trigger.Components.Effects; + +/// +/// Will electrocute the entity when triggered. +/// If TargetUser is true it will electrocute the user instead. +/// +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +public sealed partial class ShockOnTriggerComponent : BaseXOnTriggerComponent +{ + /// + /// Electrocute entity containing this entity instead (for example for wearable clothing). + /// Has priority over TargetUser. + /// + /// + /// TODO: Make this more generic so it can be used for all triggers. + /// Maybe a BeforeTriggerEvent where we modify the target. + /// + [DataField, AutoNetworkedField] + public bool TargetContainer; + + /// + /// The force of an electric shock when the trigger is triggered. + /// + [DataField, AutoNetworkedField] + public int Damage = 5; + + /// + /// Duration of electric shock when the trigger is triggered. + /// + [DataField, AutoNetworkedField] + public TimeSpan Duration = TimeSpan.FromSeconds(2); +} diff --git a/Content.Shared/Trigger/Components/Effects/SignalOnTriggerComponent.cs b/Content.Shared/Trigger/Components/Effects/SignalOnTriggerComponent.cs new file mode 100644 index 00000000000..0698f2ca331 --- /dev/null +++ b/Content.Shared/Trigger/Components/Effects/SignalOnTriggerComponent.cs @@ -0,0 +1,18 @@ +using Content.Shared.DeviceLinking; +using Robust.Shared.GameStates; +using Robust.Shared.Prototypes; + +namespace Content.Shared.Trigger.Components.Effects; + +/// +/// Sends a device link signal when triggered. +/// +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +public sealed partial class SignalOnTriggerComponent : BaseXOnTriggerComponent +{ + /// + /// The port that gets signaled when the switch turns on. + /// + [DataField] + public ProtoId Port = "Trigger"; +} diff --git a/Content.Shared/Explosion/Components/OnTrigger/SmokeOnTriggerComponent.cs b/Content.Shared/Trigger/Components/Effects/SmokeOnTriggerComponent.cs similarity index 59% rename from Content.Shared/Explosion/Components/OnTrigger/SmokeOnTriggerComponent.cs rename to Content.Shared/Trigger/Components/Effects/SmokeOnTriggerComponent.cs index 1138e74af8f..07a5bad056c 100644 --- a/Content.Shared/Explosion/Components/OnTrigger/SmokeOnTriggerComponent.cs +++ b/Content.Shared/Trigger/Components/Effects/SmokeOnTriggerComponent.cs @@ -1,34 +1,34 @@ -using Content.Shared.Explosion.EntitySystems; using Content.Shared.Chemistry.Components; using Robust.Shared.GameStates; using Robust.Shared.Prototypes; -namespace Content.Shared.Explosion.Components; +namespace Content.Shared.Trigger.Components.Effects; /// /// Creates a smoke cloud when triggered, with an optional solution to include in it. -/// No sound is played incase a grenade is stealthy, use if you want a sound. +/// No sound is played incase a grenade is stealthy, use if you want a sound. +/// If TargetUser is true the smoke is spawned at their location. /// -[RegisterComponent, NetworkedComponent, Access(typeof(SharedSmokeOnTriggerSystem))] -public sealed partial class SmokeOnTriggerComponent : Component +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +public sealed partial class SmokeOnTriggerComponent : BaseXOnTriggerComponent { /// - /// How long the smoke stays for, after it has spread. + /// How long the smoke stays for, after it has spread (in seconds). /// - [DataField, ViewVariables(VVAccess.ReadWrite)] - public float Duration = 10; + [DataField, AutoNetworkedField] + public TimeSpan Duration = TimeSpan.FromSeconds(10); /// /// How much the smoke will spread. /// - [DataField(required: true), ViewVariables(VVAccess.ReadWrite)] + [DataField(required: true), AutoNetworkedField] public int SpreadAmount; /// /// Smoke entity to spawn. /// Defaults to smoke but you can use foam if you want. /// - [DataField, ViewVariables(VVAccess.ReadWrite)] + [DataField, AutoNetworkedField] public EntProtoId SmokePrototype = "Smoke"; /// @@ -37,6 +37,6 @@ public sealed partial class SmokeOnTriggerComponent : Component /// /// When using repeating trigger this essentially gets multiplied so dont do anything crazy like omnizine or lexorin. /// - [DataField, ViewVariables(VVAccess.ReadWrite)] + [DataField, AutoNetworkedField] public Solution Solution = new(); } diff --git a/Content.Shared/Trigger/Components/Effects/SpawnOnTriggerComponent.cs b/Content.Shared/Trigger/Components/Effects/SpawnOnTriggerComponent.cs new file mode 100644 index 00000000000..782626f479b --- /dev/null +++ b/Content.Shared/Trigger/Components/Effects/SpawnOnTriggerComponent.cs @@ -0,0 +1,31 @@ +using Robust.Shared.GameStates; +using Robust.Shared.Prototypes; + +namespace Content.Shared.Trigger.Components.Effects; + +/// +/// Spawns a protoype when triggered. +/// If TargetUser is true it will be spawned at their location. +/// +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +public sealed partial class SpawnOnTriggerComponent : BaseXOnTriggerComponent +{ + /// + /// The prototype to spawn. + /// + [DataField(required: true), AutoNetworkedField] + public EntProtoId Proto = string.Empty; + + /// + /// Use MapCoordinates for spawning? + /// Set to true if you don't want the new entity parented to the spawner. + /// + [DataField, AutoNetworkedField] + public bool UseMapCoords; + + /// + /// Whether or not to use predicted spawning. + /// + [DataField, AutoNetworkedField] + public bool Predicted; +} diff --git a/Content.Shared/Trigger/Components/Effects/SpeakOnTriggerComponent.cs b/Content.Shared/Trigger/Components/Effects/SpeakOnTriggerComponent.cs new file mode 100644 index 00000000000..8fe6927046b --- /dev/null +++ b/Content.Shared/Trigger/Components/Effects/SpeakOnTriggerComponent.cs @@ -0,0 +1,26 @@ +using Content.Shared.Dataset; +using Robust.Shared.GameStates; +using Robust.Shared.Prototypes; + +namespace Content.Shared.Trigger.Components.Effects; + +/// +/// Makes the entity speak a message when triggered. +/// If TargetUser is true then they will be forced to speak instead. +/// +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +public sealed partial class SpeakOnTriggerComponent : BaseXOnTriggerComponent +{ + /// + /// The text to speak. This has priority over Pack. + /// + [DataField] + public LocId? Text; + + /// + /// The identifier for the dataset prototype containing messages to be spoken by this entity. + /// The spoken text will be picked randomly from it. + /// + [DataField] + public ProtoId? Pack; +} diff --git a/Content.Shared/Trigger/Components/Effects/UseDelayOnTriggerComponent.cs b/Content.Shared/Trigger/Components/Effects/UseDelayOnTriggerComponent.cs new file mode 100644 index 00000000000..4d43c2860be --- /dev/null +++ b/Content.Shared/Trigger/Components/Effects/UseDelayOnTriggerComponent.cs @@ -0,0 +1,26 @@ +using Content.Shared.Timing; +using Robust.Shared.GameStates; + +namespace Content.Shared.Trigger.Components.Effects; + +/// +/// Will activate an UseDelay on the target when triggered. +/// +/// +/// TODO: Support specific UseDelay IDs for each trigger key. +/// +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +public sealed partial class UseDelayOnTriggerComponent : BaseXOnTriggerComponent +{ + /// + /// The UseDelay Id to delay. + /// + [DataField, AutoNetworkedField] + public string UseDelayId = UseDelaySystem.DefaultId; + + /// + /// If true ongoing delays won't be reset. + /// + [DataField, AutoNetworkedField] + public bool CheckDelayed; +} diff --git a/Content.Server/Explosion/Components/RandomTimerTriggerComponent.cs b/Content.Shared/Trigger/Components/RandomTimerTriggerComponent.cs similarity index 50% rename from Content.Server/Explosion/Components/RandomTimerTriggerComponent.cs rename to Content.Shared/Trigger/Components/RandomTimerTriggerComponent.cs index 3863b9c313a..89b5535854f 100644 --- a/Content.Server/Explosion/Components/RandomTimerTriggerComponent.cs +++ b/Content.Shared/Trigger/Components/RandomTimerTriggerComponent.cs @@ -1,22 +1,22 @@ -using Content.Server.Explosion.EntitySystems; +using Robust.Shared.GameStates; -namespace Content.Server.Explosion.Components; +namespace Content.Shared.Trigger.Components; /// -/// This is used for randomizing a on MapInit +/// This is used for randomizing a on MapInit. /// -[RegisterComponent, Access(typeof(TriggerSystem))] +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] public sealed partial class RandomTimerTriggerComponent : Component { /// /// The minimum random trigger time. /// - [DataField] + [DataField, AutoNetworkedField] public float Min; /// /// The maximum random trigger time. /// - [DataField] + [DataField, AutoNetworkedField] public float Max; } diff --git a/Content.Shared/Trigger/Components/TimerTriggerComponent.cs b/Content.Shared/Trigger/Components/TimerTriggerComponent.cs new file mode 100644 index 00000000000..9cc58d3cda5 --- /dev/null +++ b/Content.Shared/Trigger/Components/TimerTriggerComponent.cs @@ -0,0 +1,109 @@ +using Content.Shared.Guidebook; +using Content.Shared.Trigger.Systems; +using Robust.Shared.Audio; +using Robust.Shared.GameStates; +using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom; +using System.Linq; + +namespace Content.Shared.Trigger.Components; + +/// +/// Starts a timer when activated by a trigger. +/// Will cause a different trigger once the time is over. +/// Can play a sound while the timer is active. +/// The time can be set by other components, for example . +/// +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState, AutoGenerateComponentPause] +public sealed partial class TimerTriggerComponent : Component +{ + /// + /// The keys that will activate the timer. + /// + [DataField, AutoNetworkedField] + public List KeysIn = new() { TriggerSystem.DefaultTriggerKey }; + + /// + /// The key that will trigger once the timer is finished. + /// + [DataField, AutoNetworkedField] + public string? KeyOut = "timer"; + + /// + /// The time after which this timer will trigger after it is activated. + /// + [DataField, AutoNetworkedField] + public TimeSpan Delay = TimeSpan.FromSeconds(1); + + /// + /// If not empty, a user can use verbs to configure the delay to one of these options. + /// + [DataField, AutoNetworkedField] + public List DelayOptions = new(); + + /// + /// The time at which this trigger will activate. + /// + [DataField(customTypeSerializer: typeof(TimeOffsetSerializer))] + [AutoNetworkedField, AutoPausedField] + public TimeSpan NextTrigger = TimeSpan.Zero; + + /// + /// Time of the next beeping sound. + /// + /// + /// Not networked because it's only used server side. + /// + [DataField(customTypeSerializer: typeof(TimeOffsetSerializer))] + [AutoPausedField] + public TimeSpan NextBeep = TimeSpan.Zero; + + /// + /// Initial beep delay. + /// Defaults to a single BeepInterval if null. + /// + /// + /// Not networked because it's only used server side. + /// + [DataField] + public TimeSpan? InitialBeepDelay; + + /// + /// The time between beeps. + /// + [DataField, AutoNetworkedField] + public TimeSpan BeepInterval = TimeSpan.FromSeconds(1); + + /// + /// The entity that activated this trigger. + /// + [DataField, AutoNetworkedField] + public EntityUid? User; + + /// + /// The beeping sound, if any. + /// + [DataField, AutoNetworkedField] + public SoundSpecifier? BeepSound; + + /// + /// Whether you can examine the item to see its timer or not. + /// + [DataField, AutoNetworkedField] + public bool Examinable = true; + + /// + /// The popup to show the user when starting the timer, if any. + /// + [DataField, AutoNetworkedField] + public LocId? Popup = "timer-trigger-activated"; + + #region GuidebookData + + [GuidebookData] + public float? ShortestDelayOption => DelayOptions.Count == 0 ? null : (float)DelayOptions.Min().TotalSeconds; + + [GuidebookData] + public float? LongestDelayOption => DelayOptions.Count == 0 ? null : (float)DelayOptions.Max().TotalSeconds; + + #endregion GuidebookData +} diff --git a/Content.Shared/Trigger/Components/Triggers/ActiveTriggerOnTimedCollideComponent.cs b/Content.Shared/Trigger/Components/Triggers/ActiveTriggerOnTimedCollideComponent.cs new file mode 100644 index 00000000000..88b68913f02 --- /dev/null +++ b/Content.Shared/Trigger/Components/Triggers/ActiveTriggerOnTimedCollideComponent.cs @@ -0,0 +1,6 @@ +using Robust.Shared.GameStates; + +namespace Content.Shared.Trigger.Components.Triggers; + +[RegisterComponent, NetworkedComponent] +public sealed partial class ActiveTriggerOnTimedCollideComponent : Component; diff --git a/Content.Shared/Trigger/Components/Triggers/BaseTriggerOnXComponent.cs b/Content.Shared/Trigger/Components/Triggers/BaseTriggerOnXComponent.cs new file mode 100644 index 00000000000..1f4807f2536 --- /dev/null +++ b/Content.Shared/Trigger/Components/Triggers/BaseTriggerOnXComponent.cs @@ -0,0 +1,16 @@ +using Content.Shared.Trigger.Systems; + +namespace Content.Shared.Trigger.Components.Triggers; + +/// +/// Base class for components that cause a trigger to be activated. +/// +public abstract partial class BaseTriggerOnXComponent : Component +{ + /// + /// The key that the trigger will activate. + /// null will activate all triggers. + /// + [DataField, AutoNetworkedField] + public string? KeyOut = TriggerSystem.DefaultTriggerKey; +} diff --git a/Content.Server/Explosion/Components/RepeatingTriggerComponent.cs b/Content.Shared/Trigger/Components/Triggers/RepeatingTriggerComponent.cs similarity index 56% rename from Content.Server/Explosion/Components/RepeatingTriggerComponent.cs rename to Content.Shared/Trigger/Components/Triggers/RepeatingTriggerComponent.cs index cc08de53f90..27527d7773b 100644 --- a/Content.Server/Explosion/Components/RepeatingTriggerComponent.cs +++ b/Content.Shared/Trigger/Components/Triggers/RepeatingTriggerComponent.cs @@ -1,25 +1,26 @@ -using Content.Server.Explosion.EntitySystems; +using Robust.Shared.GameStates; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom; -namespace Content.Server.Explosion.Components; +namespace Content.Shared.Trigger.Components.Triggers; /// /// Constantly triggers after being added to an entity. /// -[RegisterComponent, Access(typeof(TriggerSystem))] -[AutoGenerateComponentPause] -public sealed partial class RepeatingTriggerComponent : Component +[RegisterComponent, NetworkedComponent] +[AutoGenerateComponentState, AutoGenerateComponentPause] +public sealed partial class RepeatingTriggerComponent : BaseTriggerOnXComponent { /// /// How long to wait between triggers. /// The first trigger starts this long after the component is added. /// - [DataField] + [DataField, AutoNetworkedField] public TimeSpan Delay = TimeSpan.FromSeconds(1); /// /// When the next trigger will be. /// - [DataField(customTypeSerializer: typeof(TimeOffsetSerializer)), AutoPausedField] - public TimeSpan NextTrigger; + [DataField(customTypeSerializer: typeof(TimeOffsetSerializer))] + [AutoNetworkedField, AutoPausedField] + public TimeSpan NextTrigger = TimeSpan.Zero; } diff --git a/Content.Shared/Trigger/Components/Triggers/TriggerOnActivateComponent.cs b/Content.Shared/Trigger/Components/Triggers/TriggerOnActivateComponent.cs new file mode 100644 index 00000000000..9dd145bb265 --- /dev/null +++ b/Content.Shared/Trigger/Components/Triggers/TriggerOnActivateComponent.cs @@ -0,0 +1,17 @@ +using Robust.Shared.GameStates; + +namespace Content.Shared.Trigger.Components.Triggers; + +/// +/// Triggers when activated in hand or by clicking on the entity. +/// The user is the player activating it. +/// +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +public sealed partial class TriggerOnActivateComponent : BaseTriggerOnXComponent +{ + /// + /// Is this interaction a complex interaction? + /// + [DataField, AutoNetworkedField] + public bool RequireComplex = true; +} diff --git a/Content.Shared/Trigger/Components/Triggers/TriggerOnActivateImplantComponent.cs b/Content.Shared/Trigger/Components/Triggers/TriggerOnActivateImplantComponent.cs new file mode 100644 index 00000000000..b26f3b6875a --- /dev/null +++ b/Content.Shared/Trigger/Components/Triggers/TriggerOnActivateImplantComponent.cs @@ -0,0 +1,10 @@ +using Robust.Shared.GameStates; + +namespace Content.Shared.Trigger.Components.Triggers; + +/// +/// Triggers when activating an action granted by an implant. +/// The user is the player activating it. +/// +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +public sealed partial class TriggerOnActivateImplantComponent : BaseTriggerOnXComponent; diff --git a/Content.Shared/Trigger/Components/Triggers/TriggerOnCollideComponent.cs b/Content.Shared/Trigger/Components/Triggers/TriggerOnCollideComponent.cs new file mode 100644 index 00000000000..a1e234bd7a6 --- /dev/null +++ b/Content.Shared/Trigger/Components/Triggers/TriggerOnCollideComponent.cs @@ -0,0 +1,23 @@ +using Robust.Shared.GameStates; + +namespace Content.Shared.Trigger.Components.Triggers; + +/// +/// Triggers when colliding with another entity. +/// The user is the entity collided with. +/// +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +public sealed partial class TriggerOnCollideComponent : BaseTriggerOnXComponent +{ + /// + /// The fixture with which to collide. + /// + [DataField(required: true), AutoNetworkedField] + public string FixtureID = string.Empty; + + /// + /// Doesn't trigger if the other colliding fixture is nonhard. + /// + [DataField, AutoNetworkedField] + public bool IgnoreOtherNonHard = true; +} diff --git a/Content.Shared/Trigger/Components/Triggers/TriggerOnEmptyGunshotComponent.cs b/Content.Shared/Trigger/Components/Triggers/TriggerOnEmptyGunshotComponent.cs new file mode 100644 index 00000000000..40d468ec306 --- /dev/null +++ b/Content.Shared/Trigger/Components/Triggers/TriggerOnEmptyGunshotComponent.cs @@ -0,0 +1,10 @@ +using Robust.Shared.GameStates; + +namespace Content.Shared.Trigger.Components.Triggers; + +/// +/// Triggers when attempting to shoot a gun while it's empty. +/// The user is the player holding the gun. +/// +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +public sealed partial class TriggerOnEmptyGunshotComponent : BaseTriggerOnXComponent; diff --git a/Content.Shared/Trigger/Components/Triggers/TriggerOnMobstateChangeComponent.cs b/Content.Shared/Trigger/Components/Triggers/TriggerOnMobstateChangeComponent.cs new file mode 100644 index 00000000000..a8dab4e6cd7 --- /dev/null +++ b/Content.Shared/Trigger/Components/Triggers/TriggerOnMobstateChangeComponent.cs @@ -0,0 +1,35 @@ +using Content.Shared.Mobs; +using Robust.Shared.GameStates; + +namespace Content.Shared.Trigger.Components.Triggers; + +/// +/// Triggers when this entity's mob state changes. +/// The user is the entity that caused the state change or the owner depending on the settings. +/// If added to an implant it will trigger when the implanted entity's mob state changes. +/// +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +public sealed partial class TriggerOnMobstateChangeComponent : BaseTriggerOnXComponent +{ + /// + /// What states should trigger this? + /// + [DataField(required: true), AutoNetworkedField] + public List MobState = new(); + + /// + /// If true, prevents suicide attempts for the trigger to prevent cheese. + /// + [DataField, AutoNetworkedField] + public bool PreventSuicide = false; + + /// + /// If false, the trigger user will be the entity that caused the mobstate to change. + /// If true, the trigger user will the entity that changed its mob state. + /// + /// + /// Set this to true for implants that apply an effect on the implanted entity. + /// + [DataField, AutoNetworkedField] + public bool TargetMobstateEntity = true; +} diff --git a/Content.Shared/Trigger/Components/Triggers/TriggerOnProximityComponent.cs b/Content.Shared/Trigger/Components/Triggers/TriggerOnProximityComponent.cs new file mode 100644 index 00000000000..047d6f03748 --- /dev/null +++ b/Content.Shared/Trigger/Components/Triggers/TriggerOnProximityComponent.cs @@ -0,0 +1,91 @@ +using Content.Shared.Physics; +using Robust.Shared.GameStates; +using Robust.Shared.Physics.Collision.Shapes; +using Robust.Shared.Physics.Components; +using Robust.Shared.Physics.Dynamics; +using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom; + +namespace Content.Shared.Trigger.Components.Triggers; + +/// +/// Triggers whenever an entity collides with a fixture attached to the owner of this component. +/// The user is the entity that collided with the fixture. +/// +[RegisterComponent, NetworkedComponent] +[AutoGenerateComponentState, AutoGenerateComponentPause] +public sealed partial class TriggerOnProximityComponent : BaseTriggerOnXComponent +{ + /// + /// The ID if the fixture that is observed for collisions. + /// + public const string FixtureID = "trigger-on-proximity-fixture"; + + /// + /// Currently colliding entities. + /// + [ViewVariables] + public readonly Dictionary Colliding = new(); + + /// + /// What is the shape of the proximity fixture? + /// + [ViewVariables] + [DataField] + public IPhysShape Shape = new PhysShapeCircle(2f); + + /// + /// How long the the proximity trigger animation plays for. + /// + [DataField, AutoNetworkedField] + public TimeSpan AnimationDuration = TimeSpan.FromSeconds(0.6f); + + /// + /// Whether the entity needs to be anchored for the proximity to work. + /// + [DataField, AutoNetworkedField] + public bool RequiresAnchored = true; + + /// + /// Whether the proximity trigger is currently enabled. + /// + [DataField, AutoNetworkedField] + public bool Enabled = true; + + /// + /// The minimum delay between repeating triggers. + /// + [DataField, AutoNetworkedField] + public TimeSpan Cooldown = TimeSpan.FromSeconds(5); + + /// + /// When can the trigger run again? + /// + [DataField(customTypeSerializer: typeof(TimeOffsetSerializer))] + [AutoNetworkedField, AutoPausedField] + public TimeSpan NextTrigger = TimeSpan.Zero; + + /// + /// When will the visual state be updated again after activation? + /// + [DataField(customTypeSerializer: typeof(TimeOffsetSerializer))] + [AutoNetworkedField, AutoPausedField] + public TimeSpan NextVisualUpdate = TimeSpan.Zero; + + /// + /// What speed should the other object be moving at to trigger the proximity fixture? + /// + [DataField, AutoNetworkedField] + public float TriggerSpeed = 3.5f; + + /// + /// If this proximity is triggered should we continually repeat it? + /// + [DataField, AutoNetworkedField] + public bool Repeating = true; + + /// + /// What layer is the trigger fixture on? + /// + [DataField(customTypeSerializer: typeof(FlagSerializer))] + public int Layer = (int)(CollisionGroup.MidImpassable | CollisionGroup.LowImpassable | CollisionGroup.HighImpassable); +} diff --git a/Content.Shared/Trigger/Components/Triggers/TriggerOnSignalComponent.cs b/Content.Shared/Trigger/Components/Triggers/TriggerOnSignalComponent.cs new file mode 100644 index 00000000000..6ed81c5fcf4 --- /dev/null +++ b/Content.Shared/Trigger/Components/Triggers/TriggerOnSignalComponent.cs @@ -0,0 +1,19 @@ +using Content.Shared.DeviceLinking; +using Robust.Shared.GameStates; +using Robust.Shared.Prototypes; + +namespace Content.Shared.Trigger.Components.Triggers; + +/// +/// Sends a trigger when signal is received. +/// The user is the sender of the signal. +/// +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +public sealed partial class TriggerOnSignalComponent : BaseTriggerOnXComponent +{ + /// + /// The sink port prototype we can connect devices to. + /// + [DataField, AutoNetworkedField] + public ProtoId Port = "Trigger"; +} diff --git a/Content.Shared/Trigger/Components/Triggers/TriggerOnSlipComponent.cs b/Content.Shared/Trigger/Components/Triggers/TriggerOnSlipComponent.cs new file mode 100644 index 00000000000..b0381ee74ed --- /dev/null +++ b/Content.Shared/Trigger/Components/Triggers/TriggerOnSlipComponent.cs @@ -0,0 +1,10 @@ +using Robust.Shared.GameStates; + +namespace Content.Shared.Trigger.Components.Triggers; + +/// +/// Triggers an entity when someone slipped on it. +/// The user is the entity that was slipped. +/// +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +public sealed partial class TriggerOnSlipComponent : BaseTriggerOnXComponent; diff --git a/Content.Shared/Trigger/Components/Triggers/TriggerOnSpawnComponent.cs b/Content.Shared/Trigger/Components/Triggers/TriggerOnSpawnComponent.cs new file mode 100644 index 00000000000..c718a201486 --- /dev/null +++ b/Content.Shared/Trigger/Components/Triggers/TriggerOnSpawnComponent.cs @@ -0,0 +1,10 @@ +using Robust.Shared.GameStates; + +namespace Content.Shared.Trigger.Components.Triggers; + +/// +/// Triggers when the entity is initialized. +/// The user is null. +/// +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +public sealed partial class TriggerOnSpawnComponent : BaseTriggerOnXComponent; diff --git a/Content.Shared/Trigger/Components/Triggers/TriggerOnStepTriggerComponent.cs b/Content.Shared/Trigger/Components/Triggers/TriggerOnStepTriggerComponent.cs new file mode 100644 index 00000000000..70d33a11796 --- /dev/null +++ b/Content.Shared/Trigger/Components/Triggers/TriggerOnStepTriggerComponent.cs @@ -0,0 +1,14 @@ +using Robust.Shared.GameStates; + +namespace Content.Shared.Trigger.Components.Triggers; + +/// +/// Triggers if a StepTrigger is activated by someone stepping on this entity. +/// The user is the mob who stepped on it. +/// +/// +/// This is used for entities that want the more generic 'trigger' behavior after a step trigger occurs. +/// Not done by default, since it's not useful for everything and might cause weird behavior. But it is useful for a lot of stuff like mousetraps. +/// +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +public sealed partial class TriggerOnStepTriggerComponent : BaseTriggerOnXComponent; diff --git a/Content.Shared/Trigger/Components/Triggers/TriggerOnStuckComponent.cs b/Content.Shared/Trigger/Components/Triggers/TriggerOnStuckComponent.cs new file mode 100644 index 00000000000..073a64f66ec --- /dev/null +++ b/Content.Shared/Trigger/Components/Triggers/TriggerOnStuckComponent.cs @@ -0,0 +1,11 @@ +using Content.Shared.Sticky.Components; +using Robust.Shared.GameStates; + +namespace Content.Shared.Trigger.Components.Triggers; + +/// +/// Triggers when an entity with is stuck to something. +/// The user is the player doing so. +/// +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +public sealed partial class TriggerOnStuckComponent : BaseTriggerOnXComponent; diff --git a/Content.Shared/Trigger/Components/Triggers/TriggerOnTimedCollideComponent.cs b/Content.Shared/Trigger/Components/Triggers/TriggerOnTimedCollideComponent.cs new file mode 100644 index 00000000000..185ea7dbe40 --- /dev/null +++ b/Content.Shared/Trigger/Components/Triggers/TriggerOnTimedCollideComponent.cs @@ -0,0 +1,26 @@ +using Robust.Shared.GameStates; + +namespace Content.Shared.Trigger.Components.Triggers; + +/// +/// Triggers when the entity is overlapped for the specified duration. +/// The user is the entity that passes the time threshold while colliding. +/// +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +public sealed partial class TriggerOnTimedCollideComponent : BaseTriggerOnXComponent +{ + /// + /// The time an entity has to collide until the trigger is activated. + /// + [DataField, AutoNetworkedField] + public TimeSpan Threshold = TimeSpan.FromSeconds(1); + + /// + /// A collection of entities that are currently colliding with this, and their own unique accumulator. + /// + /// + /// TODO: Add AutoPausedField and (de)serialize values as time offsets when https://github.com/space-wizards/RobustToolbox/issues/3768 is fixed. + /// + [DataField, AutoNetworkedField] + public Dictionary Colliding = new(); +} diff --git a/Content.Shared/Trigger/Components/Triggers/TriggerOnUseComponent.cs b/Content.Shared/Trigger/Components/Triggers/TriggerOnUseComponent.cs new file mode 100644 index 00000000000..71d289741e5 --- /dev/null +++ b/Content.Shared/Trigger/Components/Triggers/TriggerOnUseComponent.cs @@ -0,0 +1,10 @@ +using Robust.Shared.GameStates; + +namespace Content.Shared.Trigger.Components.Triggers; + +/// +/// Triggers on use in hand. +/// The user is the player holding the item. +/// +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +public sealed partial class TriggerOnUseComponent : BaseTriggerOnXComponent; diff --git a/Content.Shared/Trigger/Components/Triggers/TriggerOnVerb.cs b/Content.Shared/Trigger/Components/Triggers/TriggerOnVerb.cs new file mode 100644 index 00000000000..463860f0770 --- /dev/null +++ b/Content.Shared/Trigger/Components/Triggers/TriggerOnVerb.cs @@ -0,0 +1,20 @@ +using Robust.Shared.GameStates; + +namespace Content.Shared.Trigger.Components.Triggers; + +/// +/// Starts a trigger when a verb is selected. +/// The user is the player selecting the verb. +/// +/// +/// TODO: Support multiple verbs and trigger keys. +/// +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +public sealed partial class TriggerOnVerbComponent : BaseTriggerOnXComponent +{ + /// + /// The text to display in the verb. + /// + [DataField, AutoNetworkedField] + public LocId Text = "trigger-on-verb-default"; +} diff --git a/Content.Shared/Trigger/Components/Triggers/TriggerOnVoiceComponent.cs b/Content.Shared/Trigger/Components/Triggers/TriggerOnVoiceComponent.cs new file mode 100644 index 00000000000..a36992d7da8 --- /dev/null +++ b/Content.Shared/Trigger/Components/Triggers/TriggerOnVoiceComponent.cs @@ -0,0 +1,47 @@ +using Robust.Shared.GameStates; + +namespace Content.Shared.Trigger.Components.Triggers; + +/// +/// Sends a trigger when the keyphrase is heard. +/// The User is the speaker. +/// +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +public sealed partial class TriggerOnVoiceComponent : BaseTriggerOnXComponent +{ + /// + /// Whether or not the component is actively listening at the moment. + /// + [ViewVariables] + public bool IsListening => IsRecording || !string.IsNullOrWhiteSpace(KeyPhrase); + + /// + /// The keyphrase that has been set to trigger it. + /// + [DataField, AutoNetworkedField] + public string? KeyPhrase; + + /// + /// Range in which we listen for the keyphrase. + /// + [DataField, AutoNetworkedField] + public int ListenRange = 4; + + /// + /// Whether we are currently recording a new keyphrase. + /// + [DataField, AutoNetworkedField] + public bool IsRecording; + + /// + /// Minimum keyphrase length. + /// + [DataField, AutoNetworkedField] + public int MinLength = 3; + + /// + /// Maximum keyphrase length. + /// + [DataField, AutoNetworkedField] + public int MaxLength = 50; +} diff --git a/Content.Shared/Trigger/Components/TwoStageTriggerComponent.cs b/Content.Shared/Trigger/Components/TwoStageTriggerComponent.cs new file mode 100644 index 00000000000..f0161c71755 --- /dev/null +++ b/Content.Shared/Trigger/Components/TwoStageTriggerComponent.cs @@ -0,0 +1,58 @@ +using Content.Shared.Trigger.Systems; +using Robust.Shared.GameStates; +using Robust.Shared.Prototypes; +using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom; + +namespace Content.Shared.Trigger.Components; + +/// +/// After being triggered applies the specified components and runs triggers again. +/// +[RegisterComponent, NetworkedComponent] +[AutoGenerateComponentState, AutoGenerateComponentPause] +public sealed partial class TwoStageTriggerComponent : Component +{ + /// + /// The keys that will activate the timer and add the given components (first stage). + /// + [DataField, AutoNetworkedField] + public List KeysIn = new() { TriggerSystem.DefaultTriggerKey }; + + /// + /// The key that will trigger once the timer is finished (second stage). + /// + [DataField, AutoNetworkedField] + public string? KeyOut = "stageTwo"; + + /// + /// How long it takes for the second stage to be triggered. + /// + [DataField, AutoNetworkedField] + public TimeSpan TriggerDelay = TimeSpan.FromSeconds(10); + + /// + /// This list of components that will be added on the first trigger. + /// + [DataField(required: true)] + public ComponentRegistry Components = new(); + + /// + /// The time at which the second stage will trigger. + /// + [DataField(customTypeSerializer: typeof(TimeOffsetSerializer))] + [AutoNetworkedField, AutoPausedField] + public TimeSpan? NextTriggerTime; + + /// + /// Has this entity been triggered already? + /// Used to prevent the components from being added multiple times. + /// + [DataField, AutoNetworkedField] + public bool Triggered = false; + + /// + /// The entity that activated this trigger. + /// + [DataField, AutoNetworkedField] + public EntityUid? User; +} diff --git a/Content.Shared/Trigger/Systems/AddComponentsOnTriggerSystem.cs b/Content.Shared/Trigger/Systems/AddComponentsOnTriggerSystem.cs new file mode 100644 index 00000000000..908307dad0a --- /dev/null +++ b/Content.Shared/Trigger/Systems/AddComponentsOnTriggerSystem.cs @@ -0,0 +1,33 @@ +using Content.Shared.Trigger.Components.Effects; + +namespace Content.Shared.Trigger.Systems; + +public sealed partial class AddComponentsOnTriggerSystem : EntitySystem +{ + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnTrigger); + } + + private void OnTrigger(Entity ent, ref TriggerEvent args) + { + if (args.Key != null && !ent.Comp.KeysIn.Contains(args.Key)) + return; + + var target = ent.Comp.TargetUser ? args.User : ent.Owner; + + if (target == null) + return; + + if (ent.Comp.TriggerOnce && ent.Comp.Triggered) + return; + + EntityManager.AddComponents(target.Value, ent.Comp.Components, ent.Comp.RemoveExisting); + ent.Comp.Triggered = true; + Dirty(ent); + + args.Handled = true; + } +} diff --git a/Content.Shared/Trigger/Systems/DamageOnTriggerSystem.cs b/Content.Shared/Trigger/Systems/DamageOnTriggerSystem.cs new file mode 100644 index 00000000000..9f01f233d78 --- /dev/null +++ b/Content.Shared/Trigger/Systems/DamageOnTriggerSystem.cs @@ -0,0 +1,40 @@ +using Content.Shared.Damage; +using Content.Shared.Trigger.Components.Effects; + +namespace Content.Shared.Trigger.Systems; + +public sealed class DamageOnTriggerSystem : EntitySystem +{ + [Dependency] private readonly DamageableSystem _damageableSystem = default!; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnTrigger); + } + + private void OnTrigger(Entity ent, ref TriggerEvent args) + { + if (args.Key != null && !ent.Comp.KeysIn.Contains(args.Key)) + return; + + var target = ent.Comp.TargetUser ? args.User : ent.Owner; + + if (target == null) + return; + + var damage = new DamageSpecifier(ent.Comp.Damage); + var ev = new BeforeDamageOnTriggerEvent(damage, target.Value); + RaiseLocalEvent(ent.Owner, ref ev); + + args.Handled |= _damageableSystem.TryChangeDamage(target, ev.Damage, ent.Comp.IgnoreResistances, origin: ent.Owner, targetPart: ent.Comp.TargetPart) is not null; // Shitmed Change + } +} + +/// +/// Raised on an entity before it deals damage using DamageOnTriggerComponent. +/// Used to modify the damage that will be dealt. +/// +[ByRefEvent] +public record struct BeforeDamageOnTriggerEvent(DamageSpecifier Damage, EntityUid Tripper); diff --git a/Content.Shared/Trigger/Systems/EmitSoundOnTriggerSystem.cs b/Content.Shared/Trigger/Systems/EmitSoundOnTriggerSystem.cs new file mode 100644 index 00000000000..e296ccc1779 --- /dev/null +++ b/Content.Shared/Trigger/Systems/EmitSoundOnTriggerSystem.cs @@ -0,0 +1,55 @@ +using Content.Shared.Trigger.Components.Effects; +using Robust.Shared.Audio.Systems; +using Robust.Shared.Network; + +namespace Content.Shared.Trigger.Systems; + +public sealed class EmitSoundOnTriggerSystem : EntitySystem +{ + [Dependency] private readonly INetManager _netMan = default!; + [Dependency] private readonly SharedAudioSystem _audio = default!; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnTrigger); + } + + private void OnTrigger(Entity ent, ref TriggerEvent args) + { + if (args.Key != null && !ent.Comp.KeysIn.Contains(args.Key)) + return; + + var target = ent.Comp.TargetUser ? args.User : ent.Owner; + + if (target == null) + return; + + args.Handled |= TryEmitSound(ent, target.Value, args.User); + } + + private bool TryEmitSound(Entity ent, EntityUid target, EntityUid? user = null) + { + if (ent.Comp.Sound == null) + return false; + + if (ent.Comp.Positional) + { + var coords = Transform(target).Coordinates; + if (ent.Comp.Predicted) + _audio.PlayPredicted(ent.Comp.Sound, coords, user); + else if (_netMan.IsServer) + _audio.PlayPvs(ent.Comp.Sound, coords); + } + else + { + if (ent.Comp.Predicted) + _audio.PlayPredicted(ent.Comp.Sound, target, user); + else if (_netMan.IsServer) + _audio.PlayPvs(ent.Comp.Sound, target); + } + + return true; + } +} diff --git a/Content.Shared/Trigger/Systems/EmpOnTriggerSystem.cs b/Content.Shared/Trigger/Systems/EmpOnTriggerSystem.cs new file mode 100644 index 00000000000..136c4474a22 --- /dev/null +++ b/Content.Shared/Trigger/Systems/EmpOnTriggerSystem.cs @@ -0,0 +1,31 @@ +using Content.Shared.Emp; +using Content.Shared.Trigger.Components.Effects; + +namespace Content.Shared.Trigger.Systems; + +public sealed class EmpOnTriggerSystem : EntitySystem +{ + [Dependency] private readonly SharedEmpSystem _emp = default!; + [Dependency] private readonly SharedTransformSystem _transform = default!; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnTrigger); + } + + private void OnTrigger(Entity ent, ref TriggerEvent args) + { + if (args.Key != null && !ent.Comp.KeysIn.Contains(args.Key)) + return; + + var target = ent.Comp.TargetUser ? args.User : ent.Owner; + + if (target == null) + return; + + _emp.EmpPulse(_transform.GetMapCoordinates(target.Value), ent.Comp.Range, ent.Comp.EnergyConsumption, (float)ent.Comp.DisableDuration.TotalSeconds); + args.Handled = true; + } +} diff --git a/Content.Shared/Trigger/Systems/ExplodeOnTriggerSystem.cs b/Content.Shared/Trigger/Systems/ExplodeOnTriggerSystem.cs new file mode 100644 index 00000000000..1c773b79a62 --- /dev/null +++ b/Content.Shared/Trigger/Systems/ExplodeOnTriggerSystem.cs @@ -0,0 +1,30 @@ +using Content.Shared.Explosion.EntitySystems; +using Content.Shared.Trigger.Components.Effects; + +namespace Content.Shared.Trigger.Systems; + +public sealed class ExplodeOnTriggerSystem : EntitySystem +{ + [Dependency] private readonly SharedExplosionSystem _explosion = default!; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnTrigger); + } + + private void OnTrigger(Entity ent, ref TriggerEvent args) + { + if (args.Key != null && !ent.Comp.KeysIn.Contains(args.Key)) + return; + + var target = ent.Comp.TargetUser ? args.User : ent.Owner; + + if (target == null) + return; + + _explosion.TriggerExplosive(target.Value, user: args.User); + args.Handled = true; + } +} diff --git a/Content.Shared/Trigger/Systems/FlashOnTriggerSystem.cs b/Content.Shared/Trigger/Systems/FlashOnTriggerSystem.cs new file mode 100644 index 00000000000..6153e228bf5 --- /dev/null +++ b/Content.Shared/Trigger/Systems/FlashOnTriggerSystem.cs @@ -0,0 +1,30 @@ +using Content.Shared.Flash; +using Content.Shared.Trigger.Components.Effects; + +namespace Content.Shared.Trigger.Systems; + +public sealed class FlashOnTriggerSystem : EntitySystem +{ + [Dependency] private readonly SharedFlashSystem _flash = default!; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnTrigger); + } + + private void OnTrigger(Entity ent, ref TriggerEvent args) + { + if (args.Key != null && !ent.Comp.KeysIn.Contains(args.Key)) + return; + + var target = ent.Comp.TargetUser ? args.User : ent.Owner; + + if (target == null) + return; + + _flash.FlashArea(target.Value, args.User, ent.Comp.Range, ent.Comp.Duration, probability: ent.Comp.Probability); + args.Handled = true; + } +} diff --git a/Content.Shared/Trigger/Systems/GibOnTriggerSystem.cs b/Content.Shared/Trigger/Systems/GibOnTriggerSystem.cs new file mode 100644 index 00000000000..95ef5ec1db4 --- /dev/null +++ b/Content.Shared/Trigger/Systems/GibOnTriggerSystem.cs @@ -0,0 +1,40 @@ +using Content.Shared.Body.Systems; +using Content.Shared.Inventory; +using Content.Shared.Trigger.Components.Effects; + +namespace Content.Shared.Trigger.Systems; + +public sealed class GibOnTriggerSystem : EntitySystem +{ + [Dependency] private readonly SharedBodySystem _body = default!; + [Dependency] private readonly InventorySystem _inventory = default!; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnTrigger); + } + + private void OnTrigger(Entity ent, ref TriggerEvent args) + { + if (args.Key != null && !ent.Comp.KeysIn.Contains(args.Key)) + return; + + var target = ent.Comp.TargetUser ? args.User : ent.Owner; + + if (target == null) + return; + + if (ent.Comp.DeleteItems) + { + var items = _inventory.GetHandOrInventoryEntities(target.Value); + foreach (var item in items) + { + PredictedQueueDel(item); + } + } + _body.GibBody(target.Value, true); + args.Handled = true; + } +} diff --git a/Content.Shared/Trigger/Systems/RepulseAttractOnTriggerSystem.cs b/Content.Shared/Trigger/Systems/RepulseAttractOnTriggerSystem.cs new file mode 100644 index 00000000000..9bedc87b6b9 --- /dev/null +++ b/Content.Shared/Trigger/Systems/RepulseAttractOnTriggerSystem.cs @@ -0,0 +1,34 @@ +using Content.Shared.Trigger; +using Content.Shared.Trigger.Components.Effects; +using Content.Shared.RepulseAttract; + +namespace Content.Shared.Trigger.Systems; + +public sealed class RepulseAttractOnTriggerSystem : EntitySystem +{ + [Dependency] private readonly RepulseAttractSystem _repulse = default!; + [Dependency] private readonly SharedTransformSystem _transform = default!; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnTrigger); + } + + private void OnTrigger(Entity ent, ref TriggerEvent args) + { + if (args.Key != null && !ent.Comp.KeysIn.Contains(args.Key)) + return; + + var target = ent.Comp.TargetUser ? args.User : ent.Owner; + + if (target == null) + return; + + var position = _transform.GetMapCoordinates(target.Value); + _repulse.TryRepulseAttract(position, args.User, ent.Comp.Speed, ent.Comp.Range, ent.Comp.Whitelist, ent.Comp.CollisionMask); + + args.Handled = true; + } +} diff --git a/Content.Shared/Trigger/Systems/SharedReleaseGasOnTriggerSystem.cs b/Content.Shared/Trigger/Systems/SharedReleaseGasOnTriggerSystem.cs new file mode 100644 index 00000000000..e1871e04351 --- /dev/null +++ b/Content.Shared/Trigger/Systems/SharedReleaseGasOnTriggerSystem.cs @@ -0,0 +1,36 @@ +using Content.Shared.Trigger.Components.Effects; +using Robust.Shared.Timing; + +namespace Content.Shared.Trigger.Systems; + +/// +/// Releases a gas mixture to the atmosphere when triggered. +/// Can also release gas over a set timespan to prevent trolling people +/// with the instant-wall-of-pressure-inator. +/// +public abstract class SharedReleaseGasOnTriggerSystem : EntitySystem +{ + [Dependency] private readonly SharedAppearanceSystem _appearance = default!; + [Dependency] private readonly IGameTiming _timing = default!; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnTrigger); + } + + /// + /// Shrimply sets the component to active when triggered, allowing it to release over time. + /// + private void OnTrigger(Entity ent, ref TriggerEvent args) + { + if (args.Key != null && !ent.Comp.KeysIn.Contains(args.Key)) + return; + + ent.Comp.Active = true; + ent.Comp.NextReleaseTime = _timing.CurTime; + ent.Comp.StartingTotalMoles = ent.Comp.Air.TotalMoles; + _appearance.SetData(ent, ReleaseGasOnTriggerVisuals.Key, true); + } +} diff --git a/Content.Shared/Trigger/Systems/ShockOnTriggerSystem.cs b/Content.Shared/Trigger/Systems/ShockOnTriggerSystem.cs new file mode 100644 index 00000000000..c4d34af7e1a --- /dev/null +++ b/Content.Shared/Trigger/Systems/ShockOnTriggerSystem.cs @@ -0,0 +1,44 @@ +using Content.Shared.Electrocution; +using Content.Shared.Trigger.Components.Effects; +using Robust.Shared.Containers; + +namespace Content.Shared.Trigger.Systems; + +public sealed class ShockOnTriggerSystem : EntitySystem +{ + [Dependency] private readonly SharedContainerSystem _container = default!; + [Dependency] private readonly SharedElectrocutionSystem _electrocution = default!; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnTrigger); + } + + private void OnTrigger(Entity ent, ref TriggerEvent args) + { + if (args.Key != null && !ent.Comp.KeysIn.Contains(args.Key)) + return; + + EntityUid? target; + if (ent.Comp.TargetContainer) + { + // shock whoever is wearing this clothing item + if (!_container.TryGetContainingContainer(ent.Owner, out var container)) + return; + target = container.Owner; + } + else + { + target = ent.Comp.TargetUser ? args.User : ent.Owner; + } + + if (target == null) + return; + + _electrocution.TryDoElectrocution(target.Value, null, ent.Comp.Damage, ent.Comp.Duration, true, ignoreInsulation: true); + args.Handled = true; + } + +} diff --git a/Content.Shared/Trigger/Systems/TriggerOnActivateImplantSystem.cs b/Content.Shared/Trigger/Systems/TriggerOnActivateImplantSystem.cs new file mode 100644 index 00000000000..38257085501 --- /dev/null +++ b/Content.Shared/Trigger/Systems/TriggerOnActivateImplantSystem.cs @@ -0,0 +1,22 @@ +using Content.Shared.Implants.Components; +using Content.Shared.Trigger.Components.Triggers; + +namespace Content.Shared.Trigger.Systems; + +public sealed partial class TriggerOnActivateImplantSystem : EntitySystem +{ + [Dependency] private readonly TriggerSystem _trigger = default!; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnActivateImplant); + } + + private void OnActivateImplant(Entity ent, ref ActivateImplantEvent args) + { + _trigger.Trigger(ent.Owner, args.Performer, ent.Comp.KeyOut); + args.Handled = true; + } +} diff --git a/Content.Shared/Trigger/Systems/TriggerOnEmptyGunshotSystem.cs b/Content.Shared/Trigger/Systems/TriggerOnEmptyGunshotSystem.cs new file mode 100644 index 00000000000..cc23fa2b841 --- /dev/null +++ b/Content.Shared/Trigger/Systems/TriggerOnEmptyGunshotSystem.cs @@ -0,0 +1,20 @@ +using Content.Shared.Trigger.Components.Triggers; +using Content.Shared.Weapons.Ranged.Events; + +namespace Content.Shared.Trigger.Systems; +public sealed partial class TriggerOnEmptyGunshotSystem : EntitySystem +{ + [Dependency] private readonly TriggerSystem _trigger = default!; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnEmptyGunShot); + } + + private void OnEmptyGunShot(Entity ent, ref OnEmptyGunShotEvent args) + { + _trigger.Trigger(ent.Owner, args.User, ent.Comp.KeyOut); + } +} diff --git a/Content.Server/Explosion/EntitySystems/TriggerSystem.Mobstate.cs b/Content.Shared/Trigger/Systems/TriggerOnMobstateChangeSystem.cs similarity index 56% rename from Content.Server/Explosion/EntitySystems/TriggerSystem.Mobstate.cs rename to Content.Shared/Trigger/Systems/TriggerOnMobstateChangeSystem.cs index ccd2a6e3df0..68c109aef98 100644 --- a/Content.Server/Explosion/EntitySystems/TriggerSystem.Mobstate.cs +++ b/Content.Shared/Trigger/Systems/TriggerOnMobstateChangeSystem.cs @@ -1,20 +1,25 @@ -using Content.Server.Explosion.Components; -using Content.Shared.Explosion.Components; -using Content.Shared.Implants; +using Content.Shared.Implants; using Content.Shared.Interaction.Events; using Content.Shared.Mobs; +using Content.Shared.Popups; +using Content.Shared.Trigger.Components.Triggers; -namespace Content.Server.Explosion.EntitySystems; +namespace Content.Shared.Trigger.Systems; -public sealed partial class TriggerSystem +public sealed partial class TriggerOnMobstateChangeSystem : EntitySystem { - private void InitializeMobstate() + [Dependency] private readonly TriggerSystem _trigger = default!; + [Dependency] private readonly SharedPopupSystem _popup = default!; + + public override void Initialize() { + base.Initialize(); + SubscribeLocalEvent(OnMobStateChanged); SubscribeLocalEvent(OnSuicide); - SubscribeLocalEvent>(OnSuicideRelay); SubscribeLocalEvent>(OnMobStateRelay); + SubscribeLocalEvent>(OnSuicideRelay); } private void OnMobStateChanged(EntityUid uid, TriggerOnMobstateChangeComponent component, MobStateChangedEvent args) @@ -22,25 +27,21 @@ public sealed partial class TriggerSystem if (!component.MobState.Contains(args.NewMobState)) return; - //This chains Mobstate Changed triggers with OnUseTimerTrigger if they have it - //Very useful for things that require a mobstate change and a timer - if (TryComp(uid, out var timerTrigger)) - { - HandleTimerTrigger( - uid, - args.Origin, - timerTrigger.Delay, - timerTrigger.BeepInterval, - timerTrigger.InitialBeepDelay, - timerTrigger.BeepSound); - } - else - Trigger(uid); + _trigger.Trigger(uid, component.TargetMobstateEntity ? uid : args.Origin, component.KeyOut); + } + + private void OnMobStateRelay(EntityUid uid, TriggerOnMobstateChangeComponent component, ImplantRelayEvent args) + { + if (!component.MobState.Contains(args.Event.NewMobState)) + return; + + _trigger.Trigger(uid, component.TargetMobstateEntity ? args.ImplantedEntity : args.Event.Origin, component.KeyOut); } /// /// Checks if the user has any implants that prevent suicide to avoid some cheesy strategies /// Prevents suicide by handling the event without killing the user + /// TODO: This doesn't seem to work at the moment as the event is never checked for being handled. /// private void OnSuicide(EntityUid uid, TriggerOnMobstateChangeComponent component, SuicideEvent args) { @@ -50,17 +51,19 @@ public sealed partial class TriggerSystem if (!component.PreventSuicide) return; - _popupSystem.PopupEntity(Loc.GetString("suicide-prevented"), args.Victim, args.Victim); + _popup.PopupClient(Loc.GetString("suicide-prevented"), args.Victim); args.Handled = true; } private void OnSuicideRelay(EntityUid uid, TriggerOnMobstateChangeComponent component, ImplantRelayEvent args) { - OnSuicide(uid, component, args.Event); - } + if (args.Event.Handled) + return; - private void OnMobStateRelay(EntityUid uid, TriggerOnMobstateChangeComponent component, ImplantRelayEvent args) - { - OnMobStateChanged(uid, component, args.Event); + if (!component.PreventSuicide) + return; + + _popup.PopupClient(Loc.GetString("suicide-prevented"), args.Event.Victim); + args.Event.Handled = true; } } diff --git a/Content.Shared/Trigger/Systems/TriggerOnSlipSystem.cs b/Content.Shared/Trigger/Systems/TriggerOnSlipSystem.cs new file mode 100644 index 00000000000..6940ea52e29 --- /dev/null +++ b/Content.Shared/Trigger/Systems/TriggerOnSlipSystem.cs @@ -0,0 +1,21 @@ +using Content.Shared.Slippery; +using Content.Shared.Trigger.Components.Triggers; + +namespace Content.Shared.Trigger.Systems; + +public sealed partial class TriggerOnSlipSystem : EntitySystem +{ + [Dependency] private readonly TriggerSystem _trigger = default!; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnSlip); + } + + private void OnSlip(Entity ent, ref SlipEvent args) + { + _trigger.Trigger(ent.Owner, args.Slipped, ent.Comp.KeyOut); + } +} diff --git a/Content.Shared/Trigger/Systems/TriggerOnStuckSystem.cs b/Content.Shared/Trigger/Systems/TriggerOnStuckSystem.cs new file mode 100644 index 00000000000..d364adccff2 --- /dev/null +++ b/Content.Shared/Trigger/Systems/TriggerOnStuckSystem.cs @@ -0,0 +1,21 @@ +using Content.Shared.Sticky; +using Content.Shared.Trigger.Components.Triggers; + +namespace Content.Shared.Trigger.Systems; + +public sealed class TriggerOnStuckSystem : EntitySystem +{ + [Dependency] private readonly TriggerSystem _trigger = default!; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnStuck); + } + + private void OnStuck(Entity ent, ref EntityStuckEvent args) + { + _trigger.Trigger(ent.Owner, args.User, ent.Comp.KeyOut); + } +} diff --git a/Content.Shared/Trigger/Systems/TriggerOnVerbSystem.cs b/Content.Shared/Trigger/Systems/TriggerOnVerbSystem.cs new file mode 100644 index 00000000000..d5830dd75d2 --- /dev/null +++ b/Content.Shared/Trigger/Systems/TriggerOnVerbSystem.cs @@ -0,0 +1,31 @@ +using Content.Shared.Verbs; +using Content.Shared.Trigger.Components.Triggers; + +namespace Content.Shared.Trigger.Systems; + +public sealed partial class TriggerOnVerbSystem : EntitySystem +{ + [Dependency] private readonly TriggerSystem _trigger = default!; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent>(OnGetAltVerbs); + } + + private void OnGetAltVerbs(Entity ent, ref GetVerbsEvent args) + { + if (!args.CanInteract || !args.CanAccess || args.Hands == null) + return; + + var user = args.User; + + args.Verbs.Add(new AlternativeVerb + { + Text = Loc.GetString(ent.Comp.Text), + Act = () => _trigger.Trigger(ent.Owner, user, ent.Comp.KeyOut), + Priority = 2 // should be above any timer settings + }); + } +} diff --git a/Content.Shared/Trigger/Systems/TriggerSystem.Collide.cs b/Content.Shared/Trigger/Systems/TriggerSystem.Collide.cs new file mode 100644 index 00000000000..5243b13742a --- /dev/null +++ b/Content.Shared/Trigger/Systems/TriggerSystem.Collide.cs @@ -0,0 +1,73 @@ +using Content.Shared.Trigger.Components.Triggers; +using Content.Shared.StepTrigger.Systems; +using Robust.Shared.Physics.Events; + +namespace Content.Shared.Trigger.Systems; + +public sealed partial class TriggerSystem +{ + private void InitializeCollide() + { + SubscribeLocalEvent(OnCollide); + SubscribeLocalEvent(OnStepTriggered); + + SubscribeLocalEvent(OnTimedCollide); + SubscribeLocalEvent(OnTimedEndCollide); + SubscribeLocalEvent(OnTimedShutdown); + } + + private void OnCollide(Entity ent, ref StartCollideEvent args) + { + if (args.OurFixtureId == ent.Comp.FixtureID && (!ent.Comp.IgnoreOtherNonHard || args.OtherFixture.Hard)) + Trigger(ent.Owner, args.OtherEntity, ent.Comp.KeyOut); + } + + private void OnStepTriggered(Entity ent, ref StepTriggeredOffEvent args) + { + Trigger(ent, args.Tripper, ent.Comp.KeyOut); + } + + private void OnTimedCollide(Entity ent, ref StartCollideEvent args) + { + //Ensures the trigger entity will have an active component + EnsureComp(ent); + var otherUID = args.OtherEntity; + if (ent.Comp.Colliding.ContainsKey(otherUID)) + return; + ent.Comp.Colliding.Add(otherUID, _timing.CurTime + ent.Comp.Threshold); + Dirty(ent); + } + + private void OnTimedEndCollide(Entity ent, ref EndCollideEvent args) + { + var otherUID = args.OtherEntity; + ent.Comp.Colliding.Remove(otherUID); + Dirty(ent); + + if (ent.Comp.Colliding.Count == 0) + RemComp(ent); + } + + private void OnTimedShutdown(Entity ent, ref ComponentShutdown args) + { + RemComp(ent); + } + + private void UpdateTimedCollide() + { + var curTime = _timing.CurTime; + var query = EntityQueryEnumerator(); + while (query.MoveNext(out var uid, out _, out var triggerOnTimedCollide)) + { + foreach (var (collidingEntity, collidingTime) in triggerOnTimedCollide.Colliding) + { + if (curTime > collidingTime) + { + triggerOnTimedCollide.Colliding[collidingEntity] += triggerOnTimedCollide.Threshold; + Dirty(uid, triggerOnTimedCollide); + Trigger(uid, collidingEntity, triggerOnTimedCollide.KeyOut); + } + } + } + } +} diff --git a/Content.Shared/Trigger/Systems/TriggerSystem.Condition.cs b/Content.Shared/Trigger/Systems/TriggerSystem.Condition.cs new file mode 100644 index 00000000000..a917f1ad48c --- /dev/null +++ b/Content.Shared/Trigger/Systems/TriggerSystem.Condition.cs @@ -0,0 +1,57 @@ +using Content.Shared.Trigger.Components.Conditions; +using Content.Shared.Verbs; + +namespace Content.Shared.Trigger.Systems; + +public sealed partial class TriggerSystem +{ + private void InitializeCondition() + { + SubscribeLocalEvent(OnWhitelistTriggerAttempt); + + SubscribeLocalEvent(OnUseDelayTriggerAttempt); + + SubscribeLocalEvent(OnToggleTriggerAttempt); + SubscribeLocalEvent>(OnToggleGetAltVerbs); + } + + private void OnWhitelistTriggerAttempt(Entity ent, ref AttemptTriggerEvent args) + { + if (args.Key == null || ent.Comp.Keys.Contains(args.Key)) + args.Cancelled |= !_whitelist.CheckBoth(args.User, ent.Comp.UserBlacklist, ent.Comp.UserWhitelist); + } + + private void OnUseDelayTriggerAttempt(Entity ent, ref AttemptTriggerEvent args) + { + if (args.Key == null || ent.Comp.Keys.Contains(args.Key)) + args.Cancelled |= _useDelay.IsDelayed(ent.Owner, ent.Comp.UseDelayId); + } + + private void OnToggleTriggerAttempt(Entity ent, ref AttemptTriggerEvent args) + { + if (args.Key == null || ent.Comp.Keys.Contains(args.Key)) + args.Cancelled |= !ent.Comp.Enabled; + } + + private void OnToggleGetAltVerbs(Entity ent, ref GetVerbsEvent args) + { + if (!args.CanInteract || !args.CanAccess || args.Hands == null) + return; + + var user = args.User; + + args.Verbs.Add(new AlternativeVerb() + { + Text = Loc.GetString(ent.Comp.ToggleVerb), + Act = () => Toggle(ent, user) + }); + } + + private void Toggle(Entity ent, EntityUid user) + { + var msg = ent.Comp.Enabled ? ent.Comp.ToggleOff : ent.Comp.ToggleOn; + _popup.PopupPredicted(Loc.GetString(msg), ent.Owner, user); + ent.Comp.Enabled = !ent.Comp.Enabled; + Dirty(ent); + } +} diff --git a/Content.Shared/Trigger/Systems/TriggerSystem.Interaction.cs b/Content.Shared/Trigger/Systems/TriggerSystem.Interaction.cs new file mode 100644 index 00000000000..f5069097604 --- /dev/null +++ b/Content.Shared/Trigger/Systems/TriggerSystem.Interaction.cs @@ -0,0 +1,96 @@ +using Content.Shared.Interaction; +using Content.Shared.Interaction.Events; +using Content.Shared.Item.ItemToggle.Components; +using Content.Shared.Trigger.Components.Triggers; +using Content.Shared.Trigger.Components.Effects; + +namespace Content.Shared.Trigger.Systems; + +public sealed partial class TriggerSystem +{ + private void InitializeInteraction() + { + SubscribeLocalEvent(OnActivate); + SubscribeLocalEvent(OnUse); + + SubscribeLocalEvent(HandleItemToggleOnTrigger); + SubscribeLocalEvent(HandleAnchorOnTrigger); + SubscribeLocalEvent(HandleUseDelayOnTrigger); + } + + private void OnActivate(Entity ent, ref ActivateInWorldEvent args) + { + if (args.Handled) + return; + + if (ent.Comp.RequireComplex && !args.Complex) + return; + + Trigger(ent.Owner, args.User, ent.Comp.KeyOut); + args.Handled = true; + } + + private void OnUse(Entity ent, ref UseInHandEvent args) + { + if (args.Handled) + return; + + Trigger(ent.Owner, args.User, ent.Comp.KeyOut); + args.Handled = true; + } + + private void HandleItemToggleOnTrigger(Entity ent, ref TriggerEvent args) + { + if (args.Key != null && !ent.Comp.KeysIn.Contains(args.Key)) + return; + + var target = ent.Comp.TargetUser ? args.User : ent.Owner; + + if (!TryComp(target, out var itemToggle)) + return; + + var handled = false; + if (itemToggle.Activated && ent.Comp.CanDeactivate) + handled = _itemToggle.TryDeactivate((target.Value, itemToggle), args.User, ent.Comp.Predicted, ent.Comp.ShowPopup); + else if (ent.Comp.CanActivate) + handled = _itemToggle.TryActivate((target.Value, itemToggle), args.User, ent.Comp.Predicted, ent.Comp.ShowPopup); + + args.Handled |= handled; + } + + private void HandleAnchorOnTrigger(Entity ent, ref TriggerEvent args) + { + if (args.Key != null && !ent.Comp.KeysIn.Contains(args.Key)) + return; + + var target = ent.Comp.TargetUser ? args.User : ent.Owner; + + if (target == null) + return; + + var xform = Transform(target.Value); + + if (xform.Anchored && ent.Comp.CanUnanchor) + _transform.Unanchor(target.Value, xform); + else if (ent.Comp.CanAnchor) + _transform.AnchorEntity(target.Value, xform); + + if (ent.Comp.RemoveOnTrigger) + RemCompDeferred(target.Value); + + args.Handled = true; + } + + private void HandleUseDelayOnTrigger(Entity ent, ref TriggerEvent args) + { + if (args.Key != null && !ent.Comp.KeysIn.Contains(args.Key)) + return; + + var target = ent.Comp.TargetUser ? args.User : ent.Owner; + + if (target == null) + return; + + args.Handled |= _useDelay.TryResetDelay(target.Value, ent.Comp.CheckDelayed); + } +} diff --git a/Content.Shared/Trigger/Systems/TriggerSystem.Proximity.cs b/Content.Shared/Trigger/Systems/TriggerSystem.Proximity.cs new file mode 100644 index 00000000000..cf7c11369bb --- /dev/null +++ b/Content.Shared/Trigger/Systems/TriggerSystem.Proximity.cs @@ -0,0 +1,138 @@ +using Content.Shared.Trigger.Components.Triggers; +using Robust.Shared.Physics.Components; +using Robust.Shared.Physics.Events; + +namespace Content.Shared.Trigger.Systems; + +public sealed partial class TriggerSystem +{ + private void InitializeProximity() + { + SubscribeLocalEvent(OnProximityStartCollide); + SubscribeLocalEvent(OnProximityEndCollide); + SubscribeLocalEvent(OnMapInit); + // Shouldn't need re-anchoring. + SubscribeLocalEvent(OnProximityAnchor); + } + + private void OnProximityAnchor(Entity ent, ref AnchorStateChangedEvent args) + { + ent.Comp.Enabled = !ent.Comp.RequiresAnchored || args.Anchored; + + SetProximityAppearance(ent); + + if (!ent.Comp.Enabled) + { + ent.Comp.Colliding.Clear(); + } + // Re-check for contacts as we cleared them. + else if (TryComp(ent, out var body)) + { + _physics.RegenerateContacts((ent.Owner, body)); + } + + Dirty(ent); + } + + private void OnMapInit(Entity ent, ref MapInitEvent args) + { + ent.Comp.Enabled = !ent.Comp.RequiresAnchored || Transform(ent).Anchored; + + SetProximityAppearance(ent); + + if (!TryComp(ent, out var body)) + return; + + _fixture.TryCreateFixture( + ent.Owner, + ent.Comp.Shape, + TriggerOnProximityComponent.FixtureID, + hard: false, + body: body, + collisionLayer: ent.Comp.Layer); + + Dirty(ent); + } + + private void OnProximityStartCollide(EntityUid uid, TriggerOnProximityComponent component, ref StartCollideEvent args) + { + if (args.OurFixtureId != TriggerOnProximityComponent.FixtureID) + return; + + component.Colliding[args.OtherEntity] = args.OtherBody; + } + + private static void OnProximityEndCollide(EntityUid uid, TriggerOnProximityComponent component, ref EndCollideEvent args) + { + if (args.OurFixtureId != TriggerOnProximityComponent.FixtureID) + return; + + component.Colliding.Remove(args.OtherEntity); + } + + private void SetProximityAppearance(Entity ent) + { + _appearance.SetData(ent.Owner, ProximityTriggerVisualState.State, ent.Comp.Enabled ? ProximityTriggerVisuals.Inactive : ProximityTriggerVisuals.Off); + } + + private void Activate(Entity ent, EntityUid user) + { + var curTime = _timing.CurTime; + + if (!ent.Comp.Repeating) + { + ent.Comp.Enabled = false; + ent.Comp.Colliding.Clear(); + } + else + { + ent.Comp.NextTrigger = curTime + ent.Comp.Cooldown; + } + + // Queue a visual update for when the animation is complete. + ent.Comp.NextVisualUpdate = curTime + ent.Comp.AnimationDuration; + Dirty(ent); + + _appearance.SetData(ent.Owner, ProximityTriggerVisualState.State, ProximityTriggerVisuals.Active); + + Trigger(ent.Owner, user, ent.Comp.KeyOut); + } + + private void UpdateProximity() + { + var curTime = _timing.CurTime; + + var query = EntityQueryEnumerator(); + while (query.MoveNext(out var uid, out var trigger)) + { + if (curTime >= trigger.NextVisualUpdate) + { + // Update the visual state once the animation is done. + trigger.NextVisualUpdate = TimeSpan.MaxValue; + Dirty(uid, trigger); + SetProximityAppearance((uid, trigger)); + } + + if (!trigger.Enabled) + continue; + + if (curTime < trigger.NextTrigger) + // The trigger's on cooldown. + continue; + + // Check for anything colliding and moving fast enough. + foreach (var (collidingUid, colliding) in trigger.Colliding) + { + if (TerminatingOrDeleted(collidingUid)) + continue; + + if (colliding.LinearVelocity.Length() < trigger.TriggerSpeed) + continue; + + // Trigger! + Activate((uid, trigger), collidingUid); + break; + } + } + } +} diff --git a/Content.Shared/Trigger/Systems/TriggerSystem.Signal.cs b/Content.Shared/Trigger/Systems/TriggerSystem.Signal.cs new file mode 100644 index 00000000000..fa5aa7ea6e2 --- /dev/null +++ b/Content.Shared/Trigger/Systems/TriggerSystem.Signal.cs @@ -0,0 +1,44 @@ +using Content.Shared.Trigger.Components.Triggers; +using Content.Shared.Trigger.Components.Effects; +using Content.Shared.DeviceLinking.Events; + +namespace Content.Shared.Trigger.Systems; + +public sealed partial class TriggerSystem +{ + private void InitializeSignal() + { + SubscribeLocalEvent(SignalOnTriggerInit); + SubscribeLocalEvent(TriggerOnSignalInit); + + SubscribeLocalEvent(HandleSignalOnTrigger); + SubscribeLocalEvent(OnSignalReceived); + } + + private void SignalOnTriggerInit(Entity ent, ref ComponentInit args) + { + _deviceLink.EnsureSourcePorts(ent.Owner, ent.Comp.Port); + } + + private void TriggerOnSignalInit(Entity ent, ref ComponentInit args) + { + _deviceLink.EnsureSinkPorts(ent.Owner, ent.Comp.Port); + } + + private void HandleSignalOnTrigger(Entity ent, ref TriggerEvent args) + { + if (args.Key != null && !ent.Comp.KeysIn.Contains(args.Key)) + return; + + _deviceLink.InvokePort(ent.Owner, ent.Comp.Port); + args.Handled = true; + } + + private void OnSignalReceived(Entity ent, ref SignalReceivedEvent args) + { + if (args.Port != ent.Comp.Port) + return; + + Trigger(ent.Owner, args.Trigger, ent.Comp.KeyOut); + } +} diff --git a/Content.Shared/Trigger/Systems/TriggerSystem.Spawn.cs b/Content.Shared/Trigger/Systems/TriggerSystem.Spawn.cs new file mode 100644 index 00000000000..edcdd038941 --- /dev/null +++ b/Content.Shared/Trigger/Systems/TriggerSystem.Spawn.cs @@ -0,0 +1,70 @@ +using Content.Shared.Trigger.Components.Effects; +using Content.Shared.Trigger.Components.Triggers; + +namespace Content.Shared.Trigger.Systems; + +public sealed partial class TriggerSystem +{ + + private void InitializeSpawn() + { + SubscribeLocalEvent(OnSpawnInit); + + SubscribeLocalEvent(HandleSpawnOnTrigger); + SubscribeLocalEvent(HandleDeleteOnTrigger); + } + + private void OnSpawnInit(Entity ent, ref MapInitEvent args) + { + Trigger(ent.Owner, null, ent.Comp.KeyOut); + } + + private void HandleSpawnOnTrigger(Entity ent, ref TriggerEvent args) + { + if (args.Key != null && !ent.Comp.KeysIn.Contains(args.Key)) + return; + + var target = ent.Comp.TargetUser ? args.User : ent.Owner; + + if (target == null) + return; + + var xform = Transform(target.Value); + + if (ent.Comp.UseMapCoords) + { + var mapCoords = _transform.GetMapCoordinates(target.Value, xform); + if (ent.Comp.Predicted) + EntityManager.PredictedSpawn(ent.Comp.Proto, mapCoords); + else if (_net.IsServer) + Spawn(ent.Comp.Proto, mapCoords); + + } + else + { + var coords = xform.Coordinates; + if (!coords.IsValid(EntityManager)) + return; + + if (ent.Comp.Predicted) + PredictedSpawnAttachedTo(ent.Comp.Proto, coords); + else if (_net.IsServer) + SpawnAttachedTo(ent.Comp.Proto, coords); + + } + } + + private void HandleDeleteOnTrigger(Entity ent, ref TriggerEvent args) + { + if (args.Key != null && !ent.Comp.KeysIn.Contains(args.Key)) + return; + + var target = ent.Comp.TargetUser ? args.User : ent.Owner; + + if (target == null) + return; + + PredictedQueueDel(target); + args.Handled = true; + } +} diff --git a/Content.Shared/Trigger/Systems/TriggerSystem.Timer.cs b/Content.Shared/Trigger/Systems/TriggerSystem.Timer.cs new file mode 100644 index 00000000000..776b17bda61 --- /dev/null +++ b/Content.Shared/Trigger/Systems/TriggerSystem.Timer.cs @@ -0,0 +1,179 @@ +using Content.Shared.Trigger.Components; +using Content.Shared.Trigger.Components.Triggers; +using Content.Shared.Examine; +using Content.Shared.Verbs; + +namespace Content.Shared.Trigger.Systems; + +public sealed partial class TriggerSystem +{ + private void InitializeTimer() + { + SubscribeLocalEvent(OnRepeatInit); + SubscribeLocalEvent(OnRandomInit); + SubscribeLocalEvent(OnTimerShutdown); + SubscribeLocalEvent(OnTimerExamined); + SubscribeLocalEvent(OnTimerTriggered); + SubscribeLocalEvent>(OnTimerGetAltVerbs); + } + + // set the time of the first trigger after being spawned + private void OnRepeatInit(Entity ent, ref MapInitEvent args) + { + ent.Comp.NextTrigger = _timing.CurTime + ent.Comp.Delay; + Dirty(ent); + } + + private void OnRandomInit(Entity ent, ref MapInitEvent args) + { + if (_net.IsClient) // Nextfloat will mispredict, so we set it on the server and dirty it + return; + + if (!TryComp(ent, out var timerTriggerComp)) + return; + + timerTriggerComp.Delay = TimeSpan.FromSeconds(_random.NextFloat(ent.Comp.Min, ent.Comp.Max)); + Dirty(ent.Owner, timerTriggerComp); + } + + private void OnTimerShutdown(Entity ent, ref ComponentShutdown args) + { + RemComp(ent); + } + + private void OnTimerExamined(Entity ent, ref ExaminedEvent args) + { + if (args.IsInDetailsRange && ent.Comp.Examinable) + args.PushText(Loc.GetString("timer-trigger-examine", ("time", ent.Comp.Delay.TotalSeconds))); + } + + private void OnTimerTriggered(Entity ent, ref TriggerEvent args) + { + if (args.Key != null && !ent.Comp.KeysIn.Contains(args.Key)) + return; + + args.Handled |= ActivateTimerTrigger(ent.AsNullable(), args.User); + } + + /// + /// Add an alt-click interaction that cycles through delays. + /// + private void OnTimerGetAltVerbs(Entity ent, ref GetVerbsEvent args) + { + if (!args.CanInteract || !args.CanAccess || args.Hands == null) + return; + + if (ent.Comp.DelayOptions == null || ent.Comp.DelayOptions.Count == 1) + return; + + var user = args.User; + + args.Verbs.Add(new AlternativeVerb + { + Category = TimerOptions, + Text = Loc.GetString("timer-trigger-verb-cycle"), + Act = () => CycleDelay(ent, user), + Priority = 1 + }); + + foreach (var option in ent.Comp.DelayOptions) + { + if (MathHelper.CloseTo(option.TotalSeconds, ent.Comp.Delay.TotalSeconds)) + { + args.Verbs.Add(new AlternativeVerb + { + Category = TimerOptions, + Text = Loc.GetString("timer-trigger-verb-set-current", ("time", option.TotalSeconds)), + Disabled = true, + Priority = -100 * (int)option.TotalSeconds + }); + } + else + { + args.Verbs.Add(new AlternativeVerb + { + Category = TimerOptions, + Text = Loc.GetString("timer-trigger-verb-set", ("time", option.TotalSeconds)), + Priority = -100 * (int)option.TotalSeconds, + Act = () => + { + ent.Comp.Delay = option; + Dirty(ent); + _popup.PopupClient(Loc.GetString("timer-trigger-popup-set", ("time", option.TotalSeconds)), user, user); + } + }); + } + } + } + + public static readonly VerbCategory TimerOptions = new("verb-categories-timer", "/Textures/Interface/VerbIcons/clock.svg.192dpi.png"); + + /// + /// Select the next entry from the DelayOptions. + /// + private void CycleDelay(Entity ent, EntityUid? user) + { + if (ent.Comp.DelayOptions.Count <= 1) + return; + + // This is somewhat inefficient, but its good enough. This is run rarely, and the lists should be short. + + ent.Comp.DelayOptions.Sort(); + Dirty(ent); + + if (ent.Comp.DelayOptions[^1] <= ent.Comp.Delay) + { + ent.Comp.Delay = ent.Comp.DelayOptions[0]; + _popup.PopupClient(Loc.GetString("timer-trigger-popup-set", ("time", ent.Comp.Delay)), ent.Owner, user); + return; + } + + foreach (var option in ent.Comp.DelayOptions) + { + if (option > ent.Comp.Delay) + { + ent.Comp.Delay = option; + _popup.PopupClient(Loc.GetString("timer-trigger-popup-set", ("time", option)), ent.Owner, user); + return; + } + } + } + + private void UpdateRepeat() + { + var curTime = _timing.CurTime; + var query = EntityQueryEnumerator(); + while (query.MoveNext(out var uid, out var comp)) + { + if (comp.NextTrigger > curTime) + continue; + + comp.NextTrigger += comp.Delay; + Dirty(uid, comp); + Trigger(uid, null, comp.KeyOut); + } + } + + private void UpdateTimer() + { + var curTime = _timing.CurTime; + var query = EntityQueryEnumerator(); + while (query.MoveNext(out var uid, out _, out var timer)) + { + if (_net.IsServer && timer.BeepSound != null && timer.NextBeep <= curTime) + { + _audio.PlayPvs(timer.BeepSound, uid); + timer.NextBeep += timer.BeepInterval; + } + + if (timer.NextTrigger <= curTime) + { + Trigger(uid, timer.User, timer.KeyOut); + // Remove after triggering to prevent it from starting the timer again + RemComp(uid); + if (TryComp(uid, out var appearance)) + _appearance.SetData(uid, TriggerVisuals.VisualState, TriggerVisualState.Unprimed, appearance); + } + } + } +} diff --git a/Content.Shared/Trigger/Systems/TriggerSystem.Voice.cs b/Content.Shared/Trigger/Systems/TriggerSystem.Voice.cs new file mode 100644 index 00000000000..ac67cb7ed25 --- /dev/null +++ b/Content.Shared/Trigger/Systems/TriggerSystem.Voice.cs @@ -0,0 +1,160 @@ +using Content.Shared.Trigger.Components.Triggers; +using Content.Shared.Speech; +using Content.Shared.Speech.Components; +using Content.Shared.Database; +using Content.Shared.Examine; +using Content.Shared.Verbs; + +namespace Content.Shared.Trigger.Systems; + +public sealed partial class TriggerSystem +{ + private void InitializeVoice() + { + SubscribeLocalEvent(OnVoiceInit); + SubscribeLocalEvent(OnVoiceExamine); + SubscribeLocalEvent(OnListen); + SubscribeLocalEvent>(OnVoiceGetAltVerbs); + } + + private void OnVoiceInit(Entity ent, ref ComponentInit args) + { + if (ent.Comp.IsListening) + EnsureComp(ent).Range = ent.Comp.ListenRange; + else + RemCompDeferred(ent); + } + + private void OnVoiceExamine(Entity ent, ref ExaminedEvent args) + { + if (args.IsInDetailsRange) + { + args.PushText(string.IsNullOrWhiteSpace(ent.Comp.KeyPhrase) + ? Loc.GetString("trigger-on-voice-uninitialized") + : Loc.GetString("trigger-on-voice-examine", ("keyphrase", ent.Comp.KeyPhrase))); + } + } + private void OnListen(Entity ent, ref ListenEvent args) + { + var component = ent.Comp; + var message = args.Message.Trim(); + + if (component.IsRecording) + { + var ev = new ListenAttemptEvent(args.Source); + RaiseLocalEvent(ent, ev); + + if (ev.Cancelled) + return; + + if (message.Length >= component.MinLength && message.Length <= component.MaxLength) + FinishRecording(ent, args.Source, args.Message); + else if (message.Length > component.MaxLength) + _popup.PopupEntity(Loc.GetString("trigger-on-voice-record-failed-too-long"), ent); + else if (message.Length < component.MinLength) + _popup.PopupEntity(Loc.GetString("trigger-on-voice-record-failed-too-short"), ent); + + return; + } + + if (!string.IsNullOrWhiteSpace(component.KeyPhrase) && message.IndexOf(component.KeyPhrase, StringComparison.InvariantCultureIgnoreCase) is var index and >= 0) + { + _adminLogger.Add(LogType.Trigger, LogImpact.Medium, + $"A voice-trigger on {ToPrettyString(ent):entity} was triggered by {ToPrettyString(args.Source):speaker} speaking the key-phrase {component.KeyPhrase}."); + Trigger(ent, args.Source, ent.Comp.KeyOut); + + var messageWithoutPhrase = message.Remove(index, component.KeyPhrase.Length).Trim(); + var voice = new VoiceTriggeredEvent(args.Source, message, messageWithoutPhrase); + RaiseLocalEvent(ent, ref voice); + } + } + + private void OnVoiceGetAltVerbs(Entity ent, ref GetVerbsEvent args) + { + if (!args.CanInteract || !args.CanAccess) + return; + + var user = args.User; + args.Verbs.Add(new AlternativeVerb + { + Text = Loc.GetString(ent.Comp.IsRecording ? "trigger-on-voice-stop" : "trigger-on-voice-record"), + Act = () => + { + if (ent.Comp.IsRecording) + StopRecording(ent, user); + else + StartRecording(ent, user); + }, + Priority = 1 + }); + + if (string.IsNullOrWhiteSpace(ent.Comp.KeyPhrase)) + return; + + args.Verbs.Add(new AlternativeVerb + { + Text = Loc.GetString("trigger-on-voice-clear"), + Act = () => + { + ClearRecording(ent); + } + }); + } + + /// + /// Start recording a new keyphrase. + /// + public void StartRecording(Entity ent, EntityUid? user) + { + ent.Comp.IsRecording = true; + Dirty(ent); + EnsureComp(ent).Range = ent.Comp.ListenRange; + + if (user == null) + _adminLogger.Add(LogType.Trigger, LogImpact.Low, $"A voice-trigger on {ToPrettyString(ent):entity} has started recording."); + else + _adminLogger.Add(LogType.Trigger, LogImpact.Low, $"A voice-trigger on {ToPrettyString(ent):entity} has started recording. User: {ToPrettyString(user.Value):user}"); + + _popup.PopupPredicted(Loc.GetString("trigger-on-voice-start-recording"), ent, user); + } + + /// + /// Stop recording without setting a keyphrase. + /// + public void StopRecording(Entity ent, EntityUid? user) + { + ent.Comp.IsRecording = false; + Dirty(ent); + if (string.IsNullOrWhiteSpace(ent.Comp.KeyPhrase)) + RemComp(ent); + + _popup.PopupPredicted(Loc.GetString("trigger-on-voice-stop-recording"), ent, user); + } + + + /// + /// Stop recording and set the current keyphrase message. + /// + public void FinishRecording(Entity ent, EntityUid source, string message) + { + ent.Comp.KeyPhrase = message; + ent.Comp.IsRecording = false; + Dirty(ent); + + _adminLogger.Add(LogType.Trigger, LogImpact.Low, + $"A voice-trigger on {ToPrettyString(ent):entity} has recorded a new keyphrase: '{ent.Comp.KeyPhrase}'. Recorded from {ToPrettyString(source):speaker}"); + + _popup.PopupEntity(Loc.GetString("trigger-on-voice-recorded", ("keyphrase", ent.Comp.KeyPhrase)), ent); + } + + /// + /// Resets the key phrase and stops recording. + /// + public void ClearRecording(Entity ent) + { + ent.Comp.KeyPhrase = null; + ent.Comp.IsRecording = false; + Dirty(ent); + RemComp(ent); + } +} diff --git a/Content.Shared/Trigger/Systems/TriggerSystem.cs b/Content.Shared/Trigger/Systems/TriggerSystem.cs new file mode 100644 index 00000000000..6a749b87abd --- /dev/null +++ b/Content.Shared/Trigger/Systems/TriggerSystem.cs @@ -0,0 +1,186 @@ +using Content.Shared.Administration.Logs; +using Content.Shared.Database; +using Content.Shared.DeviceLinking; +using Content.Shared.Item.ItemToggle; +using Content.Shared.Popups; +using Content.Shared.Timing; +using Content.Shared.Trigger.Components; +using Content.Shared.Whitelist; +using Robust.Shared.Network; +using Robust.Shared.Physics.Systems; +using Robust.Shared.Timing; +using Robust.Shared.Random; +using Robust.Shared.Audio.Systems; + + +namespace Content.Shared.Trigger.Systems; + +/// +/// System containing the basic trigger API. +/// +/// +/// If you add a custom trigger subscription or effect then don't put them here. +/// Put them into a separate system so we don't end up with a giant list of imports. +/// +public sealed partial class TriggerSystem : EntitySystem +{ + [Dependency] private readonly IGameTiming _timing = default!; + [Dependency] private readonly SharedTransformSystem _transform = default!; + [Dependency] private readonly SharedPopupSystem _popup = default!; + [Dependency] private readonly ISharedAdminLogManager _adminLogger = default!; + [Dependency] private readonly SharedPhysicsSystem _physics = default!; + [Dependency] private readonly SharedAppearanceSystem _appearance = default!; + [Dependency] private readonly FixtureSystem _fixture = default!; + [Dependency] private readonly INetManager _net = default!; + [Dependency] private readonly IRobustRandom _random = default!; + [Dependency] private readonly SharedAudioSystem _audio = default!; + [Dependency] private readonly UseDelaySystem _useDelay = default!; + [Dependency] private readonly EntityWhitelistSystem _whitelist = default!; + [Dependency] private readonly ItemToggleSystem _itemToggle = default!; + [Dependency] private readonly SharedDeviceLinkSystem _deviceLink = default!; + + public const string DefaultTriggerKey = "trigger"; + + public override void Initialize() + { + base.Initialize(); + + InitializeCollide(); + InitializeCondition(); + InitializeInteraction(); + InitializeProximity(); + InitializeSignal(); + InitializeTimer(); + InitializeSpawn(); + InitializeVoice(); + } + + /// + /// Trigger the given entity. + /// + /// The entity that has the components that should be triggered. + /// The user of the trigger. Some effects may target the user instead of the trigger entity. + /// A key string to allow multiple, independent triggers on the same entity. If null then all triggers will activate. + /// Whether or not the trigger has sucessfully activated an effect. + public bool Trigger(EntityUid trigger, EntityUid? user = null, string? key = null) + { + var attemptTriggerEvent = new AttemptTriggerEvent(user, key); + RaiseLocalEvent(trigger, ref attemptTriggerEvent); + if (attemptTriggerEvent.Cancelled) + return false; + + var triggerEvent = new TriggerEvent(user, key); + RaiseLocalEvent(trigger, ref triggerEvent, true); + return triggerEvent.Handled; + } + + /// + /// Activate a timer trigger on an entity with . + /// + /// Whether or not a timer was activated. + public bool ActivateTimerTrigger(Entity ent, EntityUid? user = null) + { + if (!Resolve(ent, ref ent.Comp)) + return false; + + if (HasComp(ent)) + return false; // already activated + + if (user != null) + { + _adminLogger.Add(LogType.Trigger, + $"{ToPrettyString(user.Value):user} started a {ent.Comp.Delay} second timer trigger on entity {ToPrettyString(ent.Owner):timer}"); + } + else + { + _adminLogger.Add(LogType.Trigger, + $"{ent.Comp.Delay} second timer trigger started on entity {ToPrettyString(ent.Owner):timer}"); + } + + if (ent.Comp.Popup != null) + _popup.PopupPredicted(Loc.GetString(ent.Comp.Popup.Value, ("device", ent.Owner)), ent.Owner, user); + + AddComp(ent); + var curTime = _timing.CurTime; + ent.Comp.NextTrigger = curTime + ent.Comp.Delay; + var delay = ent.Comp.InitialBeepDelay ?? ent.Comp.BeepInterval; + ent.Comp.NextBeep = curTime + delay; + Dirty(ent); + + var ev = new ActiveTimerTriggerEvent(user); + RaiseLocalEvent(ent.Owner, ref ev); + + if (TryComp(ent, out var appearance)) + _appearance.SetData(ent.Owner, TriggerVisuals.VisualState, TriggerVisualState.Primed, appearance); + + return true; + } + + /// + /// Stop a timer trigger on an entity with . + /// + /// Whether or not a timer was stopped. + public bool StopTimerTrigger(Entity ent) + { + if (!Resolve(ent, ref ent.Comp)) + return false; + + if (!HasComp(ent)) + return false; // the timer is not active + + RemComp(ent); + if (TryComp(ent.Owner, out var appearance)) + _appearance.SetData(ent.Owner, TriggerVisuals.VisualState, TriggerVisualState.Unprimed, appearance); + + _adminLogger.Add(LogType.Trigger, $"A timer trigger was stopped before triggering on entity {ToPrettyString(ent.Owner):timer}"); + return true; + } + + /// + /// Delay an active timer trigger. + /// Returns false if not active. + /// + /// The time to add. + public bool TryDelay(Entity ent, TimeSpan amount) + { + if (!Resolve(ent, ref ent.Comp, false) || !HasComp(ent)) + return false; + + ent.Comp.NextTrigger += amount; + Dirty(ent); + return true; + } + + /// + /// Setter for the Delay datafield. + /// + public void SetDelay(Entity ent, TimeSpan delay) + { + if (!Resolve(ent, ref ent.Comp)) + return; + + ent.Comp.Delay = delay; + Dirty(ent); + } + + /// + /// Gets the remaining time until the trigger will activate. + /// Returns null if the trigger is not currently active. + /// + public TimeSpan? GetRemainingTime(Entity ent) + { + if (!Resolve(ent, ref ent.Comp, false) || !HasComp(ent)) + return null; // not a timer or not currently active + + return ent.Comp.NextTrigger - _timing.CurTime; + } + public override void Update(float frameTime) + { + base.Update(frameTime); + + UpdateTimer(); + UpdateRepeat(); + UpdateProximity(); + UpdateTimedCollide(); + } +} diff --git a/Content.Shared/Trigger/Systems/TwoStageTriggerSystem.cs b/Content.Shared/Trigger/Systems/TwoStageTriggerSystem.cs new file mode 100644 index 00000000000..2461e797dcd --- /dev/null +++ b/Content.Shared/Trigger/Systems/TwoStageTriggerSystem.cs @@ -0,0 +1,51 @@ +using Robust.Shared.Timing; +using Content.Shared.Trigger.Components; + +namespace Content.Shared.Trigger.Systems; + +public sealed class TwoStageTriggerSystem : EntitySystem +{ + [Dependency] private readonly IGameTiming _timing = default!; + [Dependency] private readonly TriggerSystem _triggerSystem = default!; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnTrigger); + } + + private void OnTrigger(Entity ent, ref TriggerEvent args) + { + if (ent.Comp.Triggered) + return; // already triggered + + if (args.Key != null && !ent.Comp.KeysIn.Contains(args.Key)) + return; + + EntityManager.AddComponents(ent, ent.Comp.Components); + EnsureComp(ent); + ent.Comp.Triggered = true; + ent.Comp.NextTriggerTime = _timing.CurTime + ent.Comp.TriggerDelay; + ent.Comp.User = args.User; + Dirty(ent); + + args.Handled = true; + } + + public override void Update(float frameTime) + { + base.Update(frameTime); + + var curTime = _timing.CurTime; + var enumerator = EntityQueryEnumerator(); + while (enumerator.MoveNext(out var uid, out _, out var component)) + { + if (curTime < component.NextTriggerTime) + continue; + + RemComp(uid); + _triggerSystem.Trigger(uid, component.User, component.KeyOut); + } + } +} diff --git a/Content.Shared/Trigger/TriggerEvent.cs b/Content.Shared/Trigger/TriggerEvent.cs new file mode 100644 index 00000000000..e65e3b48a87 --- /dev/null +++ b/Content.Shared/Trigger/TriggerEvent.cs @@ -0,0 +1,33 @@ +namespace Content.Shared.Trigger; + +/// +/// Raised whenever something is Triggered on the entity. +/// +/// The entity that activated the trigger. +/// +/// Allows to have multiple independent triggers on the same entity. +/// Setting this to null will activate all triggers. +/// +/// Marks the event as handled if at least one trigger effect was activated. +[ByRefEvent] +public record struct TriggerEvent(EntityUid? User = null, string? Key = null, bool Handled = false); + +/// +/// Raised before a trigger is activated. +/// Cancelling prevents it from triggering. +/// +/// The entity that activated the trigger. +/// +/// Allows to have multiple independent triggers on the same entity. +/// Setting this to null will activate all triggers. +/// +/// Marks the event as handled if at least one trigger effect was activated. +[ByRefEvent] +public record struct AttemptTriggerEvent(EntityUid? User, string? Key = null, bool Cancelled = false); + +/// +/// Raised when a timer trigger becomes active. +/// +/// The entity that activated the trigger. +[ByRefEvent] +public readonly record struct ActiveTimerTriggerEvent(EntityUid? User); diff --git a/Content.Shared/Trigger/TriggerVisuals.cs b/Content.Shared/Trigger/TriggerVisuals.cs index ed544f35904..f1d4a55fb1d 100644 --- a/Content.Shared/Trigger/TriggerVisuals.cs +++ b/Content.Shared/Trigger/TriggerVisuals.cs @@ -1,31 +1,30 @@ using Robust.Shared.Serialization; -namespace Content.Shared.Trigger +namespace Content.Shared.Trigger; + +[Serializable, NetSerializable] +public enum ProximityTriggerVisuals : byte { - [Serializable, NetSerializable] - public enum ProximityTriggerVisuals : byte - { - Off, - Inactive, - Active, - } + Off, + Inactive, + Active, +} - [Serializable, NetSerializable] - public enum ProximityTriggerVisualState : byte - { - State, - } +[Serializable, NetSerializable] +public enum ProximityTriggerVisualState : byte +{ + State, +} - [Serializable, NetSerializable] - public enum TriggerVisuals : byte - { - VisualState, - } +[Serializable, NetSerializable] +public enum TriggerVisuals : byte +{ + VisualState, +} - [Serializable, NetSerializable] - public enum TriggerVisualState : byte - { - Primed, - Unprimed, - } +[Serializable, NetSerializable] +public enum TriggerVisualState : byte +{ + Primed, + Unprimed, } diff --git a/Content.Shared/Trigger/VoiceTriggeredEvent.cs b/Content.Shared/Trigger/VoiceTriggeredEvent.cs new file mode 100644 index 00000000000..af138b56cfa --- /dev/null +++ b/Content.Shared/Trigger/VoiceTriggeredEvent.cs @@ -0,0 +1,10 @@ +namespace Content.Shared.Trigger; + +/// +/// Raised when a voice trigger is activated, containing the message that triggered it. +/// +/// The EntityUid of the entity sending the message +/// The contents of the message +/// The message without the phrase that triggered it. +[ByRefEvent] +public readonly record struct VoiceTriggeredEvent(EntityUid Source, string? Message, string MessageWithoutPhrase); diff --git a/Content.Shared/Weapons/Ranged/Events/OnEmptyGunShotEvent.cs b/Content.Shared/Weapons/Ranged/Events/OnEmptyGunShotEvent.cs index efae42952b4..998fa8f0eb9 100644 --- a/Content.Shared/Weapons/Ranged/Events/OnEmptyGunShotEvent.cs +++ b/Content.Shared/Weapons/Ranged/Events/OnEmptyGunShotEvent.cs @@ -4,4 +4,4 @@ namespace Content.Shared.Weapons.Ranged.Events; /// Raised directed on the gun when trying to fire it while it's out of ammo /// [ByRefEvent] -public record struct OnEmptyGunShotEvent(EntityUid EmptyGun); +public record struct OnEmptyGunShotEvent(EntityUid User); diff --git a/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.cs b/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.cs index 0f978968c75..898954633a3 100644 --- a/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.cs +++ b/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.cs @@ -355,7 +355,7 @@ public abstract partial class SharedGunSystem : EntitySystem if (ev.Ammo.Count <= 0) { // triggers effects on the gun if it's empty - var emptyGunShotEvent = new OnEmptyGunShotEvent(); + var emptyGunShotEvent = new OnEmptyGunShotEvent(user); RaiseLocalEvent(gunUid, ref emptyGunShotEvent); gun.BurstActivated = false; diff --git a/Resources/Locale/en-US/machine-linking/receiver_ports.ftl b/Resources/Locale/en-US/machine-linking/receiver_ports.ftl index d7a2636e11b..40dc6814057 100644 --- a/Resources/Locale/en-US/machine-linking/receiver_ports.ftl +++ b/Resources/Locale/en-US/machine-linking/receiver_ports.ftl @@ -25,11 +25,8 @@ signal-port-description-close = Closes a device. signal-port-name-doorbolt = Door bolt signal-port-description-doorbolt = Bolts door when HIGH. -signal-port-name-trigger = Trigger -signal-port-description-trigger = Triggers some mechanism on the device. - -signal-port-name-timer = Timer -signal-port-description-timer = Starts the timer countdown of the device. +signal-port-name-trigger-receiver = Trigger +signal-port-description-trigger-receiver = Triggers some mechanism on the device. signal-port-name-order-sender = Order sender signal-port-description-order-sender = Cargo console order sender diff --git a/Resources/Locale/en-US/machine-linking/transmitter_ports.ftl b/Resources/Locale/en-US/machine-linking/transmitter_ports.ftl index 89a978479eb..d016a7e2064 100644 --- a/Resources/Locale/en-US/machine-linking/transmitter_ports.ftl +++ b/Resources/Locale/en-US/machine-linking/transmitter_ports.ftl @@ -25,8 +25,11 @@ signal-port-description-dockstatus = This port is invoked with HIGH when docked signal-port-name-middle = Middle signal-port-description-middle = This port is invoked whenever the lever is moved to the neutral position. -signal-port-name-timer-trigger = Timer Trigger -signal-port-description-timer-trigger = This port is invoked whenever the timer triggers. +signal-port-name-trigger-sender = Trigger +signal-port-description-trigger-sender = This port is invoked whenever the device triggers. + +signal-port-name-timer-trigger = Timer +signal-port-description-timer-trigger = This port is invoked whenever the timer is up. signal-port-name-timer-start = Timer Start signal-port-description-timer-start = This port is invoked whenever the timer starts. diff --git a/Resources/Locale/en-US/triggers/ghost-kick-on-trigger.ftl b/Resources/Locale/en-US/triggers/ghost-kick-on-trigger.ftl new file mode 100644 index 00000000000..acb06bda472 --- /dev/null +++ b/Resources/Locale/en-US/triggers/ghost-kick-on-trigger.ftl @@ -0,0 +1 @@ +ghost-kick-on-trigger-default = Tripped over a kick mine, crashed through the fourth wall. diff --git a/Resources/Locale/en-US/triggers/timer-trigger.ftl b/Resources/Locale/en-US/triggers/timer-trigger.ftl new file mode 100644 index 00000000000..5d6d553b459 --- /dev/null +++ b/Resources/Locale/en-US/triggers/timer-trigger.ftl @@ -0,0 +1,10 @@ + +timer-trigger-verb-set = {$time} Seconds +timer-trigger-verb-set-current = {$time} Seconds (current) +timer-trigger-verb-cycle = Cycle Time Delay + +timer-trigger-examine = The timer is set to {$time} seconds. + +timer-trigger-popup-set = Timer set to {$time} seconds. + +timer-trigger-activated = You activate {THE($device)}. diff --git a/Resources/Locale/en-US/triggers/toggle-trigger-condition.ftl b/Resources/Locale/en-US/triggers/toggle-trigger-condition.ftl new file mode 100644 index 00000000000..874490686fa --- /dev/null +++ b/Resources/Locale/en-US/triggers/toggle-trigger-condition.ftl @@ -0,0 +1,7 @@ +toggle-trigger-condition-default-verb = Toggle device +toggle-trigger-condition-default-on = Device enabled. +toggle-trigger-condition-default-off = Device disabled. + +toggle-trigger-condition-stick-verb = Toggle auto-activation +toggle-trigger-condition-stick-on = The device will now activate automatically when planted. +toggle-trigger-condition-stick-off = The device will no longer activate automatically when planted. diff --git a/Resources/Locale/en-US/triggers/trigger-on-verb.ftl b/Resources/Locale/en-US/triggers/trigger-on-verb.ftl new file mode 100644 index 00000000000..d9342e7bdd0 --- /dev/null +++ b/Resources/Locale/en-US/triggers/trigger-on-verb.ftl @@ -0,0 +1,2 @@ +trigger-on-verb-default = Trigger +trigger-on-verb-detonation = Start detonation \ No newline at end of file diff --git a/Resources/Locale/en-US/triggers/trigger-on-voice.ftl b/Resources/Locale/en-US/triggers/trigger-on-voice.ftl new file mode 100644 index 00000000000..7ace486657c --- /dev/null +++ b/Resources/Locale/en-US/triggers/trigger-on-voice.ftl @@ -0,0 +1,12 @@ +trigger-on-voice-examine = The display reads: "{$keyphrase}" +trigger-on-voice-uninitialized = The display reads: Uninitialized... + +trigger-on-voice-record = Record +trigger-on-voice-stop = Stop +trigger-on-voice-clear = Clear recording + +trigger-on-voice-start-recording = Started recording. +trigger-on-voice-stop-recording = Stopped recording. +trigger-on-voice-record-failed-too-long = Message too long, try again. +trigger-on-voice-record-failed-too-short = Message too short, try again. +trigger-on-voice-recorded = Recorded successfully! diff --git a/Resources/Locale/en-US/weapons/grenades/timer-trigger.ftl b/Resources/Locale/en-US/weapons/grenades/timer-trigger.ftl deleted file mode 100644 index 9a10e9ef044..00000000000 --- a/Resources/Locale/en-US/weapons/grenades/timer-trigger.ftl +++ /dev/null @@ -1,16 +0,0 @@ - -verb-trigger-timer-set = {$time} Seconds -verb-trigger-timer-set-current = {$time} Seconds (current) -verb-trigger-timer-cycle = Cycle Time Delay - -examine-trigger-timer = The timer is set to {$time} seconds. - -popup-trigger-timer-set = Timer set to {$time} seconds. - -verb-start-detonation = Start detonation - -verb-toggle-start-on-stick = Toggle auto-activation -popup-start-on-stick-off = The device will no longer activate automatically when planted -popup-start-on-stick-on = The device will now activate automatically when planted - -trigger-activated = You activate {THE($device)}. diff --git a/Resources/Locale/en-US/weapons/grenades/voice-trigger.ftl b/Resources/Locale/en-US/weapons/grenades/voice-trigger.ftl deleted file mode 100644 index 07ee5948d54..00000000000 --- a/Resources/Locale/en-US/weapons/grenades/voice-trigger.ftl +++ /dev/null @@ -1,12 +0,0 @@ -examine-trigger-voice = The display reads: "{$keyphrase}" -trigger-voice-uninitialized = The display reads: Uninitialized... - -verb-trigger-voice-record = Record -verb-trigger-voice-stop = Stop -verb-trigger-voice-clear = Clear recording - -popup-trigger-voice-start-recording = Started recording -popup-trigger-voice-stop-recording = Stopped recording -popup-trigger-voice-record-failed-too-long = Message too long, try again -popup-trigger-voice-record-failed-too-short = Message too short, try again -popup-trigger-voice-recorded = Recorded successfully diff --git a/Resources/Maps/Shuttles/ShuttleEvent/quark.yml b/Resources/Maps/Shuttles/ShuttleEvent/quark.yml index 49e27e3fa93..d8deb511410 100644 --- a/Resources/Maps/Shuttles/ShuttleEvent/quark.yml +++ b/Resources/Maps/Shuttles/ShuttleEvent/quark.yml @@ -1351,6 +1351,8 @@ entities: intensity: 50 type: SingularityDistortion - type: ExplodeOnTrigger + keysIn: + - stageTwo triggerDelay: 500 - proto: GravityGeneratorMini entities: @@ -1479,8 +1481,8 @@ entities: [bold]Crew of the NT-Quark[/bold] - [bold]Nuclear containment breach detected on long range - halcyon scanners. Seek immediate shelter. Avoid + [bold]Nuclear containment breach detected on long range + halcyon scanners. Seek immediate shelter. Avoid contaminated materials. Do not panic.[/bold] [color=red][bold]Alpha decay rates indicate estimated diff --git a/Resources/Prototypes/DeviceLinking/sink_ports.yml b/Resources/Prototypes/DeviceLinking/sink_ports.yml index a5313fcc4e4..66e2bee27db 100644 --- a/Resources/Prototypes/DeviceLinking/sink_ports.yml +++ b/Resources/Prototypes/DeviceLinking/sink_ports.yml @@ -45,8 +45,8 @@ - type: sinkPort id: Trigger - name: signal-port-name-trigger - description: signal-port-description-trigger + name: signal-port-name-trigger-receiver + description: signal-port-description-trigger-receiver - type: sinkPort id: Timer diff --git a/Resources/Prototypes/DeviceLinking/source_ports.yml b/Resources/Prototypes/DeviceLinking/source_ports.yml index 4a460e722d1..302679c4d99 100644 --- a/Resources/Prototypes/DeviceLinking/source_ports.yml +++ b/Resources/Prototypes/DeviceLinking/source_ports.yml @@ -157,6 +157,12 @@ name: signal-port-name-power-discharging description: signal-port-description-power-discharging +- type: sourcePort + id: Trigger + name: signal-port-name-trigger-sender + description: signal-port-description-trigger-sender + defaultLinks: [ AutoClose, On, Open, Forward, Trigger, Timer ] + - type: sourcePort id: ItemDetected name: signal-port-name-item-detected diff --git a/Resources/Prototypes/Entities/Clothing/Back/backpacks.yml b/Resources/Prototypes/Entities/Clothing/Back/backpacks.yml index 03cb75d4627..20838e17393 100644 --- a/Resources/Prototypes/Entities/Clothing/Back/backpacks.yml +++ b/Resources/Prototypes/Entities/Clothing/Back/backpacks.yml @@ -342,9 +342,9 @@ equipDelay: 5 # to avoid accidentally falling into the trap associated with SelfUnremovableClothing - type: SelfUnremovableClothing - type: ShockOnTrigger + targetContainer: true damage: 5 duration: 3 - cooldown: 4 - type: TriggerOnSignal - type: DeviceLinkSink ports: diff --git a/Resources/Prototypes/Entities/Effects/admin_triggers.yml b/Resources/Prototypes/Entities/Effects/admin_triggers.yml index 52c5a6c110d..df9e11bcff7 100644 --- a/Resources/Prototypes/Entities/Effects/admin_triggers.yml +++ b/Resources/Prototypes/Entities/Effects/admin_triggers.yml @@ -7,7 +7,7 @@ sprite: /Textures/Objects/Fun/goldbikehorn.rsi visible: false state: icon - - type: TriggerOnSpawn + - type: TriggerOnSpawn - type: TimedDespawn lifetime: 5 @@ -25,7 +25,7 @@ suffix: BluespaceFlash parent: AdminInstantEffectBase components: - - type: SpawnOnTrigger + - type: SpawnOnTrigger proto: EffectFlashBluespace - type: entity @@ -35,9 +35,9 @@ components: - type: FlashOnTrigger range: 7 - - type: SpawnOnTrigger + - type: SpawnOnTrigger proto: GrenadeFlashEffect - + - type: entity id: AdminInstantEffectSmoke3 suffix: Smoke (03 sec) @@ -46,12 +46,12 @@ - type: SmokeOnTrigger duration: 3 spreadAmount: 1 - - type: SoundOnTrigger + - type: EmitSoundOnTrigger sound: /Audio/Effects/smoke.ogg - type: TimerTriggerVisuals primingSound: path: /Audio/Effects/Smoke-grenade.ogg - + - type: entity id: AdminInstantEffectSmoke10 suffix: Smoke (10 sec) @@ -60,12 +60,12 @@ - type: SmokeOnTrigger duration: 10 spreadAmount: 30 - - type: SoundOnTrigger + - type: EmitSoundOnTrigger sound: /Audio/Effects/smoke.ogg - type: TimerTriggerVisuals primingSound: path: /Audio/Effects/Smoke-grenade.ogg - + - type: entity id: AdminInstantEffectSmoke30 suffix: Smoke (30 sec) @@ -74,7 +74,7 @@ - type: SmokeOnTrigger duration: 30 spreadAmount: 50 - - type: SoundOnTrigger + - type: EmitSoundOnTrigger sound: /Audio/Effects/smoke.ogg - type: TimerTriggerVisuals primingSound: @@ -97,12 +97,12 @@ id: AdminInstantEffectGravityWell suffix: Gravity Well parent: AdminInstantEffectBase - components: - - type: SoundOnTrigger - removeOnTrigger: true + components: + - type: EmitSoundOnTrigger sound: path: /Audio/Effects/Grenades/Supermatter/supermatter_start.ogg - volume: 5 + params: + volume: 5 - type: AmbientSound enabled: true volume: -5 @@ -117,4 +117,4 @@ - type: SingularityDistortion intensity: 10 falloffPower: 1.5 - + diff --git a/Resources/Prototypes/Entities/Mobs/Cyborgs/base_borg_chassis.yml b/Resources/Prototypes/Entities/Mobs/Cyborgs/base_borg_chassis.yml index ea532480587..e651ea10166 100644 --- a/Resources/Prototypes/Entities/Mobs/Cyborgs/base_borg_chassis.yml +++ b/Resources/Prototypes/Entities/Mobs/Cyborgs/base_borg_chassis.yml @@ -299,7 +299,7 @@ receiveFrequencyId: CyborgControl transmitFrequencyId: RoboticsConsole savableAddress: false - - type: OnUseTimerTrigger + - type: TimerTrigger delay: 10 examinable: false beepSound: @@ -307,8 +307,9 @@ params: volume: -4 # prevent any funnies if someone makes a cyborg item... - - type: AutomatedTimer - type: ExplodeOnTrigger + keysIn: + - timer # explosion does most of its damage in the center and less at the edges - type: Explosive explosionType: Minibomb diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml b/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml index 5e863da46ec..78b8178671a 100644 --- a/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml +++ b/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml @@ -2512,7 +2512,8 @@ - type: Item size: Normal sprite: Mobs/Animals/grenadepenguin.rsi - - type: OnUseTimerTrigger + - type: TriggerOnUse + - type: TimerTrigger delay: 10 beepSound: path: /Audio/Weapons/Guns/MagOut/pistol_magout.ogg #funny sfx use @@ -2525,6 +2526,8 @@ intensitySlope: 20 totalIntensity: 225 - type: ExplodeOnTrigger + keysIn: + - timer - type: Destructible thresholds: - trigger: diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/elemental.yml b/Resources/Prototypes/Entities/Mobs/NPCs/elemental.yml index c3fc1ec9596..3606594be20 100644 --- a/Resources/Prototypes/Entities/Mobs/NPCs/elemental.yml +++ b/Resources/Prototypes/Entities/Mobs/NPCs/elemental.yml @@ -56,11 +56,6 @@ critThreshold: 120 - type: Destructible thresholds: - - trigger: - !type:DamageTrigger - damage: 100 - behaviors: - - !type:TriggerBehavior - trigger: !type:DamageTrigger damage: 120 diff --git a/Resources/Prototypes/Entities/Objects/Consumable/Food/Baked/pie.yml b/Resources/Prototypes/Entities/Objects/Consumable/Food/Baked/pie.yml index eac35858bf7..58ff3774107 100644 --- a/Resources/Prototypes/Entities/Objects/Consumable/Food/Baked/pie.yml +++ b/Resources/Prototypes/Entities/Objects/Consumable/Food/Baked/pie.yml @@ -164,7 +164,7 @@ payloadSlot: whitelist: components: - - OnUseTimerTrigger + - TimerTrigger insertSound: path: /Audio/Weapons/Guns/Empty/empty.ogg ejectSound: diff --git a/Resources/Prototypes/Entities/Objects/Devices/Electronics/igniter.yml b/Resources/Prototypes/Entities/Objects/Devices/Electronics/igniter.yml index 24843f608a7..87bef747d8e 100644 --- a/Resources/Prototypes/Entities/Objects/Devices/Electronics/igniter.yml +++ b/Resources/Prototypes/Entities/Objects/Devices/Electronics/igniter.yml @@ -10,6 +10,11 @@ - type: IgnitionSource temperature: 800 - type: IgniteOnTrigger + - type: EmitSoundOnTrigger + sound: + collection: WelderOn + - type: UseDelayOnTrigger + - type: UseDelayTriggerCondition - type: TriggerOnSignal - type: DeviceNetwork deviceNetId: Wireless diff --git a/Resources/Prototypes/Entities/Objects/Devices/Electronics/signaller.yml b/Resources/Prototypes/Entities/Objects/Devices/Electronics/signaller.yml index 0a975702aaa..4b3d98f198a 100644 --- a/Resources/Prototypes/Entities/Objects/Devices/Electronics/signaller.yml +++ b/Resources/Prototypes/Entities/Objects/Devices/Electronics/signaller.yml @@ -10,6 +10,10 @@ sprite: Objects/Devices/signaller.rsi state: signaller - type: Signaller + - type: SignalOnTrigger + port: Pressed + - type: UseDelayOnTrigger + - type: UseDelayTriggerCondition - type: UseDelay - type: StaticPrice price: 40 @@ -43,4 +47,4 @@ - type: WirelessNetworkConnection range: 50 - type: StaticPrice - price: 30 \ No newline at end of file + price: 30 diff --git a/Resources/Prototypes/Entities/Objects/Devices/Electronics/triggers.yml b/Resources/Prototypes/Entities/Objects/Devices/Electronics/triggers.yml index acc82abebe4..c6943a63e3d 100644 --- a/Resources/Prototypes/Entities/Objects/Devices/Electronics/triggers.yml +++ b/Resources/Prototypes/Entities/Objects/Devices/Electronics/triggers.yml @@ -22,7 +22,13 @@ price: 40 - type: PayloadTrigger components: - - type: OnUseTimerTrigger + - type: TriggerOnUse + keyOut: startTimer + - type: TimerTrigger + keysIn: + - startTimer + # use the default trigger key so it can activate any inserted payload + keyOut: trigger delay: 5 delayOptions: [3, 5, 10, 15, 30] initialBeepDelay: 0 @@ -47,13 +53,25 @@ - SignalTrigger - type: PayloadTrigger components: - - type: TriggerOnSignal - type: DeviceNetwork deviceNetId: Wireless receiveFrequencyId: BasicDevice - type: WirelessNetworkConnection range: 200 - type: DeviceLinkSink + - type: TriggerOnSignal + keyOut: startTimer + - type: TimerTrigger + keysIn: + - startTimer + # use the default trigger key so it can activate any inserted payload + keyOut: trigger + delay: 3 + initialBeepDelay: 0 + beepSound: + path: /Audio/Machines/Nuke/general_beep.ogg + params: + volume: -2 - type: entity parent: BaseItem diff --git a/Resources/Prototypes/Entities/Objects/Devices/desynchronizer.yml b/Resources/Prototypes/Entities/Objects/Devices/desynchronizer.yml index d5f8352baa9..526d297f608 100644 --- a/Resources/Prototypes/Entities/Objects/Devices/desynchronizer.yml +++ b/Resources/Prototypes/Entities/Objects/Devices/desynchronizer.yml @@ -9,6 +9,7 @@ state: icon - type: TriggerOnUse - type: PolymorphOnTrigger + targetUser: true polymorph: VoidPocket - type: UseDelay delay: 220 # long delay to ensure it can't be spammed, use it wisely diff --git a/Resources/Prototypes/Entities/Objects/Devices/mousetrap.yml b/Resources/Prototypes/Entities/Objects/Devices/mousetrap.yml index 04349c3a1c1..f7be1943709 100644 --- a/Resources/Prototypes/Entities/Objects/Devices/mousetrap.yml +++ b/Resources/Prototypes/Entities/Objects/Devices/mousetrap.yml @@ -8,32 +8,37 @@ sprite: Objects/Devices/mousetrap.rsi drawdepth: SmallMobs # if mice can hide under tables, so can mousetraps layers: - - state: mousetrap - map: ["base"] + - state: mousetrap + map: ["enum.ToggleableVisuals.Layer"] - type: StepTrigger intersectRatio: 0.2 requiredTriggeredSpeed: 2 - type: Mousetrap + - type: ItemToggle + soundActivate: "/Audio/Items/Handcuffs/cuff_end.ogg" + soundDeactivate: "/Audio/Items/snap.ogg" + popupActivate: mousetrap-on-activate + popupDeactivate: mousetrap-on-deactivate + - type: UseDelay + - type: ItemToggleOnTrigger + canActivate: false + showPopup: false # only show the popup when arming/disarming the trap in your hand - type: TriggerOnStepTrigger - type: PreventableStepTrigger - - type: DamageUserOnTrigger + - type: DamageOnTrigger + targetUser: true damage: types: Blunt: 2 # base damage, scales based on mass - - type: EmitSoundOnUse - sound: "/Audio/Items/Handcuffs/cuff_end.ogg" - handle: false - - type: EmitSoundOnTrigger - sound: "/Audio/Items/snap.ogg" - type: Item sprite: Objects/Devices/mousetrap.rsi - type: Appearance - type: GenericVisualizer visuals: - enum.MousetrapVisuals.Visual: - base: - Armed: { state: mousetraparmed } - Unarmed: { state: mousetrap } + enum.ToggleableVisuals.Enabled: + enum.ToggleableVisuals.Layer: + True: {state: mousetraparmed} + False: {state: mousetrap} - type: Physics bodyType: Dynamic - type: CollisionWake @@ -66,6 +71,6 @@ - type: Sprite layers: - state: mousetraparmed - map: ["base"] - - type: Mousetrap - isActive: true + map: ["enum.ToggleableVisuals.Layer"] + - type: ItemToggle + activated: true diff --git a/Resources/Prototypes/Entities/Objects/Devices/payload.yml b/Resources/Prototypes/Entities/Objects/Devices/payload.yml index 0729128e8bd..546d416132f 100644 --- a/Resources/Prototypes/Entities/Objects/Devices/payload.yml +++ b/Resources/Prototypes/Entities/Objects/Devices/payload.yml @@ -98,3 +98,4 @@ - type: EmitSoundOnTrigger sound: path: "/Audio/Effects/flash_bang.ogg" + positional: true diff --git a/Resources/Prototypes/Entities/Objects/Fun/bike_horn.yml b/Resources/Prototypes/Entities/Objects/Fun/bike_horn.yml index c4be0aa4531..f124be8a426 100644 --- a/Resources/Prototypes/Entities/Objects/Fun/bike_horn.yml +++ b/Resources/Prototypes/Entities/Objects/Fun/bike_horn.yml @@ -229,3 +229,4 @@ - MobMover - type: SpawnOnTrigger proto: EffectGravityPulse + predicted: true diff --git a/Resources/Prototypes/Entities/Objects/Fun/dice.yml b/Resources/Prototypes/Entities/Objects/Fun/dice.yml index 32df1f402df..132f92212ef 100644 --- a/Resources/Prototypes/Entities/Objects/Fun/dice.yml +++ b/Resources/Prototypes/Entities/Objects/Fun/dice.yml @@ -127,7 +127,8 @@ path: /Audio/Effects/glass_step.ogg slipData: launchForwardsMultiplier: 0 - - type: DamageUserOnTrigger + - type: DamageOnTrigger + targetUser: true damage: types: Piercing: 5 diff --git a/Resources/Prototypes/Entities/Objects/Fun/figurines.yml b/Resources/Prototypes/Entities/Objects/Fun/figurines.yml index adf37635bb2..d7117e2016a 100644 --- a/Resources/Prototypes/Entities/Objects/Fun/figurines.yml +++ b/Resources/Prototypes/Entities/Objects/Fun/figurines.yml @@ -19,6 +19,8 @@ - Figurine - type: UseDelay delay: 5 + - type: UseDelayOnTrigger + - type: UseDelayTriggerCondition # prevent spam - type: TriggerOnActivate - type: TriggerOnSignal - type: Speech diff --git a/Resources/Prototypes/Entities/Objects/Fun/toys.yml b/Resources/Prototypes/Entities/Objects/Fun/toys.yml index 7b639795cfb..9364b46dde7 100644 --- a/Resources/Prototypes/Entities/Objects/Fun/toys.yml +++ b/Resources/Prototypes/Entities/Objects/Fun/toys.yml @@ -896,7 +896,7 @@ - type: StepTrigger intersectRatio: 0.2 requiredTriggeredSpeed: 2 - - type: TriggerOnStepTrigger + - type: TriggerOnStepTrigger # for payloads - type: Appearance - type: CollisionWake enabled: false diff --git a/Resources/Prototypes/Entities/Objects/Materials/shards.yml b/Resources/Prototypes/Entities/Objects/Materials/shards.yml index ecfa263a25c..91fa0905379 100644 --- a/Resources/Prototypes/Entities/Objects/Materials/shards.yml +++ b/Resources/Prototypes/Entities/Objects/Materials/shards.yml @@ -72,7 +72,8 @@ slipData: launchForwardsMultiplier: 0 - type: TriggerOnStepTrigger - - type: DamageUserOnTrigger + - type: DamageOnTrigger + targetUser: true damage: types: Piercing: 5 @@ -93,7 +94,7 @@ - type: ToolRefinable refineResult: - id: SheetGlass1 - - type: DamageUserOnTrigger + - type: DamageOnTrigger damage: types: Piercing: 4.5 @@ -129,7 +130,7 @@ refineResult: - id: SheetGlass1 - id: PartRodMetal1 - - type: DamageUserOnTrigger + - type: DamageOnTrigger damage: types: Piercing: 5.5 @@ -165,7 +166,7 @@ refineResult: - id: SheetGlass1 - id: SheetPlasma1 - - type: DamageUserOnTrigger + - type: DamageOnTrigger damage: types: Piercing: 6.5 @@ -204,7 +205,7 @@ refineResult: - id: SheetGlass1 - id: SheetUranium1 - - type: DamageUserOnTrigger + - type: DamageOnTrigger damage: types: Piercing: 5 @@ -239,7 +240,7 @@ refineResult: - id: SheetGlass1 - id: SheetBrass1 - - type: DamageUserOnTrigger + - type: DamageOnTrigger damage: types: Piercing: 5 diff --git a/Resources/Prototypes/Entities/Objects/Misc/land_mine.yml b/Resources/Prototypes/Entities/Objects/Misc/land_mine.yml index 7ed1b657ea2..a3a2b60401e 100644 --- a/Resources/Prototypes/Entities/Objects/Misc/land_mine.yml +++ b/Resources/Prototypes/Entities/Objects/Misc/land_mine.yml @@ -64,7 +64,8 @@ name: kick mine parent: BaseLandMine components: - - type: GhostKickUserOnTrigger + - type: GhostKickOnTrigger + targetUser: true - type: DeleteOnTrigger - type: entity diff --git a/Resources/Prototypes/Entities/Objects/Misc/subdermal_implants.yml b/Resources/Prototypes/Entities/Objects/Misc/subdermal_implants.yml index 85dea4507cc..cb679aa9883 100644 --- a/Resources/Prototypes/Entities/Objects/Misc/subdermal_implants.yml +++ b/Resources/Prototypes/Entities/Objects/Misc/subdermal_implants.yml @@ -61,17 +61,18 @@ description: This implant lets the user honk anywhere at any time. categories: [ HideSpawnMenu ] components: - - type: SubdermalImplant - implantAction: ActionActivateHonkImplant - - type: TriggerImplantAction - - type: EmitSoundOnTrigger - sound: - collection: BikeHorn - params: - variation: 0.125 - - type: Tag - tags: - - BikeHorn + - type: SubdermalImplant + implantAction: ActionActivateHonkImplant + - type: TriggerOnActivateImplant + - type: EmitSoundOnTrigger + predicted: true + sound: + collection: BikeHorn + params: + variation: 0.125 + - type: Tag + tags: + - BikeHorn #Security implants @@ -176,16 +177,16 @@ description: This implant creates an electromagnetic pulse when activated. categories: [ HideSpawnMenu ] components: - - type: SubdermalImplant - implantAction: ActionActivateEmpImplant - - type: TriggerImplantAction - - type: EmpOnTrigger - range: 2.75 - energyConsumption: 50000 - disableDuration: 10 - damage: # DeltaV - EMP damage - types: - Ion: 80 # Would take 2 charges if you want to actually kill with it + - type: SubdermalImplant + implantAction: ActionActivateEmpImplant + - type: TriggerOnActivateImplant + - type: EmpOnTrigger + range: 2.75 + energyConsumption: 50000 + disableDuration: 10 + damage: # DeltaV - EMP damage + types: + Ion: 80 # Would take 2 charges if you want to actually kill with it - type: entity parent: BaseSubdermalImplant @@ -194,10 +195,10 @@ description: This implant randomly teleports the user within a large radius when activated. categories: [ HideSpawnMenu ] components: - - type: SubdermalImplant - implantAction: ActionActivateScramImplant - - type: TriggerImplantAction - - type: ScramImplant + - type: SubdermalImplant + implantAction: ActionActivateScramImplant + - type: TriggerOnActivateImplant + - type: ScramImplant - type: entity parent: BaseSubdermalImplant @@ -238,27 +239,28 @@ description: This implant detonates the user upon activation or upon death. categories: [ HideSpawnMenu ] components: - - type: SubdermalImplant - permanent: true - implantAction: ActionActivateMicroBomb - - type: TriggerOnMobstateChange - mobState: - - Dead - - type: TriggerImplantAction - - type: ExplodeOnTrigger - - type: GibOnTrigger - deleteItems: true - - type: Explosive - explosionType: MicroBomb - totalIntensity: 120 - intensitySlope: 5 - maxIntensity: 30 - canCreateVacuum: false - - type: Tag - tags: - - SubdermalImplant - - HideContextMenu - - MicroBomb + - type: SubdermalImplant + permanent: true + implantAction: ActionActivateMicroBomb + - type: TriggerOnMobstateChange + mobState: + - Dead + - type: TriggerOnActivateImplant + - type: ExplodeOnTrigger + - type: GibOnTrigger + targetUser: true + deleteItems: true + - type: Explosive + explosionType: MicroBomb + totalIntensity: 120 + intensitySlope: 5 + maxIntensity: 30 + canCreateVacuum: false + - type: Tag + tags: + - SubdermalImplant + - HideContextMenu + - MicroBomb - type: entity @@ -270,20 +272,24 @@ components: - type: SubdermalImplant permanent: true - - type: TriggerOnMobstateChange #Chains with OnUseTimerTrigger + - type: TriggerOnMobstateChange #activates the timer mobState: - Dead preventSuicide: true - - type: OnUseTimerTrigger + - type: TimerTrigger delay: 7 - initialBeepDelay: 0 beepSound: path: /Audio/Machines/Nuke/general_beep.ogg params: volume: -2 - type: ExplodeOnTrigger + keysIn: + - timer - type: GibOnTrigger + targetUser: true deleteItems: true + keysIn: + - timer - type: Explosive explosionType: Default totalIntensity: 3500 @@ -309,11 +315,13 @@ - type: TriggerOnMobstateChange mobState: - Dead - - type: TriggerImplantAction + - type: TriggerOnActivateImplant - type: GibOnTrigger + targetUser: true deleteItems: true - type: SpawnOnTrigger proto: Acidifier + predicted: true - type: Tag tags: - SubdermalImplant @@ -336,7 +344,8 @@ mobState: - Critical - Dead - - type: Rattle + - type: RattleOnTrigger + targetUser: true - type: entity parent: BaseSubdermalImplant @@ -368,5 +377,5 @@ description: This implant will inform the Centcomm radio channel should the user fall into critical condition or die. categories: [ HideSpawnMenu ] components: - - type: Rattle + - type: RattleOnTrigger radioChannel: CentCom diff --git a/Resources/Prototypes/Entities/Objects/Specific/Janitorial/janitor.yml b/Resources/Prototypes/Entities/Objects/Specific/Janitorial/janitor.yml index d9d4851158e..fb740f1cd6a 100644 --- a/Resources/Prototypes/Entities/Objects/Specific/Janitorial/janitor.yml +++ b/Resources/Prototypes/Entities/Objects/Specific/Janitorial/janitor.yml @@ -181,24 +181,31 @@ path: /Audio/Effects/beep_landmine.ogg params: maxDistance: 10 - - type: ExplodeOnTrigger - type: Explosive explosionType: HardBomb # normally Default and max 5 total 60 maxIntensity: 10 # about a ~67.5 total damage totalIntensity: 30 # about a ~3 tile radius canCreateVacuum: false + - type: ExplodeOnTrigger + keysIn: + - timer + - trigger # directly explode from the landmine - type: DeleteOnTrigger - - type: OnUseTimerTrigger - useVerbInstead: true + keysIn: + - timer + - trigger + - type: TimerTrigger beepInterval: .25 beepSound: path: /Audio/Items/Janitor/floor_sign_beep.ogg params: volume: 1 examinable: false + - type: TriggerOnVerb + text: trigger-on-verb-detonation - type: Tag tags: # ignore "WhitelistChameleon" tag - - WetFloorSign + - WetFloorSign - type: entity name: plunger diff --git a/Resources/Prototypes/Entities/Objects/Specific/Janitorial/soap.yml b/Resources/Prototypes/Entities/Objects/Specific/Janitorial/soap.yml index b918a137ccb..52d0aa328e2 100644 --- a/Resources/Prototypes/Entities/Objects/Specific/Janitorial/soap.yml +++ b/Resources/Prototypes/Entities/Objects/Specific/Janitorial/soap.yml @@ -163,6 +163,7 @@ launchForwardsMultiplier: 1.5 - type: StepTrigger intersectRatio: 0.04 + - type: TriggerOnStepTrigger - type: Item heldPrefix: syndie - type: Fixtures @@ -183,10 +184,12 @@ - ItemMask - type: DeleteOnTrigger - type: EmitSoundOnTrigger + predicted: true + positional: true sound: path: "/Audio/Effects/Fluids/splat.ogg" params: - volume: -20 + volume: -8 - type: entity name: soap diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Bombs/firebomb.yml b/Resources/Prototypes/Entities/Objects/Weapons/Bombs/firebomb.yml index 23f5cc43626..fec2cca3abd 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Bombs/firebomb.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Bombs/firebomb.yml @@ -16,7 +16,8 @@ - state: wires - type: Item sprite: Objects/Weapons/Bombs/ied.rsi - - type: OnUseTimerTrigger + - type: TriggerOnUse + - type: TimerTrigger delay: 5 examinable: false initialBeepDelay: 0 @@ -34,6 +35,8 @@ maxIntensity: 3 canCreateVacuum: false - type: ExplodeOnTrigger + keysIn: + - timer - type: Appearance - type: AnimationPlayer - type: TimerTriggerVisuals diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Bombs/funny.yml b/Resources/Prototypes/Entities/Objects/Weapons/Bombs/funny.yml index 73c021748c1..298b9d7c123 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Bombs/funny.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Bombs/funny.yml @@ -23,13 +23,16 @@ damage: types: Blunt: 5 - - type: OnUseTimerTrigger + - type: TriggerOnUse + - type: TimerTrigger delay: 120 beepSound: path: /Audio/Machines/Nuke/general_beep.ogg params: volume: -2 - type: ExplodeOnTrigger + keysIn: + - timer - type: Explosive explosionType: Default maxIntensity: 50 @@ -37,6 +40,8 @@ totalIntensity: 100 canCreateVacuum: false - type: DeleteOnTrigger + keysIn: + - timer - type: HotPotato - type: DamageOnHolding enabled: false @@ -49,7 +54,7 @@ enum.Trigger.TriggerVisuals.VisualState: base: Primed: { state: activated } - Unprimed: { state: complete } + Unprimed: { state: icon } - type: entity id: HotPotatoEffect diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Bombs/pen.yml b/Resources/Prototypes/Entities/Objects/Weapons/Bombs/pen.yml index 2d641568d78..fc158c39f66 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Bombs/pen.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Bombs/pen.yml @@ -5,7 +5,7 @@ description: A dark ink pen. id: PenExploding components: - - type: OnUseTimerTrigger + - type: TimerTrigger delay: 4 examinable: false - type: Explosive @@ -16,8 +16,11 @@ canCreateVacuum: false - type: ActivateOnPaperOpened - type: ExplodeOnTrigger + keysIn: + - timer + - type: TriggerOnUse - type: TriggerOnSignal - - type: DeviceLinkSink + - type: DeviceLinkSink # This should be changed into separate behavior where triggering via signal makes beep, while triggering manually is quiet. ports: - Trigger - type: EmitSoundOnUse diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Bombs/pipebomb.yml b/Resources/Prototypes/Entities/Objects/Weapons/Bombs/pipebomb.yml index a39a1de6719..a661224f318 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Bombs/pipebomb.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Bombs/pipebomb.yml @@ -10,7 +10,8 @@ - state: base map: ["enum.TriggerVisualLayers.Base"] - state: wires - - type: OnUseTimerTrigger # todo: make it activate through welder/lighter/fire instead + - type: TriggerOnActivate # todo: make it activate through welder/lighter/fire instead + - type: TimerTrigger delay: 5 examinable: false initialBeepDelay: 0 @@ -19,6 +20,8 @@ min: 1 max: 10 - type: ExplodeOnTrigger + keysIn: + - timer - type: Explosive # Weak explosion in a very small radius. Doesn't break underplating. explosionType: Default totalIntensity: 50 diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Bombs/plastic.yml b/Resources/Prototypes/Entities/Objects/Weapons/Bombs/plastic.yml index 3dda8b6d57f..afecd66f0ff 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Bombs/plastic.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Bombs/plastic.yml @@ -33,7 +33,7 @@ enum.Trigger.TriggerVisuals.VisualState: base: Primed: { state: primed } - Unprimed: { state: complete } + Unprimed: { state: icon } - type: entity name: composition C-4 @@ -54,17 +54,29 @@ quickEquip: false equipDelay: 3 unequipDelay: 6 - - type: OnUseTimerTrigger + - type: TriggerOnActivate + - type: TriggerOnSignal + - type: TriggerOnStuck + keyOut: stuck + - type: ToggleTriggerCondition # for toggling the start on stuck ability + keys: + - stuck + toggleVerb: toggle-trigger-condition-stick-verb + toggleOn: toggle-trigger-condition-stick-on + toggleOff: toggle-trigger-condition-stick-off + - type: TimerTrigger + keysIn: + - trigger + - stuck delay: 10 delayOptions: [10, 30, 60, 120, 300] initialBeepDelay: 0 beepSound: /Audio/Machines/Nuke/general_beep.ogg - startOnStick: true - canToggleStartOnStick: true - - type: TriggerOnSignal # DeltaV: use old behaviour instead of TimerStartOnSignal + #startOnStick: true # TODO: AUM - Test behavior and clean up if its fine. + #canToggleStartOnStick: true - type: DeviceLinkSink ports: - - Trigger # DeltaV: replace Timer with Trigger for TriggerOnSignal + - Trigger - type: Explosive # Powerful explosion in a very small radius. Doesn't break underplating. explosionType: DemolitionCharge totalIntensity: 60 @@ -72,6 +84,8 @@ maxIntensity: 30 canCreateVacuum: false - type: ExplodeOnTrigger + keysIn: + - timer - type: HolidayVisuals holidays: festive: @@ -94,7 +108,20 @@ layers: - state: icon map: ["base"] - - type: OnUseTimerTrigger + - type: TriggerOnActivate + - type: TriggerOnSignal + - type: TriggerOnStuck + keyOut: stuck + - type: ToggleTriggerCondition # for toggling the start on stuck ability + keys: + - stuck + toggleVerb: toggle-trigger-condition-stick-verb + toggleOn: toggle-trigger-condition-stick-on + toggleOff: toggle-trigger-condition-stick-off + - type: TimerTrigger + keysIn: + - trigger + - stuck delay: 5 delayOptions: [5, 10, 15, 20] initialBeepDelay: 0 @@ -102,9 +129,8 @@ path: /Audio/Effects/Cargo/buzz_two.ogg params: volume: -6 - startOnStick: false - canToggleStartOnStick: true - - type: TriggerOnSignal + #startOnStick: false # TODO: AUM - Test behavior and clean up if its fine. + #canToggleStartOnStick: true - type: DeviceLinkSink ports: - Trigger @@ -115,3 +141,5 @@ maxIntensity: 30 canCreateVacuum: false - type: ExplodeOnTrigger + keysIn: + - timer diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Bombs/spider.yml b/Resources/Prototypes/Entities/Objects/Weapons/Bombs/spider.yml index 2ac23f8c3f7..d00297a7236 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Bombs/spider.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Bombs/spider.yml @@ -12,13 +12,12 @@ sprite: Objects/Weapons/Bombs/spidercharge.rsi size: Small - type: SpiderCharge - - type: OnUseTimerTrigger + - type: TriggerOnStuck + - type: TimerTrigger delay: 10 delayOptions: [5, 10, 30, 60] initialBeepDelay: 0 beepSound: /Audio/Machines/Nuke/general_beep.ogg - startOnStick: true - - type: AutomatedTimer - type: Sticky stickDelay: 5 stickPopupStart: comp-sticky-start-stick-bomb @@ -37,6 +36,8 @@ maxIntensity: 120 canCreateVacuum: true - type: ExplodeOnTrigger + keysIn: + - timer - type: StickyVisualizer - type: Appearance - type: GenericVisualizer @@ -44,4 +45,4 @@ enum.Trigger.TriggerVisuals.VisualState: base: Primed: { state: primed } - Unprimed: { state: complete } + Unprimed: { state: icon } diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Projectiles/magic.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Projectiles/magic.yml index c587787d480..9e2b6d76c18 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Projectiles/magic.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Projectiles/magic.yml @@ -161,6 +161,7 @@ - type: entity id: ProjectilePolyboltBase + abstract: true parent: BaseBullet categories: [ HideSpawnMenu ] components: @@ -175,6 +176,8 @@ Poison: 5 - type: TriggerOnCollide fixtureID: projectile + - type: PolymorphOnTrigger + targetUser: true - type: entity id: ProjectilePolyboltCarp @@ -185,8 +188,8 @@ components: - type: PolymorphOnTrigger polymorph: WizardForcedCarp - - type: TriggerWhitelist - whitelist: + - type: WhitelistTriggerCondition + userWhitelist: components: - Body @@ -199,8 +202,8 @@ components: - type: PolymorphOnTrigger polymorph: WizardForcedMonkey - - type: TriggerWhitelist - whitelist: + - type: WhitelistTriggerCondition + userWhitelist: components: - Body @@ -218,8 +221,8 @@ color: brown - type: PolymorphOnTrigger polymorph: WizardWallDoor - - type: TriggerWhitelist - whitelist: + - type: WhitelistTriggerCondition + userWhitelist: components: - Airlock - Firelock @@ -269,8 +272,8 @@ components: - type: PolymorphOnTrigger polymorph: WizardForcedCluwne - - type: TriggerWhitelist - whitelist: + - type: WhitelistTriggerCondition + userWhitelist: components: - Body @@ -299,7 +302,7 @@ components: - type: PolymorphOnTrigger polymorph: BreadMorph - - type: TriggerWhitelist - whitelist: + - type: WhitelistTriggerCondition + userWhitelist: components: - Body diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Projectiles/projectiles.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Projectiles/projectiles.yml index e6db4865d80..8133745f2cc 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Projectiles/projectiles.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Projectiles/projectiles.yml @@ -849,8 +849,6 @@ range: 7 - type: SpawnOnTrigger proto: GrenadeFlashEffect - - type: ActiveTimerTrigger - timeRemaining: 0.3 - type: DeleteOnTrigger - type: entity @@ -887,8 +885,6 @@ sprite: Objects/Weapons/Guns/Projectiles/projectiles2.rsi layers: - state: cleanade - - type: ActiveTimerTrigger - timeRemaining: 0.3 - type: SmokeOnTrigger duration: 3.5 spreadAmount: 30 @@ -897,7 +893,7 @@ reagents: - ReagentId: SpaceCleaner Quantity: 30 - - type: SoundOnTrigger + - type: EmitSoundOnTrigger sound: /Audio/Items/smoke_grenade_smoke.ogg - type: ExplodeOnTrigger - type: Explosive diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Turrets/turrets_ballistic.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Turrets/turrets_ballistic.yml index c5dbb1b216c..5259f71f586 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Turrets/turrets_ballistic.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Turrets/turrets_ballistic.yml @@ -47,7 +47,7 @@ - type: Repairable qualityNeeded: "Anchoring" doAfterDelay: 3 - - type: TriggerWhenEmpty + - type: TriggerOnEmptyGunshot - type: ExplodeOnTrigger - type: Explosive explosionType: Default @@ -135,4 +135,4 @@ interactSuccessString: petting-success-generic interactFailureString: petting-failure-generic interactSuccessSound: - path: /Audio/Animals/snake_hiss.ogg \ No newline at end of file + path: /Audio/Animals/snake_hiss.ogg diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Throwable/grenades.yml b/Resources/Prototypes/Entities/Objects/Weapons/Throwable/grenades.yml index 144bb4b3210..8db14ebac79 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Throwable/grenades.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Throwable/grenades.yml @@ -14,7 +14,8 @@ quickEquip: false slots: - Belt - - type: OnUseTimerTrigger + - type: TriggerOnUse + - type: TimerTrigger delay: 3 - type: Damageable damageContainer: Inorganic @@ -25,6 +26,7 @@ damage: 10 behaviors: - !type:TriggerBehavior + keyOut: timer # explode immediately - !type:DoActsBehavior acts: ["Destruction"] - type: Appearance @@ -56,13 +58,15 @@ id: ExGrenade components: - type: ExplodeOnTrigger + keysIn: + - timer - type: Explosive explosionType: Default maxIntensity: 10 intensitySlope: 3 totalIntensity: 120 # about a ~4 tile radius canCreateVacuum: false - - type: OnUseTimerTrigger + - type: TimerTrigger beepSound: path: "/Audio/Effects/beep1.ogg" params: @@ -79,13 +83,22 @@ - type: Sprite sprite: Objects/Weapons/Grenades/flashbang.rsi - type: FlashOnTrigger + keysIn: + - timer range: 7 - - type: SoundOnTrigger + - type: EmitSoundOnTrigger + keysIn: + - timer sound: path: "/Audio/Effects/flash_bang.ogg" - type: DeleteOnTrigger + keysIn: + - timer - type: SpawnOnTrigger + keysIn: + - timer proto: GrenadeFlashEffect + predicted: true - type: Appearance - type: TimerTriggerVisuals primingSound: @@ -137,11 +150,14 @@ damage: 45 behaviors: - !type:TriggerBehavior + keyOut: timer # immediately explode - !type:DoActsBehavior acts: ["Destruction"] - - type: OnUseTimerTrigger + - type: TimerTrigger delay: 5 - type: ExplodeOnTrigger + keysIn: + - timer - type: Explosive explosionType: Minibomb totalIntensity: 200 @@ -164,13 +180,15 @@ categories: [ HideSpawnMenu ] components: - type: ExplodeOnTrigger + keysIn: + - timer - type: Explosive explosionType: Minibomb totalIntensity: 400 intensitySlope: 30 maxIntensity: 125 canCreateVacuum: true - - type: OnUseTimerTrigger + - type: TimerTrigger delay: 4.5 beepSound: path: /Audio/Effects/Grenades/SelfDestruct/SDS_Charge2.ogg @@ -188,7 +206,7 @@ components: - type: Sprite sprite: Objects/Weapons/Grenades/singularitygrenade.rsi - - type: OnUseTimerTrigger + - type: TimerTrigger delay: 3 beepInterval: 0.46 beepSound: @@ -205,14 +223,22 @@ totalIntensity: 200 intensitySlope: 30 maxIntensity: 120 - - type: SoundOnTrigger - removeOnTrigger: true + #- type: SoundOnTrigger + # removeOnTrigger: true + - type: EmitSoundOnTrigger + keysIn: + - timer sound: path: /Audio/Effects/Grenades/Supermatter/supermatter_start.ogg - volume: 5 + params: + volume: 5 - type: AnchorOnTrigger + keysIn: + - timer removeOnTrigger: true - type: TwoStageTrigger + keysIn: + - timer triggerDelay: 10.45 components: - type: AmbientSound @@ -236,12 +262,16 @@ radius: 6 softness: 1 offset: "0, 0" - - type: SoundOnTrigger + - type: EmitSoundOnTrigger sound: path: /Audio/Effects/Grenades/Supermatter/supermatter_end.ogg params: volume: 5 + keysIn: + - stageTwo - type: ExplodeOnTrigger # DeltaV - was DeleteOnTrigger, made explosive + keysIn: + - stageTwo - type: StaticPrice price: 1000 @@ -253,14 +283,20 @@ components: - type: Sprite sprite: Objects/Weapons/Grenades/whiteholegrenade.rsi - - type: OnUseTimerTrigger + - type: TimerTrigger delay: 3 beepInterval: 0.69 - - type: SoundOnTrigger - removeOnTrigger: true + - type: EmitSoundOnTrigger + keysIn: + - timer sound: path: /Audio/Effects/Grenades/Supermatter/whitehole_start.ogg - volume: 5 + params: + volume: 5 + - type: AnchorOnTrigger + keysIn: + - timer + removeOnTrigger: true - type: TwoStageTrigger triggerDelay: 11.14 components: @@ -285,12 +321,17 @@ radius: 6 softness: 1 offset: "0, 0" - - type: SoundOnTrigger + - type: EmitSoundOnTrigger + keysIn: + - stageTwo sound: path: /Audio/Effects/Grenades/Supermatter/supermatter_end.ogg params: volume: 15 + positional: true - type: DeleteOnTrigger + keysIn: + - stageTwo - type: StaticPrice price: 1000 @@ -302,9 +343,11 @@ components: - type: Sprite sprite: Objects/Weapons/Grenades/nukenade.rsi - - type: OnUseTimerTrigger + - type: TimerTrigger delay: 5 - type: ExplodeOnTrigger + keysIn: + - timer - type: Explosive explosionType: Default totalIntensity: 20000 # ~15 tile radius. @@ -317,6 +360,7 @@ damage: 50 behaviors: - !type:TriggerBehavior + keyOut: timer # immediately explode - !type:DoActsBehavior acts: ["Destruction"] - type: Appearance @@ -381,9 +425,13 @@ - type: Sprite sprite: Objects/Weapons/Grenades/empgrenade.rsi - type: EmpOnTrigger + keysIn: + - timer range: 5.5 energyConsumption: 100000 # Delta V, Was 50000 - type: DeleteOnTrigger + keysIn: + - timer - type: Appearance - type: TimerTriggerVisuals primingSound: @@ -400,13 +448,15 @@ - type: Sprite sprite: Objects/Weapons/Grenades/holyhandgrenade.rsi - type: ExplodeOnTrigger + keysIn: + - timer - type: Explosive explosionType: Default # same as macrobomb totalIntensity: 3500 intensitySlope: 15 maxIntensity: 70 canCreateVacuum: true - - type: OnUseTimerTrigger + - type: TimerTrigger delay: 3 # by canon - type: PointLight radius: 7 @@ -427,11 +477,17 @@ - type: Sprite sprite: Objects/Weapons/Grenades/smoke.rsi - type: SmokeOnTrigger + keysIn: + - timer duration: 30 spreadAmount: 50 - - type: SoundOnTrigger + - type: EmitSoundOnTrigger + keysIn: + - timer sound: /Audio/Items/smoke_grenade_smoke.ogg - type: DeleteOnTrigger + keysIn: + - timer - type: TimerTriggerVisuals primingSound: path: /Audio/Items/smoke_grenade_prime.ogg @@ -445,6 +501,8 @@ - type: Sprite sprite: Objects/Weapons/Grenades/janitor.rsi - type: SmokeOnTrigger + keysIn: + - timer duration: 15 spreadAmount: 50 smokePrototype: Foam @@ -462,6 +520,8 @@ - type: Sprite sprite: Objects/Weapons/Grenades/tear_gas.rsi - type: SmokeOnTrigger + keysIn: + - timer duration: 10 spreadAmount: 30 smokePrototype: TearGasSmokeWhite @@ -478,9 +538,11 @@ components: - type: Sprite sprite: Objects/Weapons/Grenades/metalfoam.rsi - - type: OnUseTimerTrigger + - type: TimerTrigger delay: 5 - type: SmokeOnTrigger + keysIn: + - timer duration: 10 spreadAmount: 20 smokePrototype: AluminiumMetalFoam @@ -495,14 +557,18 @@ components: - type: Sprite sprite: Objects/Weapons/Grenades/airboom.rsi - - type: SoundOnTrigger + - type: EmitSoundOnTrigger + keysIn: + - timer sound: /Audio/Items/smoke_grenade_smoke.ogg - type: TimerTriggerVisuals primingSound: path: /Audio/Items/smoke_grenade_prime.ogg - - type: OnUseTimerTrigger + - type: TimerTrigger delay: 3 - type: ReleaseGasOnTrigger + keysIn: + - timer removeFraction: 0.25 air: volume: 1000 @@ -530,9 +596,16 @@ - type: Sprite sprite: Objects/Weapons/Grenades/grenade.rsi - type: DeleteOnTrigger + keysIn: + - timer - type: SpawnOnTrigger + keysIn: + - timer proto: GrenadeFlashEffect - - type: SoundOnTrigger + predicted: true + - type: EmitSoundOnTrigger + keysIn: + - timer sound: path: /Audio/Effects/Emotes/parp1.ogg - type: Appearance @@ -548,9 +621,11 @@ components: - type: Sprite sprite: Objects/Weapons/Grenades/syndgrenade.rsi - - type: OnUseTimerTrigger + - type: TimerTrigger delay: 5 - - type: SoundOnTrigger + - type: EmitSoundOnTrigger + keysIn: + - timer sound: path: /Audio/Effects/Emotes/parp1.ogg - type: Appearance diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Throwable/projectile_grenades.yml b/Resources/Prototypes/Entities/Objects/Weapons/Throwable/projectile_grenades.yml index bdd8370b104..f9ce11a3b98 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Throwable/projectile_grenades.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Throwable/projectile_grenades.yml @@ -7,6 +7,8 @@ - type: Damageable damageContainer: Inorganic - type: DeleteOnTrigger + keysIn: + - timer - type: Destructible thresholds: - trigger: @@ -14,6 +16,7 @@ damage: 10 behaviors: - !type:TriggerBehavior + keyOut: timer # explode immediately - type: ContainerContainer containers: cluster-payload: !type:Container @@ -54,11 +57,17 @@ fillPrototype: PelletClusterRubber capacity: 30 - type: EmitSoundOnTrigger + keysIn: + - timer sound: path: "/Audio/Effects/flash_bang.ogg" - type: SpawnOnTrigger + keysIn: + - timer proto: GrenadeFlashEffect - - type: OnUseTimerTrigger + predicted: true + - type: TriggerOnUse + - type: TimerTrigger initialBeepDelay: 0 beepInterval: 2 delay: 3.5 @@ -80,7 +89,8 @@ - type: ProjectileGrenade fillPrototype: PelletClusterIncendiary capacity: 30 - - type: OnUseTimerTrigger + - type: TriggerOnUse + - type: TimerTrigger beepSound: path: "/Audio/Effects/beep1.ogg" params: @@ -89,6 +99,8 @@ beepInterval: 2 delay: 3.5 - type: EmitSoundOnTrigger + keysIn: + - timer sound: path: "/Audio/Weapons/Guns/Gunshots/batrifle.ogg" - type: StaticPrice @@ -108,7 +120,8 @@ - type: ProjectileGrenade fillPrototype: PelletClusterLethal capacity: 30 - - type: OnUseTimerTrigger + - type: TriggerOnUse + - type: TimerTrigger beepSound: path: "/Audio/Effects/beep1.ogg" params: @@ -117,6 +130,8 @@ beepInterval: 2 delay: 3.5 - type: EmitSoundOnTrigger + keysIn: + - timer sound: path: "/Audio/Weapons/Guns/Gunshots/batrifle.ogg" - type: StaticPrice diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Throwable/scattering_grenades.yml b/Resources/Prototypes/Entities/Objects/Weapons/Throwable/scattering_grenades.yml index 9038df13e01..ce031ba6ff9 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Throwable/scattering_grenades.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Throwable/scattering_grenades.yml @@ -17,8 +17,10 @@ damage: 10 behaviors: - !type:TriggerBehavior + keyOut: timer # explode immediately - type: ScatteringGrenade - - type: OnUseTimerTrigger + - type: TriggerOnUse + - type: TimerTrigger delay: 3 - type: Tag tags: @@ -81,6 +83,8 @@ Primed: { state: primed } Unprimed: { state: icon } - type: EmitSoundOnTrigger + keysIn: + - timer sound: path: "/Audio/Machines/door_lock_off.ogg" @@ -98,7 +102,7 @@ - type: ScatteringGrenade fillPrototype: ExGrenade distance: 4 - - type: OnUseTimerTrigger + - type: TimerTrigger beepSound: path: "/Audio/Effects/beep1.ogg" params: @@ -106,6 +110,8 @@ initialBeepDelay: 0 beepInterval: 0.5 - type: EmitSoundOnTrigger + keysIn: + - timer sound: path: "/Audio/Machines/door_lock_off.ogg" - type: StaticPrice @@ -130,6 +136,8 @@ types: Blunt: 10 - type: EmitSoundOnTrigger + keysIn: + - timer sound: path: "/Audio/Items/bikehorn.ogg" @@ -155,6 +163,8 @@ types: Blunt: 10 - type: EmitSoundOnTrigger + keysIn: + - timer sound: path: "/Audio/Effects/flash_bang.ogg" - type: StaticPrice @@ -177,7 +187,7 @@ fillPrototype: BulletFoam capacity: 30 velocity: 30 - - type: OnUseTimerTrigger + - type: TimerTrigger beepSound: path: "/Audio/Effects/beep1.ogg" params: @@ -185,5 +195,7 @@ initialBeepDelay: 0 beepInterval: 2 - type: EmitSoundOnTrigger + keysIn: + - timer sound: path: "/Audio/Weapons/Guns/Gunshots/batrifle.ogg" diff --git a/Resources/Prototypes/Entities/Objects/Weapons/security.yml b/Resources/Prototypes/Entities/Objects/Weapons/security.yml index 1a27dc311aa..63e67335f6f 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/security.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/security.yml @@ -193,6 +193,7 @@ description: An ultrabright flashbulb with a proximity trigger, useful for making an area security-only. components: - type: EmitSoundOnTrigger + predicted: true sound: path: /Audio/Weapons/flash.ogg - type: FlashOnTrigger diff --git a/Resources/Prototypes/Entities/Structures/Machines/bombs.yml b/Resources/Prototypes/Entities/Structures/Machines/bombs.yml index 65eb07f064b..dc3aa359f44 100644 --- a/Resources/Prototypes/Entities/Structures/Machines/bombs.yml +++ b/Resources/Prototypes/Entities/Structures/Machines/bombs.yml @@ -23,9 +23,11 @@ intensitySlope: 5 maxIntensity: 4 - type: ExplodeOnTrigger + keysIn: + - timer # If you nerf the syndicate bomb in any major way, this should probably drop down to at least 100s (not 90s to compensate for slower movement speed & less lag in SS14) # Unless, of course, you want the 90 seconds regardless. I can't stop you. - - type: OnUseTimerTrigger + - type: TimerTrigger delay: 180 delayOptions: [180, 240, 300, 600, 900] initialBeepDelay: 0 @@ -150,6 +152,6 @@ components: - type: Defusable disposable: true - - type: OnUseTimerTrigger + - type: TimerTrigger delay: 10 delayOptions: [10, 20, 30, 60, 90, 120, 150, 180, 210, 240, 270, 300] diff --git a/Resources/Prototypes/Entities/Structures/Walls/asteroid.yml b/Resources/Prototypes/Entities/Structures/Walls/asteroid.yml index dbe2fcc79f4..55211c0cf77 100644 --- a/Resources/Prototypes/Entities/Structures/Walls/asteroid.yml +++ b/Resources/Prototypes/Entities/Structures/Walls/asteroid.yml @@ -77,7 +77,7 @@ Unprimed: state: gibtonite_inactive visible: false - - type: OnUseTimerTrigger + - type: TimerTrigger examinable: false beepInterval: 0.4 beepSound: @@ -86,6 +86,8 @@ min: 8 max: 10 - type: ExplodeOnTrigger + keysIn: + - timer - type: Explosive explosionType: DemolitionCharge totalIntensity: 450 @@ -109,6 +111,7 @@ - !type:DoActsBehavior acts: ["Destruction"] - !type:TriggerBehavior + keyOut: timer # explode immediately - type: Gatherable # DeltaV - prevent mining gibtonite toolWhitelist: tags: [] diff --git a/Resources/ServerInfo/Guidebook/Security/Defusal.xml b/Resources/ServerInfo/Guidebook/Security/Defusal.xml index 583b8a34c7b..ab3e3bca6da 100644 --- a/Resources/ServerInfo/Guidebook/Security/Defusal.xml +++ b/Resources/ServerInfo/Guidebook/Security/Defusal.xml @@ -29,7 +29,7 @@ To arm a bomb, you can either [color=yellow]right click[/color] and click [color=yellow]Begin countdown[/click], or [color=yellow]alt-click[/color] the bomb. It will begin beeping. ## Time - A bomb has a limited time, at a minimum of [protodata="SyndicateBomb" comp="OnUseTimerTrigger" member="ShortestDelayOption"/] seconds and a maximum of [protodata="SyndicateBomb" comp="OnUseTimerTrigger" member="LongestDelayOption"/] seconds. You can view the timer by examining it, unless the Proceed wire is cut. Once the timer hits zero, the bomb will detonate. + A bomb has a limited time, at a minimum of [protodata="SyndicateBomb" comp="TimerTrigger" member="ShortestDelayOption"/] seconds and a maximum of [protodata="SyndicateBomb" comp="TimerTrigger" member="LongestDelayOption"/] seconds. You can view the timer by examining it, unless the Proceed wire is cut. Once the timer hits zero, the bomb will detonate. ## Bolts By default, once armed, a bomb will bolt itself to the ground. You must find the BOLT wire and cut it to disable the bolts, after which you can unwrench it and throw it into space. From 7acebd855a8bc24c6a0a03857e9773f92d0fb0bd Mon Sep 17 00:00:00 2001 From: Vanessa Date: Mon, 10 Nov 2025 09:46:05 -0600 Subject: [PATCH 020/340] Goobstation Bluespace Lifeline migration to the new Trigger system --- .../Explosion/Components/GoobTriggerSystem.cs | 34 ----------------- .../DeleteParentOnTriggerComponent.cs | 8 ---- .../Effects/DeleteParentOnTriggerComponent.cs | 12 ++++++ .../Systems/DeleteParentOnTriggerSystem.cs | 38 +++++++++++++++++++ .../Objects/Misc/subdermal_implants.yml | 2 +- 5 files changed, 51 insertions(+), 43 deletions(-) delete mode 100644 Content.Server/_Goobstation/Explosion/Components/GoobTriggerSystem.cs delete mode 100644 Content.Server/_Goobstation/Explosion/Components/OnTrigger/DeleteParentOnTriggerComponent.cs create mode 100644 Content.Shared/_Goobstation/Trigger/Components/Effects/DeleteParentOnTriggerComponent.cs create mode 100644 Content.Shared/_Goobstation/Trigger/Systems/DeleteParentOnTriggerSystem.cs diff --git a/Content.Server/_Goobstation/Explosion/Components/GoobTriggerSystem.cs b/Content.Server/_Goobstation/Explosion/Components/GoobTriggerSystem.cs deleted file mode 100644 index e2f0ddbe307..00000000000 --- a/Content.Server/_Goobstation/Explosion/Components/GoobTriggerSystem.cs +++ /dev/null @@ -1,34 +0,0 @@ -using Content.Server.Construction.Completions; -using Content.Server.Explosion.Components; -using Content.Server.Explosion.EntitySystems; - - -namespace Content.Server._Goobstation.Explosion.EntitySystems; - - -public sealed partial class GoobTriggerSystem : EntitySystem -{ - - public override void Initialize() - { - base.Initialize(); - - SubscribeLocalEvent(HandleDeleteParentTrigger); - } - - private void HandleDeleteParentTrigger(Entity entity, ref TriggerEvent args) - { - - var uid = entity.Owner; - - if (!TryComp(uid, out var userXform)) - return; - - if (userXform.ParentUid == userXform.GridUid || userXform.ParentUid == userXform.MapUid) - return; - - EntityManager.QueueDeleteEntity(userXform.ParentUid); - args.Handled = true; - } - -} diff --git a/Content.Server/_Goobstation/Explosion/Components/OnTrigger/DeleteParentOnTriggerComponent.cs b/Content.Server/_Goobstation/Explosion/Components/OnTrigger/DeleteParentOnTriggerComponent.cs deleted file mode 100644 index 9ae11bd7ad0..00000000000 --- a/Content.Server/_Goobstation/Explosion/Components/OnTrigger/DeleteParentOnTriggerComponent.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace Content.Server.Explosion.Components; -/// -/// Deletes entity parent on -/// -[RegisterComponent] -public sealed partial class DeleteParentOnTriggerComponent : Component -{ -} diff --git a/Content.Shared/_Goobstation/Trigger/Components/Effects/DeleteParentOnTriggerComponent.cs b/Content.Shared/_Goobstation/Trigger/Components/Effects/DeleteParentOnTriggerComponent.cs new file mode 100644 index 00000000000..f718fc3b728 --- /dev/null +++ b/Content.Shared/_Goobstation/Trigger/Components/Effects/DeleteParentOnTriggerComponent.cs @@ -0,0 +1,12 @@ +using Robust.Shared.GameStates; +using Content.Shared.Trigger.Components.Effects; + +namespace Content.Shared._Goobstation.Trigger.Components.Effects; + +/// +/// Will delete the entity and its parent when triggered. +/// +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +public sealed partial class DeleteParentOnTriggerComponent : BaseXOnTriggerComponent +{ +} diff --git a/Content.Shared/_Goobstation/Trigger/Systems/DeleteParentOnTriggerSystem.cs b/Content.Shared/_Goobstation/Trigger/Systems/DeleteParentOnTriggerSystem.cs new file mode 100644 index 00000000000..453159fc630 --- /dev/null +++ b/Content.Shared/_Goobstation/Trigger/Systems/DeleteParentOnTriggerSystem.cs @@ -0,0 +1,38 @@ +using Content.Shared.Body.Systems; +using Content.Shared.Inventory; +using Content.Shared.Trigger; +using Content.Shared.Trigger.Systems; +using Content.Shared.Trigger.Components.Effects; +using Content.Shared._Goobstation.Trigger.Components.Effects; + +namespace Content.Shared._Goobstation.Trigger.Systems; + +public sealed class DeleteParentOnTriggerSystem : EntitySystem +{ + [Dependency] private readonly SharedBodySystem _body = default!; + [Dependency] private readonly InventorySystem _inventory = default!; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnTrigger); + } + + private void OnTrigger(Entity ent, ref TriggerEvent args) + { + if (args.Key != null && !ent.Comp.KeysIn.Contains(args.Key)) + return; + + var target = ent.Comp.TargetUser ? args.User : ent.Owner; + + if (!TryComp(ent.Owner, out var userXform)) + return; + + if (userXform.ParentUid == userXform.GridUid || userXform.ParentUid == userXform.MapUid) + return; + + EntityManager.QueueDeleteEntity(userXform.ParentUid); + args.Handled = true; + } +} diff --git a/Resources/Prototypes/_Goobstation/Objects/Misc/subdermal_implants.yml b/Resources/Prototypes/_Goobstation/Objects/Misc/subdermal_implants.yml index 936754f36bf..2b47120d4de 100644 --- a/Resources/Prototypes/_Goobstation/Objects/Misc/subdermal_implants.yml +++ b/Resources/Prototypes/_Goobstation/Objects/Misc/subdermal_implants.yml @@ -11,7 +11,7 @@ - type: TriggerOnMobstateChange mobState: - Dead - - type: TriggerImplantAction + - type: TriggerOnActivateImplant - type: DeleteParentOnTrigger - type: SpawnOnTrigger proto: BluespaceLifeline From 0920380cc5370c85ac2d25c1880f6fc2530c2bb7 Mon Sep 17 00:00:00 2001 From: Vanessa Date: Mon, 10 Nov 2025 10:09:00 -0600 Subject: [PATCH 021/340] Few more DV-specific trigger fixes --- .../EntitySystems/RevenantAnimatedSystem.cs | 4 +-- .../Objects/Weapons/Throwable/grenades.yml | 10 +++---- .../Objects/Misc/subdermal_implants.yml | 2 +- .../Objects/Weapons/Bombs/plastic.yml | 9 ++++-- .../Weapons/Throwable/scattering_grenades.yml | 28 ++++++++++++++----- 5 files changed, 35 insertions(+), 18 deletions(-) diff --git a/Content.Server/_Impstation/Revenant/EntitySystems/RevenantAnimatedSystem.cs b/Content.Server/_Impstation/Revenant/EntitySystems/RevenantAnimatedSystem.cs index 3b98e24d03a..d3d2ef820c6 100644 --- a/Content.Server/_Impstation/Revenant/EntitySystems/RevenantAnimatedSystem.cs +++ b/Content.Server/_Impstation/Revenant/EntitySystems/RevenantAnimatedSystem.cs @@ -19,13 +19,13 @@ using Content.Shared.Weapons.Ranged.Systems; using Content.Shared.Cuffs.Components; using Content.Shared.Movement.Systems; using Robust.Shared.Player; -using Content.Shared.Explosion.Components; using Content.Shared.Mind.Components; using Content.Shared.Mobs.Components; using Content.Shared.Mobs.Systems; using Content.Shared.Mobs; using Robust.Shared.Timing; using Content.Shared.Construction.Components; +using Content.Shared.Trigger.Components; namespace Content.Server.Revenant.EntitySystems; @@ -115,7 +115,7 @@ public sealed partial class RevenantAnimatedSystem : EntitySystem else if (HasComp(ent)) // Goals: Jump into any creature's pockets/hands and cuff them htn.RootTask = new HTNCompoundTask() { Task = "AnimatedHandcuffsCompound" }; - else if (HasComp(ent)) + else if (HasComp(ent)) // Goals: Jump into any creature's pockets/hands and activate self htn.RootTask = new HTNCompoundTask() { Task = "AnimatedGrenadeCompound" }; else diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Throwable/grenades.yml b/Resources/Prototypes/Entities/Objects/Weapons/Throwable/grenades.yml index 8db14ebac79..d7a35f9ec4e 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Throwable/grenades.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Throwable/grenades.yml @@ -218,11 +218,11 @@ path: /Audio/Effects/Grenades/Supermatter/smbeep.ogg params: volume: -5 - - type: Explosive # DeltaV - made explosive again - explosionType: Default - totalIntensity: 200 - intensitySlope: 30 - maxIntensity: 120 + #- type: Explosive # DeltaV - made explosive again # TODO: AUM - Clean-Up + # explosionType: Default + # totalIntensity: 200 + # intensitySlope: 30 + # maxIntensity: 120 #- type: SoundOnTrigger # removeOnTrigger: true - type: EmitSoundOnTrigger diff --git a/Resources/Prototypes/_DV/Entities/Objects/Misc/subdermal_implants.yml b/Resources/Prototypes/_DV/Entities/Objects/Misc/subdermal_implants.yml index d93ad120038..f845dc608e5 100644 --- a/Resources/Prototypes/_DV/Entities/Objects/Misc/subdermal_implants.yml +++ b/Resources/Prototypes/_DV/Entities/Objects/Misc/subdermal_implants.yml @@ -81,7 +81,7 @@ - type: TriggerOnMobstateChange mobState: - Critical - - type: Rattle + - type: RattleOnTrigger radioChannel: Security - type: entity diff --git a/Resources/Prototypes/_DV/Entities/Objects/Weapons/Bombs/plastic.yml b/Resources/Prototypes/_DV/Entities/Objects/Weapons/Bombs/plastic.yml index 51ee92734de..42f5042c541 100644 --- a/Resources/Prototypes/_DV/Entities/Objects/Weapons/Bombs/plastic.yml +++ b/Resources/Prototypes/_DV/Entities/Objects/Weapons/Bombs/plastic.yml @@ -10,7 +10,10 @@ layers: - state: icon map: ["base"] - - type: OnUseTimerTrigger + - type: TimerTrigger + keysIn: + - trigger + - stuck delay: 10 delayOptions: [10, 15, 20, 25] initialBeepDelay: 0 @@ -18,8 +21,8 @@ path: /Audio/Effects/Cargo/buzz_two.ogg params: volume: -6 - startOnStick: true - canToggleStartOnStick: true + #startOnStick: true # TODO: AUM - Test behavior and clean up if its fine. + #canToggleStartOnStick: true - type: Explosive explosionType: DemolitionCharge totalIntensity: 10 diff --git a/Resources/Prototypes/_DV/Entities/Objects/Weapons/Throwable/scattering_grenades.yml b/Resources/Prototypes/_DV/Entities/Objects/Weapons/Throwable/scattering_grenades.yml index 44e77a90328..051de5664a2 100644 --- a/Resources/Prototypes/_DV/Entities/Objects/Weapons/Throwable/scattering_grenades.yml +++ b/Resources/Prototypes/_DV/Entities/Objects/Weapons/Throwable/scattering_grenades.yml @@ -15,16 +15,30 @@ enum.ConstructionVisuals.Layer: Primed: { state: primed } Unprimed: { state: icon } - - type: ScatteringGrenade - fillPrototype: MobMothroachEvil - capacity: 8 - - type: OnUseTimerTrigger + - type: TimerTrigger + keysIn: + - trigger beepSound: path: "/Audio/Effects/beep1.ogg" params: volume: 5 initialBeepDelay: 0 beepInterval: 0.5 - - type: SoundOnTrigger - sound: - path: "/Audio/Voice/Moth/moth_scream.ogg" + - type: TwoStageTrigger + triggerDelay: 3 # Same as the ScatteringGrenadeBase's delay + keysIn: + - timer + components: + - type: EmitSoundOnTrigger + keysIn: + - stageTwo + sound: + path: "/Audio/Voice/Moth/moth_scream.ogg" + params: + volume: 5 + - type: ScatteringGrenade + fillPrototype: MobMothroachEvil + capacity: 8 + keysIn: # TODO: AUM - Test this + - stageTwo + From 1c834104e105cdbad7d46f4e56042b0b15f9bab6 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 10 Nov 2025 16:09:32 +0000 Subject: [PATCH 022/340] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- .../Entities/Objects/Weapons/Throwable/scattering_grenades.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/Resources/Prototypes/_DV/Entities/Objects/Weapons/Throwable/scattering_grenades.yml b/Resources/Prototypes/_DV/Entities/Objects/Weapons/Throwable/scattering_grenades.yml index 051de5664a2..2736c536e17 100644 --- a/Resources/Prototypes/_DV/Entities/Objects/Weapons/Throwable/scattering_grenades.yml +++ b/Resources/Prototypes/_DV/Entities/Objects/Weapons/Throwable/scattering_grenades.yml @@ -41,4 +41,3 @@ capacity: 8 keysIn: # TODO: AUM - Test this - stageTwo - From dd751c22d3062fd96ac351df01c690e92ac111c1 Mon Sep 17 00:00:00 2001 From: Vanessa Date: Mon, 10 Nov 2025 15:35:25 -0600 Subject: [PATCH 023/340] Trigger Fixes for Mothroach Grenade and re-added explosive to supermatter grenade. --- .../Objects/Weapons/Bombs/plastic.yml | 4 --- .../Objects/Weapons/Throwable/grenades.yml | 15 ++++++----- .../Objects/Weapons/Bombs/plastic.yml | 2 -- .../Weapons/Throwable/scattering_grenades.yml | 25 ++++++++----------- 4 files changed, 17 insertions(+), 29 deletions(-) diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Bombs/plastic.yml b/Resources/Prototypes/Entities/Objects/Weapons/Bombs/plastic.yml index afecd66f0ff..b1bfdeef9a3 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Bombs/plastic.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Bombs/plastic.yml @@ -72,8 +72,6 @@ delayOptions: [10, 30, 60, 120, 300] initialBeepDelay: 0 beepSound: /Audio/Machines/Nuke/general_beep.ogg - #startOnStick: true # TODO: AUM - Test behavior and clean up if its fine. - #canToggleStartOnStick: true - type: DeviceLinkSink ports: - Trigger @@ -129,8 +127,6 @@ path: /Audio/Effects/Cargo/buzz_two.ogg params: volume: -6 - #startOnStick: false # TODO: AUM - Test behavior and clean up if its fine. - #canToggleStartOnStick: true - type: DeviceLinkSink ports: - Trigger diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Throwable/grenades.yml b/Resources/Prototypes/Entities/Objects/Weapons/Throwable/grenades.yml index d7a35f9ec4e..deb34593ac4 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Throwable/grenades.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Throwable/grenades.yml @@ -218,13 +218,6 @@ path: /Audio/Effects/Grenades/Supermatter/smbeep.ogg params: volume: -5 - #- type: Explosive # DeltaV - made explosive again # TODO: AUM - Clean-Up - # explosionType: Default - # totalIntensity: 200 - # intensitySlope: 30 - # maxIntensity: 120 - #- type: SoundOnTrigger - # removeOnTrigger: true - type: EmitSoundOnTrigger keysIn: - timer @@ -241,6 +234,11 @@ - timer triggerDelay: 10.45 components: + - type: Explosive # DeltaV - made explosive again + explosionType: Default + totalIntensity: 200 + intensitySlope: 30 + maxIntensity: 120 - type: AmbientSound enabled: true volume: -5 @@ -269,9 +267,10 @@ volume: 5 keysIn: - stageTwo - - type: ExplodeOnTrigger # DeltaV - was DeleteOnTrigger, made explosive + - type: ExplodeOnTrigger # DeltaV - made explosive keysIn: - stageTwo + - type: StaticPrice price: 1000 diff --git a/Resources/Prototypes/_DV/Entities/Objects/Weapons/Bombs/plastic.yml b/Resources/Prototypes/_DV/Entities/Objects/Weapons/Bombs/plastic.yml index 42f5042c541..c74cd1a77bf 100644 --- a/Resources/Prototypes/_DV/Entities/Objects/Weapons/Bombs/plastic.yml +++ b/Resources/Prototypes/_DV/Entities/Objects/Weapons/Bombs/plastic.yml @@ -21,8 +21,6 @@ path: /Audio/Effects/Cargo/buzz_two.ogg params: volume: -6 - #startOnStick: true # TODO: AUM - Test behavior and clean up if its fine. - #canToggleStartOnStick: true - type: Explosive explosionType: DemolitionCharge totalIntensity: 10 diff --git a/Resources/Prototypes/_DV/Entities/Objects/Weapons/Throwable/scattering_grenades.yml b/Resources/Prototypes/_DV/Entities/Objects/Weapons/Throwable/scattering_grenades.yml index 2736c536e17..727fa6695df 100644 --- a/Resources/Prototypes/_DV/Entities/Objects/Weapons/Throwable/scattering_grenades.yml +++ b/Resources/Prototypes/_DV/Entities/Objects/Weapons/Throwable/scattering_grenades.yml @@ -24,20 +24,15 @@ volume: 5 initialBeepDelay: 0 beepInterval: 0.5 - - type: TwoStageTrigger - triggerDelay: 3 # Same as the ScatteringGrenadeBase's delay + - type: EmitSoundOnTrigger keysIn: - timer - components: - - type: EmitSoundOnTrigger - keysIn: - - stageTwo - sound: - path: "/Audio/Voice/Moth/moth_scream.ogg" - params: - volume: 5 - - type: ScatteringGrenade - fillPrototype: MobMothroachEvil - capacity: 8 - keysIn: # TODO: AUM - Test this - - stageTwo + sound: + path: /Audio/Voice/Moth/moth_scream.ogg + params: + volume: 5 + positional: true + predicted: true + - type: ScatteringGrenade + fillPrototype: MobMothroachEvil + capacity: 8 From 98c5222ea20b73112a98fefd16a4ca047bb76e42 Mon Sep 17 00:00:00 2001 From: ThatGuyUSA Date: Sat, 2 Aug 2025 19:19:17 -0700 Subject: [PATCH 024/340] Advanced Clowning Module (#35797) * pAIs can now accept keys, but can't talk in said channels * added dummy module * added adv clown module alongside projector * holopeel & projector sprite added, it's destroyable too * added experimental pie cannon * exp pie thrower throws pies, added tool icon, added bananium horn * removed the weird pAI changes, my bad! * okay NOW the pAI stuff is all gone * added icon, recipe, renamed tech for unlocking * removed bananium horn * Added in-hand sprites, credited to TiniestShark. Changed holopeel projector description to let the user know it recharges over time. --- .../Objects/Devices/holoprojectors.yml | 25 +++++- .../Specific/Robotics/borg_modules.yml | 20 +++++ .../Objects/Weapons/Guns/pneumatic_cannon.yml | 34 ++++++++ .../Structures/Holographic/projections.yml | 38 ++++++++ .../Recipes/Lathes/Packs/robotics.yml | 1 + .../Recipes/Lathes/robot_modules.yml | 10 +++ .../Prototypes/Research/civilianservices.yml | 1 + .../actions_borg.rsi/adv-clowning-module.png | Bin 0 -> 815 bytes .../Actions/actions_borg.rsi/meta.json | 5 +- .../Devices/Holoprojectors/peel.rsi/icon.png | Bin 0 -> 652 bytes .../Holoprojectors/peel.rsi/inhand-left.png | Bin 0 -> 813 bytes .../Holoprojectors/peel.rsi/inhand-right.png | Bin 0 -> 821 bytes .../Devices/Holoprojectors/peel.rsi/meta.json | 82 ++++++++++++++++++ .../borgmodule.rsi/icon-clown-adv.png | Bin 0 -> 474 bytes .../Robotics/borgmodule.rsi/meta.json | 3 + .../Structures/Holo/peel.rsi/icon.png | Bin 0 -> 1344 bytes .../Structures/Holo/peel.rsi/meta.json | 33 +++++++ 17 files changed, 249 insertions(+), 3 deletions(-) create mode 100644 Resources/Textures/Interface/Actions/actions_borg.rsi/adv-clowning-module.png create mode 100644 Resources/Textures/Objects/Devices/Holoprojectors/peel.rsi/icon.png create mode 100644 Resources/Textures/Objects/Devices/Holoprojectors/peel.rsi/inhand-left.png create mode 100644 Resources/Textures/Objects/Devices/Holoprojectors/peel.rsi/inhand-right.png create mode 100644 Resources/Textures/Objects/Devices/Holoprojectors/peel.rsi/meta.json create mode 100644 Resources/Textures/Objects/Specific/Robotics/borgmodule.rsi/icon-clown-adv.png create mode 100644 Resources/Textures/Structures/Holo/peel.rsi/icon.png create mode 100644 Resources/Textures/Structures/Holo/peel.rsi/meta.json diff --git a/Resources/Prototypes/Entities/Objects/Devices/holoprojectors.yml b/Resources/Prototypes/Entities/Objects/Devices/holoprojectors.yml index c5a8fa48b9d..3b64c1b31da 100644 --- a/Resources/Prototypes/Entities/Objects/Devices/holoprojectors.yml +++ b/Resources/Prototypes/Entities/Objects/Devices/holoprojectors.yml @@ -52,6 +52,27 @@ disableEject: true swap: false +- type: entity + parent: Holoprojector + id: HoloprojectorClownBorg + name: holopeel projector + description: A holopeel projector that creates a slippery, hard light banana peel. It recharges, so that the fun never ends! + suffix: borg + components: + - type: HolosignProjector + signProto: HoloPeel + chargeUse: 240 + - type: Sprite + sprite: Objects/Devices/Holoprojectors/peel.rsi + state: icon + - type: ItemSlots + slots: + cell_slot: + name: power-cell-slot-component-slot-name-default + startingItem: PowerCellMicroreactor + disableEject: true + swap: false + - type: entity parent: BaseItem # DeltaV - remove powercell requirement id: HolofanProjector @@ -101,8 +122,8 @@ parent: HolofanProjector id: HolofanProjectorBorg name: integrated holofan - description: Stops idiots from causing more crew harm during atmospheric emergencies. Installed directly into an engineering cyborg, it recharges over time. - #components: # DeltaV - no cell slot + description: Stops idiots from causing more crew harm during atmospheric emergencies. Installed directly into an engineering cyborg, it recharges over time. + #components: #- type: ItemSlots # slots: # cell_slot: diff --git a/Resources/Prototypes/Entities/Objects/Specific/Robotics/borg_modules.yml b/Resources/Prototypes/Entities/Objects/Specific/Robotics/borg_modules.yml index 707441ec54e..c4898df84f6 100644 --- a/Resources/Prototypes/Entities/Objects/Specific/Robotics/borg_modules.yml +++ b/Resources/Prototypes/Entities/Objects/Specific/Robotics/borg_modules.yml @@ -1148,6 +1148,26 @@ - type: BorgModuleIcon icon: { sprite: Interface/Actions/actions_borg.rsi, state: clowning-module } +- type: entity + id: BorgModuleAdvancedClowning + parent: [ BaseBorgModuleService, BaseProviderBorgModule ] + name: advanced clowning cyborg module + description: Advanced service module for only the silliest cyborgs! Comes with a built-in oven that bakes pies automatically over time, a holopeel projector, and a push horn. + components: + - type: Sprite + layers: + - state: service + - state: icon-clown-adv + - type: ItemBorgModule + items: + - HoloprojectorClownBorg + - BorgLauncherCreamPie + - ClownRecorder + - PushHorn + - BikeHornInstrument + - type: BorgModuleIcon + icon: { sprite: Interface/Actions/actions_borg.rsi, state: adv-clowning-module } + #syndicate modules - type: entity id: BorgModuleSyndicateWeapon diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/pneumatic_cannon.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/pneumatic_cannon.yml index 750a9d3da41..b1966eb2fff 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/pneumatic_cannon.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/pneumatic_cannon.yml @@ -107,6 +107,40 @@ ents: [] - type: PacifismAllowedGun # DeltaV - Allow pacifist to use the pie cannon. +- type: entity + name: experimental pie cannon + parent: BaseWeaponBattery + id: BorgLauncherCreamPie + description: Deliver a generous portion of cream directly to the crew! Automatically bakes pies over time. + components: + - type: Sprite + sprite: Objects/Weapons/Guns/Cannons/pie_cannon.rsi + layers: + - state: piecannon + - type: Gun + fireRate: 2 + selectedMode: SemiAuto + availableModes: + - SemiAuto + - FullAuto + soundGunshot: + path: /Audio/Effects/thunk.ogg + soundEmpty: + path: /Audio/Items/hiss.ogg + clumsyProof: true + - type: ProjectileBatteryAmmoProvider + proto: FoodPieBananaCream + fireCost: 30 + - type: Battery + maxCharge: 90 + startingCharge: 90 + - type: BatterySelfRecharger + autoRecharge: true + autoRechargeRate: 1 + - type: AmmoCounter + - type: Item + size: Normal + - type: entity name: syringe gun parent: BaseStorageItem diff --git a/Resources/Prototypes/Entities/Structures/Holographic/projections.yml b/Resources/Prototypes/Entities/Structures/Holographic/projections.yml index 7e5ccb282d3..6a8c7731199 100644 --- a/Resources/Prototypes/Entities/Structures/Holographic/projections.yml +++ b/Resources/Prototypes/Entities/Structures/Holographic/projections.yml @@ -57,6 +57,44 @@ radius: 3 color: yellow +- type: entity + id: HoloPeel + parent: HolosignWetFloor + name: holopeel + description: A banana peel made of slippery hard light, watch your step! + components: + - type: Sprite + sprite: Structures/Holo/peel.rsi + state: icon + - type: Physics + bodyType: Static + canCollide: true + - type: Slippery + - type: StepTrigger + intersectRatio: 0.2 + - type: CollisionWake + enabled: false + - type: Fixtures + fixtures: + slips: + shape: + !type:PhysShapeAabb + bounds: "-0.2,-0.2,0.2,0.2" + hard: false + layer: + - SlipLayer + - type: TimedDespawn + lifetime: 30 + - type: Clickable + - type: Destructible + thresholds: + - trigger: + !type:DamageTrigger + damage: 10 + behaviors: + - !type:DoActsBehavior + acts: [ "Destruction" ] + - type: entity id: HolosignSecurity parent: HolosignWetFloor diff --git a/Resources/Prototypes/Recipes/Lathes/Packs/robotics.yml b/Resources/Prototypes/Recipes/Lathes/Packs/robotics.yml index 110ade50248..ba69fe39196 100644 --- a/Resources/Prototypes/Recipes/Lathes/Packs/robotics.yml +++ b/Resources/Prototypes/Recipes/Lathes/Packs/robotics.yml @@ -46,6 +46,7 @@ recipes: - BorgModuleAdvancedCleaning - BorgModuleAdvancedTool + - BorgModuleAdvancedClowning - BorgModuleAdvancedChemical - BorgModuleAdvancedMining diff --git a/Resources/Prototypes/Recipes/Lathes/robot_modules.yml b/Resources/Prototypes/Recipes/Lathes/robot_modules.yml index 998b6e1fc2e..b7298d46034 100644 --- a/Resources/Prototypes/Recipes/Lathes/robot_modules.yml +++ b/Resources/Prototypes/Recipes/Lathes/robot_modules.yml @@ -78,3 +78,13 @@ # Science Modules # Service Modules + +- type: latheRecipe + parent: BaseGoldBorgModuleRecipe + id: BorgModuleAdvancedClowning + result: BorgModuleAdvancedClowning + materials: + Steel: 500 + Glass: 500 + Plastic: 250 + Bananium: 375 diff --git a/Resources/Prototypes/Research/civilianservices.yml b/Resources/Prototypes/Research/civilianservices.yml index 75b4fc5301c..7db941a4b85 100644 --- a/Resources/Prototypes/Research/civilianservices.yml +++ b/Resources/Prototypes/Research/civilianservices.yml @@ -215,6 +215,7 @@ cost: 4000 recipeUnlocks: - PushHorn + - BorgModuleAdvancedClowning # Tier 3 diff --git a/Resources/Textures/Interface/Actions/actions_borg.rsi/adv-clowning-module.png b/Resources/Textures/Interface/Actions/actions_borg.rsi/adv-clowning-module.png new file mode 100644 index 0000000000000000000000000000000000000000..3f546f2adb523581c62c7f3f423cfb86b5f6d4c2 GIT binary patch literal 815 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE3?yBabR7dyjKx9jP7LeL$-D$|SkfJR9T^xl z_H+M9WCil;0(?STjg5_gOa?wl1}R;siBgs;EcI9D`!4lmS<2#m+1+H1iA1MF>!Vhd z1uUZFqOwb6CHo}#L-@Jvxy7o)1QP_A6(yOa`8n+51X5*$i{v>hMFg_d#JaVGiq&}| zl*L+=gmUG0gCs?pv_xwZ*ezta{T0}agn7Kgxjn^!*6!WHJrPK0l?3?(|0fnO7_Ima z1JuP?;1OBOz`&mX!i-fFuDw7(i4xa{lHmNblJdl&REB`W%)AmkKi3ciQ$0gH6QTRd znt^JzrABzBd3tIwZ~!^13{s4&42(dQ7Z6KB*`UzWU}Of1GXdF#j7$syKspMDGuv6f z;#oj82+VI|WOxA#bQq0hDFaYy0y_f>P^E#9u>s=(h^ZhOSr{&803;i@YSlcJjsJ3i(JJTZ;uvD#-#fXxs98b4)%0#Je^O0|baW4!bI#xY z@^733OPe;j2d3}%-f-?kuk|182f3fbKiJeWPYqaJf8)S>rhMre4Vpd-N^*^Ici1=# zj%XZ_0MdPeZ7w1WhYu*Yg@$)0{K-iuuu_{i>lnvm%Y;{649^{WlbRfB%HAk0d8@0E-&wtGg{8ok44ofy`glX(f`u%tWsIx;Y9 z?C1WI$O`1E2l#}zCNL!YFa7`j!2bhtRK99r`^%bvYPO|Dc&2%JYB6vCIjjs)jI0cdK$aH}OGDWppJ^~M zgTb$b#xJG%x_kUbvaSxbcJW86fk$r;B4qg!|iR7x|hM zcwD1PyJY|W-@98>py|P+iK*2uJU8f0kNL1t)xJY=M&qY;Hj$32Q={~af-VaCH>~G# zDfT|kdD-dAg|AJko&EhkItu5_$T<3Gc35CX$yX8aoJ7kat=yjuE?@U9U2gHXGs2?4 zhA;GnKTs~ba8vTyLrq3C+#&H%zbYqMh?V)7aBVuZVD}qRy=a||M>#5-an|>uzxoHg?-1LG0W_j z%RlS0bJwl^AGwo1AKZNPzp|P9odmYD1%GZG_$^-Ivu?BPv(HOG!QkoY=d#Wzp$Pyl C?$s>- literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Devices/Holoprojectors/peel.rsi/inhand-left.png b/Resources/Textures/Objects/Devices/Holoprojectors/peel.rsi/inhand-left.png new file mode 100644 index 0000000000000000000000000000000000000000..3124ab63b21dbb307be7a9fdfe17d9a421eceffb GIT binary patch literal 813 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?H3?#oinD`S&F%}28J29*~C-V}>VM%xNb!1@J z*w6hZkrl|-3h)VWO<+iP!SLe$z5jL$cK;9jKf`e5f9Zc^W#wOA=YIbXd0>vpj56ue z)KsAIUwPN;ffQd!kYDhBWWeBh;LZu43}=ByWHC^|VGw3Kp1&dmC@4|l8c`CQpH@cG@7Lh!0?&C&cFgxVPIrzz_nszRG&lj{ad)l*E z_ZXfO)p6Pv#I9%X?=EfoUl&jnQYBQy8nEHYUWZ%_EnCgIpZChu-`1$z{{>|Ffp1bx z#$Pj8&6j@m_dYd6@BS+5!*;rYPmS47Z21w`u;tm#a|iCR`$X?~&hY3_^~}b-zdb8I z*5FVdQ&MBb@0Gh24BLDyZ literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Devices/Holoprojectors/peel.rsi/inhand-right.png b/Resources/Textures/Objects/Devices/Holoprojectors/peel.rsi/inhand-right.png new file mode 100644 index 0000000000000000000000000000000000000000..1858c5a77937f8f6d5e55fdb625466ce99f5b540 GIT binary patch literal 821 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 F0sxQwMPC2_ literal 0 HcmV?d00001 diff --git a/Resources/Textures/Structures/Holo/peel.rsi/meta.json b/Resources/Textures/Structures/Holo/peel.rsi/meta.json new file mode 100644 index 00000000000..d6d84c40e61 --- /dev/null +++ b/Resources/Textures/Structures/Holo/peel.rsi/meta.json @@ -0,0 +1,33 @@ +{ + "version": 1, + "size": { + "x": 32, + "y": 32 + }, + "license": "CC-BY-SA-3.0", + "copyright": "Made by thatguyusa (discord) / ThatGuyUSA (github) for SS14", + "states": [ + { + "name": "icon", + "delays": [ + [ + 0.2, + 0.2, + 0.2, + 0.2, + 0.2, + 0.2, + 0.2, + 0.2, + 0.2, + 0.2, + 0.2, + 0.2, + 0.2, + 0.2, + 0.2 + ] + ] + } + ] +} From c18b495f553d33bc57dbb5ea53247807f65f61fa Mon Sep 17 00:00:00 2001 From: alexalexmax <149889301+alexalexmax@users.noreply.github.com> Date: Mon, 4 Aug 2025 15:19:20 -0400 Subject: [PATCH 025/340] Updated syndicate throwing knives description (#39374) Co-authored-by: seanpimble <149889301+seanpimble@users.noreply.github.com> --- Resources/Locale/en-US/store/uplink-catalog.ftl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Resources/Locale/en-US/store/uplink-catalog.ftl b/Resources/Locale/en-US/store/uplink-catalog.ftl index 7b7432e826e..6e846537387 100644 --- a/Resources/Locale/en-US/store/uplink-catalog.ftl +++ b/Resources/Locale/en-US/store/uplink-catalog.ftl @@ -236,7 +236,7 @@ uplink-chemistry-kit-name = Chemical Synthesis Kit uplink-chemistry-kit-desc = A starter kit for the aspiring chemist, includes two vials of vestine for all your criminal needs! uplink-knives-kit-name = Throwing Knives Kit -uplink-knives-kit-desc = A set of 4 syndicate branded throwing knives, perfect for embedding into the body of your victims. +uplink-knives-kit-desc = A set of 4 syndicate branded throwing knives, perfect for embedding into the body of your victims. Capable of ignoring armor entirely when thrown. uplink-meds-bundle-name = Interdyne Medical Bundle uplink-meds-bundle-desc = An assortment of autoinjectors and premium medical equipment to cover for every possible situation. Contains an elite compact defibrillator that can be used as a weapon. From 5f0b3a96736d685541a706420f680a9ef557fc8e Mon Sep 17 00:00:00 2001 From: ArtisticRoomba <145879011+ArtisticRoomba@users.noreply.github.com> Date: Mon, 4 Aug 2025 13:10:54 -0700 Subject: [PATCH 026/340] Revert "Fix bug with pipe color" (#39135) --- .../PipeColorVisualizerSystem.cs | 37 -------------- .../Systems/Storage/Controls/ItemGridPiece.cs | 20 +------- .../Components/AtmosPipeColorComponent.cs | 11 ++--- .../EntitySystems/AtmosPipeColorSystem.cs | 48 +++++++++++++++++++ .../Sandbox/Commands/ColorNetworkCommand.cs | 6 +-- .../SprayPainter/SprayPainterSystem.cs | 6 +-- .../EntitySystems/AtmosPipeColorSystem.cs | 36 -------------- 7 files changed, 59 insertions(+), 105 deletions(-) rename {Content.Shared/Atmos => Content.Server/Atmos/Piping}/Components/AtmosPipeColorComponent.cs (63%) create mode 100644 Content.Server/Atmos/Piping/EntitySystems/AtmosPipeColorSystem.cs delete mode 100644 Content.Shared/Atmos/EntitySystems/AtmosPipeColorSystem.cs diff --git a/Content.Client/Atmos/EntitySystems/PipeColorVisualizerSystem.cs b/Content.Client/Atmos/EntitySystems/PipeColorVisualizerSystem.cs index b23a44e403d..5595f441f76 100644 --- a/Content.Client/Atmos/EntitySystems/PipeColorVisualizerSystem.cs +++ b/Content.Client/Atmos/EntitySystems/PipeColorVisualizerSystem.cs @@ -1,46 +1,11 @@ using Content.Client.Atmos.Components; using Robust.Client.GameObjects; -using Content.Client.UserInterface.Systems.Storage.Controls; using Content.Shared.Atmos.Piping; -using Content.Shared.Hands; -using Content.Shared.Atmos.Components; -using Content.Shared.Item; namespace Content.Client.Atmos.EntitySystems; public sealed class PipeColorVisualizerSystem : VisualizerSystem { - [Dependency] private readonly SharedItemSystem _itemSystem = default!; - - public override void Initialize() - { - base.Initialize(); - - SubscribeLocalEvent(OnGetVisuals); - SubscribeLocalEvent(OnDrawInGrid); - } - - /// - /// This method is used to display the color changes of the pipe on the screen.. - /// - private void OnGetVisuals(Entity item, ref GetInhandVisualsEvent args) - { - foreach (var (_, layerData) in args.Layers) - { - if (TryComp(item.Owner, out AtmosPipeColorComponent? pipeColor)) - layerData.Color = pipeColor.Color; - } - } - - /// - /// This method is used to change the pipe's color in a container grid. - /// - private void OnDrawInGrid(Entity item, ref BeforeRenderInGridEvent args) - { - if (TryComp(item.Owner, out AtmosPipeColorComponent? pipeColor)) - args.Color = pipeColor.Color; - } - protected override void OnAppearanceChange(EntityUid uid, PipeColorVisualsComponent component, ref AppearanceChangeEvent args) { if (TryComp(uid, out var sprite) @@ -50,8 +15,6 @@ public sealed class PipeColorVisualizerSystem : VisualizerSystem Entity; } -/// -/// This event gets raised before a sprite gets drawn in a grid and lets to change the sprite color for several gameobjects that have special sprites to render in containers. -/// -public sealed class BeforeRenderInGridEvent : EntityEventArgs -{ - public Color Color { get; set; } - - public BeforeRenderInGridEvent(Color color) - { - Color = color; - } -} - public enum ItemGridPieceMarks { First, diff --git a/Content.Shared/Atmos/Components/AtmosPipeColorComponent.cs b/Content.Server/Atmos/Piping/Components/AtmosPipeColorComponent.cs similarity index 63% rename from Content.Shared/Atmos/Components/AtmosPipeColorComponent.cs rename to Content.Server/Atmos/Piping/Components/AtmosPipeColorComponent.cs index ee8e55491f3..a8edb07d318 100644 --- a/Content.Shared/Atmos/Components/AtmosPipeColorComponent.cs +++ b/Content.Server/Atmos/Piping/Components/AtmosPipeColorComponent.cs @@ -1,22 +1,19 @@ -using Content.Shared.Atmos.EntitySystems; -using Robust.Shared.GameStates; +using Content.Server.Atmos.Piping.EntitySystems; using JetBrains.Annotations; -namespace Content.Shared.Atmos.Components; +namespace Content.Server.Atmos.Piping.Components; -[RegisterComponent, NetworkedComponent] -[AutoGenerateComponentState] +[RegisterComponent] public sealed partial class AtmosPipeColorComponent : Component { [DataField] - [AutoNetworkedField] public Color Color { get; set; } = Color.White; [ViewVariables(VVAccess.ReadWrite), UsedImplicitly] public Color ColorVV { get => Color; - set => IoCManager.Resolve().System().SetColor((Owner, this), value); + set => IoCManager.Resolve().System().SetColor(Owner, this, value); } } diff --git a/Content.Server/Atmos/Piping/EntitySystems/AtmosPipeColorSystem.cs b/Content.Server/Atmos/Piping/EntitySystems/AtmosPipeColorSystem.cs new file mode 100644 index 00000000000..91f70467b42 --- /dev/null +++ b/Content.Server/Atmos/Piping/EntitySystems/AtmosPipeColorSystem.cs @@ -0,0 +1,48 @@ +using Content.Server.Atmos.Piping.Components; +using Content.Shared.Atmos.Piping; +using Robust.Server.GameObjects; + +namespace Content.Server.Atmos.Piping.EntitySystems +{ + public sealed class AtmosPipeColorSystem : EntitySystem + { + [Dependency] private readonly SharedAppearanceSystem _appearance = default!; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnStartup); + SubscribeLocalEvent(OnShutdown); + } + + private void OnStartup(EntityUid uid, AtmosPipeColorComponent component, ComponentStartup args) + { + if (!TryComp(uid, out AppearanceComponent? appearance)) + return; + + _appearance.SetData(uid, PipeColorVisuals.Color, component.Color, appearance); + } + + private void OnShutdown(EntityUid uid, AtmosPipeColorComponent component, ComponentShutdown args) + { + if (!TryComp(uid, out AppearanceComponent? appearance)) + return; + + _appearance.SetData(uid, PipeColorVisuals.Color, Color.White, appearance); + } + + public void SetColor(EntityUid uid, AtmosPipeColorComponent component, Color color) + { + component.Color = color; + + if (!TryComp(uid, out AppearanceComponent? appearance)) + return; + + _appearance.SetData(uid, PipeColorVisuals.Color, color, appearance); + + var ev = new AtmosPipeColorChangedEvent(color); + RaiseLocalEvent(uid, ref ev); + } + } +} diff --git a/Content.Server/Sandbox/Commands/ColorNetworkCommand.cs b/Content.Server/Sandbox/Commands/ColorNetworkCommand.cs index 89c1182eaef..8237ccb2eb7 100644 --- a/Content.Server/Sandbox/Commands/ColorNetworkCommand.cs +++ b/Content.Server/Sandbox/Commands/ColorNetworkCommand.cs @@ -1,6 +1,6 @@ using Content.Server.Administration.Managers; -using Content.Shared.Atmos.Components; -using Content.Shared.Atmos.EntitySystems; +using Content.Server.Atmos.Piping.Components; +using Content.Server.Atmos.Piping.EntitySystems; using Content.Shared.Administration; using Content.Shared.NodeContainer; using Content.Shared.NodeContainer.NodeGroups; @@ -78,7 +78,7 @@ namespace Content.Server.Sandbox.Commands if (!EntityManager.TryGetComponent(x.Owner, out AtmosPipeColorComponent? atmosPipeColorComponent)) continue; - _pipeColorSystem.SetColor((x.Owner, atmosPipeColorComponent), color); + _pipeColorSystem.SetColor(x.Owner, atmosPipeColorComponent, color); } } } diff --git a/Content.Server/SprayPainter/SprayPainterSystem.cs b/Content.Server/SprayPainter/SprayPainterSystem.cs index a5e08a91a6f..24ab5e0ea29 100644 --- a/Content.Server/SprayPainter/SprayPainterSystem.cs +++ b/Content.Server/SprayPainter/SprayPainterSystem.cs @@ -1,5 +1,5 @@ -using Content.Shared.Atmos.Components; -using Content.Shared.Atmos.EntitySystems; +using Content.Server.Atmos.Piping.Components; +using Content.Server.Atmos.Piping.EntitySystems; using Content.Server.Charges; using Content.Server.Decals; using Content.Server.Destructible; @@ -147,7 +147,7 @@ public sealed class SprayPainterSystem : SharedSprayPainterSystem return; Audio.PlayPvs(ent.Comp.SpraySound, ent); - _pipeColor.SetColor((target, color), args.Color); + _pipeColor.SetColor(target, color, args.Color); args.Handled = true; } diff --git a/Content.Shared/Atmos/EntitySystems/AtmosPipeColorSystem.cs b/Content.Shared/Atmos/EntitySystems/AtmosPipeColorSystem.cs deleted file mode 100644 index 548136fbfa8..00000000000 --- a/Content.Shared/Atmos/EntitySystems/AtmosPipeColorSystem.cs +++ /dev/null @@ -1,36 +0,0 @@ -using Content.Shared.Atmos.Components; -using Content.Shared.Atmos.Piping; - -namespace Content.Shared.Atmos.EntitySystems; - -public sealed class AtmosPipeColorSystem : EntitySystem -{ - - [Dependency] private readonly SharedAppearanceSystem _appearance = default!; - - public override void Initialize() - { - base.Initialize(); - - SubscribeLocalEvent(OnStartup); - SubscribeLocalEvent(OnShutdown); - } - - private void OnStartup(Entity item, ref ComponentStartup args) - { - _appearance.SetData(item.Owner, PipeColorVisuals.Color, item.Comp.Color); - } - - private void OnShutdown(Entity item, ref ComponentShutdown args) - { - _appearance.SetData(item.Owner, PipeColorVisuals.Color, Color.White); - } - - public void SetColor(Entity item, Color color) - { - item.Comp.Color = color; - _appearance.SetData(item.Owner, PipeColorVisuals.Color, color); - Dirty(item); - } -} - From 2a2815e3547b2300e839a6b097b60ce0bdb8178a Mon Sep 17 00:00:00 2001 From: Tayrtahn Date: Mon, 4 Aug 2025 17:00:19 -0400 Subject: [PATCH 027/340] Move `HeadstandComponent` to Shared (#39377) Move HeadstandComponent to Shared --- .../Administration/Components/HeadstandComponent.cs | 10 ---------- .../Administration/Systems/HeadstandSystem.cs | 2 +- .../Administration/Components/HeadstandComponent.cs | 10 ---------- .../Components/SharedHeadstandComponent.cs | 6 +++--- 4 files changed, 4 insertions(+), 24 deletions(-) delete mode 100644 Content.Client/Administration/Components/HeadstandComponent.cs delete mode 100644 Content.Server/Administration/Components/HeadstandComponent.cs diff --git a/Content.Client/Administration/Components/HeadstandComponent.cs b/Content.Client/Administration/Components/HeadstandComponent.cs deleted file mode 100644 index a4e3bfc5aaf..00000000000 --- a/Content.Client/Administration/Components/HeadstandComponent.cs +++ /dev/null @@ -1,10 +0,0 @@ -using Content.Shared.Administration.Components; -using Robust.Shared.GameStates; - -namespace Content.Client.Administration.Components; - -[RegisterComponent] -public sealed partial class HeadstandComponent : SharedHeadstandComponent -{ - -} diff --git a/Content.Client/Administration/Systems/HeadstandSystem.cs b/Content.Client/Administration/Systems/HeadstandSystem.cs index d0634e4ddd6..8ab337f3ccf 100644 --- a/Content.Client/Administration/Systems/HeadstandSystem.cs +++ b/Content.Client/Administration/Systems/HeadstandSystem.cs @@ -1,4 +1,4 @@ -using Content.Client.Administration.Components; +using Content.Shared.Administration.Components; using Robust.Client.GameObjects; namespace Content.Client.Administration.Systems; diff --git a/Content.Server/Administration/Components/HeadstandComponent.cs b/Content.Server/Administration/Components/HeadstandComponent.cs deleted file mode 100644 index 2ab097fad49..00000000000 --- a/Content.Server/Administration/Components/HeadstandComponent.cs +++ /dev/null @@ -1,10 +0,0 @@ -using Content.Shared.Administration.Components; -using Robust.Shared.GameStates; - -namespace Content.Server.Administration.Components; - -[RegisterComponent] -public sealed partial class HeadstandComponent : SharedHeadstandComponent -{ - -} diff --git a/Content.Shared/Administration/Components/SharedHeadstandComponent.cs b/Content.Shared/Administration/Components/SharedHeadstandComponent.cs index 96a4dfc2ddd..25576fc4667 100644 --- a/Content.Shared/Administration/Components/SharedHeadstandComponent.cs +++ b/Content.Shared/Administration/Components/SharedHeadstandComponent.cs @@ -3,7 +3,7 @@ namespace Content.Shared.Administration.Components; /// -/// Flips the target's sprite on it's head, so they do a headstand. +/// Flips the target's sprite on its head, so they do a headstand. /// -[NetworkedComponent] -public abstract partial class SharedHeadstandComponent : Component { } +[RegisterComponent, NetworkedComponent] +public sealed partial class HeadstandComponent : Component; From 9d9f377f7bd112b5353aa2d04d21a91294682367 Mon Sep 17 00:00:00 2001 From: Mora <46364955+TrixxedHeart@users.noreply.github.com> Date: Mon, 4 Aug 2025 15:39:40 -0800 Subject: [PATCH 028/340] Add Offset Canes + Trinket Canes Group (#39272) * Added offset cane * Added offset cane colors * Added canes to the trinkets menu * added color to names instead of suffix * removes some stripes from the mime cane icon * update file organization * standard -> standard.rsi, stop making commits at nearly 3 in the morning. * updated comment to be more explicit in what doesnt work * Cane refactor :godo: * git makes me very upset sometimes (fixed cane yaml) * wooden->wood * apparently this didnt push * Standardize comments * Removed comment * Removed comment * Adds red accents to mime cane * Indent fixes --- .../Objects/Weapons/Melee/offset_cane.yml | 85 ++++++++++++++++++ .../Loadouts/Miscellaneous/trinkets.yml | 68 ++++++++++++++ .../Prototypes/Loadouts/loadout_groups.yml | 6 ++ .../Recipes/Lathes/Packs/medical.yml | 2 + .../Prototypes/Recipes/Lathes/medical.yml | 16 ++++ .../Melee/offset_canes/clown.rsi/icon.png | Bin 0 -> 761 bytes .../offset_canes/clown.rsi/inhand-left.png | Bin 0 -> 2676 bytes .../offset_canes/clown.rsi/inhand-right.png | Bin 0 -> 356 bytes .../Melee/offset_canes/clown.rsi/meta.json | 30 +++++++ .../clown.rsi/wielded-inhand-left.png | Bin 0 -> 637 bytes .../clown.rsi/wielded-inhand-right.png | Bin 0 -> 640 bytes .../Melee/offset_canes/mime.rsi/icon.png | Bin 0 -> 711 bytes .../offset_canes/mime.rsi/inhand-left.png | Bin 0 -> 2599 bytes .../offset_canes/mime.rsi/inhand-right.png | Bin 0 -> 280 bytes .../Melee/offset_canes/mime.rsi/meta.json | 30 +++++++ .../mime.rsi/wielded-inhand-left.png | Bin 0 -> 608 bytes .../mime.rsi/wielded-inhand-right.png | Bin 0 -> 607 bytes .../offset_canes/nanotrasen.rsi/icon.png | Bin 0 -> 731 bytes .../nanotrasen.rsi/inhand-left.png | Bin 0 -> 2630 bytes .../nanotrasen.rsi/inhand-right.png | Bin 0 -> 309 bytes .../offset_canes/nanotrasen.rsi/meta.json | 30 +++++++ .../nanotrasen.rsi/wielded-inhand-left.png | Bin 0 -> 639 bytes .../nanotrasen.rsi/wielded-inhand-right.png | Bin 0 -> 637 bytes .../Melee/offset_canes/standard.rsi/icon.png | Bin 0 -> 675 bytes .../offset_canes/standard.rsi/inhand-left.png | Bin 0 -> 2601 bytes .../standard.rsi/inhand-right.png | Bin 0 -> 278 bytes .../Melee/offset_canes/standard.rsi/meta.json | 30 +++++++ .../standard.rsi/wielded-inhand-left.png | Bin 0 -> 596 bytes .../standard.rsi/wielded-inhand-right.png | Bin 0 -> 596 bytes .../Melee/offset_canes/wood.rsi/icon.png | Bin 0 -> 668 bytes .../offset_canes/wood.rsi/inhand-left.png | Bin 0 -> 2638 bytes .../offset_canes/wood.rsi/inhand-right.png | Bin 0 -> 314 bytes .../Melee/offset_canes/wood.rsi/meta.json | 30 +++++++ .../wood.rsi/wielded-inhand-left.png | Bin 0 -> 632 bytes .../wood.rsi/wielded-inhand-right.png | Bin 0 -> 632 bytes 35 files changed, 327 insertions(+) create mode 100644 Resources/Prototypes/Entities/Objects/Weapons/Melee/offset_cane.yml create mode 100644 Resources/Textures/Objects/Weapons/Melee/offset_canes/clown.rsi/icon.png create mode 100644 Resources/Textures/Objects/Weapons/Melee/offset_canes/clown.rsi/inhand-left.png create mode 100644 Resources/Textures/Objects/Weapons/Melee/offset_canes/clown.rsi/inhand-right.png create mode 100644 Resources/Textures/Objects/Weapons/Melee/offset_canes/clown.rsi/meta.json create mode 100644 Resources/Textures/Objects/Weapons/Melee/offset_canes/clown.rsi/wielded-inhand-left.png create mode 100644 Resources/Textures/Objects/Weapons/Melee/offset_canes/clown.rsi/wielded-inhand-right.png create mode 100644 Resources/Textures/Objects/Weapons/Melee/offset_canes/mime.rsi/icon.png create mode 100644 Resources/Textures/Objects/Weapons/Melee/offset_canes/mime.rsi/inhand-left.png create mode 100644 Resources/Textures/Objects/Weapons/Melee/offset_canes/mime.rsi/inhand-right.png create mode 100644 Resources/Textures/Objects/Weapons/Melee/offset_canes/mime.rsi/meta.json create mode 100644 Resources/Textures/Objects/Weapons/Melee/offset_canes/mime.rsi/wielded-inhand-left.png create mode 100644 Resources/Textures/Objects/Weapons/Melee/offset_canes/mime.rsi/wielded-inhand-right.png create mode 100644 Resources/Textures/Objects/Weapons/Melee/offset_canes/nanotrasen.rsi/icon.png create mode 100644 Resources/Textures/Objects/Weapons/Melee/offset_canes/nanotrasen.rsi/inhand-left.png create mode 100644 Resources/Textures/Objects/Weapons/Melee/offset_canes/nanotrasen.rsi/inhand-right.png create mode 100644 Resources/Textures/Objects/Weapons/Melee/offset_canes/nanotrasen.rsi/meta.json create mode 100644 Resources/Textures/Objects/Weapons/Melee/offset_canes/nanotrasen.rsi/wielded-inhand-left.png create mode 100644 Resources/Textures/Objects/Weapons/Melee/offset_canes/nanotrasen.rsi/wielded-inhand-right.png create mode 100644 Resources/Textures/Objects/Weapons/Melee/offset_canes/standard.rsi/icon.png create mode 100644 Resources/Textures/Objects/Weapons/Melee/offset_canes/standard.rsi/inhand-left.png create mode 100644 Resources/Textures/Objects/Weapons/Melee/offset_canes/standard.rsi/inhand-right.png create mode 100644 Resources/Textures/Objects/Weapons/Melee/offset_canes/standard.rsi/meta.json create mode 100644 Resources/Textures/Objects/Weapons/Melee/offset_canes/standard.rsi/wielded-inhand-left.png create mode 100644 Resources/Textures/Objects/Weapons/Melee/offset_canes/standard.rsi/wielded-inhand-right.png create mode 100644 Resources/Textures/Objects/Weapons/Melee/offset_canes/wood.rsi/icon.png create mode 100644 Resources/Textures/Objects/Weapons/Melee/offset_canes/wood.rsi/inhand-left.png create mode 100644 Resources/Textures/Objects/Weapons/Melee/offset_canes/wood.rsi/inhand-right.png create mode 100644 Resources/Textures/Objects/Weapons/Melee/offset_canes/wood.rsi/meta.json create mode 100644 Resources/Textures/Objects/Weapons/Melee/offset_canes/wood.rsi/wielded-inhand-left.png create mode 100644 Resources/Textures/Objects/Weapons/Melee/offset_canes/wood.rsi/wielded-inhand-right.png diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Melee/offset_cane.yml b/Resources/Prototypes/Entities/Objects/Weapons/Melee/offset_cane.yml new file mode 100644 index 00000000000..1d2081fe936 --- /dev/null +++ b/Resources/Prototypes/Entities/Objects/Weapons/Melee/offset_cane.yml @@ -0,0 +1,85 @@ +- type: entity + parent: BaseItem + id: OffsetCane + name: standard offset cane + description: A standard offset cane, essential for getting around when your legs aren't up to the task. May or may not grant you the wisdom of the elderly. + components: + - type: Sprite + sprite: Objects/Weapons/Melee/offset_canes/standard.rsi + state: icon + - type: Item + size: Normal + sprite: Objects/Weapons/Melee/offset_canes/standard.rsi +# - type: RandomSprite # Ideally I'd rather these be their own selectable item instead of randomly picked. +# available: +# - color: "#91949C" # standard gray +# - color: "#000000" # black +# - color: "#406BDE" # blue +# - color: "#00FFFF" # cyan +# - color: "#00FF00" # green +# - color: "#FF69B4" # pink +# - color: "#800080" # purple +# - color: "#FF0000" # red +# - color: "#FFFF00" # yellow + - type: MeleeWeapon + wideAnimationRotation: 45 + damage: + types: + Blunt: 5 + - type: StaminaDamageOnHit + damage: 5 + - type: Wieldable + - type: IncreaseDamageOnWield + damage: + types: + Blunt: 3 + - type: UseDelay + delay: 1 + +- type: entity + parent: OffsetCane + id: OffsetCaneClown + name: rainbow offset cane + description: A rainbow offset cane, perfect for clowns and those who enjoy a splash of color in their lives. + components: + - type: Sprite + sprite: Objects/Weapons/Melee/offset_canes/clown.rsi + state: icon + - type: Item + sprite: Objects/Weapons/Melee/offset_canes/clown.rsi + +- type: entity + parent: OffsetCane + id: OffsetCaneMime + name: striped offset cane + description: A black and white striped cane, perfect for silent performances. + components: + - type: Sprite + sprite: Objects/Weapons/Melee/offset_canes/mime.rsi + state: icon + - type: Item + sprite: Objects/Weapons/Melee/offset_canes/mime.rsi + +- type: entity + parent: OffsetCane + id: OffsetCaneNT + name: nanotrasen offset cane + description: A nanotrasen standard issue offset cane with the NT logo, favored by those who prefer a more corporate look. + components: + - type: Sprite + sprite: Objects/Weapons/Melee/offset_canes/nanotrasen.rsi + state: icon + - type: Item + sprite: Objects/Weapons/Melee/offset_canes/nanotrasen.rsi + +- type: entity + parent: OffsetCane + id: OffsetCaneWood + name: wooden offset cane + description: A wooden offset cane, a classic choice for those who appreciate natural materials and a sturdy grip. + components: + - type: Sprite + sprite: Objects/Weapons/Melee/offset_canes/wood.rsi + state: icon + - type: Item + sprite: Objects/Weapons/Melee/offset_canes/wood.rsi diff --git a/Resources/Prototypes/Loadouts/Miscellaneous/trinkets.yml b/Resources/Prototypes/Loadouts/Miscellaneous/trinkets.yml index 837cb49302b..acc0587e69a 100644 --- a/Resources/Prototypes/Loadouts/Miscellaneous/trinkets.yml +++ b/Resources/Prototypes/Loadouts/Miscellaneous/trinkets.yml @@ -233,6 +233,74 @@ - ClothingNeckGenderfluidPin groupBy: "pin" +# Canes +# The white cane is intentionally not included here. Thats for the blind. +- type: loadout + id: OffsetCane + storage: + back: + - OffsetCane + groupBy: "canes" + +- type: loadout + id: OffsetCaneWood + storage: + back: + - OffsetCaneWood + groupBy: "canes" + +- type: loadout + id: OffsetCaneClown + effects: + - !type:JobRequirementLoadoutEffect + requirement: + !type:RoleTimeRequirement + role: JobClown + time: 3600 # 1hr + storage: + back: + - OffsetCaneClown + groupBy: "canes" + +- type: loadout + id: OffsetCaneMime + effects: + - !type:JobRequirementLoadoutEffect + requirement: + !type:RoleTimeRequirement + role: JobMime + time: 3600 # 1hr + storage: + back: + - OffsetCaneMime + groupBy: "canes" + +- type: loadout + id: OffsetCaneNT + effects: + - !type:JobRequirementLoadoutEffect + requirement: + !type:DepartmentTimeRequirement + department: Command + time: 18000 # 5hr + storage: + back: + - OffsetCaneNT + groupBy: "canes" + +- type: loadout + id: Cane + effects: + - !type:JobRequirementLoadoutEffect + requirement: + !type:RoleTimeRequirement + role: JobLibrarian + time: 3600 # 1hr same as Jamjar. + storage: + back: + - Cane + groupBy: "canes" + # Towels - type: loadout id: TowelColorWhite diff --git a/Resources/Prototypes/Loadouts/loadout_groups.yml b/Resources/Prototypes/Loadouts/loadout_groups.yml index 93f237e2bd6..d343e588912 100644 --- a/Resources/Prototypes/Loadouts/loadout_groups.yml +++ b/Resources/Prototypes/Loadouts/loadout_groups.yml @@ -40,6 +40,12 @@ - ClothingNeckTransPin - ClothingNeckAutismPin - ClothingNeckGoldAutismPin + - OffsetCane + - OffsetCaneWood + - OffsetCaneClown + - OffsetCaneMime + - OffsetCaneNT + - Cane - TowelColorBlack - TowelColorDarkBlue - TowelColorDarkGreen diff --git a/Resources/Prototypes/Recipes/Lathes/Packs/medical.yml b/Resources/Prototypes/Recipes/Lathes/Packs/medical.yml index 84b89c85e66..7bf6794e081 100644 --- a/Resources/Prototypes/Recipes/Lathes/Packs/medical.yml +++ b/Resources/Prototypes/Recipes/Lathes/Packs/medical.yml @@ -51,6 +51,8 @@ - DiseaseSwab - BodyBag - WhiteCane + - OffsetCane + - OffsetCaneWood - type: latheRecipePack id: RollerBedsStatic diff --git a/Resources/Prototypes/Recipes/Lathes/medical.yml b/Resources/Prototypes/Recipes/Lathes/medical.yml index 2f968893b15..bd3ee3773d7 100644 --- a/Resources/Prototypes/Recipes/Lathes/medical.yml +++ b/Resources/Prototypes/Recipes/Lathes/medical.yml @@ -217,6 +217,22 @@ Steel: 100 Plastic: 100 +- type: latheRecipe + id: OffsetCane + result: OffsetCane + completetime: 2 + materials: + Steel: 100 + Plastic: 100 + +- type: latheRecipe + id: OffsetCaneWood + result: OffsetCaneWood + completetime: 2 + materials: + Steel: 100 + Wood: 100 + - type: latheRecipe id: LauncherSyringe result: LauncherSyringe diff --git a/Resources/Textures/Objects/Weapons/Melee/offset_canes/clown.rsi/icon.png b/Resources/Textures/Objects/Weapons/Melee/offset_canes/clown.rsi/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..de4d7464b37b3aa20f5b5c7386dab9a693689f5d GIT binary patch literal 761 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE3?yBabRA=0U@Xscb`J1#c2)=|%1_J8No8Qr zI6rmbUhl&W636Cm^K#XeeWUP5U}2Xtx2vPf(x%u|&e8{0c^COcDS94Ob?sXH;88$< zKKl~-4F`_Jvf-ZON{Eb?2Qavyk2w!Y93E*eTy1C1t@rbf-i*^bBX`Yyp*htm;%!3MGqsNvg?CI=ttpi& zoZOM7`)noOMX9!C86%HiF|Ab*&5YuntHe^j?bg5gMR$RdoLjuKX+hDH0JZ$4D_W&j zSG-!1ZNhuS<(>WKk}oGY_gAa%me^O`yR9K`k5Q`h{BNsIdyW|jRI%u-*|y)w(zkv> zTz>XPW`$jxb7HrdmWo^4XJV7jY1Q`CbkSb%`oL?=3-JtWc@6hO?N?v3^Lxiw**x!s z)Q#Kh$6ow@@yh(|+YF|I_b2TI#zaVfPl)RiX67qQOlO#w{`WAfWn!|jvU=OZurrlG zN=iyjPVWC(hMj8|7#h?VQe+v5lo;Y=3Rf^mt0}mfQeE*NFqF7R}5 z46*RvdigfrAq4@J3-n)*pUU`psyt-J}l za-^2#On2COTUb`X<-^U+EuxtWij9v?-gEuKw4{`6Mh??k$)hRUJGRKq;$(k#&e5L5 zn)$E6B1OT3YL*{zO|Or9W4N=-dX_kU$8Po~wXFS-clIaL?YppuL8ZLmOI~Bqd8QM-V77#iNZiy3cu%~WAf#895(mXt-p^uQjR52cweN5H?z4S&F1d1XC{=#t&3SWo zmX2rkaW&%!+rm8~acS-RmkDfTdgrUBm^=P8I{(;(zxXz9KK{rD)z=Swa(-wOdphVn zGk<*9Tll^=kCdJMbcA2`*xE^LvgGk4!Ruqm(TlFrfjx8fEppnP|6b>l?bTf`oEy#v z8%Jy-3)YTTJuudjQQw-(tlgOTxar2p(ESf^+TIIuC)?|0a@#{8|DuI|-G1)i`Bp zXm7@{Hs#lYpPl~}eU0mR=|G@=OK)Og^4Ni@2T#0HPJbkf{pRw$n{U)Tiw!;f+LP*u z3G(dVrH>CJ`^Rs?{V(13@{IEG-opeul=@#vj=p_k=;D7W&Q+Ai>O(6|HLXWK%aYKV zwgAhrf1fog`zV%u55u-BBWn7!s=jqg`D`|eBxSoVjiI+vy``xY&Ey`~Z%4bvR80KA>R(P-p>UbDNMaf58 zdGR=bi-M0>?`WhO6+euL!5$U1_B6GDo=w0b5Gz-dm3q@GA|#;BW%YPG6wOc!Lm~yKbxS&*CMB&h2gzgVp$1e@(M4Ip4J;p)le&*Ud6)^JZ$Kc8 zCh~k^Y|=Gdpg1(JqYWVe#n7~yq#2U&7<sBDu0yR0Q0vPCml3rO@Oo=D8scR)QXiS;8#)Sxl(ll2r=vQ%#p`zZX zT2xFZrrJ;zR01e!l%yIrzZU=n<1m31*AUTK)S|ee_?GD#P*f4NUIs}coU8W{#;U9! z15sejk73}lyMZlCx&)V%w9_y`x*Y(JZl}ZLaXUR>+71gGPSSK<0?^IZjXly!$_D6N8AF#0|D3~pb+1zipaZsd}=-hM?f4WV*@np0;Gcp+ey0v zI7p8@Y$I(E7Xs5f4}p`wjUuwOAad&ruG#fIo=u(KuMFQx5=BtxvEaNc+Ab^X3?#NMySe#i_#bs zFIy-fyQt_Y6@Q=jBf5r~dg@x@ke@mY`@@Hq?oXFzNj$Ku?C4G17!vFi@-s2S)IzAnHsMq>Y z;s;x@*Pf9V_jXszn0Ly$AZ8DC^zW$IUprIVIs2}|Cw@}d+fbd>mc~YAzJGA2;eZc2 X`uxvlQ#FTbjsFo`psD^~T}R*NGJ}l| literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Weapons/Melee/offset_canes/clown.rsi/inhand-right.png b/Resources/Textures/Objects/Weapons/Melee/offset_canes/clown.rsi/inhand-right.png new file mode 100644 index 0000000000000000000000000000000000000000..5cb35c758fe6ed7378e8a7376543b4b40c00a893 GIT binary patch literal 356 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!7>k44ofy`glX(f`u%tWsIx;Y9 z?C1WI$O`1k1^9%xT3K2B?_qet%>4f?14DzFl0#pyW>c7a;{X5ufl4YD8At*tu96_X zV4w&DFl;)ba~>$lS>O>_%)r2R5QG_bOw0zFz_8QP#W5tp{p~bwzQYC_tdp17-~WH; zpr|1Sv))Sc-Wj|{{N*gQBTn@%QDB`avSh)h?M+MXW}mG(tad^%Vq=>ni}bbkJCa#% z>9_FAYLMrvOkh>xy76#=df04Tx04UFukxeK>Q5?m8#!RGVht+M#vs821rCRAy{LuSs&3oi%{tmSix zcZDP7lAaPi6Yg^4g2E34Tx04UFukxeK>Q5?m8#!RGVht+M#vs821rCRAy{LuSs&3oi%{tmSix zcZDP7lAaPi6Yg^4g2E34Tx04UFuk-ba9Kp4iKwn{}S9qb_D5TS}g3q?U3rGj0mLmR=WOL9$GAxXm} zMT)E7;!to9UHlsS4|Ek=6$C*MMBLo{TBOAHnnH`{;2oFu$8&jJ?w$jJS%aBQR|+sK zm*+BRX{oR*g?Y5cM`Gdf|Vguc$c;2=ow7F`K)@GsM|- z*A~1@9AjmrNPI|~;B-LZE1|1CKMOAT{4SWwxmmiK=qZ&tSnXg|<|gqtaojYjtaTo7 zlZa+5=BWhUA8rK7dYPn1|MvND@`dxE2!(h>nYG*00wS=-W5Nq);><|0eOR-=o;AD2gd0C z=;}A^?PvnQ-;%um000SaNLh0L01m(a01m(bYSxJf0002?NklST5JiuO z3_vVuC=kOiN(S-}ED)AR104mfphHyD4riGN5lB+lz5-`~K&2{oQxjUp$y zu7hzLRh_2kuFgfT#+byEcvV%Qm@$^n(_MCI~;hi=Q053HU;E7jDu_OQh002ovPDHLkV1iOwH=qCj literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Weapons/Melee/offset_canes/mime.rsi/inhand-left.png b/Resources/Textures/Objects/Weapons/Melee/offset_canes/mime.rsi/inhand-left.png new file mode 100644 index 0000000000000000000000000000000000000000..5dc2b7a9dc992cc74fa2f3d47cf9016b6bea7927 GIT binary patch literal 2599 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 X+$?Rnck>7RSs6AyoV*MEHm`{sum z&vb9UyUA~xu4~m}qp(JsXE~k|j^D2KpUP0VXR7vsCn_4>|JnqHHrT|S6rZYGx##9H zhMhU05YreKguLzDZU0G}FK&4kc*B^pT7AaSjcfPFG2ZSyYP?~B=Z81a95)vSEM%I& qvK_*Huro`hsP)%}{Kh|`7jDVF*p;`$UQWmqWS*z1pUXO@geCx_LUuU- literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Weapons/Melee/offset_canes/nanotrasen.rsi/meta.json b/Resources/Textures/Objects/Weapons/Melee/offset_canes/nanotrasen.rsi/meta.json new file mode 100644 index 00000000000..374d6f5ef44 --- /dev/null +++ b/Resources/Textures/Objects/Weapons/Melee/offset_canes/nanotrasen.rsi/meta.json @@ -0,0 +1,30 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Sprited by TrixxedHeart", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "icon" + }, + { + "name": "inhand-left", + "directions": 4 + }, + { + "name": "wielded-inhand-left", + "directions": 4 + }, + { + "name": "inhand-right", + "directions": 4 + }, + { + "name": "wielded-inhand-right", + "directions": 4 + } + ] +} diff --git a/Resources/Textures/Objects/Weapons/Melee/offset_canes/nanotrasen.rsi/wielded-inhand-left.png b/Resources/Textures/Objects/Weapons/Melee/offset_canes/nanotrasen.rsi/wielded-inhand-left.png new file mode 100644 index 0000000000000000000000000000000000000000..2bec441eb61cc9ba4b6eb0ef5820d29b739647be GIT binary patch literal 639 zcmV-_0)YLAP)4Tx04UFukxeK>Q5?m8#!RGVht+M#vs821rCRAy{LuSs&3oi%{tmSix zcZDP7lAaPi6Yg^4g2E3}p6RyczgMBMYRIqo2F@s!R zm?+3ey=xRbg8~Ww1rz`ZC;)#GpiS`p;NA}Gh&K?Za$MYC@SlSe&k{6Glj3G)4+RvM ZnQaHYKa&u<0aO40002ovPDHLkV1mVU9ku`f literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Weapons/Melee/offset_canes/nanotrasen.rsi/wielded-inhand-right.png b/Resources/Textures/Objects/Weapons/Melee/offset_canes/nanotrasen.rsi/wielded-inhand-right.png new file mode 100644 index 0000000000000000000000000000000000000000..069f7b670c8bf27d3a6d5fa997af36f84f2dbcb2 GIT binary patch literal 637 zcmV-@0)qXCP)4Tx04UFukxeK>Q5?m8#!RGVht+M#vs821rCRAy{LuSs&3oi%{tmSix zcZDP7lAaPi6Yg^4g2E3@R~`2 z_}sgAP5HS&B#;0|AOVm-0`M~d_nZ%^%{Fm>*yAM|1f3q=NY4~>hJ;2s2%aH<1ZHL% XzUe=Uf*dlK00000NkvXXu0mjfv)UkX literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Weapons/Melee/offset_canes/standard.rsi/icon.png b/Resources/Textures/Objects/Weapons/Melee/offset_canes/standard.rsi/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..2b989d43776ebc7dc4187556a6bed8ceebdb04ce GIT binary patch literal 675 zcmV;U0$lxxP)4Tx04UFuk-ba9Kp4iKwn{}S9qb_D5TS}g3q?U3rGj0mLmR=WOL9$GAxXm} zMT)E7;!to9UHlsS4|Ek=6$C*MMBLo{TBOAHnnH`{;2oFu$8&jJ?w$jJS%aBQR|+sK zm*+BRX{oR*g?Y5cM`Gdf|Vguc$c;2=ow7F`K)@GsM|- z*A~1@9AjmrNPI|~;B-LZE1|1CKMOAT{4SWwxmmiK=qZ&tSnXg|<|gqtaojYjtaTo7 zlZa+5=BWhUA8rK7dYPn1|MvND@`dxE2!(h>nYG*00wS=-W5Nq);><|0eOR-=o;AD2gd0C z=;}A^?PvnQ-;%um001OVOjJex|Nr6P;nUO8v$L~0IyxsOC*R-S9v&XW#l?<}j?2r- z00024O78an000bhQchF<|NsC0|NsC0|Nj6I-_Fhe000SaNLh0L01mW%pslQoZ=p@@iJ8p+P4*Rl1yN3ZcY`H_ z82PTRZg(eIS(sqU&s2pESiFEL-TI2Zd2S)F} zY4jF^&FBp{&He!M`}YKRU4Yve_`QNCe*$9+%56@5q`L_qx&SO4DV?T11rq=O002ov JPDHLkV1h^-CH?>a literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Weapons/Melee/offset_canes/standard.rsi/inhand-left.png b/Resources/Textures/Objects/Weapons/Melee/offset_canes/standard.rsi/inhand-left.png new file mode 100644 index 0000000000000000000000000000000000000000..37c5475b2a5a4198d489552824098cfe788874ad GIT binary patch literal 2601 zcma)-3v3ic7{?b9c^tG-;)4<;>l%qw_I7XYz1{)s_3)O`_R^M8F|qE=&RrMocDK8G zy=%p2sU#qR3MxXhYVZj~!58w7hqhQ1P-#$O0yHIR5J-WDMC9S@_U^0*(o60!bN}x* z-+cT3W|o92?$5JKv|t#P$AwC((D!uXJ!%B{Tqiaj#;{>eh=D+u3k2}6Do4dQ#IU=+ zdHz{{==1PRiz=(jg7@S%jce=!kjp+f(`dhsKOrX6fl@=ce~0>^HCK zj7zh}?jW#f>1AK|Af~!z%BX!4dR1 zuI1AW!R3#)CVKm}ZYX+W*U$O%??U&RCuT0VRPq|O{gv-tRCo1~-){cp?1tp>o{@Oq z)44l_<>$9h!wuSuBtfR$h=J(3(ytNR45>X=#NA^P!GMU`&+!ME|y(1TG4GVve(%E>{Au zK@7F1u)3w92DHovUV)f4HP7Npvxty@I*+FlaYK^=(jOV5x6PQ=lhAe@-QBd zRfs#R4l7Lt(_#}tAPA28R3XY%mCndO(8y0T=(@sER4SFSrtDT(jZrqQ*Gth1#V{mN zkXo~(^J!Aj?i_$*Fr`ofs;KCqEa3*0kH|^gPoO-^1kpbrm_`#BzA-lGnl4Zr8aU8~ zkbq)n+C$O|$#{)D3~Vl;l$YlsB`s4!R81<)E0oPjQ;9@Qt?9w0f7ZFGTB~VRAXNo5 zIjI5|Y=V-0XLd0qp40}fmDHdyW#$?eq7+KgTrsP^pDPdN^hVWUVnQ+1hBB)XKu)71 z)wub;04NxT3ADI|h_;*-#pT3TP2Yf`im;_JNE+c>sh==bWd#|C0&D(^0Jp;f>=Du} zxNW3^hEdYv1c3CooNlkj<&Dq|nB{Pirt=bj1_zO?B7(q(hjBSQZj#|`Jn8Uwy<`MN zBV;7%5f~l_z#awJ_)1ko-sR(i^D#IA;rq)vpjHqiK~8Cz`5G|+t99NelFj9@({9G;bh%u#!{yB= zYN4tj8yYYhZM883E&z50Lh;BKVuFuBN|9n__H00fye_LXvK;plMjE&glyx@pcE-5u zEE({Ixy=A5nEivBFSCnE_!v&*CVkZP!v4dpZje(_4v=Z8>rww5lw%gFdP-L3SE`kf zc@XGBrCuv6$E`wVl%}iA+>p0_l?dN}c|(XKtIb#DRt*~mO=Zdu7jd(zSsoaVz)xs= z6BLNdBxvBJ7(_=V>YxFccojqQE)cavfj|P@i45&xoFvaXU8E3oI2anZJ#NO4jo0L; zp5j$l97ElOY=L^qv;}^5#)?H*WvT%hKBE~sNjuT8Rm0FM?PYDq)Bm^u?Se9n#KC*> z83zgK;VaAFGY%V;GfY~YRFt>~)j{)>=H>=w(XEC?sLI)k(ir6~TPPvBsOTycwm>Zp_4zASvv8tSa>yPzTB2xS!g*X)ov(g>o4XGHH03kN*Gu6E>}zck>iV_ zx6e7Ss-b;-Nx{^D&9!HwHLLY4!}nHrKEUpp)H=&D?sT1HT;n?1jFd(r}o$X~qgnP|kGt}D8sZcF>l opAWartZ%*P-nZ8F@0oXUk44ofy`glX(f`u%tWsIx;Y9 z?C1WI$O`211o(uwT3K2B|NsB~{rf-xQEm5KAax}{e!)ON1_!N`Ux0kh0*}aI1_r*v zAk26?e??C~V=Aa8>M}VKYQ|omxfK zk773dj(^$)3Lh&O_cf(CYd3se;p(VAV~^0WwU5;^uJ;A5o+AA&O@Fp`pnV6>ISihz KelF{r5}E*re_=!b literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Weapons/Melee/offset_canes/standard.rsi/meta.json b/Resources/Textures/Objects/Weapons/Melee/offset_canes/standard.rsi/meta.json new file mode 100644 index 00000000000..374d6f5ef44 --- /dev/null +++ b/Resources/Textures/Objects/Weapons/Melee/offset_canes/standard.rsi/meta.json @@ -0,0 +1,30 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Sprited by TrixxedHeart", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "icon" + }, + { + "name": "inhand-left", + "directions": 4 + }, + { + "name": "wielded-inhand-left", + "directions": 4 + }, + { + "name": "inhand-right", + "directions": 4 + }, + { + "name": "wielded-inhand-right", + "directions": 4 + } + ] +} diff --git a/Resources/Textures/Objects/Weapons/Melee/offset_canes/standard.rsi/wielded-inhand-left.png b/Resources/Textures/Objects/Weapons/Melee/offset_canes/standard.rsi/wielded-inhand-left.png new file mode 100644 index 0000000000000000000000000000000000000000..0e2843d85b15093a5c7d5dbcd699f643d169f45b GIT binary patch literal 596 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 literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Weapons/Melee/offset_canes/wood.rsi/inhand-right.png b/Resources/Textures/Objects/Weapons/Melee/offset_canes/wood.rsi/inhand-right.png new file mode 100644 index 0000000000000000000000000000000000000000..7388db8476156c1af127d287657fa04124ddc4c5 GIT binary patch literal 314 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=jKx9jP7LeL$-D$|SkfJR9T^xl z_H+M9WCij$3p^r=85sBufiR<}hF1en@VuvsV@O5Z+glsC4jBkEJPe4j`o_s}^yJ3o z2}h4!41baR%VJ-b&<;JmOV{p9{QQsKYtqtkTMvyVLO{Jh(6E0(aotq+X}5i+$Icb6 zEV2J?XkSw%HR&`{$k}SEU)oMz=j;_t^xZeNC$UxkfYLp_!=^tsv8Eg`-){JW|KjJu z-dKn^3=D>~-#Dk-W9+UzEVTH@q||DY-yAVtG&17mn%3*4Z)HunC3gDAmZU;UE#+++ zY!+-u+Q^#1^Ljbc8~(j#zC<32I( A2><{9 literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Weapons/Melee/offset_canes/wood.rsi/meta.json b/Resources/Textures/Objects/Weapons/Melee/offset_canes/wood.rsi/meta.json new file mode 100644 index 00000000000..8bfbd3140d6 --- /dev/null +++ b/Resources/Textures/Objects/Weapons/Melee/offset_canes/wood.rsi/meta.json @@ -0,0 +1,30 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Sprited by TrixxedHeart, inspiration from ps3moira#9488 on discord", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "icon" + }, + { + "name": "inhand-left", + "directions": 4 + }, + { + "name": "wielded-inhand-left", + "directions": 4 + }, + { + "name": "inhand-right", + "directions": 4 + }, + { + "name": "wielded-inhand-right", + "directions": 4 + } + ] +} diff --git a/Resources/Textures/Objects/Weapons/Melee/offset_canes/wood.rsi/wielded-inhand-left.png b/Resources/Textures/Objects/Weapons/Melee/offset_canes/wood.rsi/wielded-inhand-left.png new file mode 100644 index 0000000000000000000000000000000000000000..c7cd397457ef5c05ff1731ff8ff5959295ff143d GIT binary patch literal 632 zcmV-;0*C#HP)4Tx04UFukxeK>Q5?m8#!RGVht+M#vs821rCRAy{LuSs&3oi%{tmSix zcZDP7lAaPi6Yg^4g2E3fzrGg$0001h z@O)gl>v7Yi;b6ZFUEkVW*4Gbu&B! SL&?Vg00004Tx04UFukxeK>Q5?m8#!RGVht+M#vs821rCRAy{LuSs&3oi%{tmSix zcZDP7lAaPi6Yg^4g2E3^`$p7pwRO z000000002UoOb#D|4=?)Y98Pj^>*Ivc`uLfN)BO?UuFirdA58&ssR8fO9)r2W-~m; S_?zqi0000 Date: Tue, 5 Aug 2025 01:34:41 +0200 Subject: [PATCH 029/340] Fix vox inhand displacements (#38507) fix --- .../Species/Vox/displacement.rsi/hand_r.png | Bin 247 -> 269 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/Resources/Textures/Mobs/Species/Vox/displacement.rsi/hand_r.png b/Resources/Textures/Mobs/Species/Vox/displacement.rsi/hand_r.png index c10c6abe663553559ab44d54723430cebecf68f1..2988b27a54b7ab124077e294992ddf8ca3c472c1 100644 GIT binary patch literal 269 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=jKx9jP7LeL$-D$|SkfJR9T^xl z_H+M9WCil)db&7v{6jqih-(&k2Y=$zE~pm}r*C#OU9%^q=qF z^-ZU*SpHZ0@$M{BhO1c&tFAJHtY%yh#vHJgZ9x>T!&a#VEE1hpe#z9#-v52g_k-{4 zcd@J_pd4Y&Bz}X>%oh4w1u@?*03FQ0mm1-j=IhI#1!QvoF$i1=o(!TqUHx3vIVCg! E0AQnAfdBvi literal 247 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=jKx9jP7LeL$-D$|HhQ`^hE&XX zdvhZ%vmws`2g~OF>T!QAs~E>53K=Z$W8pTP*SR_J_bhjvec#snuTgHl{$AFXaZAH8 zhA4+%2Hgdk4PqBW9Jn*M7O Date: Mon, 4 Aug 2025 10:18:55 -0300 Subject: [PATCH 030/340] Xenoborgs part 4 (#36935) Co-authored-by: ScarKy0 <106310278+ScarKy0@users.noreply.github.com> Co-authored-by: ArtisticRoomba <145879011+ArtisticRoomba@users.noreply.github.com> Co-authored-by: Quantum-cross <7065792+Quantum-cross@users.noreply.github.com> Co-authored-by: pathetic meowmeow Co-authored-by: Southbridge <7013162+southbridge-fur@users.noreply.github.com> Co-authored-by: WarPigeon Co-authored-by: Kowlin Co-authored-by: ScarKy0 --- Resources/Audio/Machines/attributions.yml | 7 +- .../Machines/warning_buzzer_xenoborg.ogg | Bin 0 -> 63559 bytes .../Audio/Voice/Xenoborg/attributions.yml | 1 + .../Audio/Voice/Xenoborg/xenoborg_scream.ogg | Bin 0 -> 18684 bytes Resources/Locale/en-US/name-identifier.ftl | 9 + Resources/Locale/en-US/station-laws/laws.ftl | 12 +- Resources/Prototypes/Alerts/alerts.yml | 4 +- .../Prototypes/Specific/mothershipcore.yml | 20 ++ .../Mobs/Cyborgs/base_borg_chassis.yml | 8 +- .../Entities/Mobs/Cyborgs/xenoborgs.yml | 11 +- .../Entities/Mobs/Player/mothershipcore.yml | 192 +++++++++++++++++ .../Entities/Objects/Devices/pinpointer.yml | 4 +- .../Specific/Robotics/borg_modules.yml | 22 +- .../Specific/Xenoborg/cloaking_device.yml | 17 +- .../Specific/Xenoborg/material_bag.yml | 2 +- .../Recipes/Lathes/Packs/xenoborgs.yml | 16 ++ .../Prototypes/Recipes/Lathes/xenoborgs.yml | 67 ++++++ .../Prototypes/SoundCollections/emotes.yml | 5 + .../Prototypes/Voice/speech_emote_sounds.yml | 2 + .../Prototypes/name_identifier_groups.yml | 8 +- .../Actions/actions_borg.rsi/meta.json | 3 + .../actions_borg.rsi/xenoborg-eye2-module.png | Bin 0 -> 313 bytes .../Interface/Alerts/shuttle.rsi/meta.json | 14 ++ .../Alerts/{ => shuttle.rsi}/piloting.png | Bin .../mothership_core.rsi/core-active.png | Bin 0 -> 9845 bytes .../Silicon/mothership_core.rsi/core-idle.png | Bin 0 -> 1737 bytes .../Silicon/mothership_core.rsi/core-load.png | Bin 0 -> 691 bytes .../Silicon/mothership_core.rsi/core-o.png | Bin 0 -> 321 bytes .../Silicon/mothership_core.rsi/meta.json | 199 ++++++++++++++++++ .../borgmodule.rsi/icon-xenoborg-cloak2.png | Bin 0 -> 152 bytes .../Robotics/borgmodule.rsi/meta.json | 7 +- 31 files changed, 604 insertions(+), 26 deletions(-) create mode 100644 Resources/Audio/Machines/warning_buzzer_xenoborg.ogg create mode 100644 Resources/Audio/Voice/Xenoborg/xenoborg_scream.ogg create mode 100644 Resources/Locale/en-US/name-identifier.ftl create mode 100644 Resources/Prototypes/Body/Prototypes/Specific/mothershipcore.yml create mode 100644 Resources/Prototypes/Entities/Mobs/Player/mothershipcore.yml create mode 100644 Resources/Prototypes/Recipes/Lathes/Packs/xenoborgs.yml create mode 100644 Resources/Prototypes/Recipes/Lathes/xenoborgs.yml create mode 100644 Resources/Textures/Interface/Actions/actions_borg.rsi/xenoborg-eye2-module.png create mode 100644 Resources/Textures/Interface/Alerts/shuttle.rsi/meta.json rename Resources/Textures/Interface/Alerts/{ => shuttle.rsi}/piloting.png (100%) create mode 100644 Resources/Textures/Mobs/Silicon/mothership_core.rsi/core-active.png create mode 100644 Resources/Textures/Mobs/Silicon/mothership_core.rsi/core-idle.png create mode 100644 Resources/Textures/Mobs/Silicon/mothership_core.rsi/core-load.png create mode 100644 Resources/Textures/Mobs/Silicon/mothership_core.rsi/core-o.png create mode 100644 Resources/Textures/Mobs/Silicon/mothership_core.rsi/meta.json create mode 100644 Resources/Textures/Objects/Specific/Robotics/borgmodule.rsi/icon-xenoborg-cloak2.png diff --git a/Resources/Audio/Machines/attributions.yml b/Resources/Audio/Machines/attributions.yml index 215944dc291..1fe20a59d99 100644 --- a/Resources/Audio/Machines/attributions.yml +++ b/Resources/Audio/Machines/attributions.yml @@ -58,6 +58,11 @@ copyright: "Taken from TG station." source: "https://github.com/tgstation/tgstation/blob/d4f678a1772007ff8d7eddd21cf7218c8e07bfc0/sound/machines/warning-buzzer.ogg" +- files: ["warning_buzzer_xenoborg.ogg"] + license: "CC-BY-SA-3.0" + copyright: "Made by Toast (Discord)" + source: "https://github.com/space-wizards/space-station-14/pull/36935" + - files: ["anomaly_sync_connect.ogg"] license: "CC0-1.0" copyright: "Created by newagesoup, convert to ogg mono by TheShuEd" @@ -208,4 +213,4 @@ - files: ["shutter.ogg"] license: "CC-BY-3.0" copyright: "Created by Tomlija, converted to OGG and modified by themias." - source: "https://freesound.org/people/Tomlija/sounds/99565/" \ No newline at end of file + source: "https://freesound.org/people/Tomlija/sounds/99565/" diff --git a/Resources/Audio/Machines/warning_buzzer_xenoborg.ogg b/Resources/Audio/Machines/warning_buzzer_xenoborg.ogg new file mode 100644 index 0000000000000000000000000000000000000000..fad2ca222962ef9d2c278f29515596f0565d004b GIT binary patch literal 63559 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 NfeZlVKY#-O_&>{Fb7TMj literal 0 HcmV?d00001 diff --git a/Resources/Audio/Voice/Xenoborg/attributions.yml b/Resources/Audio/Voice/Xenoborg/attributions.yml index 7a08f127d3a..775cc731be4 100644 --- a/Resources/Audio/Voice/Xenoborg/attributions.yml +++ b/Resources/Audio/Voice/Xenoborg/attributions.yml @@ -10,6 +10,7 @@ - xenoborg_laugh_3.ogg - xenoborg_laugh_4.ogg - xenoborg_ping.ogg + - xenoborg_scream.ogg - xenoborg_talk.ogg - xenoborg_twobeep.ogg license: "CC-BY-SA-4.0" diff --git a/Resources/Audio/Voice/Xenoborg/xenoborg_scream.ogg b/Resources/Audio/Voice/Xenoborg/xenoborg_scream.ogg new file mode 100644 index 0000000000000000000000000000000000000000..bc83ec46ff4aa5e22f427a1f517f8b7d5231a20a GIT binary patch literal 18684 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 literal 0 HcmV?d00001 diff --git a/Resources/Textures/Mobs/Silicon/mothership_core.rsi/core-load.png b/Resources/Textures/Mobs/Silicon/mothership_core.rsi/core-load.png new file mode 100644 index 0000000000000000000000000000000000000000..138e9eebcf871bc2cbad8aa639c61efebb1f951b GIT binary patch literal 691 zcmeAS@N?(olHy`uVBq!ia0vp^2Y|SNgAGW=wxnePDaPU;cPEB*=VV?oFfiqMx;TbZ z%z1mq&|fN1;=o7t$9^fVB2GOxbW~z)T7U09_WjVq4=zCCk-#3mz3&o3T|>Tx*Z!TJk$>BK-v3Xt zX4P%}eZV*)_gCA&gbz=S-z~7X^JCVpU;kHKw_Q{9{@%Zjf3ALg>h||UdG~C^}m0u+5i8Tc?0i_ zH@rV?<@`DR=KF8|f8qz&7?C`Hmzh;{_wcH&6<@xVAB}tUpz_s%eRdn-v_mrtBy{Y5 ziFF_S^dra2dsAC`UEjBLUy8RXEB*TW@6=-dSO40-%TND%u|lZ(==U&}NA3$Y=`7Yc z-O-`ZrIcEA^ZeC&t#y-cf1Z6?qF3Ee%0H~{{qmS2o`qA4mYOs?WB&b3+26G9 zjYp!s?tDAfFTFC!LPl-&{e5}7zOU9tJD;m_`StVf+;g*Eefd#X_3i4{)Jgy1jy%5e z?bn}wS6*djB<-(uPn2J= zmBcPJvcEH5_I0ny$r-hiqz!b}z3!Q?b@2*m1=~q-$1@$Lg*|Iu@Yng;|10JX?n)|V zGs3KCu>X8@-^|td@}K1o2&L^l47AZ-->z+S{`=dP`JbM8zLMdZnDZ(Jm6iK)7C*C_ z`gQlscOT#IdPsJx&Y%BDzB%0Ttk{7WwVNEyzopr0QeV(-2eap literal 0 HcmV?d00001 diff --git a/Resources/Textures/Mobs/Silicon/mothership_core.rsi/meta.json b/Resources/Textures/Mobs/Silicon/mothership_core.rsi/meta.json new file mode 100644 index 00000000000..0f8bb695308 --- /dev/null +++ b/Resources/Textures/Mobs/Silicon/mothership_core.rsi/meta.json @@ -0,0 +1,199 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Created by Samuka", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "core-active", + "directions": 4, + "delays": [ + [ + 0.2, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1 + ], + [ + 0.2, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1 + ], + [ + 0.2, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1 + ], + [ + 0.2, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1 + ] + ] + }, + { + "name": "core-idle", + "directions": 4 + }, + { + "name": "core-o", + "directions": 4 + }, + { + "name": "core-load", + "directions": 4, + "delays": [ + [ + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1 + ], + [ + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1 + ], + [ + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1 + ], + [ + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1 + ] + ] + } + ] +} diff --git a/Resources/Textures/Objects/Specific/Robotics/borgmodule.rsi/icon-xenoborg-cloak2.png b/Resources/Textures/Objects/Specific/Robotics/borgmodule.rsi/icon-xenoborg-cloak2.png new file mode 100644 index 0000000000000000000000000000000000000000..77819e93e8d67db41790602fb1f5c525de8a982f GIT binary patch literal 152 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE3?yBabR7dyjKx9jP7LeL$-D$|cmjMvT!Hiz z28M+`K39^HKV>NS1Nkf^L4Lsu|NsBrtn1JLZHZut4v7YHk t=x}Fbd0^T&GfDWv?#2cBZU-Bf7?|`K8jf`)9|h`S@O1TaS?83{1ON%ODsun; literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Specific/Robotics/borgmodule.rsi/meta.json b/Resources/Textures/Objects/Specific/Robotics/borgmodule.rsi/meta.json index 3bf41f81ff9..ae64caaa153 100644 --- a/Resources/Textures/Objects/Specific/Robotics/borgmodule.rsi/meta.json +++ b/Resources/Textures/Objects/Specific/Robotics/borgmodule.rsi/meta.json @@ -118,6 +118,9 @@ { "name": "icon-xenoborg-cloak" }, + { + "name": "icon-xenoborg-cloak2" + }, { "name": "icon-xenoborg-fire-extinguisher" }, @@ -177,10 +180,10 @@ }, { "name": "xenoborg_engi" - }, + }, { "name": "xenoborg_generic" - }, + }, { "name": "xenoborg_heavy" }, From 71f8efa37cdb567b22b9696a40343472a026b956 Mon Sep 17 00:00:00 2001 From: Perry Fraser Date: Mon, 4 Aug 2025 23:26:02 -0400 Subject: [PATCH 031/340] fix: hide timer trigger's cycle time verb if DelayOptions is empty (#39388) fix: hide cycle time verb if DelayOptions is empty --- Content.Shared/Trigger/Systems/TriggerSystem.Timer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Content.Shared/Trigger/Systems/TriggerSystem.Timer.cs b/Content.Shared/Trigger/Systems/TriggerSystem.Timer.cs index 776b17bda61..58ac43e5719 100644 --- a/Content.Shared/Trigger/Systems/TriggerSystem.Timer.cs +++ b/Content.Shared/Trigger/Systems/TriggerSystem.Timer.cs @@ -63,7 +63,7 @@ public sealed partial class TriggerSystem if (!args.CanInteract || !args.CanAccess || args.Hands == null) return; - if (ent.Comp.DelayOptions == null || ent.Comp.DelayOptions.Count == 1) + if (ent.Comp.DelayOptions.Count <= 1) return; var user = args.User; From 583a3d5f9804acc3190f0f16d62244f1a8ccb9a9 Mon Sep 17 00:00:00 2001 From: qwerltaz <69696513+qwerltaz@users.noreply.github.com> Date: Tue, 5 Aug 2025 02:34:10 +0200 Subject: [PATCH 032/340] add: air alarm scrubber select all gases button (#39296) * add select all gases button * now make it work * localize * refactor * remove redundant Orientation Co-authored-by: Perry Fraser * remove useless HorizontalExpand Co-authored-by: Perry Fraser * add nice newline Co-authored-by: Perry Fraser * deduplicate Enum.GetValues usage --------- Co-authored-by: Perry Fraser --- .../Monitor/UI/Widgets/ScrubberControl.xaml | 8 +++++++- .../Monitor/UI/Widgets/ScrubberControl.xaml.cs | 17 ++++++++++++++++- Resources/Locale/en-US/atmos/air-alarm-ui.ftl | 2 ++ 3 files changed, 25 insertions(+), 2 deletions(-) diff --git a/Content.Client/Atmos/Monitor/UI/Widgets/ScrubberControl.xaml b/Content.Client/Atmos/Monitor/UI/Widgets/ScrubberControl.xaml index 34c1a9dd1a9..85f63731fb3 100644 --- a/Content.Client/Atmos/Monitor/UI/Widgets/ScrubberControl.xaml +++ b/Content.Client/Atmos/Monitor/UI/Widgets/ScrubberControl.xaml @@ -29,7 +29,13 @@ - + + + private List RawAdminLogs { get; set; } = new(); + private bool RenderRichText { get; set; } + private bool RemoveMarkup { get; set; } public HashSet SelectedTypes { get; } = new(); public HashSet SelectedPlayers { get; } = new(); @@ -123,6 +132,19 @@ public sealed partial class AdminLogsControl : Control private void LogSearchChanged(LineEditEventArgs args) { + // This exception is thrown if the regex is invalid, which happens often, so we ignore it. + try + { + LogSearchRegex = new Regex( + "(" + LogSearch.Text + ")", + RegexOptions.IgnoreCase, + TimeSpan.FromSeconds(1)); + } + catch (ArgumentException) + { + return; + } + UpdateLogs(); } @@ -204,6 +226,26 @@ public sealed partial class AdminLogsControl : Control UpdateLogs(); } + private void RenderRichTextChanged(ButtonEventArgs args) + { + RenderRichText = args.Button.Pressed; + + RemoveMarkup = RemoveMarkup && !RenderRichText; + RemoveMarkupButton.Pressed = RemoveMarkup; + + UpdateLogs(); + } + + private void RemoveMarkupChanged(ButtonEventArgs args) + { + RemoveMarkup = args.Button.Pressed; + + RenderRichText = !RemoveMarkup && RenderRichText; + RenderRichTextButton.Pressed = RenderRichText; + + UpdateLogs(); + } + public void SetTypesSelection(HashSet selectedTypes, bool invert = false) { SelectedTypes.Clear(); @@ -262,16 +304,15 @@ public sealed partial class AdminLogsControl : Control foreach (var child in LogsContainer.Children) { - if (child is not AdminLogLabel log) - { + if (child is not AdminLogEntry log) continue; - } child.Visible = ShouldShowLog(log); - if (child.Visible) - { - ShownLogs++; - } + if (!child.Visible) + continue; + + log.RenderResults(LogSearchRegex, RenderRichText, RemoveMarkup); + ShownLogs++; } UpdateCount(); @@ -289,30 +330,30 @@ public sealed partial class AdminLogsControl : Control button.Text.Contains(PlayerSearch.Text, StringComparison.OrdinalIgnoreCase); } - private bool LogMatchesPlayerFilter(AdminLogLabel label) + private bool LogMatchesPlayerFilter(AdminLogEntry entry) { - if (label.Log.Players.Length == 0) + if (entry.Log.Players.Length == 0) return SelectedPlayers.Count == 0 || IncludeNonPlayerLogs; - return SelectedPlayers.Overlaps(label.Log.Players); + return SelectedPlayers.Overlaps(entry.Log.Players); } - private bool ShouldShowLog(AdminLogLabel label) + private bool ShouldShowLog(AdminLogEntry entry) { // Check log type - if (!SelectedTypes.Contains(label.Log.Type)) + if (!SelectedTypes.Contains(entry.Log.Type)) return false; // Check players - if (!LogMatchesPlayerFilter(label)) + if (!LogMatchesPlayerFilter(entry)) return false; // Check impact - if (!SelectedImpacts.Contains(label.Log.Impact)) + if (!SelectedImpacts.Contains(entry.Log.Impact)) return false; // Check search - if (!label.Log.Message.Contains(LogSearch.Text, StringComparison.OrdinalIgnoreCase)) + if (!LogSearchRegex.IsMatch(entry.Log.Message)) return false; return true; @@ -386,19 +427,31 @@ public sealed partial class AdminLogsControl : Control { var log = tempLogs[i]; ref var logRef = ref log; // It didn't like me doing this as one line lmao - var separator = new HSeparator(); - var label = new AdminLogLabel(ref logRef, separator); - label.Visible = ShouldShowLog(label); + var entry = new AdminLogEntry(ref log); + + //var label = new AdminLogLabel(ref logRef, separator); + //label.Visible = ShouldShowLog(label); TotalLogs++; - if (label.Visible) ShownLogs++; + //if (label.Visible) ShownLogs++; - LogsContainer.AddChild(label); - LogsContainer.AddChild(separator); + //LogsContainer.AddChild(label); + LogsContainer.AddChild(entry); } - - UpdateCount(); + UpdateLogs(); } + + /* + var span = CollectionsMarshal.AsSpan(logs); + for (var i = 0; i < span.Length; i++) + { + ref var log = ref span[i]; + var entry = new AdminLogEntry(ref log); + TotalLogs++; + LogsContainer.AddChild(entry); + } + UpdateLogs(); + */ // END DEN - Admin Log Sorting private void ImpactButtonPressed(ButtonEventArgs args) @@ -583,6 +636,7 @@ public sealed partial class AdminLogsControl : Control SelectAllTypesButton.OnPressed -= SelectAllTypes; SelectNoTypesButton.OnPressed -= SelectNoTypes; + IncludeNonPlayersButton.OnPressed -= IncludeNonPlayers; IncludeNonPlayersButton.OnPressed -= IncludeNonPlayers; SelectAllPlayersButton.OnPressed -= SelectAllPlayers; SelectNoPlayersButton.OnPressed -= SelectNoPlayers; diff --git a/Content.Client/Administration/UI/Logs/AdminLogsEui.cs b/Content.Client/Administration/UI/Logs/AdminLogsEui.cs index be1bddcd370..014b58651e7 100644 --- a/Content.Client/Administration/UI/Logs/AdminLogsEui.cs +++ b/Content.Client/Administration/UI/Logs/AdminLogsEui.cs @@ -1,4 +1,6 @@ -using System.Linq; +using System.IO; +using System.Linq; +using Content.Client.Administration.UI.Logs.Entries; using Content.Client.Eui; using Content.Shared.Administration.Logs; using Content.Shared.Eui; diff --git a/Content.Client/Administration/UI/Logs/Entries/AdminLogEntry.xaml b/Content.Client/Administration/UI/Logs/Entries/AdminLogEntry.xaml new file mode 100644 index 00000000000..7733c2b1cba --- /dev/null +++ b/Content.Client/Administration/UI/Logs/Entries/AdminLogEntry.xaml @@ -0,0 +1,14 @@ + + + + + + + + + + + diff --git a/Content.Client/Administration/UI/Logs/Entries/AdminLogEntry.xaml.cs b/Content.Client/Administration/UI/Logs/Entries/AdminLogEntry.xaml.cs new file mode 100644 index 00000000000..fc9f960b661 --- /dev/null +++ b/Content.Client/Administration/UI/Logs/Entries/AdminLogEntry.xaml.cs @@ -0,0 +1,79 @@ +using System.Text.RegularExpressions; +using Content.Client.Message; +using Content.Shared.Administration.Logs; +using Content.Shared.CCVar; +using Robust.Client.AutoGenerated; +using Robust.Client.UserInterface.Controls; +using Robust.Client.UserInterface.XAML; +using Robust.Shared.Configuration; +using Robust.Shared.Utility; + +namespace Content.Client.Administration.UI.Logs.Entries; + +[GenerateTypedNameReferences] +public sealed partial class AdminLogEntry : BoxContainer +{ + private readonly IConfigurationManager _cfgManager; + + public SharedAdminLog Log { get; } + + private readonly string _rawMessage; + + public AdminLogEntry(ref SharedAdminLog log) + { + _cfgManager = IoCManager.Resolve(); + + RobustXamlLoader.Load(this); + + Log = log; + + _rawMessage = $"{log.Date:HH:mm:ss}: {log.Message}"; + Message.SetMessage(_rawMessage); + + DetailsHeading.OnToggled += DetailsToggled; + } + + /// + /// Sets text to be highlighted from a search result, and renders rich text, or removes all rich text markup. + /// + public void RenderResults(Regex highlightRegex, bool renderRichText, bool removeMarkup) + { + var color = _cfgManager.GetCVar(CCVars.AdminLogsHighlightColor); + var formattedMessage = renderRichText + ? _rawMessage + : removeMarkup + ? FormattedMessage.RemoveMarkupPermissive(_rawMessage) + : FormattedMessage.EscapeText(_rawMessage); + + // Want to avoid highlighting smaller strings + if (highlightRegex.ToString().Length > 4) + { + try + { + formattedMessage = highlightRegex.Replace(formattedMessage, $"[color={color}]$1[/color]", 3); + } + catch (RegexMatchTimeoutException) + { + // if we time out then don't bother highlighting results + } + } + + if (!FormattedMessage.TryFromMarkup(formattedMessage, out var outputMessage)) + return; + + Message.SetMessage(outputMessage); + } + + /// + /// We perform some extra calculations in the dropdown, so we want to render that only when + /// the dropdown is actually opened. + /// This also removes itself from the event listener so it doesn't trigger again. + /// + private void DetailsToggled(BaseButton.ButtonToggledEventArgs args) + { + if (!args.Pressed || DetailsBody.ChildCount > 0) + return; + DetailsBody.AddChild(new AdminLogEntryDetails(Log)); + DetailsHeading.OnToggled -= DetailsToggled; + } +} diff --git a/Content.Client/Administration/UI/Logs/Entries/AdminLogEntryDetails.xaml b/Content.Client/Administration/UI/Logs/Entries/AdminLogEntryDetails.xaml new file mode 100644 index 00000000000..23391046b9b --- /dev/null +++ b/Content.Client/Administration/UI/Logs/Entries/AdminLogEntryDetails.xaml @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + diff --git a/Content.Client/Administration/UI/Logs/Entries/AdminLogEntryDetails.xaml.cs b/Content.Client/Administration/UI/Logs/Entries/AdminLogEntryDetails.xaml.cs new file mode 100644 index 00000000000..611626e544a --- /dev/null +++ b/Content.Client/Administration/UI/Logs/Entries/AdminLogEntryDetails.xaml.cs @@ -0,0 +1,98 @@ +using System.Linq; +using Content.Client.Administration.Systems; +using Content.Client.Administration.UI.CustomControls; +using Content.Client.UserInterface.Controls; +using Content.Client.Verbs.UI; +using Content.Shared.Administration.Logs; +using Robust.Client.AutoGenerated; +using Robust.Client.UserInterface; +using Robust.Client.UserInterface.Controls; +using Robust.Client.UserInterface.XAML; +using Robust.Shared.Input; +using Robust.Shared.Network; + +namespace Content.Client.Administration.UI.Logs.Entries; + +[GenerateTypedNameReferences] +public sealed partial class AdminLogEntryDetails : BoxContainer +{ + private readonly AdminSystem _adminSystem; + private readonly IUserInterfaceManager _uiManager; + private readonly IEntityManager _entManager; + + public AdminLogEntryDetails(SharedAdminLog log) + { + RobustXamlLoader.Load(this); + _entManager = IoCManager.Resolve(); + _uiManager = IoCManager.Resolve(); + _adminSystem = _entManager.System(); + + Type.Text = log.Type.ToString(); + Impact.Text = log.Impact.ToString(); + + LocalTime.Text = $"{log.Date.ToLocalTime():HH:mm:ss}"; + UTCTime.Text = $"{log.Date:HH:mm:ss}"; + // TimeSpan and DateTime use different formatting string conventions for some completely logical reason + // that mere mortals such as myself will never be able to understand. + CurTime.Text = new TimeSpan(log.CurTime).ToString(@"hh\:mm\:ss"); + + PlayerListContainer.ItemKeyBindDown += PlayerListItemKeyBindDown; + PlayerListContainer.GenerateItem += GenerateButton; + PopulateList(log.Players); + } + + private void PopulateList(Guid[] players) + { + if (players.Length == 0) + return; + + if (_adminSystem.PlayerList is not { } allPlayers || allPlayers.Count == 0) + return; + + var listData = new List(); + foreach (var playerGuid in players) + { + var netUserId = new NetUserId(playerGuid); + + // Linq here is fine since this runs in response to admin input in the UI and + // this loop only tends to go through 1-4 iterations. + if (allPlayers.FirstOrDefault(player => player.SessionId == netUserId) is not { } playerInfo) + continue; + + listData.Add(new PlayerListData(playerInfo)); + } + + if (listData.Count == 0) + return; + + PlayerListContainer.PopulateList(listData); + } + + private void PlayerListItemKeyBindDown(GUIBoundKeyEventArgs? args, ListData? data) + { + if (args == null || data is not PlayerListData { Info: var selectedPlayer }) + return; + + if (!(args.Function == EngineKeyFunctions.UIRightClick + || args.Function == EngineKeyFunctions.UIClick) + || selectedPlayer.NetEntity == null) + return; + + _uiManager.GetUIController().OpenVerbMenu(selectedPlayer.NetEntity.Value, true); + args.Handle(); + } + + private void GenerateButton(ListData data, ListContainerButton button) + { + if (data is not PlayerListData { Info: var info }) + return; + + var entryLabel = new Label(); + entryLabel.Text = $"{info.CharacterName} ({info.Username})"; + var entry = new BoxContainer(); + entry.AddChild(entryLabel); + + button.AddChild(entry); + button.AddStyleClass(ListContainer.StyleClassListContainerButton); + } +} diff --git a/Content.Client/Administration/UI/Tabs/PlayerTab/PlayerTab.xaml.cs b/Content.Client/Administration/UI/Tabs/PlayerTab/PlayerTab.xaml.cs index 5a75e7223f4..d32d481c74b 100644 --- a/Content.Client/Administration/UI/Tabs/PlayerTab/PlayerTab.xaml.cs +++ b/Content.Client/Administration/UI/Tabs/PlayerTab/PlayerTab.xaml.cs @@ -52,7 +52,6 @@ public sealed partial class PlayerTab : Control _config.OnValueChanged(CCVars.AdminPlayerTabColorSetting, ColorSettingChanged, true); _config.OnValueChanged(CCVars.AdminPlayerTabSymbolSetting, SymbolSettingChanged, true); - OverlayButton.OnPressed += OverlayButtonPressed; ShowDisconnectedButton.OnPressed += ShowDisconnectedPressed; @@ -65,7 +64,6 @@ public sealed partial class PlayerTab : Control SearchList.ItemKeyBindDown += (args, data) => OnEntryKeyBindDown?.Invoke(args, data); RefreshPlayerList(_adminSystem.PlayerList); - } #region Antag Overlay diff --git a/Content.Client/Options/UI/Tabs/AdminOptionsTab.xaml b/Content.Client/Options/UI/Tabs/AdminOptionsTab.xaml index ca22d7206b6..0fa5ee1754e 100644 --- a/Content.Client/Options/UI/Tabs/AdminOptionsTab.xaml +++ b/Content.Client/Options/UI/Tabs/AdminOptionsTab.xaml @@ -9,6 +9,9 @@ + Instrument = 103, - - /// - /// For anything relating to bug reports. - /// - BugReport = 104, } diff --git a/Content.Shared/BugReport/BugReportMessage.cs b/Content.Shared/BugReport/BugReportMessage.cs deleted file mode 100644 index 46976eda6e5..00000000000 --- a/Content.Shared/BugReport/BugReportMessage.cs +++ /dev/null @@ -1,42 +0,0 @@ -using Lidgren.Network; -using Robust.Shared.Network; -using Robust.Shared.Serialization; - -namespace Content.Shared.BugReport; - -/// -/// Message with bug report data, which should be handled by server and used to create issue on issue tracker -/// (or some other notification). -/// -public sealed class BugReportMessage : NetMessage -{ - public override MsgGroups MsgGroup => MsgGroups.Command; - - public PlayerBugReportInformation ReportInformation = new(); - - public override void ReadFromBuffer(NetIncomingMessage buffer, IRobustSerializer serializer) - { - ReportInformation.BugReportTitle = buffer.ReadString(); - ReportInformation.BugReportDescription = buffer.ReadString(); - } - - public override void WriteToBuffer(NetOutgoingMessage buffer, IRobustSerializer serializer) - { - buffer.Write(ReportInformation.BugReportTitle); - buffer.Write(ReportInformation.BugReportDescription); - } - - public override NetDeliveryMethod DeliveryMethod => NetDeliveryMethod.ReliableUnordered; -} - -/// -/// Stores user specified information from a bug report. -/// -/// -/// Clients can put whatever they want here so be careful! -/// -public sealed class PlayerBugReportInformation -{ - public string BugReportTitle = string.Empty; - public string BugReportDescription = string.Empty; -} diff --git a/Content.Shared/CCVar/CCVars.BugReports.cs b/Content.Shared/CCVar/CCVars.BugReports.cs deleted file mode 100644 index 789ffc9a48d..00000000000 --- a/Content.Shared/CCVar/CCVars.BugReports.cs +++ /dev/null @@ -1,64 +0,0 @@ -using Robust.Shared.Configuration; - -namespace Content.Shared.CCVar; - -public sealed partial class CCVars -{ - /// - /// Allow users to submit bug reports. Will enable a button on the hotbar. See for - /// setting up the GitHub API! - /// - public static readonly CVarDef EnablePlayerBugReports = - CVarDef.Create("bug_reports.enable_player_bug_reports", false, CVar.SERVER | CVar.REPLICATED); - - /// - /// Minimum playtime that players need to have played to submit bug reports. - /// - public static readonly CVarDef MinimumPlaytimeInMinutesToEnableBugReports = - CVarDef.Create("bug_reports.minimum_playtime_in_minutes_to_enable_bug_reports", 120, CVar.SERVER | CVar.REPLICATED); - - /// - /// Maximum number of bug reports a user can submit per round. - /// - public static readonly CVarDef MaximumBugReportsPerRound = - CVarDef.Create("bug_reports.maximum_bug_reports_per_round", 5, CVar.SERVER | CVar.REPLICATED); - - /// - /// Minimum time between bug reports. - /// - public static readonly CVarDef MinimumSecondsBetweenBugReports = - CVarDef.Create("bug_reports.minimum_seconds_between_bug_reports", 120, CVar.SERVER | CVar.REPLICATED); - - /// - /// Maximum length of a bug report title. - /// - public static readonly CVarDef MaximumBugReportTitleLength = - CVarDef.Create("bug_reports.maximum_bug_report_title_length", 35, CVar.SERVER | CVar.REPLICATED); - - /// - /// Minimum length of a bug report title. - /// - public static readonly CVarDef MinimumBugReportTitleLength = - CVarDef.Create("bug_reports.minimum_bug_report_title_length", 10, CVar.SERVER | CVar.REPLICATED); - - /// - /// Maximum length of a bug report description. - /// - public static readonly CVarDef MaximumBugReportDescriptionLength = - CVarDef.Create("bug_reports.maximum_bug_report_description_length", 750, CVar.SERVER | CVar.REPLICATED); - - /// - /// Minimum length of a bug report description. - /// - public static readonly CVarDef MinimumBugReportDescriptionLength = - CVarDef.Create("bug_reports.minimum_bug_report_description_length", 10, CVar.SERVER | CVar.REPLICATED); - - /// - /// List of tags that are added to the report. Separate each value with ",". - /// - /// - /// IG report, Bug - /// - public static readonly CVarDef BugReportTags = - CVarDef.Create("bug_reports.tags", "IG bug report", CVar.SERVER | CVar.REPLICATED); -} diff --git a/Content.Shared/CCVar/CCVars.Github.cs b/Content.Shared/CCVar/CCVars.Github.cs deleted file mode 100644 index 77c1ffc2fe4..00000000000 --- a/Content.Shared/CCVar/CCVars.Github.cs +++ /dev/null @@ -1,71 +0,0 @@ -using Robust.Shared.Configuration; - -namespace Content.Shared.CCVar; - -public sealed partial class CCVars -{ - /// - /// Marker, for if the GitHub api is enabled. If it is not enabled, any actions that require GitHub API will be ignored. - /// To fully set up the API, you also need to set , , - /// and . - /// - public static readonly CVarDef GithubEnabled = - CVarDef.Create("github.github_enabled", true, CVar.SERVERONLY); - - /// - /// GitHub app private keys location. PLEASE READ THIS CAREFULLY!! - /// - /// - /// Its highly recommend to create a new (private) repository specifically for this app. This will help avoid - /// moderation issues and also allow you to ignore duplicate or useless issues. You can just transfer legitimate - /// issues from the private repository to the main public one. - /// - /// - /// Only create the auth token with the MINIMUM required access (Specifically only give it access to one - /// repository - and the minimum required access for your use case). - ///

If this token is only for forwarding issues then you should only need to grant read and write - /// permission to "Issues" and read only permissions to "Metadata". - ///
- ///
- /// Also remember to use the testgithubapi command to test if you set everything up correctly. - /// [Insert YouTube video link with walkthrough here] - ///
- /// - /// (If your on linux): /home/beck/key.pem - /// - public static readonly CVarDef GithubAppPrivateKeyPath = - CVarDef.Create("github.github_app_private_key_path", "", CVar.SERVERONLY | CVar.CONFIDENTIAL); - - /// - /// The GitHub apps app id. Go to https://github.com/settings/apps/APPNAME to find the app id. - /// - /// - /// 1009555 - /// - public static readonly CVarDef GithubAppId = - CVarDef.Create("github.github_app_id", "", CVar.SERVERONLY | CVar.CONFIDENTIAL); - - /// - /// Name of the targeted GitHub repository. - /// - /// - /// If your URL was https://github.com/space-wizards/space-station-14 the repo name would be "space-station-14". - /// > - public static readonly CVarDef GithubRepositoryName = - CVarDef.Create("github.github_repository_name", string.Empty, CVar.SERVERONLY | CVar.CONFIDENTIAL); - - /// - /// Owner of the GitHub repository. - /// - /// - /// If your URL was https://github.com/space-wizards/space-station-14 the owner would be "space-wizards". - /// - public static readonly CVarDef GithubRepositoryOwner = - CVarDef.Create("github.github_repository_owner", string.Empty, CVar.SERVERONLY | CVar.CONFIDENTIAL); - - /// - /// The maximum number of times the api will retry requests before giving up. - /// - public static readonly CVarDef GithubMaxRetries = - CVarDef.Create("github.github_max_retries", 3, CVar.SERVERONLY | CVar.CONFIDENTIAL); -} diff --git a/Resources/Locale/en-US/HUD/game-hud.ftl b/Resources/Locale/en-US/HUD/game-hud.ftl index d88403a6afd..ea423f080ab 100644 --- a/Resources/Locale/en-US/HUD/game-hud.ftl +++ b/Resources/Locale/en-US/HUD/game-hud.ftl @@ -7,4 +7,3 @@ game-hud-open-crafting-menu-button-tooltip = Open crafting menu. game-hud-open-actions-menu-button-tooltip = Open actions menu. game-hud-open-admin-menu-button-tooltip = Open admin menu. game-hud-open-sandbox-menu-button-tooltip = Open sandbox menu. -game-hud-open-bug-report-window-button-tooltip = Open bug report menu. diff --git a/Resources/Locale/en-US/bugreport/bug-report-report.ftl b/Resources/Locale/en-US/bugreport/bug-report-report.ftl deleted file mode 100644 index c6296c520f0..00000000000 --- a/Resources/Locale/en-US/bugreport/bug-report-report.ftl +++ /dev/null @@ -1 +0,0 @@ -bug-report-report-unknown = unknown diff --git a/Resources/Locale/en-US/bugreport/bug-report-window.ftl b/Resources/Locale/en-US/bugreport/bug-report-window.ftl deleted file mode 100644 index 794014ca98c..00000000000 --- a/Resources/Locale/en-US/bugreport/bug-report-window.ftl +++ /dev/null @@ -1,13 +0,0 @@ -bug-report-window-name = Create bug report -bug-report-window-explanation = Try to be as detailed as possible. If you have recreation steps, list them! -bug-report-window-disabled-not-enabled = Bug reports are currently disabled! -bug-report-window-disabled-playtime = You do not have enough playtime to submit a bug report! -bug-report-window-disabled-cooldown = You can submit a new bug report in {$time}. -bug-report-window-disabled-submissions = You have reached the maximum number of bug reports ({$num}) for this round. -bug-report-window-title-place-holder = Bug report title -bug-report-window-description-place-holder = Type bug report here -bug-report-window-submit-button-text = Submit -bug-report-window-submit-button-confirm-text = Click again to submit! -bug-report-window-submit-button-disclaimer = Your SS14 username and other in game information will be saved. - -bug-report-window-submit-char-split = {$typed}/{$total} diff --git a/Resources/Locale/en-US/github/github-api.ftl b/Resources/Locale/en-US/github/github-api.ftl deleted file mode 100644 index c439503b602..00000000000 --- a/Resources/Locale/en-US/github/github-api.ftl +++ /dev/null @@ -1,36 +0,0 @@ -github-command-test-name = testgithubapi - -cmd-testgithubapi-desc = This command makes an issue request to the github api. Remember to check the servers console for errors. -cmd-testgithubapi-help = Usage: testgithubapi - -github-command-not-enabled = The api is not enabled! -github-command-no-path = The key path is empty! -github-command-no-app-id = The app id is empty! -github-command-no-repo-name = The repository name is empty! -github-command-no-owner = The repository owner is empty! - -github-command-issue-title-one = This is a test issue! -github-command-issue-description-one = This is the description of the first issue. :) - -github-command-finish = Check your repository for a newly created issue. If you don't see any, check the server console for errors! - -github-issue-format = ## Description: - {$description} - - ## Meta Data: - Build version: {$buildVersion} - Engine version: {$engineVersion} - - Server name: {$serverName} - Submitted time: {$submittedTime} - - -- Round information -- - Round number: {$roundNumber} - Round time: {$roundTime} - Round type: {$roundType} - Map: {$map} - Number of players: {$numberOfPlayers} - - -- Submitter information -- - Player name: {$username} - Player GUID: {$playerGUID} diff --git a/Resources/Textures/Interface/bug.svg b/Resources/Textures/Interface/bug.svg deleted file mode 100644 index f79bfe3e04d..00000000000 --- a/Resources/Textures/Interface/bug.svg +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - diff --git a/Resources/Textures/Interface/bug.svg.192dpi.png b/Resources/Textures/Interface/bug.svg.192dpi.png deleted file mode 100644 index d901996bd6ba1130b25e69c088893dbaa16199e0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1852 zcmV-C2gCS@P)EX>4Tx04R}tkv&MmKpe$iQ>8^J4rUN>$WWauh>AFB6^c+H)C#RSm|Xe=O$fqw6tAnc`2!4RL3r>nIQsV!TLW>v=j{EWM-sA2aAT+8>x4Xsw-Egc- zDkN7|Tmsr#XZa7O)5z5>(VsK@|=Xv>K$?$k2W=z(45uWpb(Hs(_JW z9vjf1cz*Cd_}#5toEZ0$Vo9L;#dSZ1fyge4ux=P;w2Zz8& ziL%!M-W~1i?cX!4{(b<}^>Sz{?N6})000JJOGiWi{{a600FA#$9smFU32;bRa{vGx zhX4Q_hXIe}@nrx200(qQO+^Rk0u%=cBQDOb`~Uz2I!Q!9RCwC$n{Q}Ubr{FLzqRI; zfA(SpsYU+7W|Si%Qev?%XO<9V5e7x{a){2dmr=cnO0(WX80Csy)Iv-lA`KkE`a@9| zlxQt&mb2Pg>2Pi8KE3c6-F}>N&%O7YbMIO13m5jg_nhbV{e92x&+|OznKX$>Od>9T z7N7%o45&-7pE~QK18B+0;O77%{EHr7bqf8gHrwME0p?^ufK>!z4=^tQ`}53J5LRVD zfT_UY5Q1lbr+`|Z3TOtl0A0XIU>Fzz4gvdtXMiPUx7O}G6Jq-?Ff}X7pdNS$I2%It zH{fRqN3RJKgtOLHeHJ&v#lQj5!vSD%)=vZnJOuoa;J^pWrc0V{Rni8Xb4co!bXma9 zBa+^hbf2U-lIkQ)lhi2bK}nsGMg#7fCaKqKXWl1R2%HLdihF^p3b=nhush)X-+{Rk zL4f@p@iB8=T#c z+yva5#B>D~c&;|UjTc+6)#(ZFbY_pil(5@tH)l=&;BIqwkEal%eCf4kC+4?A45~`f zMoCSQ_Db66oEr(b_PC_+bAC|Lc1g1&)yCxbw>egua=tt5oSPBCV~V7;l3FDll=QN5 zZmiU&+U~8reqbxm=v`Ms`BCF>Xf$s9-gWJ9ruB}H&c`gIT?5NqSh)H> z!*Nh6X{MxGC9SXkDhmCQ-jei+bFL?;U49C%&V2o`kVM56pdm$npaFO>B=It4+}7Df zm>P*1JL+=rC$OT7j!~=inTwzNjWMmxHwHZU)(UusD}i$!mks6U_=wl()(X1F+x$dn z+8r(m$oe)^P=JPjtZ`$SuJCfNz0Wx}P$>bd?~fxmCMtlR((2AYpyYG7I!ys)dhNap z2+$Y7F;M~P0s@svV>p82{~{ld8ZLSPszc)cTSCNHHUY-84Co9AoIcN+9|(y5qtKRt zd|_LWoZIs)fu@+pVkJ;4ho*c2ys6-Kb7A-{#*Ot6(z-R7_~75?*Y!aE^{T9 zgzN#EynSFK2Ju%dXE^?Msk6!F@TsJ2A$!1A&bgzZ0+Elvi3;$m*UrN0YM;Z&GzB=~wXe^B05?Q%O!UmX&O1~8 z0;)^2^&gaI<5J+XXX@HC1#m#0*I{b~1-Q#Ib0XDPz-n|p@VgRw3<(>gni{vLoo68}90}gr}@2r3Tej(M@WvL$mW&!U81R3|1O90^hfd1bBW~DXg zDl3ZKm8Tqbu$ZM#ssJ|i2lJHC?lP`bNe%pQ;8=m7<`2M?X$b&a;g!ti!!hGt6-R)m z{J>C%2=h}C;DrJ?6kHz=rA}CW;2TNnEr{vxew#1p3t&wOtIRnR}ydR?e&ai!<#2Ii6@U6WG?(n@(V5xB&%K5L7mbm-CT=Tf<^ITJ% zr<&xPof>!M5)Ko<_MQ3&PBjs~*Bj^Z1#9LXYzQc7%*83-L*V&<-=4Gg`{TZSXCga! z1(K9aKzBlQK(}im!e+w*0Ul$qSfYsx6QUW|4xA`r;3t61<>2VbEXX1|mKN&5OU&uI qP-Qk?pYJ7o=A7%*BqlM5a^N4Qe+CTN2#ARQ0000 - - - - - - - - - - - - - diff --git a/Resources/Textures/Interface/splat.svg.192dpi.png b/Resources/Textures/Interface/splat.svg.192dpi.png deleted file mode 100644 index 9540031f0445426f6148d774edb4906bb4cc9810..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2069 zcmV+w2EX>4Tx04R}tkv&MmKpe$iQ?()$hjtKA$WWau6u)rPDionYsTEpvFuC+YXws0R zxHt-~1qVMCs}3&Cx;nTDg5U>;yWphgA|?JWDYS_3;J6>}?mh0_0YbgZRI?)nsG4P@ z6LB${TM+}V=)w>}m_$rsraqfWCE+=~?&0I>U6f~epZjz4DtVIuK9P8a>4rtTPCT_~ z>74h8!>lAJ#OK7L23?T&k?XR{Z=8z`3p_JyWYTlQVPdh^#&R38lA#h$5JwbMqkJLj zvch?bvs$jQ<~{ifgL!RviR&~6k-!2Lk%9;rRcxRP3sG7%QcR?2KknflaQrE9$>iDq zBgZ@{P$4;f@IUz7tyvf!bCZH`p!3DHKZb$8F3_mi_V=-EH%pV2qvfY2?_v+DNN+{ftykfE-UH^9Lm zFjA!KHIH|9xA*q%nPz`K`UP^`_=WEk00006VoOIv03HAy03zi}T>=0A010qNS#tmY z9ftq_9ftvr{DWHV|581~32s1`dy~sld|l&_ndoA@4ZDQxgYkPo&V0v?wOsP*(3eO$>f3% zK!K!UNqr?9m9*a&(|AE!9vB5Y1MC2rIiL0etAHs${)MFYFkpRv(m}Kfxa&eteim?& z)M-7?wLL0sfEC0;JAjgQKF(x;NDBpsC0LsF@v$&zl9ROsQ`E@?u$ zaFoDJ0q^@JU}O^BB4Bv{|C;uod;##2NBEbccy?eaaNL7)U9KBox<}}D0FwgN-JX^3 zZ7NuqG{9Gmzz2bzY2dB)7<62&DqjSga)e!&CgwoTHo7=h4KT$sTO(q?{oKKQUo<3)Q(J{#Rp@Vx2D2&4ZZ+nDpvS;{-z!2a{;5pz(3PyS( z1{nu5}+!A@>}h0lCGSKJlNOAVSvRR;E73idIBFLQTz* z#uGsAII#01^>Y5J%fZ8CU#Gp>7*ijY0bGR#g;08P*0tB?=O2mVRX2=&0# zVVur=!26cLrK%iojD3K)z&ADwk3t84fnf*g3cT(CDO8S-T@{0DQfCNI0`#`+1p$+| zA<6)ccmRsjP6!z6N%%AaW5Y1dwug__RIPSKz&KCdF9c-%0M~l=B$+L}CChEL8 zK>5maDlu6$K)IXw3hH=IfbyGxVzpDU!O%H*&jQ~TC~1j@|3yhp8e>jpN%+2!MoKD@ z)F^4EF(ztJWU$k&@eMT1GxIC5IBOGuEjIn`E6zL^qDs}WRsQVoZ}fF^lbsFO*z&9s zUKuj5sYn*$dftD4GGE8PoldK=puDkBXcTG!o^p@JcIM}LR?y+|Ce}t!F5R0213Z?- zfoG3R_0I&J_bmGsD)$Y1g{R}#3@hI&Aas4p7I8WQLxH6MSLedeCtkl{9ga(-88*PI zuz{B~L`4e9_Xrw%yoX_Uh7GX6v!wGA^e?b=gSrrv?DB*=2GHNbI4Q#hsC34EHNvYi z+g`z~woY-cO`wzkeZqhgc;2gJac^%)p1W6Tm$s$B&sh#O%5!Uj(`HILUhPTKXLJer?)T0~1MkuVH&2>?o1Om4Jbel?X@DM{g6XlK`vOU@ihQn)%7r2In;_VNh)H)J!5QUYvCL-{)3)_}m}_YnMFWW8K(9n%cEOvBPC zd;P8?0q*#KgHH>67b=3wpdq^1Z+F%O#NJKzJDvq$D=*d`eB_+ht1U*GCtppP2I;P| zS8BTG>{Xk6spbsrw?w6q8g%wndb9qgwx@pqQe3SuX=^^u00000NkvXXu0mjfb}!J1 diff --git a/Resources/Textures/Interface/splat.svg.192dpi.png.yml b/Resources/Textures/Interface/splat.svg.192dpi.png.yml deleted file mode 100644 index dabd6601f78..00000000000 --- a/Resources/Textures/Interface/splat.svg.192dpi.png.yml +++ /dev/null @@ -1,2 +0,0 @@ -sample: - filter: true From d3e912f41ab9019059038894de7eed38f55d9daf Mon Sep 17 00:00:00 2001 From: Southbridge <7013162+southbridge-fur@users.noreply.github.com> Date: Thu, 28 Aug 2025 17:44:50 -0400 Subject: [PATCH 268/340] Updated Aseprite Tools (#39358) Modified aesprite tools --- .../Displacement Map Flip.lua | 4 +- .../Displacement Map Shift.lua | 63 ++++++ .../Displacement Map Visualizer.lua | 211 +++++++++++------- 3 files changed, 190 insertions(+), 88 deletions(-) create mode 100644 Tools/SS14 Aseprite Plugins/Displacement Map Shift.lua diff --git a/Tools/SS14 Aseprite Plugins/Displacement Map Flip.lua b/Tools/SS14 Aseprite Plugins/Displacement Map Flip.lua index 3291685071d..05a0562b82d 100644 --- a/Tools/SS14 Aseprite Plugins/Displacement Map Flip.lua +++ b/Tools/SS14 Aseprite Plugins/Displacement Map Flip.lua @@ -30,8 +30,8 @@ diag:button{ local selection = sprite.selection local image = cel.image:clone() - for x = 0, selection.bounds.width do - for y = 0, selection.bounds.height do + for x = 0, selection.bounds.width - 1 do + for y = 0, selection.bounds.height - 1 do local xSel = x + selection.origin.x local ySel = y + selection.origin.y diff --git a/Tools/SS14 Aseprite Plugins/Displacement Map Shift.lua b/Tools/SS14 Aseprite Plugins/Displacement Map Shift.lua new file mode 100644 index 00000000000..46320771a1c --- /dev/null +++ b/Tools/SS14 Aseprite Plugins/Displacement Map Shift.lua @@ -0,0 +1,63 @@ +local sprite = app.editor.sprite +local cel = app.cel + +function Shift(dx, dy) + if sprite.selection.isEmpty then + sprite.selection:selectAll() + end + + local selection = sprite.selection + local image = cel.image:clone() + + for it in image:pixels(selection) do + local color = Color(it()) + local position = Point(it.x, it.y) -- gets the position + + if not selection:contains(position.x + cel.position.x, position.y + cel.position.y) then + goto continue + end + + color.red = math.min(255, math.max(0, color.red + dx)) + color.green = math.min(255, math.max(0, color.green + dy)) + + it(color.rgbaPixel) + + ::continue:: + end + cel.image = image + app.refresh() +end + +local diag = Dialog{ + title = "Shift Displacement Map" +} + +diag + :button{ + text="↑", + onclick=function() + Shift(0,1) + end + } + :newrow() + :button{ + text="←", + onclick=function() + Shift(1,0) + end + } + :button{ + text="→", + onclick=function() + Shift(-1,0) + end + } + :newrow() + :button{ + text="↓", + onclick=function() + Shift(0,-1) + end + } + +diag:show{wait=false} diff --git a/Tools/SS14 Aseprite Plugins/Displacement Map Visualizer.lua b/Tools/SS14 Aseprite Plugins/Displacement Map Visualizer.lua index 49824acbede..efbf2e9a17e 100644 --- a/Tools/SS14 Aseprite Plugins/Displacement Map Visualizer.lua +++ b/Tools/SS14 Aseprite Plugins/Displacement Map Visualizer.lua @@ -5,113 +5,133 @@ -- TODO: Handling of sizes != 127 doesn't work properly and rounds differently from the real shader. Ah well. local scale = 4 +local hasOobPixels = false -- This script requires UI if not app.isUIAvailable then return end -local getOffsetPixel = function(x, y, image, rect) - local posX = x - rect.x - local posY = y - rect.y +local sprite = app.editor.sprite - if posX < 0 or posX >= image.width or posY < 0 or posY >= image.height then - return image.spec.transparentColor +local spriteChanged = sprite.events:on("change", + function() + dialog:repaint() + end +) + +dialog = Dialog{ + title = "Displacement map preview", + onclose = function(ev) + sprite.events:off(spriteChanged) + end +} + +function isOutOfBounds(x,y, dx, dy) + local size = dialog.data["frame-size"] + -- I messed around in Desmos for 2 hours trying to find a function that could do all of this at once + -- but I am sadly not a math major + -- This works by checking to see if we've wrapped around from say 31 to 01 which indicates that we've gone over + -- the edges of a sprite's bounds. + if dx > 0 and math.fmod(x+dx, size) < math.fmod(x, size) then + return true + end + -- gotta add size here in case we go from 0 -> -1, since mod -1 is just -1 not 31 + if dx < 0 and math.fmod(x+size+dx, size) > math.fmod(x, size) then + return true + end + if dy > 0 and math.fmod(y+dy, size) < math.fmod(y, size) then + return true + end + if dy < 0 and math.fmod(y+size+dy, size) > math.fmod(y, size) then + return true end - return image:getPixel(posX, posY) + return false end -local pixelValueToColor = function(sprite, value) - return Color(value) +function getOobColor(x,y) + if dialog.data["mark-oob-checkerboard"] then -- requested by Emogarbage :3 + local size = dialog.data["frame-size"] + if (math.sin(math.pi*x*8.0/size) > 0) == (math.cos(math.pi*y*8.0/size) > 0) then + return Color{r=0, g=0, b=0, a=255} + end + end + return dialog.data["mark-oob-color"] end -local applyDisplacementMap = function(width, height, size, displacement, displacementRect, target, targetRect) - -- print(Color(displacement:getPixel(17, 15)).red) - local image = target:clone() +function getOffsetPixel(x, y, dx, dy, image, bounds) + if isOutOfBounds(x,y,dx,dy,image) then + hasOobPixels = true + if dialog.data["mark-oob"] then + return getOobColor(x,y) + end + end + local adj_x = x - bounds.x + local adj_y = y - bounds.y + + if (image.bounds:contains(Rectangle{adj_x+dx, adj_y+dy, 1, 1})) then + return image:getPixel(adj_x+dx, adj_y+dy) + end + + return image.spec.transparentColor +end + + + +function applyDisplacementMap(width, height, displacement, target) + local image = target.image:clone() image:resize(width, height) image:clear() + local displacement_size = dialog.data["displacement_size"] + for x = 0, width - 1 do for y = 0, height - 1 do - local value = getOffsetPixel(x, y, displacement, displacementRect) - local color = pixelValueToColor(sprite, value) - - if color.alpha ~= 0 then - local offset_x = (color.red - 128) / 127 * size - local offset_y = (color.green - 128) / 127 * size - - local colorValue = getOffsetPixel(x + offset_x, y + offset_y, target, targetRect) - image:drawPixel(x, y, colorValue) + if not displacement.bounds:contains(Rectangle{x,y,1,1}) then + goto continue end + + local color = Color(displacement.image:getPixel(x - displacement.bounds.x,y - displacement.bounds.y)) + + if color.alpha == 0 then + goto continue + end + + local dx = (color.red - 128) / 127 * displacement_size + local dy = (color.green - 128) / 127 * displacement_size + + local colorValue = getOffsetPixel(x, y, dx, dy, target.image, target.bounds) + image:drawPixel(x, y, colorValue) + + ::continue:: end end - return image end -local dialog = nil - -local sprite = app.editor.sprite -local spriteChanged = sprite.events:on("change", - function(ev) - dialog:repaint() - end) local layers = {} for i,layer in ipairs(sprite.layers) do table.insert(layers, 1, layer.name) end -local findLayer = function(sprite, name) - for i, layer in ipairs(sprite.layers) do +function findLayer(_sprite, name) + for i,layer in ipairs(_sprite.layers) do if layer.name == name then return layer end end - return nil end -local applyOffset = function(dx, dy) - local cel = app.cel - local image = cel.image:clone() - local sprite = app.editor.sprite - local selection = sprite.selection - - for x = selection.bounds.x, selection.bounds.x + selection.bounds.width - 1 do - for y = selection.bounds.y, selection.bounds.y + selection.bounds.height - 1 do - local xImg = x - cel.position.x - local yImg = y - cel.position.y - if xImg >= 0 and xImg < image.width and yImg >= 0 and yImg < image.height then - local pixelValue = image:getPixel(xImg, yImg) - local color = Color(pixelValue) - - -- Offset R and G channel - color.red = math.min(255, math.max(0, color.red + dx)) - color.green = math.min(255, math.max(0, color.green + dy)) - - image:drawPixel(xImg, yImg, app.pixelColor.rgba(color.red, color.green, color.blue, color.alpha)) - end - end - end - - cel.image = image - dialog:repaint() -end - -dialog = Dialog{ - title = "Displacement map preview", - onclose = function(ev) - sprite.events:off(spriteChanged) - end} - dialog:canvas{ id = "canvas", width = sprite.width * scale, height = sprite.height * scale, onpaint = function(ev) local context = ev.context + hasOobPixels = false local layerDisplacement = findLayer(sprite, dialog.data["displacement-select"]) local layerTarget = findLayer(sprite, dialog.data["reference-select"]) @@ -139,9 +159,8 @@ dialog:canvas{ -- Apply displacement map and draw local image = applyDisplacementMap( sprite.width, sprite.height, - dialog.data["size"], - celDisplacement.image, celDisplacement.bounds, - celTarget.image, celTarget.bounds) + celDisplacement, + celTarget) context:drawImage( -- srcImage @@ -154,6 +173,10 @@ dialog:canvas{ 0, 0, -- dstSize image.width * scale, image.height * scale) + dialog:modify{ + id = "oob-pixels-warn", + visible = hasOobPixels + } end } @@ -185,7 +208,7 @@ dialog:combobox{ } dialog:slider{ - id = "size", + id = "displacement_size", label = "displacement size", min = 127, --We dont support non 127 atm max = 127, @@ -195,35 +218,51 @@ dialog:slider{ end } -dialog:button{ - id = "moveDown", - text = "Down", +-- Out of Bounds marking +dialog:separator() + +dialog:label{ + id = "oob-pixels-warn", + text = "Warning: Out-of-bounds displacements detected!", + visible = false +} + +dialog:check{ + id = "mark-oob", + label = "Mark Out-of-Bounds Displacements", + selected = false, + hexpand = false, onclick = function(ev) - applyOffset(0, -1) + dialog:repaint() end } -dialog:button{ - id = "moveUp", - text = "Up", +dialog:check{ + id = "mark-oob-checkerboard", + label = "Checkerboard Pattern", + selected = false, + hexpand = false, onclick = function(ev) - applyOffset(0, 1) + dialog:repaint() end } -dialog:button{ - id = "moveLeft", - text = "Left", - onclick = function(ev) - applyOffset(1, 0) +dialog:number{ + id = "frame-size", + label = "Frame Size", + text = "32", + hexpand = false, + onchange = function(ev) + dialog:repaint() end } -dialog:button{ - id = "moveRight", - text = "Right", - onclick = function(ev) - applyOffset(-1, 0) +dialog:color{ + id = "mark-oob-color", + label = "Out-of-Bounds Pixels Color", + color = Color{r = 255, g = 0, b = 0}, + onchange = function(ev) + dialog:repaint() end } From 75f0f3407deff230e41413d088c4c6c3df265d2e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C4=81da?= Date: Thu, 28 Aug 2025 11:54:06 -0500 Subject: [PATCH 269/340] Fix audio mispredict when quick inserting (#39930) surprising Co-authored-by: iaada --- Content.Shared/Interaction/SmartEquipSystem.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Content.Shared/Interaction/SmartEquipSystem.cs b/Content.Shared/Interaction/SmartEquipSystem.cs index da79fc1e691..553a4475cb8 100644 --- a/Content.Shared/Interaction/SmartEquipSystem.cs +++ b/Content.Shared/Interaction/SmartEquipSystem.cs @@ -150,7 +150,7 @@ public sealed class SmartEquipSystem : EntitySystem } _hands.TryDrop((uid, hands), hands.ActiveHandId!); - _storage.Insert(slotItem, handItem.Value, out var stacked, out _); + _storage.Insert(slotItem, handItem.Value, out var stacked, out _, user: uid); // if the hand item stacked with the things in inventory, but there's no more space left for the rest // of the stack, place the stack back in hand rather than dropping it on the floor From 04afb24584232ef7fc23a2b6500680034fd54524 Mon Sep 17 00:00:00 2001 From: Hitlinemoss <209321380+Hitlinemoss@users.noreply.github.com> Date: Thu, 28 Aug 2025 13:14:44 -0400 Subject: [PATCH 270/340] Improved cardboard-weapon descriptions (#39927) --- Resources/Prototypes/Entities/Objects/Fun/toys.yml | 2 +- Resources/Prototypes/Entities/Objects/Shields/shields.yml | 2 +- .../Entities/Objects/Weapons/Guns/Projectiles/arrows.yml | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Resources/Prototypes/Entities/Objects/Fun/toys.yml b/Resources/Prototypes/Entities/Objects/Fun/toys.yml index ee01c3d1efb..c69c3280b5b 100644 --- a/Resources/Prototypes/Entities/Objects/Fun/toys.yml +++ b/Resources/Prototypes/Entities/Objects/Fun/toys.yml @@ -783,7 +783,7 @@ parent: BaseItem id: CardSword name: cardboard sword - description: A cardboard tube thats been fashioned into a sword. + description: A cardboard tube fashioned into the shape of a sword. components: - type: Sprite sprite: Objects/Fun/card_sword.rsi diff --git a/Resources/Prototypes/Entities/Objects/Shields/shields.yml b/Resources/Prototypes/Entities/Objects/Shields/shields.yml index 88f55e7c74c..59b53bff06c 100644 --- a/Resources/Prototypes/Entities/Objects/Shields/shields.yml +++ b/Resources/Prototypes/Entities/Objects/Shields/shields.yml @@ -241,7 +241,7 @@ name: cardboard shield parent: BaseShield id: CardShield - description: A shield that wont shield you from much. + description: A shield made of cardboard. Won't protect you from much. components: - type: Sprite state: cardshield-icon diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Projectiles/arrows.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Projectiles/arrows.yml index 1e61fa32950..3f9a2d5435d 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Projectiles/arrows.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Projectiles/arrows.yml @@ -190,7 +190,7 @@ parent: BaseArrow id: ArrowCard name: cardboard arrow - description: Cant kill no matter how hard you try. + description: Careful, you'll poke an eye out! components: - type: Sprite sprite: Objects/Weapons/Guns/Projectiles/arrows.rsi @@ -209,4 +209,4 @@ damage: 10 - type: Construction graph: CardArrow - node: CardArrow \ No newline at end of file + node: CardArrow From 898f240ab1790330eaacfa67e02be686b34519d4 Mon Sep 17 00:00:00 2001 From: Minemoder5000 Date: Fri, 29 Aug 2025 02:38:48 -0600 Subject: [PATCH 271/340] Remove a default Cyborg name (#39948) * 1984 clanker * Fix prototype --- Resources/Locale/en-US/datasets/names/borg.ftl | 2 -- Resources/Prototypes/Datasets/Names/borg.yml | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/Resources/Locale/en-US/datasets/names/borg.ftl b/Resources/Locale/en-US/datasets/names/borg.ftl index 46f36b9fc22..a6682b65999 100644 --- a/Resources/Locale/en-US/datasets/names/borg.ftl +++ b/Resources/Locale/en-US/datasets/names/borg.ftl @@ -37,8 +37,6 @@ names-borg-dataset-36 = Makeshifter names-borg-dataset-37 = Twin names-borg-dataset-38 = S.A.U.L names-borg-dataset-39 = Honker -# DeltaV - was clanker -names-borg-dataset-40 = Beeper names-borg-dataset-41 = Is-The-Robot names-borg-dataset-42 = 9 of 7 names-borg-dataset-43 = Dank bot diff --git a/Resources/Prototypes/Datasets/Names/borg.yml b/Resources/Prototypes/Datasets/Names/borg.yml index 33b2565f06c..fef61090498 100644 --- a/Resources/Prototypes/Datasets/Names/borg.yml +++ b/Resources/Prototypes/Datasets/Names/borg.yml @@ -3,4 +3,4 @@ id: NamesBorg values: prefix: names-borg-dataset- - count: 43 + count: 42 From 148db476d19e7308ea8f8ce8c09a6a82ae4f1f5c Mon Sep 17 00:00:00 2001 From: Princess Cheeseballs <66055347+Princess-Cheeseballs@users.noreply.github.com> Date: Fri, 29 Aug 2025 06:32:13 -0700 Subject: [PATCH 272/340] Small Status Effect Cleanup (#39944) Heroic Co-authored-by: Princess Cheeseballs <66055347+Pronana@users.noreply.github.com> --- Content.Shared/StatusEffectNew/StatusEffectsSystem.cs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/Content.Shared/StatusEffectNew/StatusEffectsSystem.cs b/Content.Shared/StatusEffectNew/StatusEffectsSystem.cs index 3c542458293..081a14c837f 100644 --- a/Content.Shared/StatusEffectNew/StatusEffectsSystem.cs +++ b/Content.Shared/StatusEffectNew/StatusEffectsSystem.cs @@ -55,11 +55,7 @@ public sealed partial class StatusEffectsSystem : EntitySystem if (effect.AppliedTo is null) continue; - var meta = MetaData(ent); - if (meta.EntityPrototype is null) - continue; - - TryRemoveStatusEffect(effect.AppliedTo.Value, meta.EntityPrototype); + PredictedQueueDel(ent); } } From 1a7a383a2435a35b89507abb89f38485d4ea6c47 Mon Sep 17 00:00:00 2001 From: ScarKy0 <106310278+ScarKy0@users.noreply.github.com> Date: Fri, 29 Aug 2025 19:12:51 +0200 Subject: [PATCH 273/340] Add SnoutCover appearance layer (#39949) * init * cover --- Content.Shared/Humanoid/HumanoidVisualLayers.cs | 1 + Content.Shared/Humanoid/HumanoidVisualLayersExtension.cs | 5 +++++ Content.Shared/Humanoid/Markings/MarkingCategories.cs | 1 + Resources/Locale/en-US/preferences/ui/markings-picker.ftl | 1 + Resources/Prototypes/Entities/Mobs/Species/arachnid.yml | 3 ++- Resources/Prototypes/Entities/Mobs/Species/base.yml | 2 ++ Resources/Prototypes/Entities/Mobs/Species/moth.yml | 1 + Resources/Prototypes/Entities/Mobs/Species/vox.yml | 1 + 8 files changed, 14 insertions(+), 1 deletion(-) diff --git a/Content.Shared/Humanoid/HumanoidVisualLayers.cs b/Content.Shared/Humanoid/HumanoidVisualLayers.cs index e2f12c78b5b..3a5741df5eb 100644 --- a/Content.Shared/Humanoid/HumanoidVisualLayers.cs +++ b/Content.Shared/Humanoid/HumanoidVisualLayers.cs @@ -15,6 +15,7 @@ namespace Content.Shared.Humanoid Chest, Head, Snout, + SnoutCover, // things layered over snouts (i.e. noses) HeadSide, // side parts (i.e., frills) HeadTop, // top parts (i.e., ears) Eyes, diff --git a/Content.Shared/Humanoid/HumanoidVisualLayersExtension.cs b/Content.Shared/Humanoid/HumanoidVisualLayersExtension.cs index c0828d01656..31ba1ef1091 100644 --- a/Content.Shared/Humanoid/HumanoidVisualLayersExtension.cs +++ b/Content.Shared/Humanoid/HumanoidVisualLayersExtension.cs @@ -42,6 +42,11 @@ namespace Content.Shared.Humanoid yield return HumanoidVisualLayers.Hair; yield return HumanoidVisualLayers.FacialHair; yield return HumanoidVisualLayers.Snout; + yield return HumanoidVisualLayers.SnoutCover; + break; + case HumanoidVisualLayers.Snout: + yield return HumanoidVisualLayers.Snout; + yield return HumanoidVisualLayers.SnoutCover; break; case HumanoidVisualLayers.LArm: yield return HumanoidVisualLayers.LArm; diff --git a/Content.Shared/Humanoid/Markings/MarkingCategories.cs b/Content.Shared/Humanoid/Markings/MarkingCategories.cs index 56ed5cde540..57079f209d7 100644 --- a/Content.Shared/Humanoid/Markings/MarkingCategories.cs +++ b/Content.Shared/Humanoid/Markings/MarkingCategories.cs @@ -13,6 +13,7 @@ namespace Content.Shared.Humanoid.Markings HeadSide, Eyes, // DeltaV - Add Eyes Category for IPCs Snout, + SnoutCover, Chest, UndergarmentTop, UndergarmentBottom, diff --git a/Resources/Locale/en-US/preferences/ui/markings-picker.ftl b/Resources/Locale/en-US/preferences/ui/markings-picker.ftl index cdf0658f04c..afcb45ea9e0 100644 --- a/Resources/Locale/en-US/preferences/ui/markings-picker.ftl +++ b/Resources/Locale/en-US/preferences/ui/markings-picker.ftl @@ -20,6 +20,7 @@ markings-category-Head = Head markings-category-HeadTop = Head (Top) markings-category-HeadSide = Head (Side) markings-category-Snout = Snout +markings-category-SnoutCover = Snout (Cover) markings-category-UndergarmentTop = Undergarment (Top) markings-category-UndergarmentBottom = Undergarment (Bottom) markings-category-Chest = Chest diff --git a/Resources/Prototypes/Entities/Mobs/Species/arachnid.yml b/Resources/Prototypes/Entities/Mobs/Species/arachnid.yml index 27a533cc284..cf5f76f4947 100644 --- a/Resources/Prototypes/Entities/Mobs/Species/arachnid.yml +++ b/Resources/Prototypes/Entities/Mobs/Species/arachnid.yml @@ -96,6 +96,7 @@ - map: [ "enum.HumanoidVisualLayers.Tail" ] # Mentioned in moth code: This needs renaming lol. - map: [ "back" ] - map: [ "neck" ] + - map: [ "enum.HumanoidVisualLayers.SnoutCover" ] - map: [ "enum.HumanoidVisualLayers.FacialHair" ] - map: [ "enum.HumanoidVisualLayers.Hair" ] # Do these need to be here? (arachnid hair arachnid hair) - map: [ "enum.HumanoidVisualLayers.HeadSide" ] @@ -133,7 +134,7 @@ - type: HumanoidAppearance species: Arachnid - type: Inventory - speciesId: arachnid + speciesId: arachnid #>88w88< diff --git a/Resources/Prototypes/Entities/Mobs/Species/base.yml b/Resources/Prototypes/Entities/Mobs/Species/base.yml index 3166f26f40a..6b0c3300418 100644 --- a/Resources/Prototypes/Entities/Mobs/Species/base.yml +++ b/Resources/Prototypes/Entities/Mobs/Species/base.yml @@ -35,6 +35,7 @@ - map: [ "outerClothing" ] - map: [ "back" ] - map: [ "neck" ] + - map: [ "enum.HumanoidVisualLayers.SnoutCover" ] - map: [ "enum.HumanoidVisualLayers.FacialHair" ] - map: [ "enum.HumanoidVisualLayers.Hair" ] - map: [ "enum.HumanoidVisualLayers.HeadSide" ] @@ -347,6 +348,7 @@ - map: [ "outerClothing" ] - map: [ "back" ] - map: [ "neck" ] + - map: [ "enum.HumanoidVisualLayers.SnoutCover" ] - map: [ "enum.HumanoidVisualLayers.FacialHair" ] - map: [ "enum.HumanoidVisualLayers.Hair" ] - map: [ "enum.HumanoidVisualLayers.HeadSide" ] diff --git a/Resources/Prototypes/Entities/Mobs/Species/moth.yml b/Resources/Prototypes/Entities/Mobs/Species/moth.yml index 8a92947897a..c841ebc79fe 100644 --- a/Resources/Prototypes/Entities/Mobs/Species/moth.yml +++ b/Resources/Prototypes/Entities/Mobs/Species/moth.yml @@ -105,6 +105,7 @@ - map: [ "enum.HumanoidVisualLayers.Tail" ] #in the utopian future we should probably have a wings enum inserted here so everyhting doesn't break - map: [ "back" ] - map: [ "neck" ] + - map: [ "enum.HumanoidVisualLayers.SnoutCover" ] - map: [ "enum.HumanoidVisualLayers.FacialHair" ] - map: [ "enum.HumanoidVisualLayers.Hair" ] - map: [ "enum.HumanoidVisualLayers.HeadSide" ] diff --git a/Resources/Prototypes/Entities/Mobs/Species/vox.yml b/Resources/Prototypes/Entities/Mobs/Species/vox.yml index 076a2573587..1faef564cdc 100644 --- a/Resources/Prototypes/Entities/Mobs/Species/vox.yml +++ b/Resources/Prototypes/Entities/Mobs/Species/vox.yml @@ -87,6 +87,7 @@ - map: [ "back" ] - map: [ "neck" ] - map: [ "suitstorage" ] # This is not in the default order + - map: [ "enum.HumanoidVisualLayers.SnoutCover" ] - map: [ "enum.HumanoidVisualLayers.FacialHair" ] - map: [ "enum.HumanoidVisualLayers.Hair" ] - map: [ "enum.HumanoidVisualLayers.HeadSide" ] From a58797e94a3fba3a6e48041676d6a104a4572e90 Mon Sep 17 00:00:00 2001 From: FungiFellow <151778459+FungiFellow@users.noreply.github.com> Date: Fri, 29 Aug 2025 07:48:31 -0400 Subject: [PATCH 274/340] Stop Sentience Event targeting Zombified Creatures (#39950) * Strip Target From Zed * Update RandomSentienceRule.cs * Update RandomSentienceRule.cs * Update RandomSentienceRule.cs * Update RandomSentienceRule.cs * Update RandomSentienceRule.cs --- Content.Server/StationEvents/Events/RandomSentienceRule.cs | 1 + Content.Server/Zombies/ZombieSystem.Transform.cs | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/Content.Server/StationEvents/Events/RandomSentienceRule.cs b/Content.Server/StationEvents/Events/RandomSentienceRule.cs index 359c3edae45..f2fda7b8c68 100644 --- a/Content.Server/StationEvents/Events/RandomSentienceRule.cs +++ b/Content.Server/StationEvents/Events/RandomSentienceRule.cs @@ -16,6 +16,7 @@ public sealed class RandomSentienceRule : StationEventSystem(target); //we need to basically remove all of these because zombies shouldn't - //get diseases, breath, be thirst, be hungry, die in space, have offspring or be paraplegic. + //get diseases, breath, be thirst, be hungry, die in space, get double sentience, have offspring or be paraplegic. RemComp(target); RemComp(target); RemComp(target); @@ -117,6 +118,7 @@ public sealed partial class ZombieSystem RemComp(target); RemComp(target); RemComp(target); + RemComp(target); if (TryComp(target, out var psionic)) // DeltaV - Prevent psionic zombies { From 395d4e7680cc8621bb6b81333fea32aaee3af106 Mon Sep 17 00:00:00 2001 From: slarticodefast <161409025+slarticodefast@users.noreply.github.com> Date: Sat, 30 Aug 2025 00:40:24 +0200 Subject: [PATCH 275/340] Don't network ZombifyOnDeathComponent and ZombieImmuneComponent (#39963) no networking --- Content.Shared/Zombies/ZombieImmuneComponent.cs | 2 +- Content.Shared/Zombies/ZombifyOnDeathComponent.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Content.Shared/Zombies/ZombieImmuneComponent.cs b/Content.Shared/Zombies/ZombieImmuneComponent.cs index 18ad2283638..483b1810f22 100644 --- a/Content.Shared/Zombies/ZombieImmuneComponent.cs +++ b/Content.Shared/Zombies/ZombieImmuneComponent.cs @@ -5,7 +5,7 @@ namespace Content.Shared.Zombies; /// /// Entities with this component cannot be zombified. /// -[RegisterComponent, NetworkedComponent] +[RegisterComponent] public sealed partial class ZombieImmuneComponent : Component { //still no diff --git a/Content.Shared/Zombies/ZombifyOnDeathComponent.cs b/Content.Shared/Zombies/ZombifyOnDeathComponent.cs index 138ea6e4098..60029aca6fe 100644 --- a/Content.Shared/Zombies/ZombifyOnDeathComponent.cs +++ b/Content.Shared/Zombies/ZombifyOnDeathComponent.cs @@ -5,7 +5,7 @@ namespace Content.Shared.Zombies; /// /// Entities with this component zombify on death. /// -[RegisterComponent, NetworkedComponent] +[RegisterComponent] public sealed partial class ZombifyOnDeathComponent : Component { //this is not the component you are looking for From 1059c4e7da1f9d21d197a070875b13700b1af3f2 Mon Sep 17 00:00:00 2001 From: Princess Cheeseballs <66055347+Princess-Cheeseballs@users.noreply.github.com> Date: Fri, 29 Aug 2025 16:28:28 -0700 Subject: [PATCH 276/340] [STAGING] 1984 Derelict Syndicate Borgs (#39978) 1984 Co-authored-by: Princess Cheeseballs <66055347+Pronana@users.noreply.github.com> --- .../Mobs/Cyborgs/base_borg_chassis.yml | 27 ++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/Resources/Prototypes/Entities/Mobs/Cyborgs/base_borg_chassis.yml b/Resources/Prototypes/Entities/Mobs/Cyborgs/base_borg_chassis.yml index cc1b40ad810..7f0c1c12f1e 100644 --- a/Resources/Prototypes/Entities/Mobs/Cyborgs/base_borg_chassis.yml +++ b/Resources/Prototypes/Entities/Mobs/Cyborgs/base_borg_chassis.yml @@ -429,7 +429,7 @@ - type: entity id: BaseBorgChassisSyndicateDerelict #For assault borg and maybe others in time - parent: BaseBorgChassisSyndicate + parent: BaseBorgChassis # We don't want them to see Nukies or have syndi comms, their database is out of date abstract: true components: - type: SiliconLawProvider @@ -439,6 +439,31 @@ - type: IonStormTarget chance: 1 - type: ShowJobIcons + - type: NpcFactionMember # They're still syndicate even if they can't listen to the radio or see icons + factions: + - Syndicate + - type: Access + tags: + - NuclearOperative + - SyndicateAgent + - type: AccessReader + access: [ [ "SyndicateAgent" ], [ "NuclearOperative" ] ] + - type: IntrinsicRadioTransmitter # Copy components from base SyndiBorg but without the stuff we don't want + channels: + - Binary #1984 + - type: ActiveRadio + channels: + - Binary + - type: MovementAlwaysTouching + - type: Speech + speechSounds: SyndieBorg + allowedEmotes: + - Laugh + - type: Vocal + sounds: + Unsexed: UnisexSiliconSyndicate + - type: PointLight + color: "#dd200b" - type: entity parent: BaseBorgChassisNotIonStormable From a50aaff6f3054e9c83504f185bdcf719a2247600 Mon Sep 17 00:00:00 2001 From: chromiumboy <50505512+chromiumboy@users.noreply.github.com> Date: Fri, 29 Aug 2025 07:10:47 -0500 Subject: [PATCH 277/340] Sentry turrets - Part 7: Electronics and construction graphs (#35236) * Initial commit * Fixing merge conflict * Updated for deployment * Whitespace fixes * Linter fixes * Test fail fix * Fixed test failure * Add separate command circuitboards * Addressed review comments --- .../Components/ElectronicsBoardComponent.cs | 16 ++++ .../NodeEntities/BoardNodeEntity.cs | 8 +- Resources/Locale/en-US/recipes/tags.ftl | 1 + .../Devices/Circuitboards/Machine/turrets.yml | 13 ++- .../Devices/Electronics/turret_controls.yml | 43 ++++++++++ .../Weapons/Guns/Turrets/turrets_energy.yml | 2 +- .../Structures/Wallmounts/turret_controls.yml | 50 +++++------ .../Graphs/utilities/turret_controls.yml | 85 +++++++++++++++++++ .../Recipes/Construction/utilities.yml | 14 +++ 9 files changed, 204 insertions(+), 28 deletions(-) create mode 100644 Content.Shared/Construction/Components/ElectronicsBoardComponent.cs create mode 100644 Resources/Prototypes/Entities/Objects/Devices/Electronics/turret_controls.yml create mode 100644 Resources/Prototypes/Recipes/Construction/Graphs/utilities/turret_controls.yml diff --git a/Content.Shared/Construction/Components/ElectronicsBoardComponent.cs b/Content.Shared/Construction/Components/ElectronicsBoardComponent.cs new file mode 100644 index 00000000000..734edfba236 --- /dev/null +++ b/Content.Shared/Construction/Components/ElectronicsBoardComponent.cs @@ -0,0 +1,16 @@ +using Robust.Shared.Prototypes; + +namespace Content.Shared.Construction.Components; + +/// +/// Used in construction graphs for building wall-mounted electronic devices. +/// +[RegisterComponent] +public sealed partial class ElectronicsBoardComponent : Component +{ + /// + /// The device that is produced when the construction is completed. + /// + [DataField(required: true)] + public EntProtoId Prototype; +} diff --git a/Content.Shared/Construction/NodeEntities/BoardNodeEntity.cs b/Content.Shared/Construction/NodeEntities/BoardNodeEntity.cs index c1540c4a646..be55c6f7330 100644 --- a/Content.Shared/Construction/NodeEntities/BoardNodeEntity.cs +++ b/Content.Shared/Construction/NodeEntities/BoardNodeEntity.cs @@ -12,7 +12,8 @@ namespace Content.Shared.Construction.NodeEntities; [DataDefinition] public sealed partial class BoardNodeEntity : IGraphNodeEntity { - [DataField("container")] public string Container { get; private set; } = string.Empty; + [DataField] + public string Container { get; private set; } = string.Empty; public string? GetId(EntityUid? uid, EntityUid? userUid, GraphNodeEntityArgs args) { @@ -27,13 +28,16 @@ public sealed partial class BoardNodeEntity : IGraphNodeEntity var board = container.ContainedEntities[0]; - // There should not be a case where both of these components exist on the same entity... + // There should not be a case where more than one of these components exist on the same entity if (args.EntityManager.TryGetComponent(board, out MachineBoardComponent? machine)) return machine.Prototype; if (args.EntityManager.TryGetComponent(board, out ComputerBoardComponent? computer)) return computer.Prototype; + if (args.EntityManager.TryGetComponent(board, out ElectronicsBoardComponent? electronics)) + return electronics.Prototype; + return null; } } diff --git a/Resources/Locale/en-US/recipes/tags.ftl b/Resources/Locale/en-US/recipes/tags.ftl index 39d39e7f0cc..34eadc37d85 100644 --- a/Resources/Locale/en-US/recipes/tags.ftl +++ b/Resources/Locale/en-US/recipes/tags.ftl @@ -125,6 +125,7 @@ construction-graph-tag-wallmount-substation-circuit-board = wallmount substation construction-graph-tag-surveillance-camera-monitor-board = surveillance camera monitor board construction-graph-tag-television-board = television board construction-graph-tag-freezer-electronics = freezer electronics +construction-graph-tag-turret-control-electronics = sentry turret control panel electronics # crystals construction-graph-tag-cyan-crystal-shard = cyan crystal shard diff --git a/Resources/Prototypes/Entities/Objects/Devices/Circuitboards/Machine/turrets.yml b/Resources/Prototypes/Entities/Objects/Devices/Circuitboards/Machine/turrets.yml index d9d8a848c38..d9bb8611715 100644 --- a/Resources/Prototypes/Entities/Objects/Devices/Circuitboards/Machine/turrets.yml +++ b/Resources/Prototypes/Entities/Objects/Devices/Circuitboards/Machine/turrets.yml @@ -31,7 +31,7 @@ components: - type: Sprite sprite: Objects/Misc/module.rsi - state: command + state: science - type: MachineBoard prototype: WeaponEnergyTurretAI @@ -45,4 +45,15 @@ state: security - type: MachineBoard prototype: WeaponEnergyTurretSecurity + +- type: entity + parent: WeaponEnergyTurretStationMachineCircuitboardBase + id: WeaponEnergyTurretCommandMachineCircuitboard + suffix: Command + components: + - type: Sprite + sprite: Objects/Misc/module.rsi + state: command + - type: MachineBoard + prototype: WeaponEnergyTurretCommand diff --git a/Resources/Prototypes/Entities/Objects/Devices/Electronics/turret_controls.yml b/Resources/Prototypes/Entities/Objects/Devices/Electronics/turret_controls.yml new file mode 100644 index 00000000000..ced73dd9496 --- /dev/null +++ b/Resources/Prototypes/Entities/Objects/Devices/Electronics/turret_controls.yml @@ -0,0 +1,43 @@ +- type: entity + abstract: true + parent: BaseElectronics + id: WeaponEnergyTurretStationControlPanelElectronicsBase + name: sentry turret control panel electronics + description: An electronics board used in a sentry turret control panel. + components: + - type: Sprite + sprite: Objects/Misc/module.rsi + state: security + - type: ElectronicsBoard + prototype: WeaponEnergyTurretSecurityControlPanel + - type: Tag + tags: + - TurretControlElectronics + +- type: entity + parent: WeaponEnergyTurretStationControlPanelElectronicsBase + id: WeaponEnergyTurretSecurityControlPanelElectronics + suffix: Security + +- type: entity + parent: WeaponEnergyTurretStationControlPanelElectronicsBase + id: WeaponEnergyTurretAIControlPanelElectronics + suffix: AI, Silicon + components: + - type: Sprite + sprite: Objects/Misc/module.rsi + state: science + - type: ElectronicsBoard + prototype: WeaponEnergyTurretAIControlPanel + +- type: entity + parent: WeaponEnergyTurretStationControlPanelElectronicsBase + id: WeaponEnergyTurretCommandControlPanelElectronics + suffix: Command + components: + - type: Sprite + sprite: Objects/Misc/module.rsi + state: command + - type: ElectronicsBoard + prototype: WeaponEnergyTurretCommandControlPanel + diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Turrets/turrets_energy.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Turrets/turrets_energy.yml index 1fe926294c9..33d5fd6e970 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Turrets/turrets_energy.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Turrets/turrets_energy.yml @@ -190,7 +190,7 @@ - Borg - BasicSilicon - type: Machine - board: WeaponEnergyTurretSecurityMachineCircuitboard + board: WeaponEnergyTurretCommandMachineCircuitboard - type: DeviceNetwork receiveFrequencyId: TurretControl transmitFrequencyId: Turret diff --git a/Resources/Prototypes/Entities/Structures/Wallmounts/turret_controls.yml b/Resources/Prototypes/Entities/Structures/Wallmounts/turret_controls.yml index 6f2178c4bac..0df8a3c63b3 100644 --- a/Resources/Prototypes/Entities/Structures/Wallmounts/turret_controls.yml +++ b/Resources/Prototypes/Entities/Structures/Wallmounts/turret_controls.yml @@ -24,8 +24,8 @@ collection: MetalGlassBreak params: volume: -4 - #- !type:ChangeConstructionNodeBehavior - To be added in a later PR - # node: machineFrame + - !type:ChangeConstructionNodeBehavior + node: machineFrame - !type:DoActsBehavior acts: [ "Destruction" ] - type: Transform @@ -36,9 +36,11 @@ - type: ContainerContainer containers: board: !type:Container - #- type: Construction - To be added in a later PR - # graph: WeaponEnergyTurretControlPanel - # node: frame + - type: Construction + graph: WeaponEnergyTurretControlPanel + node: frame + containers: + - board placement: mode: SnapgridCenter snap: @@ -157,13 +159,13 @@ - type: Electrified enabled: false usesApcPower: true - #- type: ContainerFill - Will be added in a later PR - # containers: - # board: - # - WeaponEnergyTurretStationControlPanelElectronics - #- type: Construction - Will be added in a later PR - # graph: WeaponEnergyTurretControlPanel - # node: finish + - type: ContainerFill + containers: + board: + - WeaponEnergyTurretStationControlPanelElectronics + - type: Construction + graph: WeaponEnergyTurretControlPanel + node: finish - type: entity parent: WeaponEnergyTurretStationControlPanelBase @@ -172,10 +174,10 @@ components: - type: AccessReader access: [["StationAi"], ["ResearchDirector"]] - #- type: ContainerFill - Will be added in a later PR - # containers: - # board: - # - WeaponEnergyTurretAIControlPanelElectronics + - type: ContainerFill + containers: + board: + - WeaponEnergyTurretAIControlPanelElectronics - type: DeviceNetwork receiveFrequencyId: TurretAI transmitFrequencyId: TurretControlAI @@ -197,10 +199,10 @@ components: - type: AccessReader access: [["StationAi"], ["Security"]] - #- type: ContainerFill - Will be added in a later PR - # containers: - # board: - # - WeaponEnergyTurretSecurityControlPanelElectronics + - type: ContainerFill + containers: + board: + - WeaponEnergyTurretSecurityControlPanelElectronics - type: TurretTargetSettings exemptAccessLevels: - Security @@ -214,10 +216,10 @@ components: - type: AccessReader access: [["StationAi"], ["Command"]] - #- type: ContainerFill - Will be added in a later PR - # containers: - # board: - # - WeaponEnergyTurretCommandControlPanelElectronics + - type: ContainerFill + containers: + board: + - WeaponEnergyTurretCommandControlPanelElectronics - type: TurretTargetSettings exemptAccessLevels: - Command diff --git a/Resources/Prototypes/Recipes/Construction/Graphs/utilities/turret_controls.yml b/Resources/Prototypes/Recipes/Construction/Graphs/utilities/turret_controls.yml new file mode 100644 index 00000000000..ae48638d92e --- /dev/null +++ b/Resources/Prototypes/Recipes/Construction/Graphs/utilities/turret_controls.yml @@ -0,0 +1,85 @@ +- type: constructionGraph + id: WeaponEnergyTurretControlPanel + start: start + graph: + - node: start + edges: + - to: frame + steps: + - material: Steel + amount: 3 + doAfter: 2 + + - node: frame + entity: WeaponEnergyTurretControlPanelFrame + edges: + - to: board + steps: + - tag: TurretControlElectronics + name: construction-graph-tag-turret-control-electronics + icon: + sprite: Objects/Misc/module.rsi + state: command + store: board + + - to: start + completed: + - !type:GivePrototype + prototype: SheetSteel1 + amount: 3 + - !type:DeleteEntity {} + steps: + - tool: Screwing + doAfter: 4 + + - node: board + entity: WeaponEnergyTurretControlPanelFrame + edges: + - to: glass + steps: + - material: Glass + amount: 1 + doAfter: 1 + + - to: frame + completed: + - !type:EmptyContainer + container: board + pickup: true + steps: + - tool: Prying + doAfter: 4 + + - node: glass + edges: + - to: finish + steps: + - tool: Screwing + doAfter: 2 + + - to: board + completed: + - !type:GivePrototype + prototype: SheetGlass1 + amount: 1 + steps: + - tool: Prying + doAfter: 2 + + - node: finish + entity: !type:BoardNodeEntity { container: board } + actions: + - !type:AddContainer + container: board + edges: + - to: board + conditions: + - !type:AllWiresCut {} + - !type:WirePanel {} + completed: + - !type:GivePrototype + prototype: SheetGlass1 + amount: 1 + steps: + - tool: Prying + doAfter: 4 diff --git a/Resources/Prototypes/Recipes/Construction/utilities.yml b/Resources/Prototypes/Recipes/Construction/utilities.yml index 9dc1c7b03da..ee82d72529a 100644 --- a/Resources/Prototypes/Recipes/Construction/utilities.yml +++ b/Resources/Prototypes/Recipes/Construction/utilities.yml @@ -1008,3 +1008,17 @@ canBuildInImpassable: true conditions: - !type:WallmountCondition + +# DEFENSES +- type: construction + id: WeaponEnergyTurretControlPanel + graph: WeaponEnergyTurretControlPanel + startNode: start + targetNode: finish + category: construction-category-utilities + objectType: Structure + canRotate: true + placementMode: SnapgridCenter + canBuildInImpassable: true + conditions: + - !type:WallmountCondition From 6da624c3563b4ee8922315cad41fa1b9e7ec5050 Mon Sep 17 00:00:00 2001 From: Vanessa Date: Fri, 21 Nov 2025 16:24:39 -0600 Subject: [PATCH 278/340] YAML fix. --- .../Entities/Objects/Weapons/Guns/Battery/battery_guns.yml | 2 -- .../Entities/Structures/Storage/Closets/Lockers/lockers.yml | 1 + 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Battery/battery_guns.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Battery/battery_guns.yml index ca3866f4bdc..490d73db4cf 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Battery/battery_guns.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Battery/battery_guns.yml @@ -260,8 +260,6 @@ price: 420 proto: RedLaser fireCost: 62.5 - - type: StaticPrice - price: 420 - type: entity name: practice laser carbine diff --git a/Resources/Prototypes/Entities/Structures/Storage/Closets/Lockers/lockers.yml b/Resources/Prototypes/Entities/Structures/Storage/Closets/Lockers/lockers.yml index 04d376f9ff9..11dc69b5e6b 100644 --- a/Resources/Prototypes/Entities/Structures/Storage/Closets/Lockers/lockers.yml +++ b/Resources/Prototypes/Entities/Structures/Storage/Closets/Lockers/lockers.yml @@ -281,6 +281,7 @@ id: LockerChiefMedicalOfficer parent: LockerBaseSecure name: chief medical officer's locker + description: A standard-issue Nanotrasen storage unit. Looking closer, there are some letters etched into the side of the locker. A.G., S.H., S.D., M.N., & A.N. # DeltaV - Honoring Quanteey components: - type: Appearance - type: EntityStorageVisuals From dd462c9e0c05ac251c200ea62405cf958dc1b6cf Mon Sep 17 00:00:00 2001 From: "Mr. 27" <45323883+Dutch-VanDerLinde@users.noreply.github.com> Date: Sat, 30 Aug 2025 10:00:46 -0400 Subject: [PATCH 279/340] Fix forensic scanner leaking fingerprints onto the scanning object if you use the verb (#39964) Update ForensicScannerSystem.cs --- Content.Server/Forensics/Systems/ForensicScannerSystem.cs | 4 +++- .../Entities/Structures/Storage/Closets/Lockers/lockers.yml | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Content.Server/Forensics/Systems/ForensicScannerSystem.cs b/Content.Server/Forensics/Systems/ForensicScannerSystem.cs index 87c19c688df..b75c0ae32af 100644 --- a/Content.Server/Forensics/Systems/ForensicScannerSystem.cs +++ b/Content.Server/Forensics/Systems/ForensicScannerSystem.cs @@ -125,7 +125,9 @@ namespace Content.Server.Forensics Act = () => StartScan(uid, component, args.User, args.Target), IconEntity = GetNetEntity(uid), Text = Loc.GetString("forensic-scanner-verb-text"), - Message = Loc.GetString("forensic-scanner-verb-message") + Message = Loc.GetString("forensic-scanner-verb-message"), + // This is important because if its true using the scanner will count as touching the object. + DoContactInteraction = false }; args.Verbs.Add(verb); diff --git a/Resources/Prototypes/Entities/Structures/Storage/Closets/Lockers/lockers.yml b/Resources/Prototypes/Entities/Structures/Storage/Closets/Lockers/lockers.yml index 11dc69b5e6b..ca24611589f 100644 --- a/Resources/Prototypes/Entities/Structures/Storage/Closets/Lockers/lockers.yml +++ b/Resources/Prototypes/Entities/Structures/Storage/Closets/Lockers/lockers.yml @@ -281,7 +281,7 @@ id: LockerChiefMedicalOfficer parent: LockerBaseSecure name: chief medical officer's locker - description: A standard-issue Nanotrasen storage unit. Looking closer, there are some letters etched into the side of the locker. A.G., S.H., S.D., M.N., & A.N. # DeltaV - Honoring Quanteey + description: A standard-issue Nanotrasen storage unit. Looking closer, there are some letters etched into the side of the locker. A.G., S.H., S.D., M.N., & A.N. # DeltaV - Honoring Quanteey. I hope you're well. components: - type: Appearance - type: EntityStorageVisuals From 13ac4aa1f105968efe7dc51e8d007ac478f22584 Mon Sep 17 00:00:00 2001 From: Hannah Giovanna Dawson Date: Sat, 30 Aug 2025 15:42:43 +0100 Subject: [PATCH 280/340] Scurrets - can wear pet bags, mail bags and spears (#38774) * Scurrets - can wear pet bags, mail bags and spears * a * Resolve PR comments --- .../Entities/Clothing/Back/specific.yml | 1 + .../Entities/Objects/Weapons/Melee/spear.yml | 5 +-- .../scurret_inventory_template.yml | 12 +++++++ .../_NF/Clothing/Belt/pilot.rsi/meta.json | 34 ++++++++++++------- 4 files changed, 37 insertions(+), 15 deletions(-) diff --git a/Resources/Prototypes/Entities/Clothing/Back/specific.yml b/Resources/Prototypes/Entities/Clothing/Back/specific.yml index b80e7709d59..54b8f677b8e 100644 --- a/Resources/Prototypes/Entities/Clothing/Back/specific.yml +++ b/Resources/Prototypes/Entities/Clothing/Back/specific.yml @@ -96,6 +96,7 @@ - WhitelistChameleon - CorgiWearable - PetOnly + - ScurretWearable - type: Construction graph: ClothingBagPet node: bagPet diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Melee/spear.yml b/Resources/Prototypes/Entities/Objects/Weapons/Melee/spear.yml index d646f885a33..7d90ae318d6 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Melee/spear.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Melee/spear.yml @@ -12,6 +12,7 @@ - type: Tag tags: - Spear + - ScurretWearable - type: Fixtures fixtures: fix1: @@ -220,7 +221,7 @@ - type: entity name: sharkminnow tooth spear - parent: Spear + parent: Spear id: SpearSharkMinnow description: A spear with a sharkminnow tooth as a tip. components: @@ -236,4 +237,4 @@ types: Piercing: 25 #throw dmg enough to two-shot carp - type: Construction - graph: SpearSharkMinnow \ No newline at end of file + graph: SpearSharkMinnow diff --git a/Resources/Prototypes/InventoryTemplates/scurret_inventory_template.yml b/Resources/Prototypes/InventoryTemplates/scurret_inventory_template.yml index 28b95eb3d34..89f0af03023 100644 --- a/Resources/Prototypes/InventoryTemplates/scurret_inventory_template.yml +++ b/Resources/Prototypes/InventoryTemplates/scurret_inventory_template.yml @@ -59,6 +59,18 @@ dependsOnComponents: - type: AllowSuitStorage displayName: Suit Storage + - name: back + slotTexture: back + fullTextureName: template_small + slotFlags: BACK + slotGroup: SecondHotbar + stripTime: 6 + uiWindowPos: 3,2 + strippingWindowPos: 0,5 + displayName: Back + whitelist: + tags: + - ScurretWearable - name: outerClothing slotTexture: suit slotFlags: OUTERCLOTHING diff --git a/Resources/Textures/_NF/Clothing/Belt/pilot.rsi/meta.json b/Resources/Textures/_NF/Clothing/Belt/pilot.rsi/meta.json index 590ab440640..7d0706ed599 100644 --- a/Resources/Textures/_NF/Clothing/Belt/pilot.rsi/meta.json +++ b/Resources/Textures/_NF/Clothing/Belt/pilot.rsi/meta.json @@ -10,17 +10,25 @@ { "name": "icon" }, - { - "name": "equipped-BELT", - "directions": 4 - }, - { - "name": "inhand-left", - "directions": 4 - }, - { - "name": "inhand-right", - "directions": 4 - } - ] + "states": [ + { + "name": "icon" + }, + { + "name": "equipped-BELT", + "directions": 4 + }, + { + "name": "equipped-BACKPACK", + "directions": 4 + }, + { + "name": "inhand-left", + "directions": 4 + }, + { + "name": "inhand-right", + "directions": 4 + } + ] } From 258b4b8b762d9f22b0cb143d5c9569eebf803317 Mon Sep 17 00:00:00 2001 From: ScarKy0 <106310278+ScarKy0@users.noreply.github.com> Date: Sat, 30 Aug 2025 17:38:28 +0200 Subject: [PATCH 281/340] Messy drinker immunity and cleanup (#39989) init --- .../Nutrition/Components/MessyDrinkerComponent.cs | 8 ++++++++ .../Nutrition/EntitySystems/MessyDrinkerSystem.cs | 12 +++++++----- Resources/Prototypes/tags.yml | 3 +++ 3 files changed, 18 insertions(+), 5 deletions(-) diff --git a/Content.Shared/Nutrition/Components/MessyDrinkerComponent.cs b/Content.Shared/Nutrition/Components/MessyDrinkerComponent.cs index c077db82319..ea145019c2c 100644 --- a/Content.Shared/Nutrition/Components/MessyDrinkerComponent.cs +++ b/Content.Shared/Nutrition/Components/MessyDrinkerComponent.cs @@ -1,5 +1,6 @@ using Content.Shared.FixedPoint; using Content.Shared.Nutrition.Prototypes; +using Content.Shared.Tag; using Robust.Shared.GameStates; using Robust.Shared.Prototypes; @@ -26,6 +27,13 @@ public sealed partial class MessyDrinkerComponent : Component [DataField, AutoNetworkedField] public List> SpillableTypes = new List> { "Drink" }; + /// + /// Tag given to drinks that are immune to messy drinker. + /// For example, a spill-immune bottle. + /// + [DataField, AutoNetworkedField] + public ProtoId SpillImmuneTag = "MessyDrinkerImmune"; + [DataField, AutoNetworkedField] public LocId? SpillMessagePopup; } diff --git a/Content.Shared/Nutrition/EntitySystems/MessyDrinkerSystem.cs b/Content.Shared/Nutrition/EntitySystems/MessyDrinkerSystem.cs index bf084e6054d..d75e7bf0188 100644 --- a/Content.Shared/Nutrition/EntitySystems/MessyDrinkerSystem.cs +++ b/Content.Shared/Nutrition/EntitySystems/MessyDrinkerSystem.cs @@ -2,6 +2,7 @@ using Content.Shared.Fluids; using Content.Shared.Nutrition.Components; using Content.Shared.Popups; using Content.Shared.Random.Helpers; +using Content.Shared.Tag; using Robust.Shared.Random; using Robust.Shared.Timing; @@ -13,6 +14,7 @@ public sealed class MessyDrinkerSystem : EntitySystem [Dependency] private readonly SharedPuddleSystem _puddle = default!; [Dependency] private readonly SharedPopupSystem _popup = default!; [Dependency] private readonly IGameTiming _timing = default!; + [Dependency] private readonly TagSystem _tag = default!; public override void Initialize() { @@ -23,7 +25,11 @@ public sealed class MessyDrinkerSystem : EntitySystem private void OnIngested(Entity ent, ref IngestingEvent ev) { - if (ev.Split.Volume <= ent.Comp.SpillAmount) + if (_tag.HasTag(ev.Food, ent.Comp.SpillImmuneTag)) + return; + + // Cannot spill if you're being forced to drink. + if (ev.ForceFed) return; var proto = _ingestion.GetEdibleType(ev.Food); @@ -31,10 +37,6 @@ public sealed class MessyDrinkerSystem : EntitySystem if (proto == null || !ent.Comp.SpillableTypes.Contains(proto.Value)) return; - // Cannot spill if you're being forced to drink. - if (ev.ForceFed) - return; - // TODO: Replace with RandomPredicted once the engine PR is merged var seed = SharedRandomExtensions.HashCodeCombine(new() { (int)_timing.CurTick.Value, GetNetEntity(ent).Id }); var rand = new System.Random(seed); diff --git a/Resources/Prototypes/tags.yml b/Resources/Prototypes/tags.yml index 1131dd61fec..b6eaad9bfc0 100644 --- a/Resources/Prototypes/tags.yml +++ b/Resources/Prototypes/tags.yml @@ -934,6 +934,9 @@ - type: Tag id: Medkit +- type: Tag + id: MessyDrinkerImmune + - type: Tag id: Metal From f55ba79bb6f28bfecaba3ec8f9212b965fc72e4f Mon Sep 17 00:00:00 2001 From: Winkarst-cpu <74284083+Winkarst-cpu@users.noreply.github.com> Date: Sat, 30 Aug 2025 19:52:34 +0300 Subject: [PATCH 282/340] SharedKitchenSpikeSystem bugfixes (#39959) * Fixes * Update * Update --- .../Kitchen/SharedKitchenSpikeSystem.cs | 29 +++++++++++++++---- 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/Content.Shared/Kitchen/SharedKitchenSpikeSystem.cs b/Content.Shared/Kitchen/SharedKitchenSpikeSystem.cs index 3629539190a..e91b1c6d173 100644 --- a/Content.Shared/Kitchen/SharedKitchenSpikeSystem.cs +++ b/Content.Shared/Kitchen/SharedKitchenSpikeSystem.cs @@ -18,11 +18,11 @@ using Content.Shared.Mobs.Systems; using Content.Shared.Movement.Events; using Content.Shared.Nutrition.Components; using Content.Shared.Popups; +using Content.Shared.Random.Helpers; using Content.Shared.Throwing; using Content.Shared.Verbs; using Robust.Shared.Audio.Systems; using Robust.Shared.Containers; -using Robust.Shared.Random; using Robust.Shared.Serialization; using Robust.Shared.Timing; @@ -45,7 +45,6 @@ public sealed class SharedKitchenSpikeSystem : EntitySystem [Dependency] private readonly SharedAudioSystem _audioSystem = default!; [Dependency] private readonly SharedBodySystem _bodySystem = default!; [Dependency] private readonly IGameTiming _gameTiming = default!; - [Dependency] private readonly IRobustRandom _random = default!; public override void Initialize() { @@ -82,7 +81,7 @@ public sealed class SharedKitchenSpikeSystem : EntitySystem private void OnInit(Entity ent, ref ComponentInit args) { - ent.Comp.BodyContainer = _containerSystem.EnsureContainer(ent, ent.Comp.ContainerId); + ent.Comp.BodyContainer = _containerSystem.EnsureContainer(ent, ent.Comp.ContainerId); } private void OnInsertAttempt(Entity ent, ref ContainerIsInsertingAttemptEvent args) @@ -95,15 +94,24 @@ public sealed class SharedKitchenSpikeSystem : EntitySystem private void OnEntInsertedIntoContainer(Entity ent, ref EntInsertedIntoContainerMessage args) { + if (_gameTiming.ApplyingState) + return; + EnsureComp(args.Entity); _damageableSystem.TryChangeDamage(args.Entity, ent.Comp.SpikeDamage, true); + ent.Comp.NextDamage = _gameTiming.CurTime + ent.Comp.DamageInterval; + Dirty(ent); + // TODO: Add sprites for different species. _appearanceSystem.SetData(ent.Owner, KitchenSpikeVisuals.Status, KitchenSpikeStatus.Bloody); } private void OnEntRemovedFromContainer(Entity ent, ref EntRemovedFromContainerMessage args) { + if (_gameTiming.ApplyingState) + return; + RemComp(args.Entity); _damageableSystem.TryChangeDamage(args.Entity, ent.Comp.SpikeDamage, true); @@ -264,7 +272,7 @@ public sealed class SharedKitchenSpikeSystem : EntitySystem private void OnSpikeButcherDoAfter(Entity ent, ref SpikeButcherDoAfterEvent args) { - if (args.Handled || args.Cancelled || !args.Target.HasValue || !args.Used.HasValue || !TryComp(args.Target, out var butcherable) ) + if (args.Handled || args.Cancelled || !args.Target.HasValue || !args.Used.HasValue || !TryComp(args.Target, out var butcherable)) return; var victimIdentity = Identity.Entity(args.Target.Value, EntityManager); @@ -276,7 +284,11 @@ public sealed class SharedKitchenSpikeSystem : EntitySystem PopupType.MediumCaution); // Get a random entry to spawn. - var index = _random.Next(butcherable.SpawnedEntities.Count); + // TODO: Replace with RandomPredicted once the engine PR is merged + var seed = SharedRandomExtensions.HashCodeCombine(new() { (int)_gameTiming.CurTick.Value, GetNetEntity(ent).Id }); + var rand = new System.Random(seed); + + var index = rand.Next(butcherable.SpawnedEntities.Count); var entry = butcherable.SpawnedEntities[index]; var uid = PredictedSpawnNextToOrDrop(entry.PrototypeId, ent); @@ -387,13 +399,18 @@ public sealed class SharedKitchenSpikeSystem : EntitySystem while (query.MoveNext(out var uid, out var kitchenSpike)) { + var contained = kitchenSpike.BodyContainer.ContainedEntity; + + if (!contained.HasValue) + continue; + if (kitchenSpike.NextDamage > _gameTiming.CurTime) continue; kitchenSpike.NextDamage += kitchenSpike.DamageInterval; Dirty(uid, kitchenSpike); - _damageableSystem.TryChangeDamage(kitchenSpike.BodyContainer.ContainedEntity, kitchenSpike.TimeDamage, true); + _damageableSystem.TryChangeDamage(contained, kitchenSpike.TimeDamage, true); } } From 6803e48114dff360da4b5183dc2a384e6f893bc3 Mon Sep 17 00:00:00 2001 From: Kowlin <10947836+Kowlin@users.noreply.github.com> Date: Sat, 30 Aug 2025 19:17:49 +0200 Subject: [PATCH 283/340] Stop derelict borgs from duplicating their ghost roles. (#39992) Add reregister to derelict borgs --- Resources/Prototypes/Entities/Mobs/Player/silicon.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Resources/Prototypes/Entities/Mobs/Player/silicon.yml b/Resources/Prototypes/Entities/Mobs/Player/silicon.yml index f2108770611..016fe1be229 100644 --- a/Resources/Prototypes/Entities/Mobs/Player/silicon.yml +++ b/Resources/Prototypes/Entities/Mobs/Player/silicon.yml @@ -522,6 +522,7 @@ rules: ghost-role-information-silicon-rules raffle: settings: default + reregister: false - type: GhostTakeoverAvailable - type: entity @@ -557,6 +558,7 @@ rules: ghost-role-information-silicon-rules raffle: settings: default + reregister: false - type: GhostTakeoverAvailable - type: entity @@ -592,6 +594,7 @@ rules: ghost-role-information-silicon-rules raffle: settings: default + reregister: false - type: GhostTakeoverAvailable - type: entity @@ -628,6 +631,7 @@ rules: ghost-role-information-silicon-rules raffle: settings: default + reregister: false - type: GhostTakeoverAvailable - type: entity @@ -663,6 +667,7 @@ rules: ghost-role-information-silicon-rules raffle: settings: default + reregister: false - type: GhostTakeoverAvailable - type: entity @@ -697,4 +702,5 @@ rules: ghost-role-information-silicon-rules raffle: settings: default + reregister: false - type: GhostTakeoverAvailable From efdbdf0f19d658319aeac99bdfd616ff42b7e63f Mon Sep 17 00:00:00 2001 From: ScarKy0 <106310278+ScarKy0@users.noreply.github.com> Date: Sun, 31 Aug 2025 01:35:22 +0200 Subject: [PATCH 284/340] Nullable messydrinker tag (#40002) init --- Content.Shared/Nutrition/Components/MessyDrinkerComponent.cs | 2 +- Content.Shared/Nutrition/EntitySystems/MessyDrinkerSystem.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Content.Shared/Nutrition/Components/MessyDrinkerComponent.cs b/Content.Shared/Nutrition/Components/MessyDrinkerComponent.cs index ea145019c2c..11342727994 100644 --- a/Content.Shared/Nutrition/Components/MessyDrinkerComponent.cs +++ b/Content.Shared/Nutrition/Components/MessyDrinkerComponent.cs @@ -32,7 +32,7 @@ public sealed partial class MessyDrinkerComponent : Component /// For example, a spill-immune bottle. ///
/// Determines how antagonist status/roletype is displayed. Based on AdminOverlayAntagFormats enum /// Binary: Roletypes of interest get an "ANTAG" label diff --git a/Resources/Locale/en-US/administration/ui/admin-logs.ftl b/Resources/Locale/en-US/administration/ui/admin-logs.ftl index 377bea6e84a..8c30863a55b 100644 --- a/Resources/Locale/en-US/administration/ui/admin-logs.ftl +++ b/Resources/Locale/en-US/administration/ui/admin-logs.ftl @@ -20,3 +20,18 @@ admin-logs-include-non-player = Include Non-players admin-logs-search-logs-placeholder = Search Logs admin-logs-refresh = Refresh admin-logs-next = Next +admin-logs-render-rich-text = Render Rich Text +admin-logs-remove-markup = Remove Markup + +# Log Data Fields +admin-logs-field-type = Type +admin-logs-field-impact = Impact +admin-logs-field-time-header = Time +admin-logs-field-time-local = Local +admin-logs-field-time-utc = UTC +admin-logs-field-time-round = Round +admin-logs-field-players-header = Players + +# Log Player Fields +admin-logs-player-field-no-players = No Players +admin-logs-player-field-not-in-round = Not in round. diff --git a/Resources/Locale/en-US/escape-menu/ui/options-menu.ftl b/Resources/Locale/en-US/escape-menu/ui/options-menu.ftl index 5f44ecdfcf8..9b8eed0e186 100644 --- a/Resources/Locale/en-US/escape-menu/ui/options-menu.ftl +++ b/Resources/Locale/en-US/escape-menu/ui/options-menu.ftl @@ -382,6 +382,9 @@ ui-options-admin-player-tab-color-setting-character = Colorize antag character n ui-options-admin-player-tab-color-setting-roletype = Colorize all role types ui-options-admin-player-tab-color-setting-both = Colorize both +ui-options-admin-logs-title = Admin Logs +ui-options-admin-logs-highlight-color = Highlight Color + ui-options-admin-overlay-title = Admin Overlay ui-options-admin-overlay-antag-format = Antag label style @@ -399,3 +402,4 @@ ui-options-admin-enable-overlay-starting-job = Show starting job ui-options-admin-overlay-merge-distance = Stack merge distance ui-options-admin-overlay-ghost-fade-distance = Ghost overlay fade range from mouse ui-options-admin-overlay-ghost-hide-distance = Ghost overlay hide range from mouse + From d9bb797d322698e1c6214c1f25af77a7bbf77a13 Mon Sep 17 00:00:00 2001 From: vitopigno <103512727+VitusVeit@users.noreply.github.com> Date: Wed, 4 Jun 2025 12:12:37 +0200 Subject: [PATCH 225/340] Add text highlighting (#31442) Heavy DeltaV modications by Vanessa Co-authored-by: ScarKy0 <106310278+ScarKy0@users.noreply.github.com> Co-authored-by: Hans Larsson Co-authored-by: Tobias Berger Co-authored-by: Vanessa --- .../Options/UI/OptionColorSlider.xaml | 0 .../Options/UI/OptionColorSlider.xaml.cs | 3 +- .../Options/UI/OptionsTabControlRow.xaml.cs | 65 ++++ .../Options/UI/Tabs/AccessibilityTab.xaml | 4 + .../Options/UI/Tabs/AccessibilityTab.xaml.cs | 2 + .../Chat/ChatUIController.Highlighting.cs | 164 ++++++++ .../Systems/Chat/ChatUIController.cs | 10 +- .../Chat/Controls/ChannelFilterPopup.xaml | 13 +- .../Chat/Controls/ChannelFilterPopup.xaml.cs | 30 +- .../Systems/Chat/Widgets/ChatBox.xaml.cs | 15 +- .../Options/UI/OptionsTabControlRow.xaml.cs | 20 - .../_DV/Options/UI/OptionsTabControls.cs | 56 --- .../_DV/Options/UI/Tabs/DeltaTab.xaml | 5 +- .../_DV/Options/UI/Tabs/DeltaTab.xaml.cs | 5 +- .../Systems/Chat/ChatUIController.cs | 151 +++----- .../Chat/Controls/ChannelFilterPopup.xaml.cs | 23 -- .../Chat/Controls/Widgets/ChatBox.xaml.cs | 9 - Content.Shared/CCVar/CCVars.Chat.cs | 19 + Content.Shared/_DV/CCVars/DCCVars.cs | 4 +- .../Locale/en-US/_DV/chat/highlights.ftl | 365 ++---------------- .../Locale/en-US/_DV/chat/ui/chat-box.ftl | 8 - .../en-US/_DV/escape-menu/options-menu.ftl | 5 - Resources/Locale/en-US/chat/highlights.ftl | 58 +++ Resources/Locale/en-US/chat/ui/chat-box.ftl | 9 + .../en-US/escape-menu/ui/options-menu.ftl | 3 + .../_DV/Catalog/Chat/highlights.yml | 329 ---------------- 26 files changed, 486 insertions(+), 889 deletions(-) rename Content.Client/{_DV => }/Options/UI/OptionColorSlider.xaml (100%) rename Content.Client/{_DV => }/Options/UI/OptionColorSlider.xaml.cs (91%) create mode 100644 Content.Client/UserInterface/Systems/Chat/ChatUIController.Highlighting.cs delete mode 100644 Content.Client/_DV/Options/UI/OptionsTabControlRow.xaml.cs delete mode 100644 Content.Client/_DV/Options/UI/OptionsTabControls.cs delete mode 100644 Content.Client/_DV/UserInterfaces/Systems/Chat/Controls/Widgets/ChatBox.xaml.cs create mode 100644 Resources/Locale/en-US/chat/highlights.ftl delete mode 100644 Resources/Prototypes/_DV/Catalog/Chat/highlights.yml diff --git a/Content.Client/_DV/Options/UI/OptionColorSlider.xaml b/Content.Client/Options/UI/OptionColorSlider.xaml similarity index 100% rename from Content.Client/_DV/Options/UI/OptionColorSlider.xaml rename to Content.Client/Options/UI/OptionColorSlider.xaml diff --git a/Content.Client/_DV/Options/UI/OptionColorSlider.xaml.cs b/Content.Client/Options/UI/OptionColorSlider.xaml.cs similarity index 91% rename from Content.Client/_DV/Options/UI/OptionColorSlider.xaml.cs rename to Content.Client/Options/UI/OptionColorSlider.xaml.cs index ec30ada8181..6f8f46a3b44 100644 --- a/Content.Client/_DV/Options/UI/OptionColorSlider.xaml.cs +++ b/Content.Client/Options/UI/OptionColorSlider.xaml.cs @@ -1,7 +1,8 @@ +using Content.Client.Options.UI; using Robust.Client.AutoGenerated; using Robust.Client.UserInterface; -namespace Content.Client._DV.Options.UI; +namespace Content.Client.Options.UI; /// /// Standard UI control used for color sliders in the options menu. Intended for use with . diff --git a/Content.Client/Options/UI/OptionsTabControlRow.xaml.cs b/Content.Client/Options/UI/OptionsTabControlRow.xaml.cs index 31dd9897f4e..ad262f94a26 100644 --- a/Content.Client/Options/UI/OptionsTabControlRow.xaml.cs +++ b/Content.Client/Options/UI/OptionsTabControlRow.xaml.cs @@ -121,6 +121,19 @@ public sealed partial class OptionsTabControlRow : Control return AddOption(new OptionSliderFloatCVar(this, _cfg, cVar, slider, min, max, scale, FormatPercent)); } + /// + /// Add a color slider option, backed by a simple string CVar. + /// + /// The CVar represented by the slider. + /// The UI control for the option. + /// The option instance backing the added option. + public OptionColorSliderCVar AddOptionColorSlider( + CVarDef cVar, + OptionColorSlider slider) + { + return AddOption(new OptionColorSliderCVar(this, _cfg, cVar, slider)); + } + /// /// Add a slider option, backed by a simple integer CVar. /// @@ -518,6 +531,58 @@ public sealed class OptionSliderFloatCVar : BaseOptionCVar } } +/// +/// Implementation of a CVar option that simply corresponds with a string . +/// +/// +public sealed class OptionColorSliderCVar : BaseOptionCVar +{ + private readonly OptionColorSlider _slider; + + protected override string Value + { + get => _slider.Slider.Color.ToHex(); + set + { + _slider.Slider.Color = Color.FromHex(value); + UpdateLabelColor(); + } + } + + /// + /// Creates a new instance of this type. + /// + /// + /// + /// It is generally more convenient to call overloads on + /// such as instead of instantiating this type directly. + /// + /// + /// The control row that owns this option. + /// The configuration manager to get and set values from. + /// The CVar that is being controlled by this option. + /// The UI control for the option. + public OptionColorSliderCVar( + OptionsTabControlRow controller, + IConfigurationManager cfg, + CVarDef cVar, + OptionColorSlider slider) : base(controller, cfg, cVar) + { + _slider = slider; + + slider.Slider.OnColorChanged += _ => + { + ValueChanged(); + UpdateLabelColor(); + }; + } + + private void UpdateLabelColor() + { + _slider.ExampleLabel.FontColorOverride = Color.FromHex(Value); + } +} + /// /// Implementation of a CVar option that simply corresponds with an integer . /// diff --git a/Content.Client/Options/UI/Tabs/AccessibilityTab.xaml b/Content.Client/Options/UI/Tabs/AccessibilityTab.xaml index 5041b498a0b..41fac83c598 100644 --- a/Content.Client/Options/UI/Tabs/AccessibilityTab.xaml +++ b/Content.Client/Options/UI/Tabs/AccessibilityTab.xaml @@ -14,6 +14,10 @@ + + /// - public void PopulateQueueList(IReadOnlyCollection> queue) + public void PopulateQueueList(IReadOnlyCollection queue) { QueueList.DisposeAllChildren(); var idx = 1; - foreach (var recipeProto in queue) + foreach (var batch in queue) { - var recipe = _prototypeManager.Index(recipeProto); - var queuedRecipeBox = new BoxContainer(); - queuedRecipeBox.Orientation = BoxContainer.LayoutOrientation.Horizontal; + var recipe = _prototypeManager.Index(batch.Recipe); - queuedRecipeBox.AddChild(GetRecipeDisplayControl(recipe)); + var itemName = _lathe.GetRecipeName(batch.Recipe); + string displayText; + if (batch.ItemsRequested > 1) + displayText = Loc.GetString("lathe-menu-item-batch", ("index", idx), ("name", itemName), ("printed", batch.ItemsPrinted), ("total", batch.ItemsRequested)); + else + displayText = Loc.GetString("lathe-menu-item-single", ("index", idx), ("name", itemName)); + + var queuedRecipeBox = new QueuedRecipeControl(displayText, idx - 1, GetRecipeDisplayControl(recipe)); + queuedRecipeBox.OnDeletePressed += s => QueueDeleteAction?.Invoke(s); + queuedRecipeBox.OnMoveUpPressed += s => QueueMoveUpAction?.Invoke(s); + queuedRecipeBox.OnMoveDownPressed += s => QueueMoveDownAction?.Invoke(s); - var queuedRecipeLabel = new Label(); - queuedRecipeLabel.Text = $"{idx}. {_lathe.GetRecipeName(recipe)}"; - queuedRecipeBox.AddChild(queuedRecipeLabel); QueueList.AddChild(queuedRecipeBox); idx++; } diff --git a/Content.Client/Lathe/UI/QueuedRecipeControl.xaml b/Content.Client/Lathe/UI/QueuedRecipeControl.xaml new file mode 100644 index 00000000000..b1d4b496a14 --- /dev/null +++ b/Content.Client/Lathe/UI/QueuedRecipeControl.xaml @@ -0,0 +1,35 @@ + + + + + diff --git a/Content.Client/Lathe/UI/QueuedRecipeControl.xaml.cs b/Content.Client/Lathe/UI/QueuedRecipeControl.xaml.cs new file mode 100644 index 00000000000..c4ba9803b0d --- /dev/null +++ b/Content.Client/Lathe/UI/QueuedRecipeControl.xaml.cs @@ -0,0 +1,36 @@ +using Robust.Client.AutoGenerated; +using Robust.Client.UserInterface; +using Robust.Client.UserInterface.XAML; + +namespace Content.Client.Lathe.UI; + +[GenerateTypedNameReferences] +public sealed partial class QueuedRecipeControl : Control +{ + public Action? OnDeletePressed; + public Action? OnMoveUpPressed; + public Action? OnMoveDownPressed; + + public QueuedRecipeControl(string displayText, int index, Control displayControl) + { + RobustXamlLoader.Load(this); + + RecipeName.Text = displayText; + RecipeDisplayContainer.AddChild(displayControl); + + MoveUp.OnPressed += (_) => + { + OnMoveUpPressed?.Invoke(index); + }; + + MoveDown.OnPressed += (_) => + { + OnMoveDownPressed?.Invoke(index); + }; + + Delete.OnPressed += (_) => + { + OnDeletePressed?.Invoke(index); + }; + } +} diff --git a/Content.Server/Lathe/LatheSystem.cs b/Content.Server/Lathe/LatheSystem.cs index 65072fb4ccb..226ee993c78 100644 --- a/Content.Server/Lathe/LatheSystem.cs +++ b/Content.Server/Lathe/LatheSystem.cs @@ -75,6 +75,9 @@ namespace Content.Server.Lathe SubscribeLocalEvent(OnLatheQueueRecipeMessage); SubscribeLocalEvent(OnLatheSyncRequestMessage); + SubscribeLocalEvent(OnLatheDeleteRequestMessage); + SubscribeLocalEvent(OnLatheMoveRequestMessage); + SubscribeLocalEvent(OnLatheAbortFabricationMessage); SubscribeLocalEvent((u, c, _) => UpdateUserInterfaceState(u, c)); SubscribeLocalEvent(OnMaterialAmountChanged); @@ -168,23 +171,32 @@ namespace Content.Server.Lathe return ev.Recipes.ToList(); } - public bool TryAddToQueue(EntityUid uid, LatheRecipePrototype recipe, LatheComponent? component = null) + public bool TryAddToQueue(EntityUid uid, LatheRecipePrototype recipe, int quantity, LatheComponent? component = null) { if (!Resolve(uid, ref component)) return false; - if (!CanProduce(uid, recipe, 1, component)) + if (quantity <= 0) + return false; + quantity = int.Min(quantity, MaxItemsPerRequest); + + if (!CanProduce(uid, recipe, quantity, component)) return false; foreach (var (mat, amount) in recipe.Materials) { var adjustedAmount = recipe.ApplyMaterialDiscount - ? (int) (-amount * component.MaterialUseMultiplier) + ? (int)(-amount * component.MaterialUseMultiplier) : -amount; + adjustedAmount *= quantity; _materialStorage.TryChangeMaterialAmount(uid, mat, adjustedAmount); } - component.Queue.Enqueue(recipe); + + if (component.Queue.Last is { } node && node.ValueRef.Recipe == recipe.ID) + node.ValueRef.ItemsRequested += quantity; + else + component.Queue.AddLast(new LatheRecipeBatch(recipe.ID, 0, quantity)); return true; } @@ -196,8 +208,11 @@ namespace Content.Server.Lathe if (component.CurrentRecipe != null || component.Queue.Count <= 0 || !this.IsPowered(uid, EntityManager)) return false; - var recipeProto = component.Queue.Dequeue(); - var recipe = _proto.Index(recipeProto); + var batch = component.Queue.First(); + batch.ItemsPrinted++; + if (batch.ItemsPrinted >= batch.ItemsRequested || batch.ItemsPrinted < 0) // Rollover sanity check + component.Queue.RemoveFirst(); + var recipe = _proto.Index(batch.Recipe); var time = _reagentSpeed.ApplySpeed(uid, recipe.CompleteTime) * component.TimeMultiplier; @@ -273,8 +288,8 @@ namespace Content.Server.Lathe return; var producing = component.CurrentRecipe; - if (producing == null && component.Queue.TryPeek(out var next)) - producing = next; + if (producing == null && component.Queue.First is { } node) + producing = node.Value.Recipe; var state = new LatheUpdateState(GetAvailableRecipes(uid, component), component.Queue.ToArray(), producing); _uiSys.SetUiState(uid, LatheUiKey.Key, state); @@ -351,12 +366,10 @@ namespace Content.Server.Lathe { if (!args.Powered) { - RemComp(uid); - UpdateRunningAppearance(uid, false); + AbortProduction(uid); } - else if (component.CurrentRecipe != null) + else { - EnsureComp(uid); TryStartProducing(uid, component); } } @@ -418,25 +431,46 @@ namespace Content.Server.Lathe return GetAvailableRecipes(uid, component).Contains(recipe.ID); } + public void AbortProduction(EntityUid uid, LatheComponent? component = null) + { + if (!Resolve(uid, ref component)) + return; + + if (component.CurrentRecipe != null) + { + if (component.Queue.Count > 0) + { + // Batch abandoned while printing last item, need to create a one-item batch + var batch = component.Queue.First(); + if (batch.Recipe != component.CurrentRecipe) + { + var newBatch = new LatheRecipeBatch(component.CurrentRecipe.Value, 0, 1); + component.Queue.AddFirst(newBatch); + } + else if (batch.ItemsPrinted > 0) + { + batch.ItemsPrinted--; + } + } + + component.CurrentRecipe = null; + } + RemCompDeferred(uid); + UpdateUserInterfaceState(uid, component); + UpdateRunningAppearance(uid, false); + } + #region UI Messages private void OnLatheQueueRecipeMessage(EntityUid uid, LatheComponent component, LatheQueueRecipeMessage args) { if (_proto.TryIndex(args.ID, out LatheRecipePrototype? recipe)) { - var count = 0; - for (var i = 0; i < args.Quantity; i++) - { - if (TryAddToQueue(uid, recipe, component)) - count++; - else - break; - } - if (count > 0) + if (TryAddToQueue(uid, recipe, args.Quantity, component)) { _adminLogger.Add(LogType.Action, LogImpact.Low, - $"{ToPrettyString(args.Actor):player} queued {count} {GetRecipeName(recipe)} at {ToPrettyString(uid):lathe}"); + $"{ToPrettyString(args.Actor):player} queued {args.Quantity} {GetRecipeName(recipe)} at {ToPrettyString(uid):lathe}"); } } TryStartProducing(uid, component); @@ -447,6 +481,92 @@ namespace Content.Server.Lathe { UpdateUserInterfaceState(uid, component); } + + /// + /// Removes a batch from the batch queue by index. + /// If the index given does not exist or is outside of the bounds of the lathe's batch queue, nothing happens. + /// + /// The lathe whose queue is being altered. + /// + /// + public void OnLatheDeleteRequestMessage(EntityUid uid, LatheComponent component, ref LatheDeleteRequestMessage args) + { + if (args.Index < 0 || args.Index >= component.Queue.Count) + return; + + var node = component.Queue.First; + for (int i = 0; i < args.Index; i++) + node = node?.Next; + + if (node == null) // Shouldn't happen with checks above. + return; + + var batch = node.Value; + _adminLogger.Add(LogType.Action, + LogImpact.Low, + $"{ToPrettyString(args.Actor):player} deleted a lathe job for ({batch.ItemsPrinted}/{batch.ItemsRequested}) {GetRecipeName(batch.Recipe)} at {ToPrettyString(uid):lathe}"); + + component.Queue.Remove(node); + UpdateUserInterfaceState(uid, component); + } + + public void OnLatheMoveRequestMessage(EntityUid uid, LatheComponent component, ref LatheMoveRequestMessage args) + { + if (args.Change == 0 || args.Index < 0 || args.Index >= component.Queue.Count) + return; + + // New index must be within the bounds of the batch. + var newIndex = args.Index + args.Change; + if (newIndex < 0 || newIndex >= component.Queue.Count) + return; + + var node = component.Queue.First; + for (int i = 0; i < args.Index; i++) + node = node?.Next; + + if (node == null) // Something went wrong. + return; + + if (args.Change > 0) + { + var newRelativeNode = node.Next; + for (int i = 1; i < args.Change; i++) // 1-indexed: starting from Next + newRelativeNode = newRelativeNode?.Next; + + if (newRelativeNode == null) // Something went wrong. + return; + + component.Queue.Remove(node); + component.Queue.AddAfter(newRelativeNode, node); + } + else + { + var newRelativeNode = node.Previous; + for (int i = 1; i < -args.Change; i++) // 1-indexed: starting from Previous + newRelativeNode = newRelativeNode?.Previous; + + if (newRelativeNode == null) // Something went wrong. + return; + + component.Queue.Remove(node); + component.Queue.AddBefore(newRelativeNode, node); + } + + UpdateUserInterfaceState(uid, component); + } + + public void OnLatheAbortFabricationMessage(EntityUid uid, LatheComponent component, ref LatheAbortFabricationMessage args) + { + if (component.CurrentRecipe == null) + return; + + _adminLogger.Add(LogType.Action, + LogImpact.Low, + $"{ToPrettyString(args.Actor):player} aborted printing {GetRecipeName(component.CurrentRecipe.Value)} at {ToPrettyString(uid):lathe}"); + + component.CurrentRecipe = null; + FinishProducing(uid, component); + } #endregion } } diff --git a/Content.Shared/Lathe/LatheComponent.cs b/Content.Shared/Lathe/LatheComponent.cs index 26a164ae02b..e9e703048ab 100644 --- a/Content.Shared/Lathe/LatheComponent.cs +++ b/Content.Shared/Lathe/LatheComponent.cs @@ -26,10 +26,14 @@ namespace Content.Shared.Lathe // Otherwise the material arbitrage test and/or LatheSystem.GetAllBaseRecipes needs to be updated /// - /// The lathe's construction queue + /// The lathe's construction queue. /// + /// + /// This is a LinkedList to allow for constant time insertion/deletion (vs a List), and more efficient + /// moves (vs a Queue). + /// [DataField] - public Queue> Queue = new(); + public LinkedList Queue = new(); /// /// The sound that plays when the lathe is producing an item, if any @@ -103,6 +107,21 @@ namespace Content.Shared.Lathe } } + [Serializable] + public sealed partial class LatheRecipeBatch + { + public ProtoId Recipe; + public int ItemsPrinted; + public int ItemsRequested; + + public LatheRecipeBatch(ProtoId recipe, int itemsPrinted, int itemsRequested) + { + Recipe = recipe; + ItemsPrinted = itemsPrinted; + ItemsRequested = itemsRequested; + } + } + /// /// Event raised on a lathe when it starts producing a recipe. /// diff --git a/Content.Shared/Lathe/LatheMessages.cs b/Content.Shared/Lathe/LatheMessages.cs index 1c1c6440f11..fe72eed367e 100644 --- a/Content.Shared/Lathe/LatheMessages.cs +++ b/Content.Shared/Lathe/LatheMessages.cs @@ -10,11 +10,11 @@ public sealed class LatheUpdateState : BoundUserInterfaceState { public List> Recipes; - public ProtoId[] Queue; + public LatheRecipeBatch[] Queue; public ProtoId? CurrentlyProducing; - public LatheUpdateState(List> recipes, ProtoId[] queue, ProtoId? currentlyProducing = null) + public LatheUpdateState(List> recipes, LatheRecipeBatch[] queue, ProtoId? currentlyProducing = null) { Recipes = recipes; Queue = queue; @@ -46,6 +46,33 @@ public sealed class LatheQueueRecipeMessage : BoundUserInterfaceMessage } } +/// +/// Sent to the server to remove a batch from the queue. +/// +[Serializable, NetSerializable] +public sealed class LatheDeleteRequestMessage(int index) : BoundUserInterfaceMessage +{ + public int Index = index; +} + +/// +/// Sent to the server to move the position of a batch in the queue. +/// +[Serializable, NetSerializable] +public sealed class LatheMoveRequestMessage(int index, int change) : BoundUserInterfaceMessage +{ + public int Index = index; + public int Change = change; +} + +/// +/// Sent to the server to stop producing the current item. +/// +[Serializable, NetSerializable] +public sealed class LatheAbortFabricationMessage() : BoundUserInterfaceMessage +{ +} + [NetSerializable, Serializable] public enum LatheUiKey { diff --git a/Content.Shared/Lathe/PrototypeIdLinkedListSerializer.cs b/Content.Shared/Lathe/PrototypeIdLinkedListSerializer.cs new file mode 100644 index 00000000000..1c616ff1057 --- /dev/null +++ b/Content.Shared/Lathe/PrototypeIdLinkedListSerializer.cs @@ -0,0 +1,81 @@ +using Robust.Shared.Serialization; +using Robust.Shared.Serialization.Manager; +using Robust.Shared.Serialization.Markdown; +using Robust.Shared.Serialization.Markdown.Sequence; +using Robust.Shared.Serialization.Markdown.Validation; +using Robust.Shared.Serialization.TypeSerializers.Interfaces; + +namespace Content.Shared.Lathe; + +/// +/// Handles reading, writing, and validation for linked lists of prototypes. +/// +/// The type of prototype this linked list represents +/// +/// This is in the Content.Shared.Lathe namespace as there are no other LinkedList ProtoId instances. +/// +[TypeSerializer] +public sealed class LinkedListSerializer : ITypeSerializer, SequenceDataNode>, ITypeCopier> where T : class +{ + public ValidationNode Validate(ISerializationManager serializationManager, SequenceDataNode node, + IDependencyCollection dependencies, ISerializationContext? context = null) + { + var list = new List(); + + foreach (var elem in node.Sequence) + { + list.Add(serializationManager.ValidateNode(elem, context)); + } + + return new ValidatedSequenceNode(list); + } + + public DataNode Write(ISerializationManager serializationManager, LinkedList value, + IDependencyCollection dependencies, + bool alwaysWrite = false, + ISerializationContext? context = null) + { + var sequence = new SequenceDataNode(); + + foreach (var elem in value) + { + sequence.Add(serializationManager.WriteValue(elem, alwaysWrite, context)); + } + + return sequence; + } + + LinkedList ITypeReader, SequenceDataNode>.Read(ISerializationManager serializationManager, + SequenceDataNode node, + IDependencyCollection dependencies, + SerializationHookContext hookCtx, + ISerializationContext? context, ISerializationManager.InstantiationDelegate>? instanceProvider) + { + var list = instanceProvider != null ? instanceProvider() : new LinkedList(); + + foreach (var dataNode in node.Sequence) + { + list.AddLast(serializationManager.Read(dataNode, hookCtx, context)); + } + + return list; + } + + public void CopyTo( + ISerializationManager serializationManager, + LinkedList source, + ref LinkedList target, + IDependencyCollection dependencies, + SerializationHookContext hookCtx, + ISerializationContext? context = null) + { + target.Clear(); + using var enumerator = source.GetEnumerator(); + + while (enumerator.MoveNext()) + { + var current = enumerator.Current; + target.AddLast(current); + } + } +} diff --git a/Content.Shared/Lathe/SharedLatheSystem.cs b/Content.Shared/Lathe/SharedLatheSystem.cs index 524d83fd848..5942f4bf6c8 100644 --- a/Content.Shared/Lathe/SharedLatheSystem.cs +++ b/Content.Shared/Lathe/SharedLatheSystem.cs @@ -22,6 +22,7 @@ public abstract class SharedLatheSystem : EntitySystem [Dependency] private readonly EmagSystem _emag = default!; public readonly Dictionary> InverseRecipes = new(); + public const int MaxItemsPerRequest = 10_000; public override void Initialize() { @@ -86,6 +87,8 @@ public abstract class SharedLatheSystem : EntitySystem return false; if (!HasRecipe(uid, recipe, component)) return false; + if (amount <= 0) + return false; foreach (var (material, needed) in recipe.Materials) { diff --git a/Resources/Locale/en-US/lathe/ui/lathe-menu.ftl b/Resources/Locale/en-US/lathe/ui/lathe-menu.ftl index 076a70447cb..c04c0951626 100644 --- a/Resources/Locale/en-US/lathe/ui/lathe-menu.ftl +++ b/Resources/Locale/en-US/lathe/ui/lathe-menu.ftl @@ -29,3 +29,9 @@ lathe-menu-silo-linked-message = Silo Linked lathe-menu-fabricating-message = Fabricating... lathe-menu-materials-title = Materials lathe-menu-queue-title = Build Queue +lathe-menu-delete-fabricating-tooltip = Cancel printing the current item. +lathe-menu-delete-item-tooltip = Cancel printing this batch. +lathe-menu-move-up-tooltip = Move this batch ahead in the queue. +lathe-menu-move-down-tooltip = Move this batch back in the queue. +lathe-menu-item-single = {$index}. {$name} +lathe-menu-item-batch = {$index}. {$name} ({$printed}/{$total}) From 9d42f336db1c359deae0e2b56050361d7e08601b Mon Sep 17 00:00:00 2001 From: M4rchy-S <89603088+M4rchy-S@users.noreply.github.com> Date: Sun, 24 Aug 2025 23:46:23 +0300 Subject: [PATCH 241/340] Moving FlammableComponent to Shared (#39870) --- .../Administration/Systems/AdminVerbSystem.Smites.cs | 5 +---- Content.Server/Anomaly/Effects/PyroclasticAnomalySystem.cs | 2 +- Content.Server/EntityEffects/EntityEffectSystem.cs | 1 + Content.Server/Explosion/EntitySystems/ExplosionSystem.cs | 1 + Content.Server/NPC/Systems/NPCUtilitySystem.cs | 4 +--- .../Xenoarchaeology/Artifact/XAE/XAEIgniteSystem.cs | 2 +- .../Atmos/Components/FlammableComponent.cs | 5 +++-- 7 files changed, 9 insertions(+), 11 deletions(-) rename {Content.Server => Content.Shared}/Atmos/Components/FlammableComponent.cs (95%) diff --git a/Content.Server/Administration/Systems/AdminVerbSystem.Smites.cs b/Content.Server/Administration/Systems/AdminVerbSystem.Smites.cs index 578bda48cd8..854f58b9861 100644 --- a/Content.Server/Administration/Systems/AdminVerbSystem.Smites.cs +++ b/Content.Server/Administration/Systems/AdminVerbSystem.Smites.cs @@ -1,10 +1,8 @@ using System.Threading; using Content.Server.Administration.Components; -using Content.Server.Atmos.Components; using Content.Server.Atmos.EntitySystems; using Content.Server.Body.Components; using Content.Server.Body.Systems; -using Content.Server.Clothing.Systems; using Content.Server.Electrocution; using Content.Server.Explosion.EntitySystems; using Content.Server.GhostKick; @@ -19,6 +17,7 @@ using Content.Server.Tabletop; using Content.Server.Tabletop.Components; using Content.Shared.Administration; using Content.Shared.Administration.Components; +using Content.Shared.Atmos.Components; using Content.Shared.Body.Components; using Content.Shared.Body.Part; using Content.Shared.Clumsy; @@ -41,7 +40,6 @@ using Content.Shared.Nutrition.Components; using Content.Shared.Popups; using Content.Shared.Slippery; using Content.Shared.Storage.Components; -using Content.Shared.Stunnable; using Content.Shared.Tabletop.Components; using Content.Shared.Tools.Systems; using Content.Shared.Verbs; @@ -51,7 +49,6 @@ using Robust.Shared.Physics.Components; using Robust.Shared.Physics.Systems; using Robust.Shared.Player; using Robust.Shared.Random; -using Robust.Shared.Timing; using Robust.Shared.Utility; using Timer = Robust.Shared.Timing.Timer; diff --git a/Content.Server/Anomaly/Effects/PyroclasticAnomalySystem.cs b/Content.Server/Anomaly/Effects/PyroclasticAnomalySystem.cs index d38bda562bc..5ceb9888f4a 100644 --- a/Content.Server/Anomaly/Effects/PyroclasticAnomalySystem.cs +++ b/Content.Server/Anomaly/Effects/PyroclasticAnomalySystem.cs @@ -1,7 +1,7 @@ -using Content.Server.Atmos.Components; using Content.Server.Atmos.EntitySystems; using Content.Shared.Anomaly.Components; using Content.Shared.Anomaly.Effects.Components; +using Content.Shared.Atmos.Components; using Robust.Shared.Map; namespace Content.Server.Anomaly.Effects; diff --git a/Content.Server/EntityEffects/EntityEffectSystem.cs b/Content.Server/EntityEffects/EntityEffectSystem.cs index c460a1bc436..d7dbd11f9c7 100644 --- a/Content.Server/EntityEffects/EntityEffectSystem.cs +++ b/Content.Server/EntityEffects/EntityEffectSystem.cs @@ -25,6 +25,7 @@ using Content.Server.Traits.Assorted; using Content.Server.Xenoarchaeology.XenoArtifacts; using Content.Server.Zombies; using Content.Shared.Atmos; +using Content.Shared.Atmos.Components; using Content.Shared.Body.Components; using Content.Shared.Coordinates.Helpers; using Content.Shared.EntityEffects; diff --git a/Content.Server/Explosion/EntitySystems/ExplosionSystem.cs b/Content.Server/Explosion/EntitySystems/ExplosionSystem.cs index c50b1e53faa..fc31a770412 100644 --- a/Content.Server/Explosion/EntitySystems/ExplosionSystem.cs +++ b/Content.Server/Explosion/EntitySystems/ExplosionSystem.cs @@ -4,6 +4,7 @@ using Content.Server.Administration.Logs; using Content.Server.Atmos.Components; using Content.Server.NodeContainer.EntitySystems; using Content.Server.NPC.Pathfinding; +using Content.Shared.Atmos.Components; using Content.Shared.Camera; using Content.Shared.CCVar; using Content.Shared.Damage; diff --git a/Content.Server/NPC/Systems/NPCUtilitySystem.cs b/Content.Server/NPC/Systems/NPCUtilitySystem.cs index 5f077a06bb5..813626a1c44 100644 --- a/Content.Server/NPC/Systems/NPCUtilitySystem.cs +++ b/Content.Server/NPC/Systems/NPCUtilitySystem.cs @@ -1,4 +1,3 @@ -using Content.Server.Atmos.Components; using Content.Server.Fluids.EntitySystems; using Content.Server.Hands.Systems; using Content.Server.NPC.Queries; @@ -6,13 +5,11 @@ using Content.Server.NPC.Queries.Considerations; using Content.Server.NPC.Queries.Curves; using Content.Server.NPC.Queries.Queries; using Content.Server.Nutrition.Components; -using Content.Server.Nutrition.EntitySystems; using Content.Server.Temperature.Components; using Content.Shared.Chemistry.EntitySystems; using Content.Shared.Damage; using Content.Shared.Examine; using Content.Shared.Fluids.Components; -using Content.Shared.Hands.Components; using Content.Shared.Inventory; using Content.Shared.Mobs; using Content.Shared.Mobs.Systems; @@ -31,6 +28,7 @@ using Microsoft.Extensions.ObjectPool; using Robust.Server.Containers; using Robust.Shared.Prototypes; using Robust.Shared.Utility; +using Content.Shared.Atmos.Components; using System.Linq; namespace Content.Server.NPC.Systems; diff --git a/Content.Server/Xenoarchaeology/Artifact/XAE/XAEIgniteSystem.cs b/Content.Server/Xenoarchaeology/Artifact/XAE/XAEIgniteSystem.cs index 14270fb8662..7e8fff73ad3 100644 --- a/Content.Server/Xenoarchaeology/Artifact/XAE/XAEIgniteSystem.cs +++ b/Content.Server/Xenoarchaeology/Artifact/XAE/XAEIgniteSystem.cs @@ -1,6 +1,6 @@ -using Content.Server.Atmos.Components; using Content.Server.Atmos.EntitySystems; using Content.Server.Xenoarchaeology.Artifact.XAE.Components; +using Content.Shared.Atmos.Components; using Content.Shared.Xenoarchaeology.Artifact; using Content.Shared.Xenoarchaeology.Artifact.XAE; using Robust.Shared.Random; diff --git a/Content.Server/Atmos/Components/FlammableComponent.cs b/Content.Shared/Atmos/Components/FlammableComponent.cs similarity index 95% rename from Content.Server/Atmos/Components/FlammableComponent.cs rename to Content.Shared/Atmos/Components/FlammableComponent.cs index 9ae99a15136..acfb9e25401 100644 --- a/Content.Server/Atmos/Components/FlammableComponent.cs +++ b/Content.Shared/Atmos/Components/FlammableComponent.cs @@ -1,11 +1,12 @@ using Content.Shared.Alert; using Content.Shared.Damage; +using Robust.Shared.GameStates; using Robust.Shared.Physics.Collision.Shapes; using Robust.Shared.Prototypes; -namespace Content.Server.Atmos.Components +namespace Content.Shared.Atmos.Components { - [RegisterComponent] + [RegisterComponent, NetworkedComponent] public sealed partial class FlammableComponent : Component { [DataField] From 581f58ca04432fda21ad0346329fe5da12fc03e8 Mon Sep 17 00:00:00 2001 From: Vanessa Date: Fri, 21 Nov 2025 15:28:59 -0600 Subject: [PATCH 242/340] Updated FlammableComponent in a few DeltaV specific files to Shared --- .../Abilities/Psionics/Abilities/PyrokinesisPowerSystem.cs | 2 +- .../Nyanotrasen/StationEvents/Events/NoosphericFryRule.cs | 2 +- .../_EE/Silicon/Charge/Systems/SiliconChargeSystem.cs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/PyrokinesisPowerSystem.cs b/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/PyrokinesisPowerSystem.cs index b7a8a7097b5..fc299b2ac8a 100644 --- a/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/PyrokinesisPowerSystem.cs +++ b/Content.Server/Nyanotrasen/Abilities/Psionics/Abilities/PyrokinesisPowerSystem.cs @@ -1,6 +1,6 @@ using Content.Shared.Actions; using Content.Shared.Abilities.Psionics; -using Content.Server.Atmos.Components; +using Content.Shared.Atmos.Components; using Content.Server.Atmos.EntitySystems; using Content.Server.Popups; using Robust.Shared.Prototypes; diff --git a/Content.Server/Nyanotrasen/StationEvents/Events/NoosphericFryRule.cs b/Content.Server/Nyanotrasen/StationEvents/Events/NoosphericFryRule.cs index 36d51664550..70303c8851c 100644 --- a/Content.Server/Nyanotrasen/StationEvents/Events/NoosphericFryRule.cs +++ b/Content.Server/Nyanotrasen/StationEvents/Events/NoosphericFryRule.cs @@ -1,4 +1,4 @@ -using Content.Server.Atmos.Components; +using Content.Shared.Atmos.Components; using Content.Server.Atmos.EntitySystems; using Content.Server.Popups; using Content.Server.Power.Components; diff --git a/Content.Server/_EE/Silicon/Charge/Systems/SiliconChargeSystem.cs b/Content.Server/_EE/Silicon/Charge/Systems/SiliconChargeSystem.cs index 84cb526875d..489e9711154 100644 --- a/Content.Server/_EE/Silicon/Charge/Systems/SiliconChargeSystem.cs +++ b/Content.Server/_EE/Silicon/Charge/Systems/SiliconChargeSystem.cs @@ -3,7 +3,7 @@ using Content.Shared._EE.Silicon.Components; using Content.Server.Power.Components; using Content.Shared.Mobs.Systems; using Content.Server.Temperature.Components; -using Content.Server.Atmos.Components; +using Content.Shared.Atmos.Components; using Content.Server.Atmos.EntitySystems; using Content.Server.Popups; using Content.Shared.Popups; From d677e755cab1abfafdb1029f49bca298ef8aa30e Mon Sep 17 00:00:00 2001 From: Kyle Tyo <36606155+VerinSenpai@users.noreply.github.com> Date: Mon, 25 Aug 2025 09:49:27 -0400 Subject: [PATCH 243/340] Combine AdminFrozenSystem in shared. (#39885) commit --- .../Administration/Systems/AdminFrozenSystem.cs | 7 ------- .../Administration/Systems/AdminFrozenSystem.cs | 16 ---------------- .../Administration/AdminFrozenComponent.cs | 2 +- ...AdminFrozenSystem.cs => AdminFrozenSystem.cs} | 14 +++++++++++--- 4 files changed, 12 insertions(+), 27 deletions(-) delete mode 100644 Content.Client/Administration/Systems/AdminFrozenSystem.cs delete mode 100644 Content.Server/Administration/Systems/AdminFrozenSystem.cs rename Content.Shared/Administration/{SharedAdminFrozenSystem.cs => AdminFrozenSystem.cs} (91%) diff --git a/Content.Client/Administration/Systems/AdminFrozenSystem.cs b/Content.Client/Administration/Systems/AdminFrozenSystem.cs deleted file mode 100644 index 885585f985c..00000000000 --- a/Content.Client/Administration/Systems/AdminFrozenSystem.cs +++ /dev/null @@ -1,7 +0,0 @@ -using Content.Shared.Administration; - -namespace Content.Client.Administration.Systems; - -public sealed class AdminFrozenSystem : SharedAdminFrozenSystem -{ -} diff --git a/Content.Server/Administration/Systems/AdminFrozenSystem.cs b/Content.Server/Administration/Systems/AdminFrozenSystem.cs deleted file mode 100644 index baf7b682b85..00000000000 --- a/Content.Server/Administration/Systems/AdminFrozenSystem.cs +++ /dev/null @@ -1,16 +0,0 @@ -using Content.Shared.Administration; - -namespace Content.Server.Administration.Systems; - -public sealed class AdminFrozenSystem : SharedAdminFrozenSystem -{ - /// - /// Freezes and mutes the given entity. - /// - public void FreezeAndMute(EntityUid uid) - { - var comp = EnsureComp(uid); - comp.Muted = true; - Dirty(uid, comp); - } -} diff --git a/Content.Shared/Administration/AdminFrozenComponent.cs b/Content.Shared/Administration/AdminFrozenComponent.cs index bfcf1db5261..28df7c5fd07 100644 --- a/Content.Shared/Administration/AdminFrozenComponent.cs +++ b/Content.Shared/Administration/AdminFrozenComponent.cs @@ -2,7 +2,7 @@ namespace Content.Shared.Administration; -[RegisterComponent, Access(typeof(SharedAdminFrozenSystem))] +[RegisterComponent, Access(typeof(AdminFrozenSystem))] [NetworkedComponent, AutoGenerateComponentState] public sealed partial class AdminFrozenComponent : Component { diff --git a/Content.Shared/Administration/SharedAdminFrozenSystem.cs b/Content.Shared/Administration/AdminFrozenSystem.cs similarity index 91% rename from Content.Shared/Administration/SharedAdminFrozenSystem.cs rename to Content.Shared/Administration/AdminFrozenSystem.cs index 259df2bdf2a..7419137da81 100644 --- a/Content.Shared/Administration/SharedAdminFrozenSystem.cs +++ b/Content.Shared/Administration/AdminFrozenSystem.cs @@ -12,15 +12,13 @@ using Content.Shared.Throwing; namespace Content.Shared.Administration; // TODO deduplicate with BlockMovementComponent -public abstract class SharedAdminFrozenSystem : EntitySystem +public sealed class AdminFrozenSystem : EntitySystem { [Dependency] private readonly ActionBlockerSystem _blocker = default!; [Dependency] private readonly PullingSystem _pulling = default!; public override void Initialize() { - base.Initialize(); - SubscribeLocalEvent(OnAttempt); SubscribeLocalEvent(OnAttempt); SubscribeLocalEvent(OnAttempt); @@ -35,6 +33,16 @@ public abstract class SharedAdminFrozenSystem : EntitySystem SubscribeLocalEvent(OnSpeakAttempt); } + /// + /// Freezes and mutes the given entity. + /// + public void FreezeAndMute(EntityUid uid) + { + var comp = EnsureComp(uid); + comp.Muted = true; + Dirty(uid, comp); + } + private void OnInteractAttempt(Entity ent, ref InteractionAttemptEvent args) { args.Cancelled = true; From a1dcf2b66ce8aed89d23ff7f9328bb339e105f6e Mon Sep 17 00:00:00 2001 From: Princess Cheeseballs <66055347+Princess-Cheeseballs@users.noreply.github.com> Date: Mon, 25 Aug 2025 11:05:55 -0700 Subject: [PATCH 244/340] [Bugfix] Fix topical self healing time multiplier not working (#39883) * Commit * Fix 2 * Prettier --------- Co-authored-by: Princess Cheeseballs <66055347+Pronana@users.noreply.github.com> --- .../Medical/Healing/HealingComponent.cs | 2 +- .../Medical/Healing/HealingSystem.cs | 40 +++++++++++-------- 2 files changed, 25 insertions(+), 17 deletions(-) diff --git a/Content.Shared/Medical/Healing/HealingComponent.cs b/Content.Shared/Medical/Healing/HealingComponent.cs index 53358fd28d9..40fb1807002 100644 --- a/Content.Shared/Medical/Healing/HealingComponent.cs +++ b/Content.Shared/Medical/Healing/HealingComponent.cs @@ -43,7 +43,7 @@ public sealed partial class HealingComponent : Component /// How long it takes to apply the damage. /// [DataField, AutoNetworkedField] - public float Delay = 3f; + public TimeSpan Delay = TimeSpan.FromSeconds(3f); /// /// Delay multiplier when healing yourself. diff --git a/Content.Shared/Medical/Healing/HealingSystem.cs b/Content.Shared/Medical/Healing/HealingSystem.cs index 1837fd8fbfa..83a55aa72fc 100644 --- a/Content.Shared/Medical/Healing/HealingSystem.cs +++ b/Content.Shared/Medical/Healing/HealingSystem.cs @@ -117,10 +117,18 @@ public sealed class HealingSystem : EntitySystem _audio.PlayPredicted(healing.HealingEndSound, target.Owner, args.User); // Logic to determine the whether or not to repeat the healing action - args.Repeat = (HasDamage((args.Used.Value, healing), target) || IsPartDamaged(args.User, target)); // Shitmed Change - if (!args.Repeat && !dontRepeat) - _popupSystem.PopupClient(Loc.GetString("medical-item-finished-using", ("item", args.Used)), target.Owner, args.User); + args.Repeat = (HasDamage((args.Used.Value, healing), target) || IsPartDamaged(args.User, target)) && !dontRepeat; // Shitmed Change args.Handled = true; + + if (!args.Repeat) + { + _popupSystem.PopupClient(Loc.GetString("medical-item-finished-using", ("item", args.Used)), target.Owner, args.User); + return; + } + + // Update our self heal delay so it shortens as we heal more damage. + if (args.User == target.Owner) + args.Args.Delay = healing.Delay * GetScaledHealingPenalty(target.Owner, healing.SelfHealPenaltyMultiplier); } private bool HasDamage(Entity healing, Entity target) @@ -227,7 +235,7 @@ public sealed class HealingSystem : EntitySystem var delay = isNotSelf ? healing.Comp.Delay - : healing.Comp.Delay * GetScaledHealingPenalty(healing); + : healing.Comp.Delay * GetScaledHealingPenalty(target, healing.Comp.SelfHealPenaltyMultiplier); var doAfterEventArgs = new DoAfterArgs(EntityManager, user, delay, new HealingDoAfterEvent(), target, target: target, used: healing) @@ -246,21 +254,21 @@ public sealed class HealingSystem : EntitySystem /// /// Scales the self-heal penalty based on the amount of damage taken /// - /// - /// - /// - public float GetScaledHealingPenalty(Entity healing) + /// Entity we're healing + /// Maximum modifier we can have. + /// Modifier we multiply our healing time by + public float GetScaledHealingPenalty(Entity ent, float mod) { - var output = healing.Comp.Delay; - if (!TryComp(healing, out var mobThreshold) || - !TryComp(healing, out var damageable)) - return output; - if (!_mobThresholdSystem.TryGetThresholdForState(healing, MobState.Critical, out var amount, mobThreshold)) + if (!Resolve(ent, ref ent.Comp1, ref ent.Comp2, false)) + return mod; + + if (!_mobThresholdSystem.TryGetThresholdForState(ent, MobState.Critical, out var amount, ent.Comp2)) return 1; - var percentDamage = (float)(damageable.TotalDamage / amount); + var percentDamage = (float)(ent.Comp1.TotalDamage / amount); //basically make it scale from 1 to the multiplier. - var modifier = percentDamage * (healing.Comp.SelfHealPenaltyMultiplier - 1) + 1; - return Math.Max(modifier, 1); + + var output = percentDamage * (mod - 1) + 1; + return Math.Max(output, 1); } } From ec7ca3bdeaee166c7f43c4729f80fd9fa06745f4 Mon Sep 17 00:00:00 2001 From: ToastEnjoyer Date: Mon, 25 Aug 2025 19:44:01 -0500 Subject: [PATCH 245/340] Fixed pacified people using the laser carbine (#39891) --- .../Weapons/Guns/Battery/battery_guns.yml | 31 ++++++++++--------- .../Weapons/Guns/Battery/emergencylaser.yml | 2 +- 2 files changed, 18 insertions(+), 15 deletions(-) diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Battery/battery_guns.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Battery/battery_guns.yml index d3c73834d65..ca3866f4bdc 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Battery/battery_guns.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Battery/battery_guns.yml @@ -227,10 +227,10 @@ - type: Appearance - type: entity - name: practice laser carbine + name: laser carbine parent: [BaseWeaponBattery, BaseGunWieldable] - id: WeaponLaserCarbinePractice - description: This modified laser carbine fires nearly harmless beams in the 40-watt range, for target practice. + id: WeaponLaserCarbine + description: Favoured by Nanotrasen Security for being cheap and easy to use. components: - type: Item size: Large @@ -257,20 +257,23 @@ proto: RedLaserPractice fireCost: 50 #Delta-V was 62.5 - type: StaticPrice - price: 300 - - type: PacifismAllowedGun - -- type: entity - name: laser carbine - parent: [WeaponLaserCarbinePractice, BaseGunWieldable, BaseSecurityContraband] - id: WeaponLaserCarbine - description: Favoured by Nanotrasen Security for being cheap and easy to use. - components: + price: 420 + proto: RedLaser + fireCost: 62.5 - type: StaticPrice price: 420 + +- type: entity + name: practice laser carbine + parent: [WeaponLaserCarbine, BaseGunWieldable] + id: WeaponLaserCarbinePractice + description: This modified laser carbine fires nearly harmless beams in the 40-watt range, for target practice. + components: + - type: StaticPrice + price: 300 - type: HitscanBatteryAmmoProvider - proto: RedLaser - fireCost: 50 #Delta-V was 62.5 + proto: RedLaserPractice + fireCost: 62.5 - type: entity name: pulse pistol diff --git a/Resources/Prototypes/_Impstation/Entities/Objects/Weapons/Guns/Battery/emergencylaser.yml b/Resources/Prototypes/_Impstation/Entities/Objects/Weapons/Guns/Battery/emergencylaser.yml index 2c154bb2343..97ce3c16f6b 100644 --- a/Resources/Prototypes/_Impstation/Entities/Objects/Weapons/Guns/Battery/emergencylaser.yml +++ b/Resources/Prototypes/_Impstation/Entities/Objects/Weapons/Guns/Battery/emergencylaser.yml @@ -13,7 +13,7 @@ map: ["enum.GunVisualLayers.MagUnshaded"] shader: unshaded - type: StaticPrice - price: 420 + price: 300 - type: HitscanBatteryAmmoProvider proto: EmergencyRedLaser fireCost: 50 From ffe77c607199c89a01d46ca1cdefbdbf575ca9a9 Mon Sep 17 00:00:00 2001 From: Perry Fraser Date: Tue, 26 Aug 2025 06:29:12 -0400 Subject: [PATCH 246/340] fix: Block EntityStorage from inserting into mechs (#37942) This additionally moves the hard-coded check for HandsComp that previously did this, and moves it into an event which now both HandsSystem and MechSystem subscribe to. --- .../EntitySystems/SharedHandsSystem.Drop.cs | 10 ++++++++ .../Mech/EntitySystems/SharedMechSystem.cs | 23 +++++++++++++++---- .../Components/EntityStorageComponent.cs | 7 ++++++ .../SharedEntityStorageSystem.cs | 9 +++++--- 4 files changed, 42 insertions(+), 7 deletions(-) diff --git a/Content.Shared/Hands/EntitySystems/SharedHandsSystem.Drop.cs b/Content.Shared/Hands/EntitySystems/SharedHandsSystem.Drop.cs index c1b44efba47..6512bbd7f15 100644 --- a/Content.Shared/Hands/EntitySystems/SharedHandsSystem.Drop.cs +++ b/Content.Shared/Hands/EntitySystems/SharedHandsSystem.Drop.cs @@ -3,6 +3,7 @@ using Content.Shared.Database; using Content.Shared.Hands.Components; using Content.Shared.Interaction; using Content.Shared.Inventory.VirtualItem; +using Content.Shared.Storage.Components; using Content.Shared.Tag; using Robust.Shared.Containers; using Robust.Shared.Map; @@ -20,6 +21,7 @@ public abstract partial class SharedHandsSystem private void InitializeDrop() { SubscribeLocalEvent(HandleEntityRemoved); + SubscribeLocalEvent(OnEntityStorageDump); } protected virtual void HandleEntityRemoved(EntityUid uid, HandsComponent hands, EntRemovedFromContainerMessage args) @@ -39,6 +41,14 @@ public abstract partial class SharedHandsSystem _virtualSystem.DeleteVirtualItem((args.Entity, @virtual), uid); } + + private void OnEntityStorageDump(Entity ent, ref EntityStorageIntoContainerAttemptEvent args) + { + // If you're physically carrying an EntityStroage which tries to dump its contents out, + // we want those contents to fall to the floor. + args.Cancelled = true; + } + private bool ShouldIgnoreRestrictions(EntityUid user) { //Checks if the Entity is something that shouldn't care about drop distance or walls ie Aghost diff --git a/Content.Shared/Mech/EntitySystems/SharedMechSystem.cs b/Content.Shared/Mech/EntitySystems/SharedMechSystem.cs index 3ba9330ffcb..fa010f646d9 100644 --- a/Content.Shared/Mech/EntitySystems/SharedMechSystem.cs +++ b/Content.Shared/Mech/EntitySystems/SharedMechSystem.cs @@ -14,6 +14,7 @@ using Content.Shared.Mech.Equipment.Components; using Content.Shared.Movement.Components; using Content.Shared.Movement.Systems; using Content.Shared.Popups; +using Content.Shared.Storage.Components; using Content.Shared.Weapons.Melee; using Content.Shared.Whitelist; using Robust.Shared.Containers; @@ -64,6 +65,7 @@ public abstract partial class SharedMechSystem : EntitySystem SubscribeLocalEvent(RelayInteractionEvent); SubscribeLocalEvent(OnStartup); SubscribeLocalEvent(OnDestruction); + SubscribeLocalEvent(OnEntityStorageDump); SubscribeLocalEvent(OnGetAdditionalAccess); SubscribeLocalEvent(OnDragDrop); SubscribeLocalEvent(OnCanDragDrop); @@ -128,6 +130,12 @@ public abstract partial class SharedMechSystem : EntitySystem BreakMech(uid, component); } + private void OnEntityStorageDump(Entity entity, ref EntityStorageIntoContainerAttemptEvent args) + { + // There's no reason we should dump into /any/ of the mech's containers. + args.Cancelled = true; + } + private void OnGetAdditionalAccess(EntityUid uid, MechComponent component, ref GetAdditionalAccessEvent args) { var pilot = component.PilotSlot.ContainedEntity; @@ -171,7 +179,7 @@ public abstract partial class SharedMechSystem : EntitySystem } /// - /// Destroys the mech, removing the user and ejecting all installed equipment. + /// Destroys the mech, removing the user and ejecting anything contained. /// /// /// @@ -261,14 +269,19 @@ public abstract partial class SharedMechSystem : EntitySystem /// /// /// - /// Whether or not the removal can be cancelled + /// + /// Whether or not the removal can be cancelled, and if non-mech equipment should be ejected. + /// public void RemoveEquipment(EntityUid uid, EntityUid toRemove, MechComponent? component = null, MechEquipmentComponent? equipmentComponent = null, bool forced = false) { if (!Resolve(uid, ref component)) return; - if (!Resolve(toRemove, ref equipmentComponent)) + // When forced, we also want to handle the possibility that the "equipment" isn't actually equipment. + // This /shouldn't/ be possible thanks to OnEntityStorageDump, but there's been quite a few regressions + // with entities being hardlock stuck inside mechs. + if (!Resolve(toRemove, ref equipmentComponent) && !forced) return; if (!forced) @@ -285,7 +298,9 @@ public abstract partial class SharedMechSystem : EntitySystem if (component.CurrentSelectedEquipment == toRemove) CycleEquipment(uid, component); - equipmentComponent.EquipmentOwner = null; + if (forced && equipmentComponent != null) + equipmentComponent.EquipmentOwner = null; + _container.Remove(toRemove, component.EquipmentContainer); UpdateUserInterface(uid, component); } diff --git a/Content.Shared/Storage/Components/EntityStorageComponent.cs b/Content.Shared/Storage/Components/EntityStorageComponent.cs index 9d720e4736f..628cc85252c 100644 --- a/Content.Shared/Storage/Components/EntityStorageComponent.cs +++ b/Content.Shared/Storage/Components/EntityStorageComponent.cs @@ -166,6 +166,13 @@ public record struct InsertIntoEntityStorageAttemptEvent(EntityUid ItemToInsert, [ByRefEvent] public record struct EntityStorageInsertedIntoAttemptEvent(EntityUid ItemToInsert, bool Cancelled = false); +/// +/// Raised on the Container's owner whenever an entity storage tries to dump its +/// contents while within a container. +/// +[ByRefEvent] +public record struct EntityStorageIntoContainerAttemptEvent(BaseContainer Container, bool Cancelled = false); + [ByRefEvent] public record struct StorageOpenAttemptEvent(EntityUid User, bool Silent, bool Cancelled = false); diff --git a/Content.Shared/Storage/EntitySystems/SharedEntityStorageSystem.cs b/Content.Shared/Storage/EntitySystems/SharedEntityStorageSystem.cs index 6039d3b9407..066cd2d8861 100644 --- a/Content.Shared/Storage/EntitySystems/SharedEntityStorageSystem.cs +++ b/Content.Shared/Storage/EntitySystems/SharedEntityStorageSystem.cs @@ -305,10 +305,13 @@ public abstract class SharedEntityStorageSystem : EntitySystem _container.Remove(toRemove, component.Contents); - if (_container.IsEntityInContainer(container)) + if (_container.IsEntityInContainer(container) + && _container.TryGetOuterContainer(container, Transform(container), out var outerContainer)) { - if (_container.TryGetOuterContainer(container, Transform(container), out var outerContainer) && - !HasComp(outerContainer.Owner)) + + var attemptEvent = new EntityStorageIntoContainerAttemptEvent(outerContainer); + RaiseLocalEvent(outerContainer.Owner, ref attemptEvent); + if (!attemptEvent.Cancelled) { _container.Insert(toRemove, outerContainer); return true; From 6f8377683c7cddf32c1a41d040b99a7688e3e3e5 Mon Sep 17 00:00:00 2001 From: beck-thompson <107373427+beck-thompson@users.noreply.github.com> Date: Tue, 26 Aug 2025 07:18:10 -0700 Subject: [PATCH 247/340] Syndicate locks are now selectable (#39532) * Syndicate locks are now selectable * Minor tweaks * Make not syndicate themed * Address refview * review --------- Co-authored-by: slarticodefast <161409025+slarticodefast@users.noreply.github.com> --- .../SelectableComponentAdderComponent.cs | 77 +++++++++++++++ .../SelectableComponentAdderSystem.cs | 95 +++++++++++++++++++ .../Triggers/TriggerOnVoiceComponent.cs | 12 +-- .../Locale/en-US/locks/selectable-locks.ftl | 3 + .../Locale/en-US/locks/voice-trigger-lock.ftl | 3 + .../selectable-component.ftl | 1 + .../Entities/Objects/Devices/pda.yml | 2 +- .../Entities/Objects/Specific/locks.yml | 31 ++++-- .../Entities/Objects/Weapons/Melee/cane.yml | 2 +- .../Objects/Weapons/Melee/e_sword.yml | 2 +- Resources/Prototypes/chameleon.yml | 2 +- 11 files changed, 211 insertions(+), 19 deletions(-) create mode 100644 Content.Shared/SelectableComponentAdder/SelectableComponentAdderComponent.cs create mode 100644 Content.Shared/SelectableComponentAdder/SelectableComponentAdderSystem.cs create mode 100644 Resources/Locale/en-US/locks/selectable-locks.ftl create mode 100644 Resources/Locale/en-US/selectable-component/selectable-component.ftl diff --git a/Content.Shared/SelectableComponentAdder/SelectableComponentAdderComponent.cs b/Content.Shared/SelectableComponentAdder/SelectableComponentAdderComponent.cs new file mode 100644 index 00000000000..5b7ccffafbd --- /dev/null +++ b/Content.Shared/SelectableComponentAdder/SelectableComponentAdderComponent.cs @@ -0,0 +1,77 @@ +using Robust.Shared.GameStates; +using Robust.Shared.Prototypes; +using Robust.Shared.Serialization; + +namespace Content.Shared.SelectableComponentAdder; + +/// +/// Brings up a verb menu that allows players to select components that will get added to the item with this component. +/// +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +public sealed partial class SelectableComponentAdderComponent : Component +{ + /// + /// List of verb -> components to add for that verb when selected basically! + /// + [DataField(required: true)] + public List Entries = new(); + + /// + /// The amount of times players can make a selection and add a component. If null, there is no limit. + /// + [DataField, AutoNetworkedField] + public int? Selections; + + /// + /// The verb category name that will be used. + /// + [DataField, AutoNetworkedField] + public LocId VerbCategoryName = "selectable-component-adder-category-name"; +} + +[DataDefinition] +public sealed partial class ComponentAdderEntry +{ + /// + /// Name of the verb that will add the components in . + /// + [DataField(required: true)] + public LocId VerbName; + + /// + /// Popup to show when this option is selected. + /// + [DataField(required: true)] + public LocId? Popup; + + /// + /// List of all the components that will get added when the verb is selected. + /// + [DataField(required: true)] + public ComponentRegistry? ComponentsToAdd; + + /// + /// The type of behavior that occurs when the component(s) already exist on the entity. + /// + [DataField] + public ComponentExistsSetting ComponentExistsBehavior = ComponentExistsSetting.Skip; + + /// + /// The priorty of the verb in the list + /// + [DataField] + public int Priority; +} + +[Serializable, NetSerializable] +public enum ComponentExistsSetting : byte +{ + // If one of the components exist, skip adding it and continue adding the rest. + // If all components already exist, disable the verb. + Skip = 0, + // If a component already exists, replace it with the new one. + // The verb is always enabled. + Replace = 1, + // Disable the verb if any one of the components already exists. + Block = 2, +} diff --git a/Content.Shared/SelectableComponentAdder/SelectableComponentAdderSystem.cs b/Content.Shared/SelectableComponentAdder/SelectableComponentAdderSystem.cs new file mode 100644 index 00000000000..29619904d70 --- /dev/null +++ b/Content.Shared/SelectableComponentAdder/SelectableComponentAdderSystem.cs @@ -0,0 +1,95 @@ +using Content.Shared.Popups; +using Content.Shared.Verbs; +using Robust.Shared.Prototypes; + +namespace Content.Shared.SelectableComponentAdder; + +public sealed partial class SelectableComponentAdderSystem : EntitySystem +{ + [Dependency] private readonly SharedPopupSystem _popup = default!; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent>(OnGetVerb); + } + + private void OnGetVerb(Entity ent, ref GetVerbsEvent args) + { + if (!args.CanAccess || !args.CanInteract || ent.Comp.Selections <= 0) + return; + + var target = args.Target; + var user = args.User; + var verbCategory = new VerbCategory(ent.Comp.VerbCategoryName, null); + + foreach (var entry in ent.Comp.Entries) + { + var verb = new Verb + { + Priority = entry.Priority, + Category = verbCategory, + Disabled = CheckDisabled(target, entry.ComponentsToAdd, entry.ComponentExistsBehavior), + Act = () => + { + AddComponents(target, entry.ComponentsToAdd, entry.ComponentExistsBehavior); + ent.Comp.Selections--; + Dirty(ent); + if (entry.Popup == null) + return; + var message = Loc.GetString(entry.Popup.Value, ("target", target)); + _popup.PopupClient(message, target, user); + }, + Text = Loc.GetString(entry.VerbName), + }; + args.Verbs.Add(verb); + } + } + + private bool CheckDisabled(EntityUid target, ComponentRegistry? registry, ComponentExistsSetting setting) + { + if (registry == null) + return false; + + switch (setting) + { + case ComponentExistsSetting.Skip: + // disable the verb if all components already exist + foreach (var component in registry) + { + if (!EntityManager.HasComponent(target, Factory.GetComponent(component.Key).GetType())) + return false; + } + return true; + case ComponentExistsSetting.Replace: + // always allow the verb + return false; + case ComponentExistsSetting.Block: + // disable the verb if any component already exists. + foreach (var component in registry) + { + if (EntityManager.HasComponent(target, Factory.GetComponent(component.Key).GetType())) + return true; + } + return false; + default: + throw new NotImplementedException(); + } + } + + private void AddComponents(EntityUid target, ComponentRegistry? registry, ComponentExistsSetting setting) + { + if (registry == null || CheckDisabled(target, registry, setting)) + return; + + foreach (var component in registry) + { + if (EntityManager.HasComponent(target, Factory.GetComponent(component.Key).GetType()) && + setting is ComponentExistsSetting.Skip or ComponentExistsSetting.Block) + continue; + + EntityManager.AddComponent(target, component.Value, true); + } + } +} diff --git a/Content.Shared/Trigger/Components/Triggers/TriggerOnVoiceComponent.cs b/Content.Shared/Trigger/Components/Triggers/TriggerOnVoiceComponent.cs index 1fc3c1b966c..974d5322e02 100644 --- a/Content.Shared/Trigger/Components/Triggers/TriggerOnVoiceComponent.cs +++ b/Content.Shared/Trigger/Components/Triggers/TriggerOnVoiceComponent.cs @@ -60,36 +60,36 @@ public sealed partial class TriggerOnVoiceComponent : BaseTriggerOnXComponent /// /// The verb text that is shown when you can start recording a message. /// - [DataField] + [DataField, AutoNetworkedField] public LocId StartRecordingVerb = "trigger-on-voice-record"; /// /// The verb text that is shown when you can stop recording a message. /// - [DataField] + [DataField, AutoNetworkedField] public LocId StopRecordingVerb = "trigger-on-voice-stop"; /// /// Tooltip that appears when hovering over the stop or start recording verbs. /// - [DataField] + [DataField, AutoNetworkedField] public LocId? RecordingVerbMessage; /// /// The verb text that is shown when you can clear a recording. /// - [DataField] + [DataField, AutoNetworkedField] public LocId ClearRecordingVerb = "trigger-on-voice-clear"; /// /// The loc string that is shown when inspecting an uninitialized voice trigger. /// - [DataField] + [DataField, AutoNetworkedField] public LocId? InspectUninitializedLoc = "trigger-on-voice-uninitialized"; /// /// The loc string to use when inspecting voice trigger. Will also include the triggering phrase /// - [DataField] + [DataField, AutoNetworkedField] public LocId? InspectInitializedLoc = "trigger-on-voice-examine"; } diff --git a/Resources/Locale/en-US/locks/selectable-locks.ftl b/Resources/Locale/en-US/locks/selectable-locks.ftl new file mode 100644 index 00000000000..3dbf088505a --- /dev/null +++ b/Resources/Locale/en-US/locks/selectable-locks.ftl @@ -0,0 +1,3 @@ +selectable-lock-verb-category-name = Add lock +selectable-lock-verb-no-lock = No lock +selectable-lock-verb-no-lock-popup = No lock has been added to {THE($target)}. diff --git a/Resources/Locale/en-US/locks/voice-trigger-lock.ftl b/Resources/Locale/en-US/locks/voice-trigger-lock.ftl index fd2dc38d23e..a7069378f85 100644 --- a/Resources/Locale/en-US/locks/voice-trigger-lock.ftl +++ b/Resources/Locale/en-US/locks/voice-trigger-lock.ftl @@ -1,3 +1,6 @@ +voice-trigger-lock-add-verb = Voice Lock +voice-trigger-lock-add-verb-popup = A voice lock has been added to {THE($target)}. + voice-trigger-lock-verb-record = Record lock phrase voice-trigger-lock-verb-message = Locking the item will disable features that reveal its true nature! diff --git a/Resources/Locale/en-US/selectable-component/selectable-component.ftl b/Resources/Locale/en-US/selectable-component/selectable-component.ftl new file mode 100644 index 00000000000..f30c499f76e --- /dev/null +++ b/Resources/Locale/en-US/selectable-component/selectable-component.ftl @@ -0,0 +1 @@ +selectable-component-adder-category-name = Add feature diff --git a/Resources/Prototypes/Entities/Objects/Devices/pda.yml b/Resources/Prototypes/Entities/Objects/Devices/pda.yml index 3e25e30ac96..320c8e6b2d3 100644 --- a/Resources/Prototypes/Entities/Objects/Devices/pda.yml +++ b/Resources/Prototypes/Entities/Objects/Devices/pda.yml @@ -1530,7 +1530,7 @@ - NanoChatCartridge # DeltaV - type: entity - parent: [BasePDA, VoiceLock] + parent: [BasePDA, SelectableLock] id: ChameleonPDA name: passenger PDA description: Why isn't it gray? diff --git a/Resources/Prototypes/Entities/Objects/Specific/locks.yml b/Resources/Prototypes/Entities/Objects/Specific/locks.yml index 296b9fd7d9c..c280c4a60e7 100644 --- a/Resources/Prototypes/Entities/Objects/Specific/locks.yml +++ b/Resources/Prototypes/Entities/Objects/Specific/locks.yml @@ -1,5 +1,5 @@ - type: entity - id: VoiceLock + id: SelectableLock abstract: true components: - type: Lock @@ -11,14 +11,27 @@ useAccess: false unlockingSound: null # TODO: Maybe add sounds but just to the user? lockingSound: null + breakOnAccessBreaker: true # more fun lockTime: 0 unlockTime: 0 - - type: TriggerOnVoice - listenRange: 2 # more fun - startRecordingVerb: voice-trigger-lock-verb-record - recordingVerbMessage: voice-trigger-lock-verb-message - inspectUninitializedLoc: voice-trigger-lock-on-uninitialized - inspectInitializedLoc: voice-trigger-lock-on-examine - type: LockOnTrigger - - type: ActiveListener - - type: VoiceTriggerLock + - type: SelectableComponentAdder + selections: 1 + entries: + - verbName: selectable-lock-verb-no-lock + popup: selectable-lock-verb-no-lock-popup + priority: 0 + componentsToAdd: null + - verbName: voice-trigger-lock-add-verb + popup: voice-trigger-lock-add-verb-popup + priority: 1 + componentsToAdd: + - type: TriggerOnVoice + listenRange: 2 # more fun + startRecordingVerb: voice-trigger-lock-verb-record + recordingVerbMessage: voice-trigger-lock-verb-message + inspectUninitializedLoc: voice-trigger-lock-on-uninitialized + inspectInitializedLoc: voice-trigger-lock-on-examine + - type: ActiveListener + - type: VoiceTriggerLock + verbCategoryName: selectable-lock-verb-category-name diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Melee/cane.yml b/Resources/Prototypes/Entities/Objects/Weapons/Melee/cane.yml index 8b891a75333..fcf0b91f8ec 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Melee/cane.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Melee/cane.yml @@ -54,7 +54,7 @@ - type: DisarmMalus - type: entity - parent: [Cane, VoiceLock] + parent: [Cane, SelectableLock] id: CaneSheath suffix: Empty components: diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Melee/e_sword.yml b/Resources/Prototypes/Entities/Objects/Weapons/Melee/e_sword.yml index 345fcf282f0..d0e01aae5a2 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Melee/e_sword.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Melee/e_sword.yml @@ -170,7 +170,7 @@ - type: entity name: pen - parent: [BaseMeleeWeaponEnergy, VoiceLock] + parent: [BaseMeleeWeaponEnergy, SelectableLock] id: EnergyDagger suffix: E-Dagger description: 'A dark ink pen.' diff --git a/Resources/Prototypes/chameleon.yml b/Resources/Prototypes/chameleon.yml index 6969380621d..ed08c979b5c 100644 --- a/Resources/Prototypes/chameleon.yml +++ b/Resources/Prototypes/chameleon.yml @@ -1,6 +1,6 @@ # for clothing that can be toggled, like magboots - type: entity - parent: VoiceLock + parent: SelectableLock abstract: true id: BaseChameleon components: From d4340bdb685295f022cd62c448a41d35e095b792 Mon Sep 17 00:00:00 2001 From: InsoPL Date: Tue, 26 Aug 2025 21:32:45 +0200 Subject: [PATCH 248/340] Option to disable Crawling in Cvar (#39739) --- Content.Shared/CCVar/CCVars.Movement.cs | 8 ++++++++ Content.Shared/Stunnable/SharedStunSystem.Knockdown.cs | 9 ++++++--- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/Content.Shared/CCVar/CCVars.Movement.cs b/Content.Shared/CCVar/CCVars.Movement.cs index 37e355b0321..96ceada0994 100644 --- a/Content.Shared/CCVar/CCVars.Movement.cs +++ b/Content.Shared/CCVar/CCVars.Movement.cs @@ -56,4 +56,12 @@ public sealed partial class CCVars [CVarControl(AdminFlags.VarEdit)] public static readonly CVarDef MovementPushMassCap = CVarDef.Create("movement.push_mass_cap", 1.75f, CVar.SERVER | CVar.REPLICATED); + + /// + /// Is crawling enabled + /// + [CVarControl(AdminFlags.VarEdit)] + public static readonly CVarDef MovementCrawling = + CVarDef.Create("movement.crawling", true, CVar.SERVER | CVar.REPLICATED); + } diff --git a/Content.Shared/Stunnable/SharedStunSystem.Knockdown.cs b/Content.Shared/Stunnable/SharedStunSystem.Knockdown.cs index 1a7bc88ec32..3ab4791269d 100644 --- a/Content.Shared/Stunnable/SharedStunSystem.Knockdown.cs +++ b/Content.Shared/Stunnable/SharedStunSystem.Knockdown.cs @@ -1,5 +1,6 @@ -using Content.Shared.Alert; +using Content.Shared.Alert; using Content.Shared.Buckle.Components; +using Content.Shared.CCVar; using Content.Shared.Damage; using Content.Shared.Damage.Components; using Content.Shared.Database; @@ -13,6 +14,7 @@ using Content.Shared.Popups; using Content.Shared.Rejuvenate; using Content.Shared.Standing; using Robust.Shared.Audio; +using Robust.Shared.Configuration; using Robust.Shared.Input.Binding; using Robust.Shared.Physics; using Robust.Shared.Physics.Systems; @@ -33,6 +35,7 @@ public abstract partial class SharedStunSystem [Dependency] private readonly SharedPopupSystem _popup = default!; [Dependency] private readonly SharedPhysicsSystem _physics = default!; [Dependency] private readonly StandingStateSystem _standingState = default!; + [Dependency] private readonly IConfigurationManager _cfgManager = default!; public static readonly ProtoId KnockdownAlert = "Knockdown"; @@ -238,7 +241,7 @@ public abstract partial class SharedStunSystem private void ToggleKnockdown(Entity entity) { // We resolve here instead of using TryCrawling to be extra sure someone without crawler can't stand up early. - if (!Resolve(entity, ref entity.Comp1, false)) + if (!Resolve(entity, ref entity.Comp1, false) || !_cfgManager.GetCVar(CCVars.MovementCrawling)) return; if (!Resolve(entity, ref entity.Comp2, false)) @@ -263,7 +266,7 @@ public abstract partial class SharedStunSystem if (!KnockdownOver((entity, entity.Comp))) return false; - if (!_crawlerQuery.TryComp(entity, out var crawler)) + if (!_crawlerQuery.TryComp(entity, out var crawler) || !_cfgManager.GetCVar(CCVars.MovementCrawling)) { // If we can't crawl then just have us sit back up... // In case you're wondering, the KnockdownOverCheck, returns if we're able to move, so if next update is null. From 199dff258fa8e08a262ba0a5ef528b011f043322 Mon Sep 17 00:00:00 2001 From: slarticodefast <161409025+slarticodefast@users.noreply.github.com> Date: Tue, 26 Aug 2025 21:42:18 +0200 Subject: [PATCH 249/340] Remove the dynamic game mode from player votes (#39902) disable --- Resources/Prototypes/game_presets.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Resources/Prototypes/game_presets.yml b/Resources/Prototypes/game_presets.yml index 80de553c4f6..55ea7aa080a 100644 --- a/Resources/Prototypes/game_presets.yml +++ b/Resources/Prototypes/game_presets.yml @@ -112,7 +112,7 @@ - multiantag - director name: dynamic-title - showInVote: true + showInVote: false # admin-only for now until we fix some bugs description: dynamic-description rules: - DynamicRule From 8849ebae7ef83fb5c0d3822afe18ea104e1d2171 Mon Sep 17 00:00:00 2001 From: FungiFellow <151778459+FungiFellow@users.noreply.github.com> Date: Tue, 26 Aug 2025 16:59:23 -0400 Subject: [PATCH 250/340] Prevented Engiborgs from picking up AI lawboards (#39730) Update borg_modules.yml --- .../Entities/Objects/Specific/Robotics/borg_modules.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Resources/Prototypes/Entities/Objects/Specific/Robotics/borg_modules.yml b/Resources/Prototypes/Entities/Objects/Specific/Robotics/borg_modules.yml index 0eea2318623..34e64cb84cf 100644 --- a/Resources/Prototypes/Entities/Objects/Specific/Robotics/borg_modules.yml +++ b/Resources/Prototypes/Entities/Objects/Specific/Robotics/borg_modules.yml @@ -661,6 +661,9 @@ whitelist: components: - Circuitboard + blacklist: + components: + - SiliconLawProvider - hand: emptyRepresentative: MicroManipulatorStockPart emptyLabel: borg-slot-construction-empty From e014c9592d2a2e18340ce4d4c1b0480a5086cd98 Mon Sep 17 00:00:00 2001 From: beck-thompson <107373427+beck-thompson@users.noreply.github.com> Date: Tue, 26 Aug 2025 14:50:19 -0700 Subject: [PATCH 251/340] Fix chameleon backpacks not being able to be opened when locked (#39784) * Fix chameleon backpacks not being able to be opened when locked * rename --------- Co-authored-by: slarticodefast <161409025+slarticodefast@users.noreply.github.com> --- Content.Shared/Lock/LockSystem.cs | 7 ++++--- Content.Shared/Lock/LockedStorageComponent.cs | 10 ++++++++++ .../Specific/Xenoarchaeology/artifact_equipment.yml | 1 + .../Entities/Structures/Wallmounts/Storage/shelfs.yml | 1 + 4 files changed, 16 insertions(+), 3 deletions(-) create mode 100644 Content.Shared/Lock/LockedStorageComponent.cs diff --git a/Content.Shared/Lock/LockSystem.cs b/Content.Shared/Lock/LockSystem.cs index d69c1c6e48e..f60716d2946 100644 --- a/Content.Shared/Lock/LockSystem.cs +++ b/Content.Shared/Lock/LockSystem.cs @@ -48,11 +48,12 @@ public sealed class LockSystem : EntitySystem SubscribeLocalEvent(OnEmagged); SubscribeLocalEvent(OnDoAfterLock); SubscribeLocalEvent(OnDoAfterUnlock); - SubscribeLocalEvent(OnStorageInteractAttempt); + SubscribeLocalEvent(OnLockToggleAttempt); SubscribeLocalEvent(OnAttemptChangePanel); SubscribeLocalEvent(OnUnanchorAttempt); + SubscribeLocalEvent(OnStorageInteractAttempt); SubscribeLocalEvent(OnUIOpenAttempt); SubscribeLocalEvent(LockToggled); @@ -358,9 +359,9 @@ public sealed class LockSystem : EntitySystem TryUnlock(uid, args.User, skipDoAfter: true); } - private void OnStorageInteractAttempt(Entity ent, ref StorageInteractAttemptEvent args) + private void OnStorageInteractAttempt(Entity ent, ref StorageInteractAttemptEvent args) { - if (ent.Comp.Locked) + if (IsLocked(ent.Owner)) args.Cancelled = true; } diff --git a/Content.Shared/Lock/LockedStorageComponent.cs b/Content.Shared/Lock/LockedStorageComponent.cs new file mode 100644 index 00000000000..25d6dba381c --- /dev/null +++ b/Content.Shared/Lock/LockedStorageComponent.cs @@ -0,0 +1,10 @@ +using Content.Shared.Storage; +using Robust.Shared.GameStates; + +namespace Content.Shared.Lock; + +/// +/// Prevents using an entity's if its is locked. +/// +[RegisterComponent, NetworkedComponent] +public sealed partial class LockedStorageComponent : Component; diff --git a/Resources/Prototypes/Entities/Objects/Specific/Xenoarchaeology/artifact_equipment.yml b/Resources/Prototypes/Entities/Objects/Specific/Xenoarchaeology/artifact_equipment.yml index bdd042df57b..8352933f8bd 100644 --- a/Resources/Prototypes/Entities/Objects/Specific/Xenoarchaeology/artifact_equipment.yml +++ b/Resources/Prototypes/Entities/Objects/Specific/Xenoarchaeology/artifact_equipment.yml @@ -138,6 +138,7 @@ - type: AccessReader access: [["Research"], ["Cargo"]] - type: Lock + - type: LockedStorage - type: SuppressArtifactContainer - type: RadiationBlockingContainer resistance: 5 diff --git a/Resources/Prototypes/Entities/Structures/Wallmounts/Storage/shelfs.yml b/Resources/Prototypes/Entities/Structures/Wallmounts/Storage/shelfs.yml index aeceba8f2e8..dd3e7dd0a48 100644 --- a/Resources/Prototypes/Entities/Structures/Wallmounts/Storage/shelfs.yml +++ b/Resources/Prototypes/Entities/Structures/Wallmounts/Storage/shelfs.yml @@ -45,6 +45,7 @@ description: It looks as strong as reality itself. components: - type: Lock + - type: LockedStorage - type: LockVisuals - type: Sprite sprite: Structures/Storage/Shelfs/wood.rsi From b3dca0c7096605abb9e829f163f255ef974e19c1 Mon Sep 17 00:00:00 2001 From: ToastEnjoyer Date: Tue, 26 Aug 2025 18:43:49 -0500 Subject: [PATCH 252/340] Wizard can no longer teleport to arrivals (#39901) * Fixed pacified people using the laser carbine * Fix wizards being able to teleport to arrivals * Removed spaces that we causing fails * Made using the in game map editor this time --- Resources/Maps/Misc/terminal.yml | 178 +++++++++++++++++++++++++------ 1 file changed, 144 insertions(+), 34 deletions(-) diff --git a/Resources/Maps/Misc/terminal.yml b/Resources/Maps/Misc/terminal.yml index 8ca17b4ebcf..d2d767d121d 100644 --- a/Resources/Maps/Misc/terminal.yml +++ b/Resources/Maps/Misc/terminal.yml @@ -1,6 +1,17 @@ meta: - format: 6 - postmapinit: false + format: 7 + category: Map + engineVersion: 266.0.0 + forkId: "" + forkVersion: "" + time: 08/26/2025 19:28:14 + entityCount: 928 +maps: +- 638 +grids: +- 818 +orphans: [] +nullspace: [] tilemap: 0: Space 7: FloorAsteroidSand @@ -17,38 +28,48 @@ tilemap: entities: - proto: "" entities: + - uid: 638 + components: + - type: MetaData + name: Map Entity + - type: Transform + - type: Map + mapPaused: True + - type: GridTree + - type: Broadphase + - type: OccluderTree - uid: 818 components: - type: MetaData name: NT-EM Terminal - type: Transform - parent: invalid + parent: 638 - type: MapGrid chunks: -1,-1: ind: -1,-1 - tiles: AAAAAAAAeQAAAAAAHQAAAAAAWQAAAAAAHQAAAAADBwAAAAAAHQAAAAABWQAAAAACHQAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAHQAAAAABWQAAAAADHQAAAAAABwAAAAAAHQAAAAAAWQAAAAADHQAAAAADeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAHQAAAAABWQAAAAACHQAAAAADBwAAAAAAHQAAAAABWQAAAAADHQAAAAADeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAHQAAAAACWQAAAAAAHQAAAAAABwAAAAAAHQAAAAABWQAAAAAAHQAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAWQAAAAADWQAAAAACWQAAAAADWQAAAAACWQAAAAACeQAAAAAAeQAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAWQAAAAAAWQAAAAADTAAAAAAAWQAAAAADWQAAAAABeQAAAAAAeQAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAWQAAAAAAWQAAAAACWQAAAAAAWQAAAAAAWQAAAAADeQAAAAAAeQAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAWQAAAAADWQAAAAACTAAAAAAAWQAAAAADWQAAAAACeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAWQAAAAADWQAAAAACWQAAAAAAWQAAAAAAWQAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAWQAAAAACWQAAAAAATAAAAAAAWQAAAAACWQAAAAACeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAWQAAAAAAWQAAAAADWQAAAAAAWQAAAAACWQAAAAABeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAWQAAAAADWQAAAAAAWQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAHQAAAAACWQAAAAABWQAAAAACWQAAAAACWQAAAAABWQAAAAABWQAAAAABeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAHQAAAAABWQAAAAAAWQAAAAAATAAAAAAAWQAAAAACWQAAAAACWQAAAAABeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAAAAAAAAAeQAAAAAAHQAAAAABWQAAAAAAWQAAAAACWQAAAAAAWQAAAAAAWQAAAAABWQAAAAADWQAAAAADWQAAAAADWQAAAAABWQAAAAABWQAAAAABWQAAAAADWQAAAAABAAAAAAAAeQAAAAAAHQAAAAABWQAAAAABWQAAAAABTAAAAAAAWQAAAAAATAAAAAAAWQAAAAACWQAAAAACWQAAAAACWQAAAAAAWQAAAAABWQAAAAACWQAAAAAAWQAAAAAD - version: 6 + tiles: AAAAAAAAAHkAAAAAAAAdAAAAAAAAWQAAAAAAAB0AAAAAAwAHAAAAAAAAHQAAAAABAFkAAAAAAgAdAAAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB5AAAAAAAAHQAAAAABAFkAAAAAAwAdAAAAAAAABwAAAAAAAB0AAAAAAABZAAAAAAMAHQAAAAADAHkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAAB0AAAAAAQBZAAAAAAIAHQAAAAADAAcAAAAAAAAdAAAAAAEAWQAAAAADAB0AAAAAAwB5AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHkAAAAAAAAdAAAAAAIAWQAAAAAAAB0AAAAAAAAHAAAAAAAAHQAAAAABAFkAAAAAAAAdAAAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAFkAAAAAAwBZAAAAAAIAWQAAAAADAFkAAAAAAgBZAAAAAAIAeQAAAAAAAHkAAAAAAAB5AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAABZAAAAAAAAWQAAAAADAEwAAAAAAABZAAAAAAMAWQAAAAABAHkAAAAAAAB5AAAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAWQAAAAAAAFkAAAAAAgBZAAAAAAAAWQAAAAAAAFkAAAAAAwB5AAAAAAAAeQAAAAAAAHkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAAFkAAAAAAwBZAAAAAAIATAAAAAAAAFkAAAAAAwBZAAAAAAIAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHkAAAAAAABZAAAAAAMAWQAAAAACAFkAAAAAAABZAAAAAAAAWQAAAAAAAHkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB5AAAAAAAAWQAAAAACAFkAAAAAAABMAAAAAAAAWQAAAAACAFkAAAAAAgB5AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAAFkAAAAAAABZAAAAAAMAWQAAAAAAAFkAAAAAAgBZAAAAAAEAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAWQAAAAADAFkAAAAAAABZAAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHkAAAAAAAAdAAAAAAIAWQAAAAABAFkAAAAAAgBZAAAAAAIAWQAAAAABAFkAAAAAAQBZAAAAAAEAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB5AAAAAAAAHQAAAAABAFkAAAAAAABZAAAAAAAATAAAAAAAAFkAAAAAAgBZAAAAAAIAWQAAAAABAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAAAAAAAAAAAeQAAAAAAAB0AAAAAAQBZAAAAAAAAWQAAAAACAFkAAAAAAABZAAAAAAAAWQAAAAABAFkAAAAAAwBZAAAAAAMAWQAAAAADAFkAAAAAAQBZAAAAAAEAWQAAAAABAFkAAAAAAwBZAAAAAAEAAAAAAAAAAHkAAAAAAAAdAAAAAAEAWQAAAAABAFkAAAAAAQBMAAAAAAAAWQAAAAAAAEwAAAAAAABZAAAAAAIAWQAAAAACAFkAAAAAAgBZAAAAAAAAWQAAAAABAFkAAAAAAgBZAAAAAAAAWQAAAAADAA== + version: 7 0,0: ind: 0,0 - tiles: WQAAAAADWQAAAAADWQAAAAACWQAAAAAAWQAAAAADWQAAAAAAWQAAAAABWQAAAAABWQAAAAACWQAAAAAAWQAAAAABWQAAAAADWQAAAAABeQAAAAAAAAAAAAAAAAAAAAAAWQAAAAACWQAAAAACWQAAAAABWQAAAAABWQAAAAAAeQAAAAAAWQAAAAABWQAAAAACWQAAAAACWQAAAAAAWQAAAAAAWQAAAAADWQAAAAACeQAAAAAAAAAAAAAAAAAAAAAAWQAAAAAAWQAAAAAAWQAAAAAAWQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAWQAAAAACWQAAAAADWQAAAAAAWQAAAAAAWQAAAAABeQAAAAAAeQAAAAAAAAAAAAAAAAAAAAAALwAAAAAALwAAAAAAeQAAAAAAaQAAAAAAeQAAAAAAeAAAAAAAeQAAAAAAWQAAAAAAWQAAAAACWQAAAAADWQAAAAAAWQAAAAACeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALwAAAAAALwAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeAAAAAAAeQAAAAAAeQAAAAAAWQAAAAABWQAAAAACWQAAAAAAeQAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALwAAAAAALwAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeAAAAAAAAAAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAaAAAAAAATQAAAAAAaAAAAAAAaAAAAAAAaQAAAAAAeAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeAAAAAAAeAAAAAAAeAAAAAAAeAAAAAAAeAAAAAAAeAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - version: 6 + tiles: WQAAAAADAFkAAAAAAwBZAAAAAAIAWQAAAAAAAFkAAAAAAwBZAAAAAAAAWQAAAAABAFkAAAAAAQBZAAAAAAIAWQAAAAAAAFkAAAAAAQBZAAAAAAMAWQAAAAABAHkAAAAAAAAAAAAAAAAAAAAAAAAAAFkAAAAAAgBZAAAAAAIAWQAAAAABAFkAAAAAAQBZAAAAAAAAeQAAAAAAAFkAAAAAAQBZAAAAAAIAWQAAAAACAFkAAAAAAABZAAAAAAAAWQAAAAADAFkAAAAAAgB5AAAAAAAAAAAAAAAAAAAAAAAAAABZAAAAAAAAWQAAAAAAAFkAAAAAAABZAAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAWQAAAAACAFkAAAAAAwBZAAAAAAAAWQAAAAAAAFkAAAAAAQB5AAAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAALwAAAAAAAC8AAAAAAAB5AAAAAAAAaQAAAAAAAHkAAAAAAAB4AAAAAAAAeQAAAAAAAFkAAAAAAABZAAAAAAIAWQAAAAADAFkAAAAAAABZAAAAAAIAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC8AAAAAAAAvAAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeAAAAAAAAHkAAAAAAAB5AAAAAAAAWQAAAAABAFkAAAAAAgBZAAAAAAAAeQAAAAAAAHkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAvAAAAAAAALwAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHgAAAAAAAAAAAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABoAAAAAAAATQAAAAAAAGgAAAAAAABoAAAAAAAAaQAAAAAAAHgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHgAAAAAAAB4AAAAAAAAeAAAAAAAAHgAAAAAAAB4AAAAAAAAeAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA== + version: 7 0,-1: ind: 0,-1 - tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAHQAAAAADWQAAAAABHQAAAAAABwAAAAAAHQAAAAABWQAAAAACHQAAAAADeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAHQAAAAACWQAAAAACHQAAAAAABwAAAAAAHQAAAAACWQAAAAADHQAAAAADeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAHQAAAAAAWQAAAAABHQAAAAADBwAAAAAAHQAAAAABWQAAAAAAHQAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAHQAAAAADWQAAAAADHQAAAAACBwAAAAAAHQAAAAADWQAAAAACHQAAAAABeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAWQAAAAAAWQAAAAADWQAAAAABWQAAAAADWQAAAAABeQAAAAAAeQAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAWQAAAAABWQAAAAACTAAAAAAAWQAAAAACWQAAAAACeQAAAAAAeQAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAWQAAAAAAWQAAAAAAWQAAAAAAWQAAAAADWQAAAAABeQAAAAAAeQAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAWQAAAAABWQAAAAAATAAAAAAAWQAAAAABWQAAAAABeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAWQAAAAACWQAAAAAAWQAAAAAAWQAAAAACWQAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAWQAAAAACWQAAAAAATAAAAAAAWQAAAAADWQAAAAADeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAWQAAAAABWQAAAAACWQAAAAAAWQAAAAAAWQAAAAACeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAWQAAAAABWQAAAAADWQAAAAADeQAAAAAAeQAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAWQAAAAABWQAAAAACWQAAAAACWQAAAAABWQAAAAAAWQAAAAADWQAAAAACeQAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAWQAAAAACWQAAAAABWQAAAAADWQAAAAAAWQAAAAADWQAAAAAAWQAAAAACeQAAAAAAAAAAAAAAAAAAAAAAWQAAAAABWQAAAAADWQAAAAADWQAAAAAAWQAAAAAAWQAAAAAAWQAAAAADWQAAAAAAWQAAAAACWQAAAAAAWQAAAAADWQAAAAACWQAAAAADeQAAAAAAAAAAAAAAAAAAAAAAWQAAAAADWQAAAAADWQAAAAABWQAAAAAAWQAAAAAAWQAAAAADWQAAAAADWQAAAAAAWQAAAAABWQAAAAAAWQAAAAAAWQAAAAAAWQAAAAACeQAAAAAAAAAAAAAAAAAAAAAA - version: 6 + tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB5AAAAAAAAHQAAAAADAFkAAAAAAQAdAAAAAAAABwAAAAAAAB0AAAAAAQBZAAAAAAIAHQAAAAADAHkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAAB0AAAAAAgBZAAAAAAIAHQAAAAAAAAcAAAAAAAAdAAAAAAIAWQAAAAADAB0AAAAAAwB5AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHkAAAAAAAAdAAAAAAAAWQAAAAABAB0AAAAAAwAHAAAAAAAAHQAAAAABAFkAAAAAAAAdAAAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB5AAAAAAAAHQAAAAADAFkAAAAAAwAdAAAAAAIABwAAAAAAAB0AAAAAAwBZAAAAAAIAHQAAAAABAHkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAABZAAAAAAAAWQAAAAADAFkAAAAAAQBZAAAAAAMAWQAAAAABAHkAAAAAAAB5AAAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAWQAAAAABAFkAAAAAAgBMAAAAAAAAWQAAAAACAFkAAAAAAgB5AAAAAAAAeQAAAAAAAHkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAFkAAAAAAABZAAAAAAAAWQAAAAAAAFkAAAAAAwBZAAAAAAEAeQAAAAAAAHkAAAAAAAB5AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHkAAAAAAABZAAAAAAEAWQAAAAAAAEwAAAAAAABZAAAAAAEAWQAAAAABAHkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB5AAAAAAAAWQAAAAACAFkAAAAAAABZAAAAAAAAWQAAAAACAFkAAAAAAAB5AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAAFkAAAAAAgBZAAAAAAAATAAAAAAAAFkAAAAAAwBZAAAAAAMAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHkAAAAAAABZAAAAAAEAWQAAAAACAFkAAAAAAABZAAAAAAAAWQAAAAACAHkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAFkAAAAAAQBZAAAAAAMAWQAAAAADAHkAAAAAAAB5AAAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB5AAAAAAAAWQAAAAABAFkAAAAAAgBZAAAAAAIAWQAAAAABAFkAAAAAAABZAAAAAAMAWQAAAAACAHkAAAAAAAAAAAAAAAAAAAAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAFkAAAAAAgBZAAAAAAEAWQAAAAADAFkAAAAAAABZAAAAAAMAWQAAAAAAAFkAAAAAAgB5AAAAAAAAAAAAAAAAAAAAAAAAAABZAAAAAAEAWQAAAAADAFkAAAAAAwBZAAAAAAAAWQAAAAAAAFkAAAAAAABZAAAAAAMAWQAAAAAAAFkAAAAAAgBZAAAAAAAAWQAAAAADAFkAAAAAAgBZAAAAAAMAeQAAAAAAAAAAAAAAAAAAAAAAAAAAWQAAAAADAFkAAAAAAwBZAAAAAAEAWQAAAAAAAFkAAAAAAABZAAAAAAMAWQAAAAADAFkAAAAAAABZAAAAAAEAWQAAAAAAAFkAAAAAAABZAAAAAAAAWQAAAAACAHkAAAAAAAAAAAAAAAAAAAAAAAAAAA== + version: 7 -1,0: ind: -1,0 - tiles: AAAAAAAAeQAAAAAAHQAAAAACWQAAAAABWQAAAAABWQAAAAADWQAAAAAAWQAAAAAAWQAAAAACWQAAAAAAWQAAAAAAWQAAAAABWQAAAAAAWQAAAAACWQAAAAACWQAAAAADAAAAAAAAeQAAAAAAHQAAAAADHQAAAAADHQAAAAACHQAAAAADHQAAAAACHQAAAAABHQAAAAACeQAAAAAAWQAAAAADWQAAAAAAWQAAAAAAWQAAAAADWQAAAAADWQAAAAAAAAAAAAAAeQAAAAAAeQAAAAAAJgAAAAAAJgAAAAAAJgAAAAAAJgAAAAAAJgAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAWQAAAAAAWQAAAAAAWQAAAAAAWQAAAAAAWQAAAAAAAAAAAAAAAAAAAAAAJgAAAAAAJgAAAAAAJgAAAAAAJgAAAAAAJgAAAAAAJgAAAAAAJgAAAAAAeAAAAAAAeQAAAAAAeQAAAAAAeQAAAAAALwAAAAAALwAAAAAALwAAAAAAAAAAAAAAAAAAAAAAJgAAAAAAJgAAAAAAJgAAAAAAJgAAAAAAJgAAAAAAJgAAAAAAJgAAAAAAeAAAAAAAeQAAAAAAeQAAAAAAeQAAAAAALwAAAAAALwAAAAAALwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJgAAAAAAJgAAAAAAJgAAAAAAJgAAAAAAJgAAAAAAAAAAAAAAeAAAAAAAeQAAAAAAeQAAAAAAeQAAAAAALwAAAAAALwAAAAAALwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeAAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeAAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeAAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeAAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeAAAAAAAeAAAAAAAeAAAAAAAeAAAAAAAeAAAAAAAeAAAAAAAeAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - version: 6 + tiles: AAAAAAAAAHkAAAAAAAAdAAAAAAIAWQAAAAABAFkAAAAAAQBZAAAAAAMAWQAAAAAAAFkAAAAAAABZAAAAAAIAWQAAAAAAAFkAAAAAAABZAAAAAAEAWQAAAAAAAFkAAAAAAgBZAAAAAAIAWQAAAAADAAAAAAAAAAB5AAAAAAAAHQAAAAADAB0AAAAAAwAdAAAAAAIAHQAAAAADAB0AAAAAAgAdAAAAAAEAHQAAAAACAHkAAAAAAABZAAAAAAMAWQAAAAAAAFkAAAAAAABZAAAAAAMAWQAAAAADAFkAAAAAAAAAAAAAAAAAeQAAAAAAAHkAAAAAAAAmAAAAAAAAJgAAAAAAACYAAAAAAAAmAAAAAAAAJgAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAFkAAAAAAABZAAAAAAAAWQAAAAAAAFkAAAAAAABZAAAAAAAAAAAAAAAAAAAAAAAAAAAmAAAAAAAAJgAAAAAAACYAAAAAAAAmAAAAAAAAJgAAAAAAACYAAAAAAAAmAAAAAAAAeAAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAC8AAAAAAAAvAAAAAAAALwAAAAAAAAAAAAAAAAAAAAAAAAAAJgAAAAAAACYAAAAAAAAmAAAAAAAAJgAAAAAAACYAAAAAAAAmAAAAAAAAJgAAAAAAAHgAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAAvAAAAAAAALwAAAAAAAC8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmAAAAAAAAJgAAAAAAACYAAAAAAAAmAAAAAAAAJgAAAAAAAAAAAAAAAAB4AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAALwAAAAAAAC8AAAAAAAAvAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeAAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHgAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB4AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeAAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHgAAAAAAAB4AAAAAAAAeAAAAAAAAHgAAAAAAAB4AAAAAAAAeAAAAAAAAHgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA== + version: 7 0,-2: ind: 0,-2 - tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAeQAAAAAAWQAAAAACWQAAAAADWQAAAAABeQAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAWQAAAAADWQAAAAAATAAAAAAAWQAAAAADWQAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAWQAAAAACWQAAAAABWQAAAAAAWQAAAAADWQAAAAADeQAAAAAAeQAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAWQAAAAADWQAAAAADTAAAAAAAWQAAAAADWQAAAAABeQAAAAAAeQAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAWQAAAAABWQAAAAABWQAAAAADWQAAAAABWQAAAAACeQAAAAAAeQAAAAAAeQAAAAAAAAAAAAAA - version: 6 + tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB5AAAAAAAAeQAAAAAAAFkAAAAAAgBZAAAAAAMAWQAAAAABAHkAAAAAAAB5AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAAFkAAAAAAwBZAAAAAAAATAAAAAAAAFkAAAAAAwBZAAAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAABZAAAAAAIAWQAAAAABAFkAAAAAAABZAAAAAAMAWQAAAAADAHkAAAAAAAB5AAAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAWQAAAAADAFkAAAAAAwBMAAAAAAAAWQAAAAADAFkAAAAAAQB5AAAAAAAAeQAAAAAAAHkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAFkAAAAAAQBZAAAAAAEAWQAAAAADAFkAAAAAAQBZAAAAAAIAeQAAAAAAAHkAAAAAAAB5AAAAAAAAAAAAAAAAAA== + version: 7 -1,-2: ind: -1,-2 - tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAeQAAAAAAWQAAAAABWQAAAAAAWQAAAAACeQAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAWQAAAAAAWQAAAAABTAAAAAAAWQAAAAADWQAAAAADeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAWQAAAAACWQAAAAABWQAAAAAAWQAAAAABWQAAAAABeQAAAAAAeQAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAWQAAAAADWQAAAAABTAAAAAAAWQAAAAABWQAAAAACeQAAAAAAeQAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAWQAAAAACWQAAAAADWQAAAAADWQAAAAADWQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - version: 6 + tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHkAAAAAAAB5AAAAAAAAWQAAAAABAFkAAAAAAABZAAAAAAIAeQAAAAAAAHkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB5AAAAAAAAWQAAAAAAAFkAAAAAAQBMAAAAAAAAWQAAAAADAFkAAAAAAwB5AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHkAAAAAAAB5AAAAAAAAeQAAAAAAAFkAAAAAAgBZAAAAAAEAWQAAAAAAAFkAAAAAAQBZAAAAAAEAeQAAAAAAAHkAAAAAAAB5AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAABZAAAAAAMAWQAAAAABAEwAAAAAAABZAAAAAAEAWQAAAAACAHkAAAAAAAB5AAAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAAHkAAAAAAAB5AAAAAAAAWQAAAAACAFkAAAAAAwBZAAAAAAMAWQAAAAADAFkAAAAAAAB5AAAAAAAAeQAAAAAAAHkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA== + version: 7 - type: Broadphase - type: Physics bodyStatus: InAir @@ -62,6 +83,7 @@ entities: id: Empty - type: OccluderTree - type: Shuttle + dampingModifier: 0.25 - type: Gravity gravityShakeSound: !type:SoundPathSpecifier path: /Audio/Effects/alert.ogg @@ -949,6 +971,7 @@ entities: - type: SpreaderGrid - type: GridPathfinding - type: Godmode + - type: ImplicitRoof - proto: AirlockExternalGlass entities: - uid: 2 @@ -1389,6 +1412,8 @@ entities: - type: BatterySelfRecharger autoRechargeRate: 50000 autoRecharge: True + - type: Fixtures + fixtures: {} missingComponents: - Construction - Destructible @@ -1404,6 +1429,8 @@ entities: - type: BatterySelfRecharger autoRechargeRate: 50000 autoRecharge: True + - type: Fixtures + fixtures: {} missingComponents: - Construction - Destructible @@ -1419,6 +1446,8 @@ entities: - type: BatterySelfRecharger autoRechargeRate: 50000 autoRecharge: True + - type: Fixtures + fixtures: {} missingComponents: - Construction - Destructible @@ -1434,6 +1463,8 @@ entities: - type: BatterySelfRecharger autoRechargeRate: 50000 autoRecharge: True + - type: Fixtures + fixtures: {} missingComponents: - Construction - Destructible @@ -1450,6 +1481,8 @@ entities: - type: BatterySelfRecharger autoRechargeRate: 50000 autoRecharge: True + - type: Fixtures + fixtures: {} missingComponents: - Construction - Destructible @@ -1465,6 +1498,8 @@ entities: - type: BatterySelfRecharger autoRechargeRate: 50000 autoRecharge: True + - type: Fixtures + fixtures: {} missingComponents: - Construction - Destructible @@ -1476,32 +1511,32 @@ entities: pos: -7.5,-5.5 parent: 818 - type: Godmode - missingComponents: - - Construction + - type: Fixtures + fixtures: {} - uid: 633 components: - type: Transform pos: 6.5,-5.5 parent: 818 - type: Godmode - missingComponents: - - Construction + - type: Fixtures + fixtures: {} - uid: 928 components: - type: Transform pos: -6.5,-14.5 parent: 818 - type: Godmode - missingComponents: - - Construction + - type: Fixtures + fixtures: {} - uid: 929 components: - type: Transform pos: 5.5,-14.5 parent: 818 - type: Godmode - missingComponents: - - Construction + - type: Fixtures + fixtures: {} - proto: AtmosDeviceFanTiny entities: - uid: 296 @@ -1566,9 +1601,11 @@ entities: pos: -10.5,5.5 parent: 818 - type: Godmode + - type: Fixtures + fixtures: {} missingComponents: - - ApcPowerReceiver - Destructible + - ApcPowerReceiver - proto: BlockGameArcade entities: - uid: 727 @@ -4380,6 +4417,8 @@ entities: pos: -5.5,2.5 parent: 818 - type: Godmode + - type: Fixtures + fixtures: {} missingComponents: - Destructible - Construction @@ -4391,6 +4430,8 @@ entities: pos: 4.5,2.5 parent: 818 - type: Godmode + - type: Fixtures + fixtures: {} missingComponents: - Destructible - Construction @@ -5142,6 +5183,8 @@ entities: pos: -6.5,-2.5 parent: 818 - type: Godmode + - type: Fixtures + fixtures: {} missingComponents: - Destructible - uid: 816 @@ -5150,6 +5193,8 @@ entities: pos: 5.5,-2.5 parent: 818 - type: Godmode + - type: Fixtures + fixtures: {} missingComponents: - Destructible - proto: FirelockEdge @@ -5477,6 +5522,15 @@ entities: missingComponents: - Anchorable - Destructible +- proto: GhostWarpPoint + entities: + - uid: 916 + components: + - type: MetaData + name: Terminal + - type: Transform + pos: -0.5,1.5 + parent: 818 - proto: GravityGeneratorMini entities: - uid: 808 @@ -6418,6 +6472,8 @@ entities: pos: -6.5,1.5 parent: 818 - type: Godmode + - type: Fixtures + fixtures: {} missingComponents: - Destructible - proto: PosterLegitEnlist @@ -6428,6 +6484,8 @@ entities: pos: -14.5,1.5 parent: 818 - type: Godmode + - type: Fixtures + fixtures: {} missingComponents: - Destructible - proto: PosterLegitHighClassMartini @@ -6438,6 +6496,8 @@ entities: pos: -6.5,-3.5 parent: 818 - type: Godmode + - type: Fixtures + fixtures: {} missingComponents: - Destructible - proto: PosterLegitJustAWeekAway @@ -6448,6 +6508,8 @@ entities: pos: 5.5,1.5 parent: 818 - type: Godmode + - type: Fixtures + fixtures: {} missingComponents: - Destructible - proto: PosterLegitNanomichiAd @@ -6458,6 +6520,8 @@ entities: pos: -4.5,3.5 parent: 818 - type: Godmode + - type: Fixtures + fixtures: {} missingComponents: - Destructible - proto: PosterLegitNanotrasenLogo @@ -6468,6 +6532,8 @@ entities: pos: -7.5,-11.5 parent: 818 - type: Godmode + - type: Fixtures + fixtures: {} missingComponents: - Destructible - uid: 247 @@ -6476,6 +6542,8 @@ entities: pos: -13.5,-4.5 parent: 818 - type: Godmode + - type: Fixtures + fixtures: {} missingComponents: - Destructible - uid: 248 @@ -6484,6 +6552,8 @@ entities: pos: 12.5,-4.5 parent: 818 - type: Godmode + - type: Fixtures + fixtures: {} missingComponents: - Destructible - uid: 249 @@ -6492,6 +6562,8 @@ entities: pos: 6.5,-16.5 parent: 818 - type: Godmode + - type: Fixtures + fixtures: {} missingComponents: - Destructible - uid: 250 @@ -6500,6 +6572,8 @@ entities: pos: -13.5,-16.5 parent: 818 - type: Godmode + - type: Fixtures + fixtures: {} missingComponents: - Destructible - uid: 251 @@ -6508,6 +6582,8 @@ entities: pos: 12.5,-11.5 parent: 818 - type: Godmode + - type: Fixtures + fixtures: {} missingComponents: - Destructible - uid: 922 @@ -6516,6 +6592,8 @@ entities: pos: -0.5,6.5 parent: 818 - type: Godmode + - type: Fixtures + fixtures: {} missingComponents: - Destructible - proto: PosterLegitNTTGC @@ -6526,6 +6604,8 @@ entities: pos: 5.5,-3.5 parent: 818 - type: Godmode + - type: Fixtures + fixtures: {} missingComponents: - Destructible - proto: PosterLegitPDAAd @@ -6536,6 +6616,8 @@ entities: pos: 12.5,-16.5 parent: 818 - type: Godmode + - type: Fixtures + fixtures: {} missingComponents: - Destructible - proto: PosterLegitVacation @@ -6546,6 +6628,8 @@ entities: pos: -7.5,-16.5 parent: 818 - type: Godmode + - type: Fixtures + fixtures: {} missingComponents: - Destructible - proto: PosterLegitWorkForAFuture @@ -6556,6 +6640,8 @@ entities: pos: 12.5,2.5 parent: 818 - type: Godmode + - type: Fixtures + fixtures: {} missingComponents: - Destructible - proto: PottedPlantRandom @@ -7540,6 +7626,8 @@ entities: pos: -2.5,-2.5 parent: 818 - type: Godmode + - type: Fixtures + fixtures: {} missingComponents: - Destructible - proto: SignNanotrasen2 @@ -7550,6 +7638,8 @@ entities: pos: -1.5,-2.5 parent: 818 - type: Godmode + - type: Fixtures + fixtures: {} missingComponents: - Destructible - proto: SignNanotrasen3 @@ -7560,6 +7650,8 @@ entities: pos: -0.5,-2.5 parent: 818 - type: Godmode + - type: Fixtures + fixtures: {} missingComponents: - Destructible - proto: SignNanotrasen4 @@ -7570,6 +7662,8 @@ entities: pos: 0.5,-2.5 parent: 818 - type: Godmode + - type: Fixtures + fixtures: {} missingComponents: - Destructible - proto: SignNanotrasen5 @@ -7580,6 +7674,8 @@ entities: pos: 1.5,-2.5 parent: 818 - type: Godmode + - type: Fixtures + fixtures: {} missingComponents: - Destructible - proto: SignNosmoking @@ -7590,6 +7686,8 @@ entities: pos: -7.5,2.5 parent: 818 - type: Godmode + - type: Fixtures + fixtures: {} missingComponents: - Destructible - proto: SignShipDock @@ -7600,6 +7698,8 @@ entities: pos: 6.5,-4.5 parent: 818 - type: Godmode + - type: Fixtures + fixtures: {} missingComponents: - Destructible - uid: 245 @@ -7608,6 +7708,8 @@ entities: pos: -7.5,-4.5 parent: 818 - type: Godmode + - type: Fixtures + fixtures: {} missingComponents: - Destructible - proto: SignSpace @@ -7618,6 +7720,8 @@ entities: pos: 12.5,-18.5 parent: 818 - type: Godmode + - type: Fixtures + fixtures: {} missingComponents: - Destructible - uid: 640 @@ -7626,6 +7730,8 @@ entities: pos: -7.5,-18.5 parent: 818 - type: Godmode + - type: Fixtures + fixtures: {} missingComponents: - Destructible - uid: 688 @@ -7634,6 +7740,8 @@ entities: pos: -13.5,-18.5 parent: 818 - type: Godmode + - type: Fixtures + fixtures: {} missingComponents: - Destructible - uid: 689 @@ -7642,6 +7750,8 @@ entities: pos: -7.5,-9.5 parent: 818 - type: Godmode + - type: Fixtures + fixtures: {} missingComponents: - Destructible - uid: 691 @@ -7650,6 +7760,8 @@ entities: pos: -13.5,-9.5 parent: 818 - type: Godmode + - type: Fixtures + fixtures: {} missingComponents: - Destructible - uid: 705 @@ -7658,6 +7770,8 @@ entities: pos: 12.5,-9.5 parent: 818 - type: Godmode + - type: Fixtures + fixtures: {} missingComponents: - Destructible - uid: 709 @@ -7666,6 +7780,8 @@ entities: pos: 6.5,-9.5 parent: 818 - type: Godmode + - type: Fixtures + fixtures: {} missingComponents: - Destructible - uid: 817 @@ -7674,6 +7790,8 @@ entities: pos: 6.5,-18.5 parent: 818 - type: Godmode + - type: Fixtures + fixtures: {} missingComponents: - Destructible - uid: 819 @@ -7682,6 +7800,8 @@ entities: pos: 4.5,7.5 parent: 818 - type: Godmode + - type: Fixtures + fixtures: {} missingComponents: - Destructible - proto: SinkWide @@ -9532,16 +9652,6 @@ entities: - type: Godmode missingComponents: - Destructible -- proto: WarpPoint - entities: - - uid: 638 - components: - - type: Transform - pos: -0.5,1.5 - parent: 818 - - type: WarpPoint - location: Terminal - - type: Godmode - proto: Windoor entities: - uid: 806 From b7752742dab9c61fcde51d9ef1d26b2afa62a67d Mon Sep 17 00:00:00 2001 From: GR1231 <200696955+GR1231@users.noreply.github.com> Date: Tue, 26 Aug 2025 02:48:31 +0200 Subject: [PATCH 253/340] Fix Smile's hat displacement map (#39824) Fix Smile's head displacement map --- .../Pets/Smile/smile_displacement.rsi/head.png | Bin 236 -> 318 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/Resources/Textures/Mobs/Pets/Smile/smile_displacement.rsi/head.png b/Resources/Textures/Mobs/Pets/Smile/smile_displacement.rsi/head.png index a579919824015b187ab41f3e38719b6591ea2f93..5cc098d50f2b9d57447f4adf14aca0892909c18f 100644 GIT binary patch literal 318 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=jKx9jPK-BC>eK@{Ea{HEjtmSN z`?>!lvI6-E$sR$z3=CCj3=9n|3=F@3LJcn%7)lKo7+xhXFj&oCU=S~uvn$XBD8ZKG z?e4@HbQwab7 literal 236 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=jKx9jP7LeL$-D$|mU+53hE&XX zdvhaiLjcc_3oM2vvWq_-uVDSglpgtV(|hCl4q<)g&$NEGWWB&Niz$QAmvKwOGKMIJ zU#y?xE8RQ;E{fJmA~rDd;JBZ=|VE}ETh0Drs~pzlh*-V%;4$j=d#Wz Gp$Pyua!d07 From e42fabbb7c22476aaad35c9b1c17704a397c6b38 Mon Sep 17 00:00:00 2001 From: Serylis of Five Date: Wed, 27 Aug 2025 00:26:13 +0200 Subject: [PATCH 254/340] Make Modular Grenades with Chemical payload respect their trigger delay (#39905) * adds `KeysIn` data field to `ChemicalPayloadComponent` And check when handling chemical payloads that a trigger key exists. * Update Content.Server/Payload/EntitySystems/PayloadSystem.cs --------- Co-authored-by: slarticodefast <161409025+slarticodefast@users.noreply.github.com> --- Content.Server/Payload/EntitySystems/PayloadSystem.cs | 4 +++- .../Payload/Components/ChemicalPayloadComponent.cs | 7 +++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/Content.Server/Payload/EntitySystems/PayloadSystem.cs b/Content.Server/Payload/EntitySystems/PayloadSystem.cs index 11e97c5b935..542c3559d52 100644 --- a/Content.Server/Payload/EntitySystems/PayloadSystem.cs +++ b/Content.Server/Payload/EntitySystems/PayloadSystem.cs @@ -150,7 +150,9 @@ public sealed class PayloadSystem : EntitySystem private void HandleChemicalPayloadTrigger(Entity entity, ref TriggerEvent args) { - // TODO: Adjust to the new trigger system + if (args.Key != null && !entity.Comp.KeysIn.Contains(args.Key)) + return; + if (entity.Comp.BeakerSlotA.Item is not EntityUid beakerA || entity.Comp.BeakerSlotB.Item is not EntityUid beakerB || !TryComp(beakerA, out FitsInDispenserComponent? compA) diff --git a/Content.Shared/Payload/Components/ChemicalPayloadComponent.cs b/Content.Shared/Payload/Components/ChemicalPayloadComponent.cs index d00382ee84e..3b29d787773 100644 --- a/Content.Shared/Payload/Components/ChemicalPayloadComponent.cs +++ b/Content.Shared/Payload/Components/ChemicalPayloadComponent.cs @@ -1,4 +1,5 @@ using Content.Shared.Containers.ItemSlots; +using Content.Shared.Trigger.Systems; using Robust.Shared.Serialization; namespace Content.Shared.Payload.Components; @@ -14,6 +15,12 @@ public sealed partial class ChemicalPayloadComponent : Component [DataField("beakerSlotB", required: true)] public ItemSlot BeakerSlotB = new(); + + /// + /// The keys that will activate the chemical payload. + /// + [DataField] + public List KeysIn = new() { TriggerSystem.DefaultTriggerKey }; } [Serializable, NetSerializable] From 7297cad90657762aa27425622bd6d8062309ef44 Mon Sep 17 00:00:00 2001 From: Princess Cheeseballs <66055347+Princess-Cheeseballs@users.noreply.github.com> Date: Wed, 27 Aug 2025 07:26:32 -0700 Subject: [PATCH 255/340] [Bugfix] Fix Cross Grid Magboots (#39910) * Augh * Remove that * ViewVariables property so it can be debugged at the very least. * Remove --------- Co-authored-by: Princess Cheeseballs <66055347+Pronana@users.noreply.github.com> --- Content.Shared/Clothing/MagbootsSystem.cs | 2 +- Content.Shared/Gravity/GravityAffectedComponent.cs | 2 +- Content.Shared/Gravity/SharedGravitySystem.cs | 5 +++-- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/Content.Shared/Clothing/MagbootsSystem.cs b/Content.Shared/Clothing/MagbootsSystem.cs index 58bc2f0796c..d00211fa656 100644 --- a/Content.Shared/Clothing/MagbootsSystem.cs +++ b/Content.Shared/Clothing/MagbootsSystem.cs @@ -52,7 +52,7 @@ public sealed class SharedMagbootsSystem : EntitySystem if (TryComp(user, out var moved)) moved.Enabled = !state; - _gravity.RefreshWeightless(user, !state); + _gravity.RefreshWeightless(user); if (state) _alerts.ShowAlert(user, ent.Comp.MagbootsAlert); diff --git a/Content.Shared/Gravity/GravityAffectedComponent.cs b/Content.Shared/Gravity/GravityAffectedComponent.cs index 2da7458b070..7991677759f 100644 --- a/Content.Shared/Gravity/GravityAffectedComponent.cs +++ b/Content.Shared/Gravity/GravityAffectedComponent.cs @@ -12,6 +12,6 @@ public sealed partial class GravityAffectedComponent : Component /// /// If true, this entity will be considered "weightless" /// - [DataField, AutoNetworkedField] + [ViewVariables, AutoNetworkedField] public bool Weightless = true; } diff --git a/Content.Shared/Gravity/SharedGravitySystem.cs b/Content.Shared/Gravity/SharedGravitySystem.cs index b54f9b21c8e..4ba312f4e08 100644 --- a/Content.Shared/Gravity/SharedGravitySystem.cs +++ b/Content.Shared/Gravity/SharedGravitySystem.cs @@ -92,7 +92,8 @@ public abstract partial class SharedGravitySystem : EntitySystem /// /// Overload of which also takes a bool for the weightlessness value we want to change to. - /// This method is LOAD BEARING for UninitializedSaveTest. DO NOT REMOVE IT. + /// This method should only be called if there is no chance something can override the weightless value you're trying to change to. + /// This is really only the case if you're applying a weightless value that overrides non-conditionally from events or are a grid with the gravity component. /// /// The entity we are updating the weightless status of /// The weightless value we are trying to change to, helps avoid needless networking @@ -142,7 +143,7 @@ public abstract partial class SharedGravitySystem : EntitySystem if (args.OldParent == args.Transform.GridUid) return; - RefreshWeightless((entity.Owner, entity.Comp), !EntityGridOrMapHaveGravity((entity, args.Transform))); + RefreshWeightless((entity.Owner, entity.Comp)); } private void OnBodyTypeChanged(Entity entity, ref PhysicsBodyTypeChangedEvent args) From b0f80ffa741efab21672afa93a135a4be893c9c4 Mon Sep 17 00:00:00 2001 From: SlamBamActionman <83650252+SlamBamActionman@users.noreply.github.com> Date: Wed, 27 Aug 2025 16:45:59 +0200 Subject: [PATCH 256/340] TriggerOnSimpleToolUsage and add tool locks to syndicate items (#39900) --- .../Components/SimpleToolUsageComponent.cs | 54 +++++++++++++++++++ .../Triggers/TriggerOnSimpleToolUsage.cs | 12 +++++ .../Trigger/Systems/TriggerOnToolUseSystem.cs | 21 ++++++++ .../Locale/en-US/locks/selectable-locks.ftl | 17 +++++- .../Locale/en-US/locks/voice-trigger-lock.ftl | 3 -- .../Entities/Objects/Specific/locks.yml | 46 +++++++++++++--- 6 files changed, 141 insertions(+), 12 deletions(-) create mode 100644 Content.Shared/Tools/Components/SimpleToolUsageComponent.cs create mode 100644 Content.Shared/Trigger/Components/Triggers/TriggerOnSimpleToolUsage.cs create mode 100644 Content.Shared/Trigger/Systems/TriggerOnToolUseSystem.cs diff --git a/Content.Shared/Tools/Components/SimpleToolUsageComponent.cs b/Content.Shared/Tools/Components/SimpleToolUsageComponent.cs new file mode 100644 index 00000000000..a425073ce8f --- /dev/null +++ b/Content.Shared/Tools/Components/SimpleToolUsageComponent.cs @@ -0,0 +1,54 @@ +using Content.Shared.DoAfter; +using Content.Shared.Tools.Systems; +using Robust.Shared.GameStates; +using Robust.Shared.Prototypes; +using Robust.Shared.Serialization; + +namespace Content.Shared.Tools.Components; + +/// +/// Component responsible for simple tool interactions. +/// Using a tool with the correct quality on an entity with this component will start a DoAfter and raise the other systems can subscribe to. +/// +[RegisterComponent, NetworkedComponent] +[Access(typeof(SimpleToolUsageSystem))] +public sealed partial class SimpleToolUsageComponent : Component +{ + /// + /// Tool quality required to use a tool on this. + /// + [DataField] + public ProtoId Quality = "Slicing"; + + /// + /// The duration using a tool on this entity will take in seconds. + /// + [DataField] + public float DoAfter = 5; + + /// + /// What verb should display to allow you to use a tool on this entity. + /// If null, no verb will be shown. + /// + [DataField] + public LocId? UsageVerb; + + /// + /// The message to show when the verb is disabled. + /// + [DataField] + public LocId BlockedMessage = "simple-tool-usage-blocked-message"; +} + +/// +/// Cancelable event that can be used to prevent tool interaction. +/// +[ByRefEvent] +public record struct AttemptSimpleToolUseEvent(EntityUid User, bool Cancelled = false); + +/// +/// Raised after the right tool is used on an entity with +/// and the DoAfter has finished. +/// +[Serializable, NetSerializable] +public sealed partial class SimpleToolDoAfterEvent : SimpleDoAfterEvent; diff --git a/Content.Shared/Trigger/Components/Triggers/TriggerOnSimpleToolUsage.cs b/Content.Shared/Trigger/Components/Triggers/TriggerOnSimpleToolUsage.cs new file mode 100644 index 00000000000..ffa60c35ee3 --- /dev/null +++ b/Content.Shared/Trigger/Components/Triggers/TriggerOnSimpleToolUsage.cs @@ -0,0 +1,12 @@ +using Content.Shared.Tools.Components; +using Robust.Shared.GameStates; + +namespace Content.Shared.Trigger.Components.Triggers; + +/// +/// Triggers an entity with when the correct tool +/// is used on it and the DoAfter has finished. +/// The user is the player using the tool. +/// +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +public sealed partial class TriggerOnSimpleToolUsageComponent : BaseTriggerOnXComponent; diff --git a/Content.Shared/Trigger/Systems/TriggerOnToolUseSystem.cs b/Content.Shared/Trigger/Systems/TriggerOnToolUseSystem.cs new file mode 100644 index 00000000000..01f612aadf6 --- /dev/null +++ b/Content.Shared/Trigger/Systems/TriggerOnToolUseSystem.cs @@ -0,0 +1,21 @@ +using Content.Shared.Tools.Components; +using Content.Shared.Trigger.Components.Triggers; + +namespace Content.Shared.Trigger.Systems; + +public sealed class TriggerOnToolUseSystem : EntitySystem +{ + [Dependency] private readonly TriggerSystem _trigger = default!; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnToolUse); + } + + private void OnToolUse(Entity ent, ref SimpleToolDoAfterEvent args) + { + _trigger.Trigger(ent.Owner, args.User, ent.Comp.KeyOut); + } +} diff --git a/Resources/Locale/en-US/locks/selectable-locks.ftl b/Resources/Locale/en-US/locks/selectable-locks.ftl index 3dbf088505a..574e784dd70 100644 --- a/Resources/Locale/en-US/locks/selectable-locks.ftl +++ b/Resources/Locale/en-US/locks/selectable-locks.ftl @@ -1,3 +1,16 @@ selectable-lock-verb-category-name = Add lock -selectable-lock-verb-no-lock = No lock -selectable-lock-verb-no-lock-popup = No lock has been added to {THE($target)}. + +selectable-lock-no-lock-verb = No lock +selectable-lock-no-lock-popup = No lock has been added to {THE($target)}. + +selectable-lock-voice-verb = Voice Lock +selectable-lock-voice-popup = A voice lock has been added to {THE($target)}. + +selectable-lock-tool-prying-verb = Tool Lock (Crowbar) +selectable-lock-tool-prying-popup = A prying tool lock has been added to {THE($target)}. + +selectable-lock-tool-screwing-verb = Tool Lock (Screwdriver) +selectable-lock-tool-screwing-popup = A screwing tool lock has been added to {THE($target)}. + +selectable-lock-tool-cutting-verb = Tool Lock (Wirecutter) +selectable-lock-tool-cutting-popup = A cutting tool lock has been added to {THE($target)}. diff --git a/Resources/Locale/en-US/locks/voice-trigger-lock.ftl b/Resources/Locale/en-US/locks/voice-trigger-lock.ftl index a7069378f85..fd2dc38d23e 100644 --- a/Resources/Locale/en-US/locks/voice-trigger-lock.ftl +++ b/Resources/Locale/en-US/locks/voice-trigger-lock.ftl @@ -1,6 +1,3 @@ -voice-trigger-lock-add-verb = Voice Lock -voice-trigger-lock-add-verb-popup = A voice lock has been added to {THE($target)}. - voice-trigger-lock-verb-record = Record lock phrase voice-trigger-lock-verb-message = Locking the item will disable features that reveal its true nature! diff --git a/Resources/Prototypes/Entities/Objects/Specific/locks.yml b/Resources/Prototypes/Entities/Objects/Specific/locks.yml index c280c4a60e7..bcb204cf488 100644 --- a/Resources/Prototypes/Entities/Objects/Specific/locks.yml +++ b/Resources/Prototypes/Entities/Objects/Specific/locks.yml @@ -15,18 +15,46 @@ lockTime: 0 unlockTime: 0 - type: LockOnTrigger + keysIn: [ lock ] - type: SelectableComponentAdder selections: 1 + verbCategoryName: selectable-lock-verb-category-name entries: - - verbName: selectable-lock-verb-no-lock - popup: selectable-lock-verb-no-lock-popup - priority: 0 - componentsToAdd: null - - verbName: voice-trigger-lock-add-verb - popup: voice-trigger-lock-add-verb-popup + - verbName: selectable-lock-tool-prying-verb + popup: selectable-lock-tool-prying-popup + priority: 4 + componentsToAdd: + - type: TriggerOnSimpleToolUsage + keyOut: lock + - type: SimpleToolUsage + quality: Prying + doAfter: 1 + - verbName: selectable-lock-tool-screwing-verb + popup: selectable-lock-tool-screwing-popup + priority: 3 + componentsToAdd: + - type: TriggerOnSimpleToolUsage + keyOut: lock + - type: SimpleToolUsage + quality: Screwing + doAfter: 1 + - verbName: selectable-lock-tool-cutting-verb + popup: selectable-lock-tool-cutting-popup + priority: 2 + componentsToAdd: + - type: TriggerOnSimpleToolUsage + keyOut: lock + - type: SimpleToolUsage + quality: Cutting + doAfter: 1 + # no anchoring since some objects might be anchorable + # no pulsing because it conflicts with the linking ability of the multitool + - verbName: selectable-lock-voice-verb + popup: selectable-lock-voice-popup priority: 1 componentsToAdd: - type: TriggerOnVoice + keyOut: lock listenRange: 2 # more fun startRecordingVerb: voice-trigger-lock-verb-record recordingVerbMessage: voice-trigger-lock-verb-message @@ -34,4 +62,8 @@ inspectInitializedLoc: voice-trigger-lock-on-examine - type: ActiveListener - type: VoiceTriggerLock - verbCategoryName: selectable-lock-verb-category-name + - verbName: selectable-lock-no-lock-verb + popup: selectable-lock-no-lock-popup + priority: 0 + componentsToAdd: null + From 66ada0ed93da5595802ab05dc146f42a768c2fa0 Mon Sep 17 00:00:00 2001 From: Vanessa Date: Fri, 21 Nov 2025 15:50:52 -0600 Subject: [PATCH 257/340] Ported base implementation of SimpleToolSystem. --- .../Tools/Systems/SimpleToolUsageSystem.cs | 79 +++++++++++++++++++ .../Locale/en-US/tools/simple-tool-usage.ftl | 1 + 2 files changed, 80 insertions(+) create mode 100644 Content.Shared/Tools/Systems/SimpleToolUsageSystem.cs create mode 100644 Resources/Locale/en-US/tools/simple-tool-usage.ftl diff --git a/Content.Shared/Tools/Systems/SimpleToolUsageSystem.cs b/Content.Shared/Tools/Systems/SimpleToolUsageSystem.cs new file mode 100644 index 00000000000..0f7da9af8a0 --- /dev/null +++ b/Content.Shared/Tools/Systems/SimpleToolUsageSystem.cs @@ -0,0 +1,79 @@ +using Content.Shared.DoAfter; +using Content.Shared.Interaction; +using Content.Shared.Tools.Components; +using Content.Shared.Verbs; +using Robust.Shared.Utility; + +namespace Content.Shared.Tools.Systems; + +public sealed partial class SimpleToolUsageSystem : EntitySystem +{ + [Dependency] private readonly SharedDoAfterSystem _doAfterSystem = default!; + [Dependency] private readonly SharedToolSystem _tools = default!; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnAfterInteract); + SubscribeLocalEvent>(OnGetInteractionVerbs); + } + + private void OnAfterInteract(Entity ent, ref AfterInteractUsingEvent args) + { + if (!args.CanReach || args.Handled) + return; + + if (!_tools.HasQuality(args.Used, ent.Comp.Quality)) + return; + + AttemptToolUsage(ent, args.User, args.Used); + } + + public void OnGetInteractionVerbs(Entity ent, ref GetVerbsEvent args) + { + if (ent.Comp.UsageVerb == null) + return; + + if (!args.CanAccess || !args.CanInteract) + return; + + var disabled = args.Using == null || !_tools.HasQuality(args.Using.Value, ent.Comp.Quality); + + var used = args.Using; + var user = args.User; + + InteractionVerb verb = new() + { + Act = () => + { + if (used != null) + AttemptToolUsage(ent, user, used.Value); + }, + Disabled = disabled, + Message = disabled ? Loc.GetString(ent.Comp.BlockedMessage, ("quality", ent.Comp.Quality)) : null, + Text = Loc.GetString(ent.Comp.UsageVerb), + }; + + args.Verbs.Add(verb); + } + + private void AttemptToolUsage(Entity ent, EntityUid user, EntityUid tool) + { + var attemptEv = new AttemptSimpleToolUseEvent(user); + RaiseLocalEvent(ent, ref attemptEv); + + if (attemptEv.Cancelled) + return; + + var doAfterArgs = new DoAfterArgs(EntityManager, user, ent.Comp.DoAfter, new SimpleToolDoAfterEvent(), ent, tool) + { + BreakOnDamage = true, + BreakOnDropItem = true, + BreakOnMove = true, + BreakOnHandChange = true, + }; + + _doAfterSystem.TryStartDoAfter(doAfterArgs); + } +} diff --git a/Resources/Locale/en-US/tools/simple-tool-usage.ftl b/Resources/Locale/en-US/tools/simple-tool-usage.ftl new file mode 100644 index 00000000000..fd6ae49d224 --- /dev/null +++ b/Resources/Locale/en-US/tools/simple-tool-usage.ftl @@ -0,0 +1 @@ +simple-tool-usage-blocked-message = You need a tool that can perform {$quality}! From 4a3d79faa0fd8f042836317f4fe0c9fc8e6bd227 Mon Sep 17 00:00:00 2001 From: Centronias Date: Wed, 27 Aug 2025 07:56:13 -0700 Subject: [PATCH 258/340] Fixes Diona rooting not working since event based weightlessness refactor (#39893) * Fixes Diona rooting not working since event based weightlessness refactor Caused by #37971 * pr comments --- Content.Shared/Rootable/SharedRootableSystem.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Content.Shared/Rootable/SharedRootableSystem.cs b/Content.Shared/Rootable/SharedRootableSystem.cs index 1216bd16ba0..d7a0e83121e 100644 --- a/Content.Shared/Rootable/SharedRootableSystem.cs +++ b/Content.Shared/Rootable/SharedRootableSystem.cs @@ -107,6 +107,7 @@ public abstract class SharedRootableSystem : EntitySystem if (TryComp(entity, out var moved)) // Delta-V - Prevent spacewind moved.Enabled = !entity.Comp.Rooted; _movementSpeedModifier.RefreshMovementSpeedModifiers(entity); + _gravity.RefreshWeightless(entity.Owner); Dirty(entity); if (entity.Comp.Rooted) @@ -122,7 +123,6 @@ public abstract class SharedRootableSystem : EntitySystem { _alerts.ClearAlert(entity, entity.Comp.RootedAlert); } - _audio.PlayPredicted(entity.Comp.RootSound, entity.Owner.ToCoordinates(), entity); return true; From 648d4539a52f4d44ef06facf2a73cdeb35030ff8 Mon Sep 17 00:00:00 2001 From: Tayrtahn Date: Wed, 27 Aug 2025 16:30:53 -0400 Subject: [PATCH 259/340] Add test of disposal unit throw-insert behavior (#39479) * Add test of disposal unit throw-insert behavior * Remove initially-empty check --- .../Disposal/DisposalUnitInteractionTest.cs | 54 +++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 Content.IntegrationTests/Tests/Disposal/DisposalUnitInteractionTest.cs diff --git a/Content.IntegrationTests/Tests/Disposal/DisposalUnitInteractionTest.cs b/Content.IntegrationTests/Tests/Disposal/DisposalUnitInteractionTest.cs new file mode 100644 index 00000000000..d4b20a55a86 --- /dev/null +++ b/Content.IntegrationTests/Tests/Disposal/DisposalUnitInteractionTest.cs @@ -0,0 +1,54 @@ +using Content.IntegrationTests.Tests.Interaction; +using Content.Server.Containers; +using Robust.Shared.Containers; +using Robust.Shared.Prototypes; + +namespace Content.IntegrationTests.Tests.Disposal; + +public sealed class DisposalUnitInteractionTest : InteractionTest +{ + private static readonly EntProtoId DisposalUnit = "DisposalUnit"; + private static readonly EntProtoId TrashItem = "BrokenBottle"; + + private const string TestDisposalUnitId = "TestDisposalUnit"; + + [TestPrototypes] + private static readonly string TestPrototypes = $@" +# A modified disposal unit with a 100% chance of a thrown item being inserted +- type: entity + parent: {DisposalUnit.Id} + id: {TestDisposalUnitId} + components: + - type: ThrowInsertContainer + probability: 1 +"; + + /// + /// Spawns a disposal unit, gives the player a trash item, and makes the + /// player throw the item at the disposal unit. + /// After a short delay, verifies that the thrown item is contained inside + /// the disposal unit. + /// + [Test] + public async Task ThrowItemIntoDisposalUnitTest() + { + var containerSys = Server.System(); + + // Spawn the target disposal unit + var disposalUnit = await SpawnTarget(TestDisposalUnitId); + + // Give the player some trash to throw + var trash = await PlaceInHands(TrashItem); + + // Throw the item at the disposal unit + await ThrowItem(); + + // Wait a moment + await RunTicks(10); + + // Make sure the trash is in the disposal unit + var throwInsertComp = Comp(); + var container = containerSys.GetContainer(ToServer(disposalUnit), throwInsertComp.ContainerId); + Assert.That(container.ContainedEntities, Contains.Item(ToServer(trash))); + } +} From 150464d64dbd9ad1f787b03c1b144c0aa003b6b7 Mon Sep 17 00:00:00 2001 From: Princess Cheeseballs <66055347+Princess-Cheeseballs@users.noreply.github.com> Date: Wed, 27 Aug 2025 13:37:31 -0700 Subject: [PATCH 260/340] [Bugfix] Generators can now be weightless. (#39787) FIX Co-authored-by: Princess Cheeseballs <66055347+Pronana@users.noreply.github.com> --- .../Structures/Power/Generation/generators.yml | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/Resources/Prototypes/Entities/Structures/Power/Generation/generators.yml b/Resources/Prototypes/Entities/Structures/Power/Generation/generators.yml index 410df050214..456a83046b8 100644 --- a/Resources/Prototypes/Entities/Structures/Power/Generation/generators.yml +++ b/Resources/Prototypes/Entities/Structures/Power/Generation/generators.yml @@ -2,6 +2,7 @@ - type: entity abstract: true + parent: BaseMachine id: BaseGenerator description: A high efficiency thermoelectric generator. name: generator @@ -12,10 +13,6 @@ range: 5 sound: path: /Audio/Ambience/Objects/engine_hum.ogg - - type: Clickable - - type: InteractionOutline - - type: Physics - bodyType: Static - type: Fixtures fixtures: fix1: @@ -27,9 +24,6 @@ - MachineMask layer: - MachineLayer - - type: Transform - anchored: true - noRot: true - type: Sprite sprite: Structures/Power/power.rsi state: generator @@ -49,8 +43,7 @@ supplyRate: 3000 supplyRampRate: 500 supplyRampTolerance: 500 - - type: Anchorable - - type: Pullable + - type: Anchorable # Reduces anchor time to 1 second - type: Damageable damageContainer: StructuralInorganic damageModifierSet: Metallic From 55069b405da6ad6e31cf10730a1523744b985172 Mon Sep 17 00:00:00 2001 From: Princess Cheeseballs <66055347+Princess-Cheeseballs@users.noreply.github.com> Date: Wed, 27 Aug 2025 13:43:55 -0700 Subject: [PATCH 261/340] [Cleanup] Remove FellDownEvent (#39762) * Remove * Better description maybe --------- Co-authored-by: Princess Cheeseballs <66055347+Pronana@users.noreply.github.com> --- Content.Server/Hands/Systems/HandsSystem.cs | 3 --- Content.Shared/Standing/StandingStateSystem.cs | 18 ++---------------- 2 files changed, 2 insertions(+), 19 deletions(-) diff --git a/Content.Server/Hands/Systems/HandsSystem.cs b/Content.Server/Hands/Systems/HandsSystem.cs index c0e39fd6bf3..e3cdb8bfef0 100644 --- a/Content.Server/Hands/Systems/HandsSystem.cs +++ b/Content.Server/Hands/Systems/HandsSystem.cs @@ -235,13 +235,10 @@ namespace Content.Server.Hands.Systems var holderVelocity = _physicsQuery.TryComp(entity, out var physics) ? physics.LinearVelocity : Vector2.Zero; var spreadMaxAngle = Angle.FromDegrees(DropHeldItemsSpread); - var fellEvent = new FellDownEvent(entity); - RaiseLocalEvent(entity, fellEvent); if (HasComp(entity)) // Frontier: stop dropping items when falling over. return; // Frontier - var worldRotation = TransformSystem.GetWorldRotation(entity).ToVec(); foreach (var hand in entity.Comp.Hands.Keys) { if (!TryGetHeldItem(entity.AsNullable(), hand, out var heldEntity)) diff --git a/Content.Shared/Standing/StandingStateSystem.cs b/Content.Shared/Standing/StandingStateSystem.cs index 7e63de71c32..01c7e0f8ccf 100644 --- a/Content.Shared/Standing/StandingStateSystem.cs +++ b/Content.Shared/Standing/StandingStateSystem.cs @@ -241,22 +241,8 @@ public sealed class DownedEvent : EntityEventArgs, IInventoryRelayEvent /// -/// Raised after an entity falls down. -/// -public sealed class FellDownEvent : EntityEventArgs -{ - public EntityUid Uid { get; } - - public FellDownEvent(EntityUid uid) - { - Uid = uid; - } -} - -/// -/// Raised on the entity being thrown due to the holder falling down. +/// Raised on an inhand entity being held by an entity who is dropping items as part of an attempted state change to down. +/// If cancelled the inhand entity will not be dropped. /// [ByRefEvent] public record struct FellDownThrowAttemptEvent(EntityUid Thrower, bool Cancelled = false); - - From 93a74d4c630ccbe0443679a0b11e8127321e60ca Mon Sep 17 00:00:00 2001 From: Blaine Pavlock <146504016+PavlockBlaine03@users.noreply.github.com> Date: Wed, 27 Aug 2025 16:06:50 -0500 Subject: [PATCH 262/340] Reagents now drop when dispensers are deconstructed (#39676) * Reagents now drop when dispensers are deconstructed * Updated containers to include beakerSlot types * Update Resources/Prototypes/Entities/Structures/Dispensers/base_structuredispensers.yml --------- Co-authored-by: slarticodefast <161409025+slarticodefast@users.noreply.github.com> --- .../Structures/Dispensers/base_structuredispensers.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Resources/Prototypes/Entities/Structures/Dispensers/base_structuredispensers.yml b/Resources/Prototypes/Entities/Structures/Dispensers/base_structuredispensers.yml index e9797ee24ac..d69ab97bab1 100644 --- a/Resources/Prototypes/Entities/Structures/Dispensers/base_structuredispensers.yml +++ b/Resources/Prototypes/Entities/Structures/Dispensers/base_structuredispensers.yml @@ -77,3 +77,7 @@ - type: StaticPrice price: 1000 - type: WiresPanel + - type: EmptyOnMachineDeconstruct + containers: + - storagebase + - beakerSlot From cb57b84578ac18ee2ec84828c9ed5cee9071cf67 Mon Sep 17 00:00:00 2001 From: Perry Fraser Date: Wed, 27 Aug 2025 17:08:54 -0400 Subject: [PATCH 263/340] fix: monoify card_drag, card_tube_bonk (#39511) Also move an attribution to the right directory. --- Resources/Audio/Effects/attributions.yml | 7 +------ Resources/Audio/Effects/card_drag.ogg | Bin 21803 -> 39438 bytes Resources/Audio/Items/Toys/attributions.yml | 6 ++++++ Resources/Audio/Items/Toys/card_tube_bonk.ogg | Bin 8379 -> 9903 bytes 4 files changed, 7 insertions(+), 6 deletions(-) diff --git a/Resources/Audio/Effects/attributions.yml b/Resources/Audio/Effects/attributions.yml index 9f85c4fb050..efac498a3bd 100644 --- a/Resources/Audio/Effects/attributions.yml +++ b/Resources/Audio/Effects/attributions.yml @@ -258,11 +258,6 @@ source: "https://freesound.org/people/CheChoDj/sounds/609353/" - files: [card_drag.ogg] - copyright: 'created by Tao7891' + copyright: 'created by Tao7891; perryprog (GitHub) downmixed to mono' license: CC0-1.0 source: https://github.com/space-wizards/space-station-14/pull/37363 - -- files: [card_tube_bonk.ogg] - copyright: 'created by Crinkem on Freesound' - license: "CC0-1.0" - source: https://freesound.org/people/Crinkem/sounds/492027/ diff --git a/Resources/Audio/Effects/card_drag.ogg b/Resources/Audio/Effects/card_drag.ogg index 8ecf632e8abb092b042de64b42dca3fac9518d25..d79309953efac0c67ef87c528b03c95b9e4e4261 100644 GIT binary patch delta 38175 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 YS_1H>PWD5#Xqh+#0LKFs7yu3d0MA|vLjV8( diff --git a/Resources/Audio/Items/Toys/attributions.yml b/Resources/Audio/Items/Toys/attributions.yml index 23caefc0d0b..504e5b7ac65 100644 --- a/Resources/Audio/Items/Toys/attributions.yml +++ b/Resources/Audio/Items/Toys/attributions.yml @@ -107,3 +107,9 @@ license: "CC0-1.0" copyright: "Created by Orsoniks, from the game Casualties Unknown" source: "https://orsonik.itch.io/scav-prototype" + +- files: [card_tube_bonk.ogg] + copyright: 'created by Crinkem on Freesound; perryprog (GitHub) downmixed to mono' + license: "CC0-1.0" + source: https://freesound.org/people/Crinkem/sounds/492027/ + diff --git a/Resources/Audio/Items/Toys/card_tube_bonk.ogg b/Resources/Audio/Items/Toys/card_tube_bonk.ogg index b300702c25c7addd53796def93a5e5ab1bb3bccd..de84b852a88f0b1529132fa952bf262a052ae2b7 100644 GIT binary patch delta 8186 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 literal 8379 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 OULQ2f6C4 Date: Thu, 28 Aug 2025 00:56:09 +0300 Subject: [PATCH 264/340] New Feature: Symptoms of radiation poisoning (#39805) * New Feature * Cleanup * Bump threshold * Update * Update * Single change * Me when I forgor the yaml --------- Co-authored-by: Princess Cheeseballs <66055347+Pronana@users.noreply.github.com> --- .../Thresholds/Behaviors/PopupBehavior.cs | 12 +++++++++++- .../Thresholds/Behaviors/VomitBehavior.cs | 12 ++++++++++++ Resources/Locale/en-US/damage/radiation.ftl | 1 + Resources/Prototypes/Entities/Mobs/base.yml | 15 +++++++++++++++ 4 files changed, 39 insertions(+), 1 deletion(-) create mode 100644 Content.Server/Destructible/Thresholds/Behaviors/VomitBehavior.cs create mode 100644 Resources/Locale/en-US/damage/radiation.ftl diff --git a/Content.Server/Destructible/Thresholds/Behaviors/PopupBehavior.cs b/Content.Server/Destructible/Thresholds/Behaviors/PopupBehavior.cs index 59589c19aa7..344da3535e2 100644 --- a/Content.Server/Destructible/Thresholds/Behaviors/PopupBehavior.cs +++ b/Content.Server/Destructible/Thresholds/Behaviors/PopupBehavior.cs @@ -20,11 +20,21 @@ public sealed partial class PopupBehavior : IThresholdBehavior [DataField("popupType")] public PopupType PopupType; + /// + /// Only the affected entity will see the popup. + /// + [DataField] + public bool TargetOnly; + public void Execute(EntityUid uid, DestructibleSystem system, EntityUid? cause = null) { var popup = system.EntityManager.System(); // popup is placed at coords since the entity could be deleted after, no more popup then var coords = system.EntityManager.GetComponent(uid).Coordinates; - popup.PopupCoordinates(Loc.GetString(Popup), coords, PopupType); + + if (TargetOnly) + popup.PopupCoordinates(Loc.GetString(Popup), coords, uid, PopupType); + else + popup.PopupCoordinates(Loc.GetString(Popup), coords, PopupType); } } diff --git a/Content.Server/Destructible/Thresholds/Behaviors/VomitBehavior.cs b/Content.Server/Destructible/Thresholds/Behaviors/VomitBehavior.cs new file mode 100644 index 00000000000..067e7d45659 --- /dev/null +++ b/Content.Server/Destructible/Thresholds/Behaviors/VomitBehavior.cs @@ -0,0 +1,12 @@ +using Content.Server.Medical; + +namespace Content.Server.Destructible.Thresholds.Behaviors; + +[DataDefinition] +public sealed partial class VomitBehavior : IThresholdBehavior +{ + public void Execute(EntityUid uid, DestructibleSystem system, EntityUid? cause = null) + { + system.EntityManager.System().Vomit(uid); + } +} diff --git a/Resources/Locale/en-US/damage/radiation.ftl b/Resources/Locale/en-US/damage/radiation.ftl new file mode 100644 index 00000000000..bfe32fa9bb6 --- /dev/null +++ b/Resources/Locale/en-US/damage/radiation.ftl @@ -0,0 +1 @@ +mouth-taste-metal = You taste something metallic in your mouth! diff --git a/Resources/Prototypes/Entities/Mobs/base.yml b/Resources/Prototypes/Entities/Mobs/base.yml index 603950fb9aa..f54a4c2093e 100644 --- a/Resources/Prototypes/Entities/Mobs/base.yml +++ b/Resources/Prototypes/Entities/Mobs/base.yml @@ -86,6 +86,21 @@ # - !type:PlaySoundBehavior # sound: # collection: MeatLaserImpact + - trigger: + !type:DamageTypeTrigger + damageType: Radiation + damage: 15 + behaviors: + - !type:PopupBehavior + popup: mouth-taste-metal + popupType: LargeCaution + targetOnly: true + - trigger: + !type:DamageTypeTrigger + damageType: Radiation + damage: 40 + behaviors: + - !type:VomitBehavior - type: RadiationReceiver - type: Stamina - type: MobState From 1b24b46e00f8bf3480ce967ede1ce1085a37be16 Mon Sep 17 00:00:00 2001 From: Hitlinemoss <209321380+Hitlinemoss@users.noreply.github.com> Date: Wed, 27 Aug 2025 03:07:32 -0400 Subject: [PATCH 265/340] Clipboards added to autolathe (and other folder changes) (#37705) * Added plastic clipboards; added plastic clipboards to the PTech machine; added clipboards & plastic clipboards to the autolathe * Fixed plastic clipboard inhand sprites; added and implemented 'empty' clipboard prototypes * Cleaned up code for empty clipboards; removed BoxFolderBaseEmpty since now it's redundant * Extensive folder cleanup * Bugfixed random folder spawns * Reduced amount of paper in CrateServiceBureaucracy * Medical folder sprite rename * BaseTraitorSocialObjective sprite fix * Added office paper to bureaucracy crate * First pass at addressing recent review * Second pass at addressing recent review * Fix of weird migration.yml error * whoops, forgot to undo the rename to folder-white.png in the last few commits * whoops, didn't commit that last commit properly * whoops, forgot to undo this reordering --- .../Catalog/Fills/Crates/permaescape.yml | 39 ++-- .../Catalog/Fills/Crates/service.yml | 2 +- .../VendingMachines/Inventories/cart.yml | 1 + .../Markers/Spawners/Random/folders.yml | 18 +- .../Entities/Objects/Misc/folders.yml | 188 ++++++++++++++---- .../Entities/Structures/Machines/lathe.yml | 1 + .../Structures/Storage/filing_cabinets.yml | 5 +- Resources/Prototypes/Objectives/traitor.yml | 2 +- .../Recipes/Lathes/Packs/shared.yml | 6 + Resources/Prototypes/Recipes/Lathes/misc.yml | 17 +- .../Roles/Jobs/Cargo/quartermaster.yml | 2 +- .../Roles/Jobs/CentComm/official.yml | 2 +- .../Roles/Jobs/Command/head_of_personnel.yml | 4 +- .../Roles/Jobs/Fun/visitors_startinggear.yml | 6 +- .../Misc/plastic_clipboard.rsi/clipboard.png | Bin 0 -> 442 bytes .../plastic_clipboard.rsi/clipboard_over.png | Bin 0 -> 141 bytes .../plastic_clipboard.rsi/clipboard_paper.png | Bin 0 -> 166 bytes .../plastic_clipboard.rsi/clipboard_pen.png | Bin 0 -> 148 bytes .../plastic_clipboard.rsi/equipped-BELT.png | Bin 0 -> 479 bytes .../plastic_clipboard.rsi/inhand-left.png | Bin 0 -> 668 bytes .../plastic_clipboard.rsi/inhand-right.png | Bin 0 -> 667 bytes .../Misc/plastic_clipboard.rsi/meta.json | 35 ++++ 22 files changed, 242 insertions(+), 86 deletions(-) create mode 100644 Resources/Textures/Objects/Misc/plastic_clipboard.rsi/clipboard.png create mode 100644 Resources/Textures/Objects/Misc/plastic_clipboard.rsi/clipboard_over.png create mode 100644 Resources/Textures/Objects/Misc/plastic_clipboard.rsi/clipboard_paper.png create mode 100644 Resources/Textures/Objects/Misc/plastic_clipboard.rsi/clipboard_pen.png create mode 100644 Resources/Textures/Objects/Misc/plastic_clipboard.rsi/equipped-BELT.png create mode 100644 Resources/Textures/Objects/Misc/plastic_clipboard.rsi/inhand-left.png create mode 100644 Resources/Textures/Objects/Misc/plastic_clipboard.rsi/inhand-right.png create mode 100644 Resources/Textures/Objects/Misc/plastic_clipboard.rsi/meta.json diff --git a/Resources/Prototypes/Catalog/Fills/Crates/permaescape.yml b/Resources/Prototypes/Catalog/Fills/Crates/permaescape.yml index 4ee0d5f9ea4..ed48479cd20 100644 --- a/Resources/Prototypes/Catalog/Fills/Crates/permaescape.yml +++ b/Resources/Prototypes/Catalog/Fills/Crates/permaescape.yml @@ -82,7 +82,7 @@ prob: 0.25 - id: OxygenTankFilled prob: 0.05 - + - type: entity id: CratePermaEscapeGun parent: CrateGenericSteel @@ -124,40 +124,37 @@ contents: - id: RubberStampApproved - id: RubberStampDenied + - id: Paper + amount: 5 - id: Pen - - id: Pen - - id: Pen - - id: BoxFolderBase + amount: 3 + - id: BoxFolderBaseEmpty orGroup: folderA - - id: BoxFolderBlack + - id: BoxFolderBlackEmpty orGroup: folderA - - id: BoxFolderBlue + - id: BoxFolderBlueEmpty orGroup: folderA - - id: BoxFolderGreen + - id: BoxFolderGreenEmpty orGroup: folderA - - id: BoxFolderGrey + - id: BoxFolderGreyEmpty orGroup: folderA - - id: BoxFolderRed + - id: BoxFolderRedEmpty orGroup: folderA - - id: BoxFolderWhite + - id: BoxFolderYellowEmpty orGroup: folderA - - id: BoxFolderYellow - orGroup: folderA - - id: BoxFolderBase + - id: BoxFolderBaseEmpty orGroup: folderB - - id: BoxFolderBlack + - id: BoxFolderBlackEmpty orGroup: folderB - - id: BoxFolderBlue + - id: BoxFolderBlueEmpty orGroup: folderB - - id: BoxFolderGreen + - id: BoxFolderGreenEmpty orGroup: folderB - - id: BoxFolderGrey + - id: BoxFolderGreyEmpty orGroup: folderB - - id: BoxFolderRed + - id: BoxFolderRedEmpty orGroup: folderB - - id: BoxFolderWhite - orGroup: folderB - - id: BoxFolderYellow + - id: BoxFolderYellowEmpty orGroup: folderB - id: CrayonBox prob: 0.50 diff --git a/Resources/Prototypes/Catalog/Fills/Crates/service.yml b/Resources/Prototypes/Catalog/Fills/Crates/service.yml index bf6d89867bf..5ceca81460e 100644 --- a/Resources/Prototypes/Catalog/Fills/Crates/service.yml +++ b/Resources/Prototypes/Catalog/Fills/Crates/service.yml @@ -143,7 +143,7 @@ # amount: 15 - id: Pen amount: 2 - - id: BoxFolderClipboard + - id: BoxFolderClipboardEmpty amount: 2 - id: HandLabeler - id: BoxFolderBlue diff --git a/Resources/Prototypes/Catalog/VendingMachines/Inventories/cart.yml b/Resources/Prototypes/Catalog/VendingMachines/Inventories/cart.yml index 3a15aaf62ac..7fff28d74cd 100644 --- a/Resources/Prototypes/Catalog/VendingMachines/Inventories/cart.yml +++ b/Resources/Prototypes/Catalog/VendingMachines/Inventories/cart.yml @@ -23,6 +23,7 @@ ClothingHeadsetService: 5 # Delta-V RubberStampApproved: 1 RubberStampDenied: 1 + BoxFolderPlasticClipboardEmpty: 2 Paper: 10 Envelope: 10 HandLabeler: 2 diff --git a/Resources/Prototypes/Entities/Markers/Spawners/Random/folders.yml b/Resources/Prototypes/Entities/Markers/Spawners/Random/folders.yml index 7631d43316b..5d4c133a034 100644 --- a/Resources/Prototypes/Entities/Markers/Spawners/Random/folders.yml +++ b/Resources/Prototypes/Entities/Markers/Spawners/Random/folders.yml @@ -10,15 +10,15 @@ - type: Sprite sprite: Objects/Misc/folders.rsi layers: - - state: folder-base - - state: folder-colormap + - state: folder-base + - state: folder-colormap - type: RandomSpawner offset: 0 prototypes: - - BoxFolderRed - - BoxFolderBlue - - BoxFolderYellow - - BoxFolderWhite - - BoxFolderGrey - - BoxFolderBlack - - BoxFolderGreen + - BoxFolderBase + - BoxFolderRed + - BoxFolderBlue + - BoxFolderYellow + - BoxFolderGrey + - BoxFolderBlack + - BoxFolderGreen diff --git a/Resources/Prototypes/Entities/Objects/Misc/folders.yml b/Resources/Prototypes/Entities/Objects/Misc/folders.yml index f72d4c3abce..cee720b6ea8 100644 --- a/Resources/Prototypes/Entities/Objects/Misc/folders.yml +++ b/Resources/Prototypes/Entities/Objects/Misc/folders.yml @@ -1,6 +1,6 @@ - type: entity - id: BoxFolderNuclearCodes parent: BaseItem + id: BoxFolderNuclearCodes name: nuclear code folder components: - type: Sprite @@ -19,8 +19,8 @@ - type: Appearance - type: entity - id: BoxFolderBase parent: BoxBase + id: BoxFolderBaseEmpty name: folder description: A folder filled with top secret paperwork. components: @@ -62,22 +62,42 @@ - type: Tag tags: - Folder - - type: StorageFill - contents: - - id: Paper - prob: 0.5 - - id: PaperOffice - prob: 0.4 - - id: Paper - prob: 0.3 - - id: PaperOffice - prob: 0.2 - - id: Paper - prob: 0.2 - type: entity - id: BoxFolderRed - parent: BoxFolderBase + abstract: true + id: BoxFolderFill # Include this as a parent prototype to add 0-5 random papers to a folder's inventory when spawned. + suffix: Filled + components: + - type: StorageFill + contents: + - id: Paper + prob: 0.5 + - id: PaperOffice + prob: 0.4 + - id: Paper + prob: 0.3 + - id: PaperOffice + prob: 0.2 + - id: Paper + prob: 0.2 + +- type: entity + abstract: true + id: BoxFolderFillThreePapers # Like BoxFolderFill, but always has exactly three sheets of standard paper; use for roles' startingGear + suffix: 3 papers + components: + - type: StorageFill + contents: + - id: Paper + amount: 3 + +- type: entity + parent: [BoxFolderBaseEmpty, BoxFolderFill] + id: BoxFolderBase + +- type: entity + parent: BoxFolderBaseEmpty + id: BoxFolderRedEmpty suffix: Red components: - type: Sprite @@ -87,8 +107,13 @@ - state: folder-base - type: entity - id: BoxFolderBlue - parent: BoxFolderBase + parent: [BoxFolderRedEmpty, BoxFolderFill] + id: BoxFolderRed + suffix: Red, Filled + +- type: entity + parent: BoxFolderBaseEmpty + id: BoxFolderBlueEmpty suffix: Blue components: - type: Sprite @@ -98,8 +123,13 @@ - state: folder-base - type: entity - id: BoxFolderYellow - parent: BoxFolderBase + parent: [BoxFolderBlueEmpty, BoxFolderFill] + id: BoxFolderBlue + suffix: Blue, Filled + +- type: entity + parent: BoxFolderBaseEmpty + id: BoxFolderYellowEmpty suffix: Yellow components: - type: Sprite @@ -109,18 +139,13 @@ - state: folder-base - type: entity - id: BoxFolderWhite - parent: BoxFolderBase - suffix: White - components: - - type: Sprite - layers: - - state: folder-white - - state: folder-base + parent: [BoxFolderYellowEmpty, BoxFolderFill] + id: BoxFolderYellow + suffix: Yellow, Filled - type: entity - id: BoxFolderGrey - parent: BoxFolderBase + parent: BoxFolderBaseEmpty + id: BoxFolderGreyEmpty suffix: Grey components: - type: Sprite @@ -130,8 +155,13 @@ - state: folder-base - type: entity - id: BoxFolderBlack - parent: BoxFolderBase + parent: [BoxFolderGreyEmpty, BoxFolderFill] + id: BoxFolderGrey + suffix: Grey, Filled + +- type: entity + parent: BoxFolderBaseEmpty + id: BoxFolderBlackEmpty suffix: Black components: - type: Sprite @@ -141,8 +171,13 @@ - state: folder-base - type: entity - id: BoxFolderGreen - parent: BoxFolderBase + parent: [BoxFolderBlackEmpty, BoxFolderFill] + id: BoxFolderBlack + suffix: Black, Filled + +- type: entity + parent: BoxFolderBaseEmpty + id: BoxFolderGreenEmpty suffix: Green components: - type: Sprite @@ -152,10 +187,30 @@ - state: folder-base - type: entity - id: BoxFolderCentCom - name: CentComm folder - parent: BoxFolderBase + parent: [BoxFolderGreenEmpty, BoxFolderFill] + id: BoxFolderGreen + suffix: Green, Filled + +- type: entity + parent: BoxFolderBaseEmpty + id: BoxFolderWhiteEmpty + suffix: White + components: + - type: Sprite + layers: + - state: folder-white + - state: folder-base + +- type: entity + parent: [BoxFolderWhiteEmpty, BoxFolderFill] + id: BoxFolderWhite + suffix: White, Filled + +- type: entity + parent: BoxFolderBaseEmpty + id: BoxFolderCentComEmpty categories: [ DoNotMap ] + name: CentComm folder description: CentComm's miserable little pile of secrets! components: - type: Sprite @@ -164,8 +219,13 @@ - state: folder-base - type: entity - id: BoxFolderClipboard - parent: BoxFolderBase + parent: [BoxFolderCentComEmpty, BoxFolderFill] + id: BoxFolderCentCom + suffix: DO NOT MAP, Filled + +- type: entity + parent: BoxFolderBaseEmpty + id: BoxFolderClipboardEmpty name: clipboard description: The weapon of choice for those on the front lines of bureaucracy. components: @@ -223,8 +283,42 @@ Blunt: 6 - type: entity - id: BoxFolderCentComClipboard - parent: BoxFolderClipboard + parent: [BoxFolderClipboardEmpty, BoxFolderFill] + id: BoxFolderClipboard + +- type: entity + parent: [BoxFolderClipboardEmpty, BoxFolderFillThreePapers] + id: BoxFolderClipboardThreePapers + +- type: entity + parent: BoxFolderClipboardEmpty + id: BoxFolderPlasticClipboardEmpty + name: plastic clipboard + description: A cheap clipboard made of blue plastic. For those who aren't yet ready to wield the bureaucratic might of a proper wooden clipboard. + components: + - type: Sprite + sprite: Objects/Misc/plastic_clipboard.rsi + layers: + - state: clipboard + - state: clipboard_paper + map: ["clipboard_paper"] + visible: false + - state: clipboard_pen + map: ["clipboard_pen"] + visible: false + - state: clipboard_over + - type: Item + sprite: Objects/Misc/plastic_clipboard.rsi + - type: Clothing + sprite: Objects/Misc/plastic_clipboard.rsi + +- type: entity + parent: [BoxFolderPlasticClipboardEmpty, BoxFolderFill] + id: BoxFolderPlasticClipboard + +- type: entity + parent: BoxFolderClipboardEmpty + id: BoxFolderCentComClipboardEmpty name: CentComm clipboard description: A luxurious clipboard upholstered with green velvet. Often seen carried by CentComm officials, seldom seen actually used. components: @@ -245,8 +339,16 @@ sprite: Objects/Misc/cc-clipboard.rsi - type: entity + parent: [BoxFolderCentComClipboardEmpty, BoxFolderFill] + id: BoxFolderCentComClipboard + +- type: entity + parent: [BoxFolderCentComClipboardEmpty, BoxFolderFillThreePapers] + id: BoxFolderCentComClipboardThreePapers + +- type: entity + parent: [BoxFolderClipboardEmpty, BaseGrandTheftContraband] id: BoxFolderQmClipboard - parent: [BoxFolderClipboard, BaseGrandTheftContraband] name: requisition digi-board description: A bulky electric clipboard, filled with shipping orders and financing details. With so many compromising documents, you ought to keep this safe. components: @@ -278,8 +380,6 @@ grid: - 0,0,4,3 quickInsert: true - - type: StorageFill - contents: [] #to override base clipboard fill - type: ItemMapper mapLayers: qm_clipboard_paper: diff --git a/Resources/Prototypes/Entities/Structures/Machines/lathe.yml b/Resources/Prototypes/Entities/Structures/Machines/lathe.yml index ae8c76443d3..228a91f69ce 100644 --- a/Resources/Prototypes/Entities/Structures/Machines/lathe.yml +++ b/Resources/Prototypes/Entities/Structures/Machines/lathe.yml @@ -139,6 +139,7 @@ - PartsStatic - AtmosStatic - CablesStatic + - PaperworkStatic - CargoStatic - MaterialsStatic - BasicChemistryStatic diff --git a/Resources/Prototypes/Entities/Structures/Storage/filing_cabinets.yml b/Resources/Prototypes/Entities/Structures/Storage/filing_cabinets.yml index f0e79a841ee..c53dfb5d78b 100644 --- a/Resources/Prototypes/Entities/Structures/Storage/filing_cabinets.yml +++ b/Resources/Prototypes/Entities/Structures/Storage/filing_cabinets.yml @@ -6,12 +6,13 @@ rolls: !type:RangeNumberSelector range: 2, 4 children: - - id: BoxFolderBlue + - id: BoxFolderBase - id: BoxFolderRed + - id: BoxFolderBlue - id: BoxFolderYellow - - id: BoxFolderWhite - id: BoxFolderGrey - id: BoxFolderBlack + - id: BoxFolderGreen - !type:GroupSelector rolls: !type:RangeNumberSelector range: 0, 3 diff --git a/Resources/Prototypes/Objectives/traitor.yml b/Resources/Prototypes/Objectives/traitor.yml index 87dcc548a76..b50d31a6b63 100644 --- a/Resources/Prototypes/Objectives/traitor.yml +++ b/Resources/Prototypes/Objectives/traitor.yml @@ -17,7 +17,7 @@ - type: Objective icon: sprite: Objects/Misc/folders.rsi - state: folder-white + state: folder-colormap - type: MultipleTraitorsRequirement - type: entity diff --git a/Resources/Prototypes/Recipes/Lathes/Packs/shared.yml b/Resources/Prototypes/Recipes/Lathes/Packs/shared.yml index a71807878dd..db38e056647 100644 --- a/Resources/Prototypes/Recipes/Lathes/Packs/shared.yml +++ b/Resources/Prototypes/Recipes/Lathes/Packs/shared.yml @@ -40,6 +40,12 @@ - CableMVStack - CableHVStack +- type: latheRecipePack + id: PaperworkStatic + recipes: + - BoxFolderClipboardEmpty + - BoxFolderPlasticClipboardEmpty + ## Dynamic # Things you'd expect sci salv and engi to make use of diff --git a/Resources/Prototypes/Recipes/Lathes/misc.yml b/Resources/Prototypes/Recipes/Lathes/misc.yml index ec7910ac5ef..59a2d8f6067 100644 --- a/Resources/Prototypes/Recipes/Lathes/misc.yml +++ b/Resources/Prototypes/Recipes/Lathes/misc.yml @@ -277,4 +277,19 @@ completetime: 1 materials: Steel: 30 - + +- type: latheRecipe + id: BoxFolderClipboardEmpty + result: BoxFolderClipboardEmpty + completetime: 2 + materials: + Wood: 100 + Steel: 25 + +- type: latheRecipe + id: BoxFolderPlasticClipboardEmpty + result: BoxFolderPlasticClipboardEmpty + completetime: 2 + materials: + Plastic: 100 + Steel: 25 diff --git a/Resources/Prototypes/Roles/Jobs/Cargo/quartermaster.yml b/Resources/Prototypes/Roles/Jobs/Cargo/quartermaster.yml index bda61be6ca6..9232a8af94b 100644 --- a/Resources/Prototypes/Roles/Jobs/Cargo/quartermaster.yml +++ b/Resources/Prototypes/Roles/Jobs/Cargo/quartermaster.yml @@ -44,7 +44,7 @@ equipment: id: QuartermasterPDA ears: ClothingHeadsetQM - belt: BoxFolderClipboard + belt: BoxFolderClipboardThreePapers pocket1: AppraisalTool storage: back: diff --git a/Resources/Prototypes/Roles/Jobs/CentComm/official.yml b/Resources/Prototypes/Roles/Jobs/CentComm/official.yml index 9c28c560023..86cf79d2079 100644 --- a/Resources/Prototypes/Roles/Jobs/CentComm/official.yml +++ b/Resources/Prototypes/Roles/Jobs/CentComm/official.yml @@ -28,7 +28,7 @@ id: CentcomPDA ears: ClothingHeadsetAltCentCom belt: WeaponPistolN1984 - pocket1: BoxFolderBlack + pocket1: BoxFolderCentComClipboardThreePapers pocket2: PenCentcom diff --git a/Resources/Prototypes/Roles/Jobs/Command/head_of_personnel.yml b/Resources/Prototypes/Roles/Jobs/Command/head_of_personnel.yml index b1545fca057..02b6a675620 100644 --- a/Resources/Prototypes/Roles/Jobs/Command/head_of_personnel.yml +++ b/Resources/Prototypes/Roles/Jobs/Command/head_of_personnel.yml @@ -78,8 +78,8 @@ #shoes: ClothingShoesLeather # DeltaV - Commented for Loadouts id: HoPPDA #gloves: ClothingHandsGlovesHop # DeltaV - Commented for Loadouts - ears: ClothingHeadsetHoP # DeltaV - HoP is now a service role, replaces their all channels headset. - belt: BoxFolderClipboard + ears: ClothingHeadsetHoP # DeltaV - HoP is now a service role, replaces ClothingHeadsetAltCommand headset. + belt: BoxFolderClipboardThreePapers eyes: ClothingEyesHudCommand storage: back: diff --git a/Resources/Prototypes/Roles/Jobs/Fun/visitors_startinggear.yml b/Resources/Prototypes/Roles/Jobs/Fun/visitors_startinggear.yml index b7db27a9723..35e92f553c3 100644 --- a/Resources/Prototypes/Roles/Jobs/Fun/visitors_startinggear.yml +++ b/Resources/Prototypes/Roles/Jobs/Fun/visitors_startinggear.yml @@ -1239,7 +1239,7 @@ pocket1: BookSun pocket2: BookRandomStory inhand: - - BoxFolderClipboard + - BoxFolderClipboardThreePapers - type: startingGear id: VisitorMusicianFancyAltA @@ -1509,7 +1509,7 @@ back: ClothingBackpackSatchel ears: ClothingHeadsetService pocket1: MicrophoneInstrument - pocket2: BoxFolderClipboard + pocket2: BoxFolderClipboardThreePapers - type: startingGear id: VisitorReporterAlt @@ -1520,7 +1520,7 @@ back: ClothingBackpackSatchel ears: ClothingHeadsetService pocket1: MicrophoneInstrument - pocket2: BoxFolderClipboard + pocket2: BoxFolderClipboardThreePapers - type: startingGear id: VisitorServiceWorker diff --git a/Resources/Textures/Objects/Misc/plastic_clipboard.rsi/clipboard.png b/Resources/Textures/Objects/Misc/plastic_clipboard.rsi/clipboard.png new file mode 100644 index 0000000000000000000000000000000000000000..6267c74c6bdc4bb5abf52e8995a6ce874e7043e5 GIT binary patch literal 442 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz#^NA%Cx&(BWL^R}Ea{HEjtmSN z`?>!lvI6;>1s;*b3=DjSL74G){)!Z!phSslL`iUdT1k0gQ7S_~VrE{6o}X)of~lUN zo_Y7R@0LI{+fpMu(>y)37&w3&Rt70XRt82O%L|C5p=^+AG#Ht|;!HrcAtMum0FaIX z;>>myuy_`b4FU;34AKvy(JWr9FI?MWw3+dk1j89i#*U7q o_tHbJ=7(6^VTlCGh5j< z%lGfxz02o@HK@E@y64_{L!JAt*v_;uFmWgxh;u4`xs1(1nxEl=wA`*pzDe%&N^gL6 OF?hQAxvX@ve#4-y2I^Bl@dv-cfS&;As5s_ei0mkMTkBW@`n_^SAD%U#)IkVzPP7 ur@2#qPF=j)#pO=wT5g+9OhB_9TonAmtPE0&tPG4mmKP99L)jqLXfQH^#hHL?Lq;YB0U#X( z#F_0ZVDT&<8w3)77^ELYqgl$p%)l^#oq+|Y!obMbfN=rDRFDqV1rU>_0NEhG1T=>U ztTM>b0?2~uGBhv%$*Q`~>s@TJ^(c_p=jq}YQW5v|vLfFh2LaX#OPN%zJl?^<)%rw4 zrepF0OGd8V!wR#4JSQ_HZf3ikBzDhR?epY9`FVdQ&MBb@0M(RrssI20 literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Misc/plastic_clipboard.rsi/inhand-left.png b/Resources/Textures/Objects/Misc/plastic_clipboard.rsi/inhand-left.png new file mode 100644 index 0000000000000000000000000000000000000000..250724510732c7fe92db91eab6f4417a6b0e61d9 GIT binary patch literal 668 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=jKx9jP7LeL$-D$|SkfJR9T^xl z_H+M9WCij$3p^r=85sBufiR<}hF1enP@=>&q9iy!t)x7$D3u`~F*C13&(AeP!Bo#s z&q6x$)e4}RZK)BSX`Y^13>-iXD}xjxD+42tvp@3Xlx~Oh9v) zz$$|*Er2YjE<*zYknEW}u^O-77c#(L@%D6a45^5Fd+V&xC(eQlDXci68rafZjMDU+G5tTKJP z{&(h$80Y18r=8JNXPvR+U#fY#37??O|wF|E|>?dgrxh zxuDFxJ-qYUADiUZy&+yrt#w zO~tFfu*b~HUHyeK^=90Xy^C+JtTdB0pQL*%lTk>JrLpJ5$LlqZLv1cw)&6)Ted1a7 zFJW1wZ^u60+4FP_!?xzfnti>!8eJ(N=QC`KPF5RmdKI;Vst0HfyDhX4Qo literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Misc/plastic_clipboard.rsi/inhand-right.png b/Resources/Textures/Objects/Misc/plastic_clipboard.rsi/inhand-right.png new file mode 100644 index 0000000000000000000000000000000000000000..e9e00780371f6352451a879faa0f4caa4d7d3cb8 GIT binary patch literal 667 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=jKx9jP7LeL$-D$|SkfJR9T^xl z_H+M9WCij$3p^r=85sBufiR<}hF1enP@=>&q9iy!t)x7$D3u`~F*C13&(AeP!Bo#s z&q6x$)e4}RZK)BSX`Y^13>-iXD}xjxD+42tvp@3Xlx~Oh9v) zz$$|*Er2YjE<*zYknEW}u^O-77c#(L@$z(W45^5Fd+VUrVF!VRhrWhcwkwV{M;(;g zQz<6Dz}D6F7eky#&3c=rS<_zxS7hwj8e!wHdLnOdZ^q+wX{Me3*`3>XP2Nt(V=@MX zKSRU+AN^$&`z@D-1O1 zgs=1;{CN2Ci#i)$=jTPMO1@S9y}0N2xAd& Date: Wed, 27 Aug 2025 10:04:39 -0500 Subject: [PATCH 266/340] Re-anchorable structures (#39542) * Initial commit * Reverted reinvention of an existing feature... * Fixed two missed entries * Added extra examine check * AI core and high security doors visuals snap to always face south --- .../Construction/Components/AnchorableComponent.cs | 1 - .../Construction/EntitySystems/AnchorableSystem.cs | 7 +++++++ Resources/Prototypes/Entities/Mobs/Player/silicon.yml | 5 +++++ .../Objects/Weapons/Guns/Turrets/turrets_energy.yml | 4 ++++ .../Structures/Doors/Airlocks/base_structureairlocks.yml | 4 ++++ .../Entities/Structures/Doors/Airlocks/highsec.yml | 5 +++++ .../Entities/Structures/Doors/Firelocks/firelock.yml | 4 ++++ .../Structures/Doors/MaterialDoors/material_doors.yml | 4 ++++ .../Entities/Structures/Doors/SecretDoor/secret_door.yml | 4 ++++ .../Entities/Structures/Doors/Shutter/shutters.yml | 4 ++++ .../Structures/Doors/Windoors/base_structurewindoors.yml | 4 ++++ .../Entities/Structures/Wallmounts/base_wallmount.yml | 4 ++++ Resources/Prototypes/Entities/Structures/Walls/walls.yml | 4 ++++ .../Prototypes/Entities/Structures/Windows/window.yml | 4 ++++ Resources/Prototypes/Entities/Structures/catwalk.yml | 4 ++++ .../Entities/Structures/cryogenic_sleep_unit.yml | 4 ++++ Resources/Prototypes/Entities/Structures/plastic_flaps.yml | 4 ++++ Resources/Prototypes/Entities/Structures/stairs.yml | 4 ++++ 18 files changed, 73 insertions(+), 1 deletion(-) diff --git a/Content.Shared/Construction/Components/AnchorableComponent.cs b/Content.Shared/Construction/Components/AnchorableComponent.cs index 064f839efa5..e17a49937af 100644 --- a/Content.Shared/Construction/Components/AnchorableComponent.cs +++ b/Content.Shared/Construction/Components/AnchorableComponent.cs @@ -2,7 +2,6 @@ using Content.Shared.Construction.EntitySystems; using Content.Shared.Tools; using Robust.Shared.GameStates; using Robust.Shared.Prototypes; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; namespace Content.Shared.Construction.Components { diff --git a/Content.Shared/Construction/EntitySystems/AnchorableSystem.cs b/Content.Shared/Construction/EntitySystems/AnchorableSystem.cs index e690b938263..d53a100acc6 100644 --- a/Content.Shared/Construction/EntitySystems/AnchorableSystem.cs +++ b/Content.Shared/Construction/EntitySystems/AnchorableSystem.cs @@ -102,6 +102,13 @@ public sealed partial class AnchorableSystem : EntitySystem private void OnAnchoredExamine(EntityUid uid, AnchorableComponent component, ExaminedEvent args) { var isAnchored = Comp(uid).Anchored; + + if (isAnchored && (component.Flags & AnchorableFlags.Unanchorable) == 0x0) + return; + + if (!isAnchored && (component.Flags & AnchorableFlags.Anchorable) == 0x0) + return; + var messageId = isAnchored ? "examinable-anchored" : "examinable-unanchored"; args.PushMarkup(Loc.GetString(messageId, ("target", uid))); } diff --git a/Resources/Prototypes/Entities/Mobs/Player/silicon.yml b/Resources/Prototypes/Entities/Mobs/Player/silicon.yml index 0c691074a0b..f2108770611 100644 --- a/Resources/Prototypes/Entities/Mobs/Player/silicon.yml +++ b/Resources/Prototypes/Entities/Mobs/Player/silicon.yml @@ -183,6 +183,10 @@ - AiHolder suffix: Empty components: + - type: Anchorable + flags: + - Anchorable + - type: Rotatable - type: WarpPoint blacklist: tags: @@ -208,6 +212,7 @@ - type: StationAiVision - type: InteractionOutline - type: Sprite + snapCardinals: true sprite: Mobs/Silicon/station_ai.rsi layers: - state: base diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Turrets/turrets_energy.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Turrets/turrets_energy.yml index 40c67c898df..1fe926294c9 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Turrets/turrets_energy.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Turrets/turrets_energy.yml @@ -5,6 +5,10 @@ name: sentry turret description: A high-tech autonomous weapons system designed to keep unauthorized personnel out of sensitive areas. components: + - type: Anchorable + flags: + - Anchorable + - type: Rotatable - type: Fixtures fixtures: body: diff --git a/Resources/Prototypes/Entities/Structures/Doors/Airlocks/base_structureairlocks.yml b/Resources/Prototypes/Entities/Structures/Doors/Airlocks/base_structureairlocks.yml index 1d71290e62c..e8a80d0e866 100644 --- a/Resources/Prototypes/Entities/Structures/Doors/Airlocks/base_structureairlocks.yml +++ b/Resources/Prototypes/Entities/Structures/Doors/Airlocks/base_structureairlocks.yml @@ -4,6 +4,10 @@ name: airlock description: It opens, it closes, and maybe crushes you. components: + - type: Anchorable + flags: + - Anchorable + - type: Rotatable - type: StationAiWhitelist - type: MeleeSound soundGroups: diff --git a/Resources/Prototypes/Entities/Structures/Doors/Airlocks/highsec.yml b/Resources/Prototypes/Entities/Structures/Doors/Airlocks/highsec.yml index bf8857311c3..7079339e4e8 100644 --- a/Resources/Prototypes/Entities/Structures/Doors/Airlocks/highsec.yml +++ b/Resources/Prototypes/Entities/Structures/Doors/Airlocks/highsec.yml @@ -6,9 +6,14 @@ placement: mode: SnapgridCenter components: + - type: Anchorable + flags: + - Anchorable + - type: Rotatable - type: StationAiWhitelist - type: InteractionOutline - type: Sprite + snapCardinals: true sprite: _DV/Structures/Doors/Airlocks/highsec/highsec.rsi #Delta V - Resprite Doors layers: - state: closed diff --git a/Resources/Prototypes/Entities/Structures/Doors/Firelocks/firelock.yml b/Resources/Prototypes/Entities/Structures/Doors/Firelocks/firelock.yml index b9b3a175194..5c61e440bb8 100644 --- a/Resources/Prototypes/Entities/Structures/Doors/Firelocks/firelock.yml +++ b/Resources/Prototypes/Entities/Structures/Doors/Firelocks/firelock.yml @@ -5,6 +5,10 @@ name: firelock description: Apply crowbar. components: + - type: Anchorable + flags: + - Anchorable + - type: Rotatable - type: AtmosAlarmable syncWith: - FireAlarm diff --git a/Resources/Prototypes/Entities/Structures/Doors/MaterialDoors/material_doors.yml b/Resources/Prototypes/Entities/Structures/Doors/MaterialDoors/material_doors.yml index 1ce3d1b61c7..510b76b41eb 100644 --- a/Resources/Prototypes/Entities/Structures/Doors/MaterialDoors/material_doors.yml +++ b/Resources/Prototypes/Entities/Structures/Doors/MaterialDoors/material_doors.yml @@ -5,6 +5,10 @@ abstract: true description: A door, where will it lead? components: + - type: Anchorable + flags: + - Anchorable + - type: Rotatable - type: InteractionOutline - type: Sprite sprite: Structures/Doors/MineralDoors/metal_door.rsi diff --git a/Resources/Prototypes/Entities/Structures/Doors/SecretDoor/secret_door.yml b/Resources/Prototypes/Entities/Structures/Doors/SecretDoor/secret_door.yml index 8c17ea8f1d9..a2e3befe52e 100644 --- a/Resources/Prototypes/Entities/Structures/Doors/SecretDoor/secret_door.yml +++ b/Resources/Prototypes/Entities/Structures/Doors/SecretDoor/secret_door.yml @@ -6,6 +6,10 @@ abstract: true description: Keeps the air in and the greytide out. components: + - type: Anchorable + flags: + - Anchorable + - type: Rotatable - type: Sprite sprite: _DV/Structures/Doors/secret_door.rsi #Delta V - Resprite Doors layers: diff --git a/Resources/Prototypes/Entities/Structures/Doors/Shutter/shutters.yml b/Resources/Prototypes/Entities/Structures/Doors/Shutter/shutters.yml index ca870d7c7da..6e855a150f1 100644 --- a/Resources/Prototypes/Entities/Structures/Doors/Shutter/shutters.yml +++ b/Resources/Prototypes/Entities/Structures/Doors/Shutter/shutters.yml @@ -7,6 +7,10 @@ placement: mode: SnapgridCenter components: + - type: Anchorable + flags: + - Anchorable + - type: Rotatable - type: StationAiWhitelist - type: Sprite sprite: Structures/Doors/Shutters/shutters.rsi diff --git a/Resources/Prototypes/Entities/Structures/Doors/Windoors/base_structurewindoors.yml b/Resources/Prototypes/Entities/Structures/Doors/Windoors/base_structurewindoors.yml index d3bf9a8ff96..991b999273f 100644 --- a/Resources/Prototypes/Entities/Structures/Doors/Windoors/base_structurewindoors.yml +++ b/Resources/Prototypes/Entities/Structures/Doors/Windoors/base_structurewindoors.yml @@ -6,6 +6,10 @@ placement: mode: SnapgridCenter components: + - type: Anchorable + flags: + - Anchorable + - type: Rotatable - type: MeleeSound soundGroups: Brute: diff --git a/Resources/Prototypes/Entities/Structures/Wallmounts/base_wallmount.yml b/Resources/Prototypes/Entities/Structures/Wallmounts/base_wallmount.yml index 49e4a62fd46..b064d4a231a 100644 --- a/Resources/Prototypes/Entities/Structures/Wallmounts/base_wallmount.yml +++ b/Resources/Prototypes/Entities/Structures/Wallmounts/base_wallmount.yml @@ -6,6 +6,10 @@ snap: - Wallmount components: + - type: Anchorable + flags: + - Anchorable + - type: Rotatable - type: Physics canCollide: false - type: Clickable diff --git a/Resources/Prototypes/Entities/Structures/Walls/walls.yml b/Resources/Prototypes/Entities/Structures/Walls/walls.yml index a273e73f3fd..643f06dc85b 100644 --- a/Resources/Prototypes/Entities/Structures/Walls/walls.yml +++ b/Resources/Prototypes/Entities/Structures/Walls/walls.yml @@ -9,6 +9,10 @@ snap: - Wall components: + - type: Anchorable + flags: + - Anchorable + - type: Rotatable - type: RangedDamageSound soundGroups: Brute: diff --git a/Resources/Prototypes/Entities/Structures/Windows/window.yml b/Resources/Prototypes/Entities/Structures/Windows/window.yml index c62edeec438..59facb454e0 100644 --- a/Resources/Prototypes/Entities/Structures/Windows/window.yml +++ b/Resources/Prototypes/Entities/Structures/Windows/window.yml @@ -8,6 +8,10 @@ snap: - Window components: + - type: Anchorable + flags: + - Anchorable + - type: Rotatable - type: MeleeSound soundGroups: Brute: diff --git a/Resources/Prototypes/Entities/Structures/catwalk.yml b/Resources/Prototypes/Entities/Structures/catwalk.yml index 0a44c338a4d..669f4a6800c 100644 --- a/Resources/Prototypes/Entities/Structures/catwalk.yml +++ b/Resources/Prototypes/Entities/Structures/catwalk.yml @@ -6,6 +6,10 @@ placement: mode: SnapgridCenter components: + - type: Anchorable + flags: + - Anchorable + - type: Rotatable - type: Clickable - type: Sprite sprite: Structures/catwalk.rsi diff --git a/Resources/Prototypes/Entities/Structures/cryogenic_sleep_unit.yml b/Resources/Prototypes/Entities/Structures/cryogenic_sleep_unit.yml index 568c38a5d22..7458cd2b699 100644 --- a/Resources/Prototypes/Entities/Structures/cryogenic_sleep_unit.yml +++ b/Resources/Prototypes/Entities/Structures/cryogenic_sleep_unit.yml @@ -4,6 +4,10 @@ name: cryogenic sleep unit description: A super-cooled container that keeps crewmates safe during space travel. components: + - type: Anchorable + flags: + - Anchorable + - type: Rotatable - type: Sprite noRot: true sprite: Structures/cryostorage.rsi diff --git a/Resources/Prototypes/Entities/Structures/plastic_flaps.yml b/Resources/Prototypes/Entities/Structures/plastic_flaps.yml index 088ddfda61b..a8fa40b69dc 100644 --- a/Resources/Prototypes/Entities/Structures/plastic_flaps.yml +++ b/Resources/Prototypes/Entities/Structures/plastic_flaps.yml @@ -5,6 +5,10 @@ placement: mode: SnapgridCenter components: + - type: Anchorable + flags: + - Anchorable + - type: Rotatable - type: Sprite sprite: Structures/plastic_flaps.rsi state: plasticflaps diff --git a/Resources/Prototypes/Entities/Structures/stairs.yml b/Resources/Prototypes/Entities/Structures/stairs.yml index 9174e0ae0e7..c796a7a06ab 100644 --- a/Resources/Prototypes/Entities/Structures/stairs.yml +++ b/Resources/Prototypes/Entities/Structures/stairs.yml @@ -6,6 +6,10 @@ placement: mode: SnapgridCenter components: + - type: Anchorable + flags: + - Anchorable + - type: Rotatable - type: Clickable - type: Sprite sprite: _DV/Structures/stairs.rsi # Delta V - Resprite stairs From 8aa6bdc284f6873d5c5f25a9c43a5028f0421286 Mon Sep 17 00:00:00 2001 From: Fildrance Date: Thu, 28 Aug 2025 11:46:24 +0300 Subject: [PATCH 267/340] Revert "Added button and manager for in game bug reports (Part 1)" (#39872) Revert "Added button and manager for in game bug reports (Part 1) (#35350)" This reverts commit a8d6dbc3241c880f846a7abba8bd330788df9fc1. --- .../BugReport/BugReportUIController.cs | 113 ----- .../BugReport/Windows/BugReportWindow.xaml | 31 -- .../BugReport/Windows/BugReportWindow.xaml.cs | 181 -------- .../MenuBar/GameTopMenuBarUIController.cs | 4 - .../MenuBar/Widgets/GameTopMenuBar.xaml | 9 - Content.Server/BugReports/BugReportManager.cs | 221 ---------- Content.Server/BugReports/IBugReportEvents.cs | 94 ---- .../BugReports/IBugReportManager.cs | 22 - Content.Server/Entry/EntryPoint.cs | 10 +- .../GameTicking/GameTicker.RoundFlow.cs | 2 - Content.Server/GameTicking/GameTicker.cs | 2 - .../Github/Commands/TestGithubApiCommand.cs | 71 --- Content.Server/Github/GithubApiManager.cs | 53 --- .../Github/GithubBackgroundWorker.cs | 74 ---- Content.Server/Github/GithubClient.cs | 417 ------------------ .../Github/Requests/CreateIssueRequest.cs | 38 -- .../Github/Requests/IGithubRequest.cs | 44 -- .../Github/Requests/InstallationsRequest.cs | 18 - .../Github/Requests/TokenRequest.cs | 22 - .../Github/Responses/InstallationResponse.cs | 21 - .../Github/Responses/TokenResponse.cs | 15 - Content.Server/Github/RetryHttpHandler.cs | 100 ----- Content.Server/IoC/ServerContentIoC.cs | 7 +- Content.Shared.Database/LogType.cs | 6 - Content.Shared/BugReport/BugReportMessage.cs | 42 -- Content.Shared/CCVar/CCVars.BugReports.cs | 64 --- Content.Shared/CCVar/CCVars.Github.cs | 71 --- Resources/Locale/en-US/HUD/game-hud.ftl | 1 - .../en-US/bugreport/bug-report-report.ftl | 1 - .../en-US/bugreport/bug-report-window.ftl | 13 - Resources/Locale/en-US/github/github-api.ftl | 36 -- Resources/Textures/Interface/bug.svg | 13 - .../Textures/Interface/bug.svg.192dpi.png | Bin 1852 -> 0 bytes .../Textures/Interface/bug.svg.192dpi.png.yml | 2 - Resources/Textures/Interface/splat.svg | 14 - .../Textures/Interface/splat.svg.192dpi.png | Bin 2069 -> 0 bytes .../Interface/splat.svg.192dpi.png.yml | 2 - 37 files changed, 3 insertions(+), 1831 deletions(-) delete mode 100644 Content.Client/UserInterface/Systems/BugReport/BugReportUIController.cs delete mode 100644 Content.Client/UserInterface/Systems/BugReport/Windows/BugReportWindow.xaml delete mode 100644 Content.Client/UserInterface/Systems/BugReport/Windows/BugReportWindow.xaml.cs delete mode 100644 Content.Server/BugReports/BugReportManager.cs delete mode 100644 Content.Server/BugReports/IBugReportEvents.cs delete mode 100644 Content.Server/BugReports/IBugReportManager.cs delete mode 100644 Content.Server/Github/Commands/TestGithubApiCommand.cs delete mode 100644 Content.Server/Github/GithubApiManager.cs delete mode 100644 Content.Server/Github/GithubBackgroundWorker.cs delete mode 100644 Content.Server/Github/GithubClient.cs delete mode 100644 Content.Server/Github/Requests/CreateIssueRequest.cs delete mode 100644 Content.Server/Github/Requests/IGithubRequest.cs delete mode 100644 Content.Server/Github/Requests/InstallationsRequest.cs delete mode 100644 Content.Server/Github/Requests/TokenRequest.cs delete mode 100644 Content.Server/Github/Responses/InstallationResponse.cs delete mode 100644 Content.Server/Github/Responses/TokenResponse.cs delete mode 100644 Content.Server/Github/RetryHttpHandler.cs delete mode 100644 Content.Shared/BugReport/BugReportMessage.cs delete mode 100644 Content.Shared/CCVar/CCVars.BugReports.cs delete mode 100644 Content.Shared/CCVar/CCVars.Github.cs delete mode 100644 Resources/Locale/en-US/bugreport/bug-report-report.ftl delete mode 100644 Resources/Locale/en-US/bugreport/bug-report-window.ftl delete mode 100644 Resources/Locale/en-US/github/github-api.ftl delete mode 100644 Resources/Textures/Interface/bug.svg delete mode 100644 Resources/Textures/Interface/bug.svg.192dpi.png delete mode 100644 Resources/Textures/Interface/bug.svg.192dpi.png.yml delete mode 100644 Resources/Textures/Interface/splat.svg delete mode 100644 Resources/Textures/Interface/splat.svg.192dpi.png delete mode 100644 Resources/Textures/Interface/splat.svg.192dpi.png.yml diff --git a/Content.Client/UserInterface/Systems/BugReport/BugReportUIController.cs b/Content.Client/UserInterface/Systems/BugReport/BugReportUIController.cs deleted file mode 100644 index 7d45829bd27..00000000000 --- a/Content.Client/UserInterface/Systems/BugReport/BugReportUIController.cs +++ /dev/null @@ -1,113 +0,0 @@ -using Content.Client.Gameplay; -using Content.Client.Resources; -using Content.Client.UserInterface.Controls; -using Content.Client.UserInterface.Systems.BugReport.Windows; -using Content.Client.UserInterface.Systems.MenuBar.Widgets; -using Content.Shared.BugReport; -using Content.Shared.CCVar; -using JetBrains.Annotations; -using Robust.Client.ResourceManagement; -using Robust.Client.UserInterface.Controllers; -using Robust.Client.UserInterface.Controls; -using Robust.Shared.Configuration; -using Robust.Shared.Network; -using Robust.Shared.Utility; - -namespace Content.Client.UserInterface.Systems.BugReport; - -[UsedImplicitly] -public sealed class BugReportUIController : UIController, IOnStateEntered, IOnStateExited -{ - [Dependency] private readonly IClientNetManager _net = default!; - [Dependency] private readonly IConfigurationManager _cfg = default!; - [Dependency] private readonly IResourceCache _resource = default!; - - // This is the link to the hotbar button - private MenuButton? BugReportButton => UIManager.GetActiveUIWidgetOrNull()?.ReportBugButton; - - // Don't clear this window. It needs to be saved so the input doesn't get erased when it's closed! - private BugReportWindow _bugReportWindow = default!; - - private ResPath Bug = new("/Textures/Interface/bug.svg.192dpi.png"); - private ResPath Splat = new("/Textures/Interface/splat.svg.192dpi.png"); - - public void OnStateEntered(GameplayState state) - { - SetupWindow(); - } - - public void OnStateExited(GameplayState state) - { - CleanupWindow(); - } - - public void LoadButton() - { - if (BugReportButton != null) - BugReportButton.OnPressed += ButtonToggleWindow; - } - - public void UnloadButton() - { - if (BugReportButton != null) - BugReportButton.OnPressed -= ButtonToggleWindow; - } - - private void SetupWindow() - { - if (BugReportButton == null) - return; - - _bugReportWindow = UIManager.CreateWindow(); - // This is to make sure the hotbar button gets checked and unchecked when the window is opened / closed. - _bugReportWindow.OnClose += () => - { - BugReportButton.Pressed = false; - BugReportButton.Icon = _resource.GetTexture(Bug); - }; - _bugReportWindow.OnOpen += () => - { - BugReportButton.Pressed = true; - BugReportButton.Icon = _resource.GetTexture(Splat); - }; - - _bugReportWindow.OnBugReportSubmitted += OnBugReportSubmitted; - - _cfg.OnValueChanged(CCVars.EnablePlayerBugReports, UpdateButtonVisibility, true); - } - - private void CleanupWindow() - { - _bugReportWindow.CleanupCCvars(); - - _cfg.UnsubValueChanged(CCVars.EnablePlayerBugReports, UpdateButtonVisibility); - } - - private void ToggleWindow() - { - if (_bugReportWindow.IsOpen) - _bugReportWindow.Close(); - else - _bugReportWindow.OpenCentered(); - } - - private void OnBugReportSubmitted(PlayerBugReportInformation report) - { - var message = new BugReportMessage { ReportInformation = report }; - _net.ClientSendMessage(message); - _bugReportWindow.Close(); - } - - private void ButtonToggleWindow(BaseButton.ButtonEventArgs obj) - { - ToggleWindow(); - } - - private void UpdateButtonVisibility(bool val) - { - if (BugReportButton == null) - return; - - BugReportButton.Visible = val; - } -} diff --git a/Content.Client/UserInterface/Systems/BugReport/Windows/BugReportWindow.xaml b/Content.Client/UserInterface/Systems/BugReport/Windows/BugReportWindow.xaml deleted file mode 100644 index d3d6570a41d..00000000000 --- a/Content.Client/UserInterface/Systems/BugReport/Windows/BugReportWindow.xaml +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Content.Client/UserInterface/Systems/BugReport/Windows/BugReportWindow.xaml.cs b/Content.Client/UserInterface/Systems/BugReport/Windows/BugReportWindow.xaml.cs deleted file mode 100644 index a43ba15d68a..00000000000 --- a/Content.Client/UserInterface/Systems/BugReport/Windows/BugReportWindow.xaml.cs +++ /dev/null @@ -1,181 +0,0 @@ -using System.Diagnostics.CodeAnalysis; -using Content.Client.Players.PlayTimeTracking; -using Content.Shared.BugReport; -using Content.Shared.CCVar; -using Robust.Client.AutoGenerated; -using Robust.Client.UserInterface.CustomControls; -using Robust.Client.UserInterface.XAML; -using Robust.Shared.Configuration; -using Robust.Shared.Timing; -using Robust.Shared.Utility; - -namespace Content.Client.UserInterface.Systems.BugReport.Windows; - -[GenerateTypedNameReferences] -public sealed partial class BugReportWindow : DefaultWindow -{ - [Dependency] private readonly IConfigurationManager _cfg = default!; - // TODO: Use SharedPlaytimeManager when its refactored out of job requirements - [Dependency] private readonly JobRequirementsManager _job = default!; - - // This action gets invoked when the user submits a bug report. - public event Action? OnBugReportSubmitted; - - private DateTime _lastIsEnabledUpdated; - private readonly TimeSpan _isEnabledUpdateInterval = TimeSpan.FromSeconds(1); - - // These are NOT always up to date. If someone disconnects and reconnects, the values will be reset. - // The only other way of getting updated values would be a message from client -> server then from server -> client. - // I don't think that is worth the added complexity. - private DateTime _lastBugReportSubmittedTime = DateTime.MinValue; - private int _amountOfBugReportsSubmitted; - - private readonly ConfigurationMultiSubscriptionBuilder _configSub; - - #region ccvar - - private bool _enablePlayerBugReports; - private int _minimumPlaytimeBugReports; - private int _minimumTimeBetweenBugReports; - private int _maximumBugReportsPerRound; - - private int _maximumBugReportTitleLength; - private int _minimumBugReportTitleLength; - private int _maximumBugReportDescriptionLength; - private int _minimumBugReportDescriptionLength; - - #endregion - - public BugReportWindow() - { - RobustXamlLoader.Load(this); - IoCManager.InjectDependencies(this); - - _configSub = _cfg.SubscribeMultiple() - .OnValueChanged(CCVars.EnablePlayerBugReports, x => _enablePlayerBugReports = x, true) - .OnValueChanged(CCVars.MinimumPlaytimeInMinutesToEnableBugReports, x => _minimumPlaytimeBugReports = x, true) - .OnValueChanged(CCVars.MinimumSecondsBetweenBugReports, x => _minimumTimeBetweenBugReports = x, true) - .OnValueChanged(CCVars.MaximumBugReportsPerRound, x => _maximumBugReportsPerRound = x, true) - .OnValueChanged(CCVars.MaximumBugReportTitleLength, x => _maximumBugReportTitleLength = x, true) - .OnValueChanged(CCVars.MinimumBugReportTitleLength, x => _minimumBugReportTitleLength = x, true) - .OnValueChanged(CCVars.MaximumBugReportDescriptionLength, x => _maximumBugReportDescriptionLength = x, true) - .OnValueChanged(CCVars.MinimumBugReportDescriptionLength, x => _minimumBugReportDescriptionLength = x, true); - - // Hook up the events - SubmitButton.OnPressed += _ => OnSubmitButtonPressed(); - BugReportTitle.OnTextChanged += _ => HandleInputChange(); - BugReportDescription.OnTextChanged += _ => HandleInputChange(); - OnOpen += UpdateEnabled; - - HandleInputChange(); - UpdateEnabled(); - } - - private void OnSubmitButtonPressed() - { - var report = new PlayerBugReportInformation - { - BugReportTitle = BugReportTitle.Text, - BugReportDescription = Rope.Collapse(BugReportDescription.TextRope), - }; - OnBugReportSubmitted?.Invoke(report); - - _lastBugReportSubmittedTime = DateTime.UtcNow; - _amountOfBugReportsSubmitted++; - - BugReportTitle.Text = string.Empty; - BugReportDescription.TextRope = Rope.Leaf.Empty; - - HandleInputChange(); - UpdateEnabled(); - } - - /// - /// Deals with the user changing their input. Ensures that things that depend on what the user has inputted get updated - /// (E.g. the amount of characters they have typed) - /// - private void HandleInputChange() - { - var titleLen = BugReportTitle.Text.Length; - var descriptionLen = BugReportDescription.TextLength; - - var invalidTitleLen = titleLen < _minimumBugReportTitleLength || titleLen > _maximumBugReportTitleLength; - var invalidDescriptionLen = descriptionLen < _minimumBugReportDescriptionLength || descriptionLen > _maximumBugReportDescriptionLength; - - TitleCharacterCounter.Text = Loc.GetString("bug-report-window-submit-char-split", ("typed", titleLen), ("total", _maximumBugReportTitleLength)); - TitleCharacterCounter.FontColorOverride = invalidTitleLen ? Color.Red : Color.Green; - - DescriptionCharacterCounter.Text = Loc.GetString("bug-report-window-submit-char-split", ("typed", descriptionLen), ("total", _maximumBugReportDescriptionLength)); - - DescriptionCharacterCounter.FontColorOverride = invalidDescriptionLen ? Color.Red : Color.Green; - - SubmitButton.Disabled = invalidTitleLen || invalidDescriptionLen; - - PlaceholderCenter.Visible = descriptionLen == 0; - } - - /// - /// Checks if the bug report window should be enabled for this client. - /// - private bool IsEnabled([NotNullWhen(false)] out string? errorMessage) - { - errorMessage = null; - - if (!_enablePlayerBugReports) - { - errorMessage = Loc.GetString("bug-report-window-disabled-not-enabled"); - return false; - } - - if (TimeSpan.FromMinutes(_minimumPlaytimeBugReports) > _job.FetchOverallPlaytime()) - { - errorMessage = Loc.GetString("bug-report-window-disabled-playtime"); - return false; - } - - if (_amountOfBugReportsSubmitted >= _maximumBugReportsPerRound) - { - errorMessage = Loc.GetString("bug-report-window-disabled-submissions", ("num", _maximumBugReportsPerRound)); - return false; - } - - var timeSinceLastReport = DateTime.UtcNow - _lastBugReportSubmittedTime; - var timeBetweenBugReports = TimeSpan.FromSeconds(_minimumTimeBetweenBugReports); - - if (timeSinceLastReport <= timeBetweenBugReports) - { - var time = timeBetweenBugReports - timeSinceLastReport; - errorMessage = Loc.GetString("bug-report-window-disabled-cooldown", ("time", time.ToString(@"d\.hh\:mm\:ss"))); - return false; - } - - return true; - } - - // Update the state of the window to display either the bug report window or an error explaining why you can't submit a report. - private void UpdateEnabled() - { - var isEnabled = IsEnabled(out var errorMessage); - DisabledLabel.Text = errorMessage; - - DisabledLabel.Visible = !isEnabled; - BugReportContainer.Visible = isEnabled; - _lastIsEnabledUpdated = DateTime.UtcNow; - } - - protected override void FrameUpdate(FrameEventArgs args) - { - base.FrameUpdate(args); - - if (!Visible) // Don't bother updating if no one can see the window anyway. - return; - - if(DateTime.UtcNow - _lastIsEnabledUpdated > _isEnabledUpdateInterval) - UpdateEnabled(); - } - - public void CleanupCCvars() - { - _configSub.Dispose(); - } -} diff --git a/Content.Client/UserInterface/Systems/MenuBar/GameTopMenuBarUIController.cs b/Content.Client/UserInterface/Systems/MenuBar/GameTopMenuBarUIController.cs index fb7c7f9d25a..e314310bc0c 100644 --- a/Content.Client/UserInterface/Systems/MenuBar/GameTopMenuBarUIController.cs +++ b/Content.Client/UserInterface/Systems/MenuBar/GameTopMenuBarUIController.cs @@ -1,6 +1,5 @@ using Content.Client.UserInterface.Systems.Actions; using Content.Client.UserInterface.Systems.Admin; -using Content.Client.UserInterface.Systems.BugReport; using Content.Client.UserInterface.Systems.Bwoink; using Content.Client.UserInterface.Systems.Character; using Content.Client.UserInterface.Systems.Crafting; @@ -25,7 +24,6 @@ public sealed class GameTopMenuBarUIController : UIController [Dependency] private readonly SandboxUIController _sandbox = default!; [Dependency] private readonly GuidebookUIController _guidebook = default!; [Dependency] private readonly EmotesUIController _emotes = default!; - [Dependency] private readonly BugReportUIController _bug = default!; private GameTopMenuBar? GameTopMenuBar => UIManager.GetActiveUIWidgetOrNull(); @@ -49,7 +47,6 @@ public sealed class GameTopMenuBarUIController : UIController _action.UnloadButton(); _sandbox.UnloadButton(); _emotes.UnloadButton(); - _bug.UnloadButton(); } public void LoadButtons() @@ -63,6 +60,5 @@ public sealed class GameTopMenuBarUIController : UIController _action.LoadButton(); _sandbox.LoadButton(); _emotes.LoadButton(); - _bug.LoadButton(); } } diff --git a/Content.Client/UserInterface/Systems/MenuBar/Widgets/GameTopMenuBar.xaml b/Content.Client/UserInterface/Systems/MenuBar/Widgets/GameTopMenuBar.xaml index c85224e5f83..85b404e5c9b 100644 --- a/Content.Client/UserInterface/Systems/MenuBar/Widgets/GameTopMenuBar.xaml +++ b/Content.Client/UserInterface/Systems/MenuBar/Widgets/GameTopMenuBar.xaml @@ -105,15 +105,6 @@ AppendStyleClass="{x:Static style:StyleBase.ButtonSquare}" /> - -public sealed class BugReportManager : IBugReportManager, IPostInjectInit -{ - [Dependency] private readonly IServerNetManager _net = default!; - [Dependency] private readonly IEntityManager _entity = default!; - [Dependency] private readonly PlayTimeTrackingManager _playTime = default!; - [Dependency] private readonly IPlayerManager _player = default!; - [Dependency] private readonly IConfigurationManager _cfg = default!; - [Dependency] private readonly IAdminLogManager _admin = default!; - [Dependency] private readonly IGameMapManager _map = default!; - [Dependency] private readonly GithubApiManager _githubApiManager = default!; - [Dependency] private readonly IGameTiming _timing = default!; - [Dependency] private readonly ILogManager _log = default!; - - private ISawmill _sawmill = default!; - - /// - /// List of player NetIds and the number of bug reports they have submitted this round. - /// UserId -> (bug reports this round, last submitted bug report) - /// - private readonly Dictionary _bugReportsPerPlayerThisRound = new(); - - private BugReportLimits _limits = default!; - - private List _tags = []; - - private ConfigurationMultiSubscriptionBuilder _configSub = default!; - - public void Initialize() - { - _net.RegisterNetMessage(ReceivedPlayerBugReport); - - _limits = new BugReportLimits(); - - _configSub = _cfg.SubscribeMultiple() - .OnValueChanged(CCVars.MaximumBugReportTitleLength, x => _limits.TitleMaxLength = x, true) - .OnValueChanged(CCVars.MinimumBugReportTitleLength, x => _limits.TitleMinLength = x, true) - .OnValueChanged(CCVars.MaximumBugReportDescriptionLength, x => _limits.DescriptionMaxLength = x, true) - .OnValueChanged(CCVars.MinimumBugReportDescriptionLength, x => _limits.DescriptionMinLength = x, true) - .OnValueChanged(CCVars.MinimumPlaytimeInMinutesToEnableBugReports, x => _limits.MinimumPlaytimeToEnableBugReports = TimeSpan.FromMinutes(x), true) - .OnValueChanged(CCVars.MaximumBugReportsPerRound, x => _limits.MaximumBugReportsForPlayerPerRound = x, true) - .OnValueChanged(CCVars.MinimumSecondsBetweenBugReports, x => _limits.MinimumTimeBetweenBugReports = TimeSpan.FromSeconds(x), true) - .OnValueChanged(CCVars.BugReportTags, x => _tags = x.Split(",").ToList(), true); - } - - public void Restart() - { - // When the round restarts, clear the dictionary. - _bugReportsPerPlayerThisRound.Clear(); - } - - public void Shutdown() - { - _configSub.Dispose(); - } - - private void ReceivedPlayerBugReport(BugReportMessage message) - { - if (!_cfg.GetCVar(CCVars.EnablePlayerBugReports)) - return; - - var netId = message.MsgChannel.UserId; - var userName = message.MsgChannel.UserName; - var report = message.ReportInformation; - if (!IsBugReportValid(report, (NetId: netId, UserName: userName)) || !CanPlayerSendReport(netId, userName)) - return; - - var playerBugReportingStats = _bugReportsPerPlayerThisRound.GetValueOrDefault(netId); - _bugReportsPerPlayerThisRound[netId] = (playerBugReportingStats.ReportsCount + 1, DateTime.UtcNow); - - var title = report.BugReportTitle; - var description = report.BugReportDescription; - - _admin.Add(LogType.BugReport, LogImpact.High, $"{message.MsgChannel.UserName}, {netId}: submitted a bug report. Title: {title}, Description: {description}"); - - var bugReport = CreateBugReport(message); - - _githubApiManager.TryCreateIssue(bugReport); - } - - /// - /// Checks that the given report is valid (E.g. not too long etc...). - /// Logs problems if report is invalid. - /// - /// True if the report is valid, false there is an issue with the report. - private bool IsBugReportValid(PlayerBugReportInformation report, (NetUserId NetId, string UserName) userData) - { - var descriptionLen = report.BugReportDescription.Length; - var titleLen = report.BugReportTitle.Length; - - // These should only happen if there is a hacked client or a glitch! - if (titleLen < _limits.TitleMinLength || titleLen > _limits.TitleMaxLength) - { - _sawmill.Warning( - $"{userData.UserName}, {userData.NetId}: has tried to submit a bug report " - + $"with a title of {titleLen} characters, min/max: {_limits.TitleMinLength}/{_limits.TitleMaxLength}." - ); - return false; - } - - if (descriptionLen < _limits.DescriptionMinLength || descriptionLen > _limits.DescriptionMaxLength) - { - _sawmill.Warning( - $"{userData.UserName}, {userData.NetId}: has tried to submit a bug report " - + $"with a description of {descriptionLen} characters, min/max: {_limits.DescriptionMinLength}/{_limits.DescriptionMaxLength}." - ); - return false; - } - - return true; - } - - /// - /// Checks that the player sending the report is allowed to (E.g. not spamming etc...). - /// Logs problems if report is invalid. - /// - /// True if the player can submit a report, false if they can't. - private bool CanPlayerSendReport(NetUserId netId, string userName) - { - var session = _player.GetSessionById(netId); - var playtime = _playTime.GetOverallPlaytime(session); - if (_limits.MinimumPlaytimeToEnableBugReports > playtime) - return false; - - var playerBugReportingStats = _bugReportsPerPlayerThisRound.GetValueOrDefault(netId); - var maximumBugReportsForPlayerPerRound = _limits.MaximumBugReportsForPlayerPerRound; - if (playerBugReportingStats.ReportsCount >= maximumBugReportsForPlayerPerRound) - { - _admin.Add(LogType.BugReport, - LogImpact.High, - $"{userName}, {netId}: has tried to submit more than {maximumBugReportsForPlayerPerRound} bug reports this round."); - return false; - } - - var timeSinceLastReport = DateTime.UtcNow - playerBugReportingStats.ReportedDateTime; - var timeBetweenBugReports = _limits.MinimumTimeBetweenBugReports; - if (timeSinceLastReport <= timeBetweenBugReports) - { - _admin.Add(LogType.BugReport, - LogImpact.High, - $"{userName}, {netId}: has tried to submit a bug report. " - + $"Last bug report was {timeSinceLastReport:g} ago. The limit is {timeBetweenBugReports:g} minutes." - ); - return false; - } - - return true; - } - - /// - /// Create a bug report out of the given message. Add will extra metadata that could be useful, along with - /// the original text report from the user. - /// - /// The message from user. - /// A based of the user report. - private ValidPlayerBugReportReceivedEvent CreateBugReport(BugReportMessage message) - { - // todo: dont request entity system out of sim, check if you are in-sim before doing so. Bug report should work out of sim too. - var ticker = _entity.System(); - var metadata = new BugReportMetaData - { - Username = message.MsgChannel.UserName, - PlayerGUID = message.MsgChannel.UserData.UserId, - ServerName = _cfg.GetCVar(CCVars.AdminLogsServerName), - NumberOfPlayers = _player.PlayerCount, - SubmittedTime = DateTime.UtcNow, - BuildVersion = _cfg.GetCVar(CVars.BuildVersion), - EngineVersion = _cfg.GetCVar(CVars.BuildEngineVersion), - }; - - // Only add these if your in round. - if (ticker.Preset != null) - { - metadata.RoundTime = _timing.CurTime.Subtract(ticker.RoundStartTimeSpan); - metadata.RoundNumber = ticker.RoundId; - metadata.RoundType = Loc.GetString(ticker.CurrentPreset?.ModeTitle ?? "bug-report-report-unknown"); - metadata.Map = _map.GetSelectedMap()?.MapName ?? Loc.GetString("bug-report-report-unknown"); - } - - return new ValidPlayerBugReportReceivedEvent( - message.ReportInformation.BugReportTitle.Trim(), - message.ReportInformation.BugReportDescription.Trim(), - metadata, - _tags - ); - } - - void IPostInjectInit.PostInject() - { - _sawmill = _log.GetSawmill("BugReport"); - } - - private sealed class BugReportLimits - { - public int TitleMaxLength; - public int TitleMinLength; - public int DescriptionMaxLength; - public int DescriptionMinLength; - - public TimeSpan MinimumPlaytimeToEnableBugReports; - public int MaximumBugReportsForPlayerPerRound; - public TimeSpan MinimumTimeBetweenBugReports; - } -} diff --git a/Content.Server/BugReports/IBugReportEvents.cs b/Content.Server/BugReports/IBugReportEvents.cs deleted file mode 100644 index 3e79ff542ea..00000000000 --- a/Content.Server/BugReports/IBugReportEvents.cs +++ /dev/null @@ -1,94 +0,0 @@ -using Robust.Shared.Network; - -namespace Content.Server.BugReports; - -/// -/// This event stores information related to a player submitted bug report. -/// -public sealed class ValidPlayerBugReportReceivedEvent(string title, string description, BugReportMetaData metaData, List tags) : EventArgs -{ - /// - /// Title for the bug report. This is player controlled! - /// - public string Title = title; - - /// - /// Description for the bug report. This is player controlled! - /// - public string Description = description; - - /// - /// Metadata for bug report, containing data collected by server. - /// - public BugReportMetaData MetaData = metaData; - - public List Tags = tags; -} - -/// -/// Metadata for a bug report. Holds relevant data for bug reports that aren't directly player controlled. -/// -public sealed class BugReportMetaData -{ - /// - /// Bug reporter SS14 username. - /// - /// piggylongsnout - public required string Username; - - /// - /// The GUID of the player who reported the bug. - /// - public required NetUserId PlayerGUID; - - /// - /// Name of the server from which bug report was issued. - /// - /// DeltaV> - public required string ServerName; - - /// - /// Date and time on which player submitted report (NOT round time). - /// The time is UTC and based off the servers clock. - /// - public required DateTime SubmittedTime; - - /// - /// Time that has elapsed in the round. Can be null if bug was not reported during a round. - /// - public TimeSpan? RoundTime; - - /// - /// Round number during which bug report was issued. Can be null if bug was reported not during round. - /// - /// 1311 - public int? RoundNumber; - - /// - /// Type preset title (type of round that is being played). Can be null if bug was reported not during round. - /// - /// Sandbox - public string? RoundType; - - /// - /// The map being played. - /// - /// "Dev"> - public string? Map; - - /// - /// Number of players currently on server. - /// - public int NumberOfPlayers; - - /// - /// Build version of the game. - /// - public required string BuildVersion; - - /// - /// Engine version of the game. - /// - /// 253.0.0 - public required string EngineVersion; -} diff --git a/Content.Server/BugReports/IBugReportManager.cs b/Content.Server/BugReports/IBugReportManager.cs deleted file mode 100644 index 28264bc8c02..00000000000 --- a/Content.Server/BugReports/IBugReportManager.cs +++ /dev/null @@ -1,22 +0,0 @@ -namespace Content.Server.BugReports; - -/// -/// Manager for validating client bug reports, issued in-game, and relaying creation of issue in tracker to dedicated api client. -/// -public interface IBugReportManager -{ - /// Will get called when the manager is first initialized. - public void Initialize(); - - /// - /// Will get called whenever the round is restarted. - /// Should be used to clean up anything that needs reset after each round. - /// - public void Restart(); - - /// - /// Will get called whenever the round is restarted. - /// Should be used to clean up anything that needs reset after each round. - /// - public void Shutdown(); -} diff --git a/Content.Server/Entry/EntryPoint.cs b/Content.Server/Entry/EntryPoint.cs index 76ba99b6ea5..ede71e503c2 100644 --- a/Content.Server/Entry/EntryPoint.cs +++ b/Content.Server/Entry/EntryPoint.cs @@ -3,7 +3,6 @@ using Content.Server.Administration; using Content.Server.Administration.Logs; using Content.Server.Administration.Managers; using Content.Server.Afk; -using Content.Server.BugReports; using Content.Server.Chat.Managers; using Content.Server.Connection; using Content.Server.Database; @@ -12,12 +11,13 @@ using Content.Server.Discord.DiscordLink; using Content.Server.EUI; using Content.Server.GameTicking; using Content.Server.GhostKick; -using Content.Server.Github; using Content.Server.GuideGenerator; using Content.Server.Info; using Content.Server.IoC; using Content.Server.Maps; using Content.Server.NodeContainer.NodeGroups; +using Content.Server.Objectives; +using Content.Server.Players; using Content.Server.Players.JobWhitelist; using Content.Server.Players.PlayTimeTracking; using Content.Server.Players.RateLimiting; @@ -114,10 +114,6 @@ namespace Content.Server.Entry IoCManager.Resolve().Initialize(); IoCManager.Resolve().Initialize(); IoCManager.Resolve().Initialize(); - IoCManager.Resolve().Initialize(); - IoCManager.Resolve().Initialize(); - IoCManager.Resolve().Initialize(); - IoCManager.Resolve().Initialize(); _voteManager.Initialize(); _updateManager.Initialize(); @@ -200,8 +196,6 @@ namespace Content.Server.Entry IoCManager.Resolve().Shutdown(); IoCManager.Resolve().Shutdown(); - - IoCManager.Resolve().Shutdown(); } private static void LoadConfigPresets(IConfigurationManager cfg, IResourceManager res, ISawmill sawmill) diff --git a/Content.Server/GameTicking/GameTicker.RoundFlow.cs b/Content.Server/GameTicking/GameTicker.RoundFlow.cs index cb5a1a41877..1dadca4c038 100644 --- a/Content.Server/GameTicking/GameTicker.RoundFlow.cs +++ b/Content.Server/GameTicking/GameTicker.RoundFlow.cs @@ -725,8 +725,6 @@ namespace Content.Server.GameTicking _banManager.Restart(); - _bugManager.Restart(); - _gameMapManager.ClearSelectedMap(); // Clear up any game rules. diff --git a/Content.Server/GameTicking/GameTicker.cs b/Content.Server/GameTicking/GameTicker.cs index 24ce7497594..cb6cb995521 100644 --- a/Content.Server/GameTicking/GameTicker.cs +++ b/Content.Server/GameTicking/GameTicker.cs @@ -1,7 +1,6 @@ using Content.Server._Corvax.Respawn; // DeltaV using Content.Server.Administration.Logs; using Content.Server.Administration.Managers; -using Content.Server.BugReports; using Content.Server.Chat.Managers; using Content.Server.Chat.Systems; using Content.Server.Database; @@ -68,7 +67,6 @@ namespace Content.Server.GameTicking [Dependency] private readonly SharedRoleSystem _roles = default!; [Dependency] private readonly ServerDbEntryManager _dbEntryManager = default!; [Dependency] private readonly RespawnSystem _respawn = default!; // DeltaV - [Dependency] private readonly IBugReportManager _bugManager = default!; [ViewVariables] private bool _initialized; [ViewVariables] private bool _postInitialized; diff --git a/Content.Server/Github/Commands/TestGithubApiCommand.cs b/Content.Server/Github/Commands/TestGithubApiCommand.cs deleted file mode 100644 index 85ac798057a..00000000000 --- a/Content.Server/Github/Commands/TestGithubApiCommand.cs +++ /dev/null @@ -1,71 +0,0 @@ -using Content.Server.Administration; -using Content.Server.Github.Requests; -using Content.Shared.Administration; -using Content.Shared.CCVar; -using Robust.Shared.Configuration; -using Robust.Shared.Console; - -namespace Content.Server.Github.Commands; - -/// -/// Simple command for testing if the GitHub api is set up correctly! It ensures that all necessary ccvars are set, -/// and will also create one new issue on the targeted repository. -/// -[AdminCommand(AdminFlags.Server)] -public sealed class TestGithubApiCommand : LocalizedCommands -{ - [Dependency] private readonly GithubApiManager _git = default!; - [Dependency] private readonly IConfigurationManager _cfg = default!; - - public override string Command => Loc.GetString("github-command-test-name"); - - public override async void Execute(IConsoleShell shell, string argStr, string[] args) - { - var enabled = _cfg.GetCVar(CCVars.GithubEnabled); - var path = _cfg.GetCVar(CCVars.GithubAppPrivateKeyPath); - var appId = _cfg.GetCVar(CCVars.GithubAppId); - var repoName = _cfg.GetCVar(CCVars.GithubRepositoryName); - var owner = _cfg.GetCVar(CCVars.GithubRepositoryOwner); - - if (!enabled) - { - shell.WriteError(Loc.GetString("github-command-not-enabled")); - return; - } - - if (string.IsNullOrWhiteSpace(path)) - { - shell.WriteError(Loc.GetString("github-command-no-path")); - return; - } - - if (string.IsNullOrWhiteSpace(appId)) - { - shell.WriteError(Loc.GetString("github-command-no-app-id")); - return; - } - - if (string.IsNullOrWhiteSpace(repoName)) - { - shell.WriteError(Loc.GetString("github-command-no-repo-name")); - return; - } - - if (string.IsNullOrWhiteSpace(owner)) - { - shell.WriteError(Loc.GetString("github-command-no-owner")); - return; - } - - // Create two issues and send them to the api. - var request = new CreateIssueRequest - { - Title = Loc.GetString("github-command-issue-title-one"), - Body = Loc.GetString("github-command-issue-description-one"), - }; - - _git.TryMakeRequest(request); - - shell.WriteLine(Loc.GetString("github-command-finish")); - } -} diff --git a/Content.Server/Github/GithubApiManager.cs b/Content.Server/Github/GithubApiManager.cs deleted file mode 100644 index 44f164fdf04..00000000000 --- a/Content.Server/Github/GithubApiManager.cs +++ /dev/null @@ -1,53 +0,0 @@ -using Content.Server.Github.Requests; -using System.Threading.Tasks; -using Content.Server.BugReports; - -namespace Content.Server.Github; - -public sealed class GithubApiManager -{ - [Dependency] private readonly GithubBackgroundWorker _githubWorker = default!; - - public void Initialize() - { - Task.Run(() => _githubWorker.HandleQueue()); - } - - public bool TryCreateIssue(ValidPlayerBugReportReceivedEvent bugReport) - { - var createIssueRequest = ConvertToCreateIssue(bugReport); - return TryMakeRequest(createIssueRequest); - } - - public bool TryMakeRequest(IGithubRequest request) - { - return _githubWorker.Writer.TryWrite(request); - } - - private CreateIssueRequest ConvertToCreateIssue(ValidPlayerBugReportReceivedEvent bugReport) - { - var request = new CreateIssueRequest - { - Title = bugReport.Title, - Labels = bugReport.Tags, - }; - - var metadata = bugReport.MetaData; - - request.Body = Loc.GetString("github-issue-format", - ("description", bugReport.Description), - ("buildVersion", metadata.BuildVersion), - ("engineVersion", metadata.EngineVersion), - ("serverName", metadata.ServerName), - ("submittedTime", metadata.SubmittedTime), - ("roundNumber", metadata.RoundNumber.ToString() ?? ""), - ("roundTime", metadata.RoundTime.ToString() ?? ""), - ("roundType", metadata.RoundType ?? ""), - ("map", metadata.Map ?? ""), - ("numberOfPlayers", metadata.NumberOfPlayers), - ("username", metadata.Username), - ("playerGUID", metadata.PlayerGUID)); - - return request; - } -} diff --git a/Content.Server/Github/GithubBackgroundWorker.cs b/Content.Server/Github/GithubBackgroundWorker.cs deleted file mode 100644 index 06d85dd0016..00000000000 --- a/Content.Server/Github/GithubBackgroundWorker.cs +++ /dev/null @@ -1,74 +0,0 @@ -using System.Threading; -using System.Threading.Channels; -using System.Threading.Tasks; -using Content.Server.Github.Requests; -using Content.Shared.CCVar; -using Robust.Shared.Configuration; - -namespace Content.Server.Github; - -public sealed class GithubBackgroundWorker -{ - [Dependency] private readonly GithubClient _client = default!; - [Dependency] private readonly IConfigurationManager _cfg = default!; - [Dependency] private readonly ILogManager _log = default!; - - private ISawmill _sawmill = default!; - - private bool _enabled; - private readonly Channel _channel = Channel.CreateUnbounded(); - private readonly CancellationTokenSource _cts = new CancellationTokenSource(); - - public ChannelWriter Writer => _channel.Writer; - - public void Initialize() - { - _sawmill = _log.GetSawmill("github-ratelimit"); - _cfg.OnValueChanged(CCVars.GithubEnabled, val => Interlocked.Exchange(ref _enabled, val), true); - } - - public async Task HandleQueue() - { - var token = _cts.Token; - var reader = _channel.Reader; - while (!token.IsCancellationRequested) - { - await reader.WaitToReadAsync(token); - if (!reader.TryRead(out var request)) - continue; - - await SendRequest(request, token); - } - } - - // this should be called in BaseServer.Cleanup! - public void Shutdown() - { - _cts.Cancel(); - } - - /// - /// Directly send a request to the API. This does not have any rate limits checks so be careful! - /// Only use this if you have a very good reason to! - /// - /// The request to make. - /// Request cancellation token. - /// The direct HTTP response from the API. If null the request could not be made. - private async Task SendRequest(T request, CancellationToken ct) where T : IGithubRequest - { - if (!_enabled) - { - _sawmill.Info("Tried to make a github api request but the api was not enabled."); - return; - } - - try - { - await _client.TryMakeRequestSafe(request, ct); - } - catch (Exception e) - { - _sawmill.Error("Github API exception: {error}", e.ToString()); - } - } -} diff --git a/Content.Server/Github/GithubClient.cs b/Content.Server/Github/GithubClient.cs deleted file mode 100644 index ed7563dd3f3..00000000000 --- a/Content.Server/Github/GithubClient.cs +++ /dev/null @@ -1,417 +0,0 @@ -using System.Diagnostics.CodeAnalysis; -using System.IO; -using System.Linq; -using System.Net.Http; -using System.Net.Http.Headers; -using System.Net.Http.Json; -using System.Security.Cryptography; -using System.Text; -using System.Text.Json; -using System.Threading; -using System.Threading.Tasks; -using Content.Server.Github.Requests; -using Content.Server.Github.Responses; -using Content.Shared.CCVar; -using JetBrains.Annotations; -using Robust.Shared.Configuration; - -namespace Content.Server.Github; - -/// -/// Basic implementation of the GitHub api. This was mainly created for making issues from users bug reports - it is not -/// a full implementation! I tried to follow the spec very closely and the docs are really well done. I highly recommend -/// taking a look at them! -///
-///
Some useful information about the api: -///
Api home page -///
Best practices -///
Rate limit information -///
Troubleshooting -///
-/// As it uses async, it should be called from background worker when possible, like . -public sealed class GithubClient -{ - [Dependency] private readonly ILogManager _log = default!; - [Dependency] private readonly IConfigurationManager _cfg = default!; - private HttpClient _httpClient = default!; - - private ISawmill _sawmill = default!; - - // Token data for the GitHub app (This is used to authenticate stuff like new issue creation) - private (DateTime? Expiery, string Token) _tokenData; - - // Json web token for the GitHub app (This is used to authenticate stuff like seeing where the app is installed) - // The token is created locally. - private (DateTime? Expiery, string JWT) _jwtData; - - private const int ErrorResponseMaxLogSize = 200; - - private readonly JsonSerializerOptions _jsonSerializerOptions = new() - { - PropertyNamingPolicy = JsonNamingPolicy.CamelCase, - }; - - // Docs say 10 should be the maximum. - private readonly TimeSpan _jwtExpiration = TimeSpan.FromMinutes(10); - private readonly TimeSpan _jwtBackDate = TimeSpan.FromMinutes(1); - - // Buffers because requests can take a while. We don't want the tokens to expire in the middle of doing requests! - private readonly TimeSpan _jwtBuffer = TimeSpan.FromMinutes(2); - private readonly TimeSpan _tokenBuffer = TimeSpan.FromMinutes(2); - - private string _privateKey = ""; - - #region Header constants - - private const string ProductName = "SpaceStation14GithubApi"; - private const string ProductVersion = "1"; - - private const string AcceptHeader = "Accept"; - private const string AcceptHeaderType = "application/vnd.github+json"; - - private const string AuthHeader = "Authorization"; - private const string AuthHeaderBearer = "Bearer "; - - private const string VersionHeader = "X-GitHub-Api-Version"; - private const string VersionNumber = "2022-11-28"; - - #endregion - - private readonly Uri _baseUri = new("https://api.github.com/"); - - #region CCvar values - - private string _appId = ""; - private string _repository = ""; - private string _owner = ""; - private int _maxRetries; - - #endregion - - public void Initialize() - { - _sawmill = _log.GetSawmill("github"); - _tokenData = (null, ""); - _jwtData = (null, ""); - - _cfg.OnValueChanged(CCVars.GithubAppPrivateKeyPath, OnPrivateKeyPathChanged, true); - _cfg.OnValueChanged(CCVars.GithubAppId, val => Interlocked.Exchange(ref _appId, val), true); - _cfg.OnValueChanged(CCVars.GithubRepositoryName, val => Interlocked.Exchange(ref _repository, val), true); - _cfg.OnValueChanged(CCVars.GithubRepositoryOwner, val => Interlocked.Exchange(ref _owner, val), true); - _cfg.OnValueChanged(CCVars.GithubMaxRetries, val => SetValueAndInitHttpClient(ref _maxRetries, val), true); - } - - private void OnPrivateKeyPathChanged(string path) - { - if (string.IsNullOrEmpty(path)) - return; - - if (!File.Exists(path)) - { - _sawmill.Error($"\"{path}\" does not exist."); - return; - } - - string fileText; - try - { - fileText = File.ReadAllText(path); - } - catch (Exception e) - { - _sawmill.Error($"\"{path}\" could not be read!\n{e}"); - return; - } - - var rsa = RSA.Create(); - try - { - rsa.ImportFromPem(fileText); - } - catch - { - _sawmill.Error($"\"{path}\" does not contain a valid private key!"); - return; - } - - _privateKey = fileText; - } - - private void SetValueAndInitHttpClient(ref T toSet, T value) - { - Interlocked.Exchange(ref toSet, value); - - var httpMessageHandler = new RetryHandler(new HttpClientHandler(), _maxRetries, _sawmill); - var newClient = new HttpClient(httpMessageHandler) - { - BaseAddress = _baseUri, - DefaultRequestHeaders = - { - { AcceptHeader, AcceptHeaderType }, - { VersionHeader, VersionNumber }, - }, - Timeout = TimeSpan.FromSeconds(15), - }; - - newClient.DefaultRequestHeaders.UserAgent.Add(new ProductInfoHeaderValue(ProductName, ProductVersion)); - - Interlocked.Exchange(ref _httpClient, newClient); - } - - #region Public functions - - /// - /// The standard way to make requests to the GitHub api. This will ensure that the request respects the rate limit - /// and will also retry the request if it fails. Awaiting this to finish could take a very long time depending - /// on what exactly is going on! Only await for it if you're willing to wait a long time. - /// - /// The request you want to make. - /// Token for operation cancellation. - /// The direct HTTP response from the API. If null the request could not be made. - public async Task TryMakeRequestSafe(IGithubRequest request, CancellationToken ct) - { - if (!HaveFullApiData()) - { - _sawmill.Info("Tried to make a github api request but the api was not enabled."); - return null; - } - - if (request.AuthenticationMethod == GithubAuthMethod.Token && !await TryEnsureTokenNotExpired(ct)) - return null; - - return await MakeRequest(request, ct); - } - - private async Task MakeRequest(IGithubRequest request, CancellationToken ct) - { - var httpRequestMessage = BuildRequest(request); - - var response = await _httpClient.SendAsync(httpRequestMessage, ct); - - var message = $"Made a github api request to: '{httpRequestMessage.RequestUri}', status is {response.StatusCode}"; - if (response.IsSuccessStatusCode) - { - _sawmill.Info(message); - return response; - } - - _sawmill.Error(message); - var responseText = await response.Content.ReadAsStringAsync(ct); - - if (responseText.Length > ErrorResponseMaxLogSize) - responseText = responseText.Substring(0, ErrorResponseMaxLogSize); - - _sawmill.Error(message + "\r\n" + responseText); - - return null; - } - - /// - /// A simple helper function that just tries to parse a header value that is expected to be a long int. - /// In general, there are just a lot of single value headers that are longs so this removes a lot of duplicate code. - /// - /// The headers that you want to search. - /// The header you want to get the long value for. - /// Value of header, if found, null otherwise. - /// The headers value if it exists, null otherwise. - public static bool TryGetHeaderAsLong(HttpResponseHeaders? headers, string header, [NotNullWhen(true)] out long? value) - { - value = null; - if (headers == null) - return false; - - if (!headers.TryGetValues(header, out var headerValues)) - return false; - - if (!long.TryParse(headerValues.First(), out var result)) - return false; - - value = result; - return true; - } - - # endregion - - #region Helper functions - - private HttpRequestMessage BuildRequest(IGithubRequest request) - { - var json = JsonSerializer.Serialize(request, _jsonSerializerOptions); - var payload = new StringContent(json, Encoding.UTF8, "application/json"); - - var builder = new UriBuilder(_baseUri) - { - Port = -1, - Path = request.GetLocation(_owner, _repository), - }; - - var httpRequest = new HttpRequestMessage - { - Method = request.RequestMethod, - RequestUri = builder.Uri, - Content = payload, - }; - - httpRequest.Headers.Add(AuthHeader, CreateAuthenticationHeader(request)); - - return httpRequest; - } - - private bool HaveFullApiData() - { - return !string.IsNullOrWhiteSpace(_privateKey) && - !string.IsNullOrWhiteSpace(_repository) && - !string.IsNullOrWhiteSpace(_owner); - } - - private string CreateAuthenticationHeader(IGithubRequest request) - { - return request.AuthenticationMethod switch - { - GithubAuthMethod.Token => AuthHeaderBearer + _tokenData.Token, - GithubAuthMethod.JWT => AuthHeaderBearer + GetValidJwt(), - _ => throw new Exception("Unknown auth method!"), - }; - } - - // TODO: Maybe ensure that perms are only read metadata / write issues so people don't give full access - /// - /// Try to get a valid verification token from the GitHub api - /// - /// True if the token is valid and successfully found, false if there was an error. - private async Task TryEnsureTokenNotExpired(CancellationToken ct) - { - if (_tokenData.Expiery != null && _tokenData.Expiery - _tokenBuffer > DateTime.UtcNow) - return true; - - _sawmill.Info("Token expired - requesting new token!"); - - var installationRequest = new InstallationsRequest(); - var installationHttpResponse = await MakeRequest(installationRequest, ct); - if (installationHttpResponse == null) - { - _sawmill.Error("Could not make http installation request when creating token."); - return false; - } - - var installationResponse = await installationHttpResponse.Content.ReadFromJsonAsync>(_jsonSerializerOptions, ct); - if (installationResponse == null) - { - _sawmill.Error("Could not parse installation response."); - return false; - } - - if (installationResponse.Count == 0) - { - _sawmill.Error("App not installed anywhere."); - return false; - } - - int? installationId = null; - foreach (var installation in installationResponse) - { - if (installation.Account.Login != _owner) - continue; - - installationId = installation.Id; - break; - } - - if (installationId == null) - { - _sawmill.Error("App not installed in given repository."); - return false; - } - - var tokenRequest = new TokenRequest - { - InstallationId = installationId.Value, - }; - - var tokenHttpResponse = await MakeRequest(tokenRequest, ct); - if (tokenHttpResponse == null) - { - _sawmill.Error("Could not make http token request when creating token.."); - return false; - } - - var tokenResponse = await tokenHttpResponse.Content.ReadFromJsonAsync(_jsonSerializerOptions, ct); - if (tokenResponse == null) - { - _sawmill.Error("Could not parse token response."); - return false; - } - - _tokenData = (tokenResponse.ExpiresAt, tokenResponse.Token); - return true; - } - - // See: https://docs.github.com/en/apps/creating-github-apps/authenticating-with-a-github-app/generating-a-json-web-token-jwt-for-a-github-app - private string GetValidJwt() - { - if (_jwtData.Expiery != null && _jwtData.Expiery - _jwtBuffer > DateTime.UtcNow) - return _jwtData.JWT; - - var githubClientId = _appId; - var apiPrivateKey = _privateKey; - - var time = DateTime.UtcNow; - var expTime = time + _jwtExpiration; - var iatTime = time - _jwtBackDate; - - var iat = ((DateTimeOffset) iatTime).ToUnixTimeSeconds(); - var exp = ((DateTimeOffset) expTime).ToUnixTimeSeconds(); - - const string headerJson = """ - { - "typ":"JWT", - "alg":"RS256" - } - """; - - var headerEncoded = Base64EncodeUrlSafe(headerJson); - - var payloadJson = $$""" - { - "iat":{{iat}}, - "exp":{{exp}}, - "iss":"{{githubClientId}}" - } - """; - - var payloadJsonEncoded = Base64EncodeUrlSafe(payloadJson); - - var headPayload = $"{headerEncoded}.{payloadJsonEncoded}"; - - var rsa = System.Security.Cryptography.RSA.Create(); - rsa.ImportFromPem(apiPrivateKey); - - var bytesPlainTextData = Encoding.UTF8.GetBytes(headPayload); - - var signedData = rsa.SignData(bytesPlainTextData, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1); - var signBase64 = Base64EncodeUrlSafe(signedData); - - var jwt = $"{headPayload}.{signBase64}"; - - _jwtData = (expTime, jwt); - - _sawmill.Info("Generated new JWT."); - - return jwt; - } - - private string Base64EncodeUrlSafe(string plainText) - { - return Base64EncodeUrlSafe(Encoding.UTF8.GetBytes(plainText)); - } - - private string Base64EncodeUrlSafe(byte[] plainText) - { - return Convert.ToBase64String(plainText) - .TrimEnd('=') - .Replace('+', '-') - .Replace('/', '_'); - } - - #endregion -} diff --git a/Content.Server/Github/Requests/CreateIssueRequest.cs b/Content.Server/Github/Requests/CreateIssueRequest.cs deleted file mode 100644 index 92cee609fa2..00000000000 --- a/Content.Server/Github/Requests/CreateIssueRequest.cs +++ /dev/null @@ -1,38 +0,0 @@ -using System.Net.Http; -using System.Text.Json.Serialization; - -namespace Content.Server.Github.Requests; - -/// -/// > -/// -public sealed class CreateIssueRequest : IGithubRequest -{ - [JsonIgnore] - public HttpMethod RequestMethod => HttpMethod.Post; - - [JsonIgnore] - public GithubAuthMethod AuthenticationMethod => GithubAuthMethod.Token; - - #region JSON fields - - [JsonInclude, JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - public required string Title; - [JsonInclude, JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - public string? Body; - [JsonInclude, JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - public string? Assignee; - [JsonInclude, JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - public string? Milestone; - [JsonInclude, JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - public List Labels = []; - [JsonInclude, JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - public List Assignees = []; - - #endregion - - public string GetLocation(string owner, string repository) - { - return $"repos/{owner}/{repository}/issues"; - } -} diff --git a/Content.Server/Github/Requests/IGithubRequest.cs b/Content.Server/Github/Requests/IGithubRequest.cs deleted file mode 100644 index afc421722df..00000000000 --- a/Content.Server/Github/Requests/IGithubRequest.cs +++ /dev/null @@ -1,44 +0,0 @@ -using System.Net.Http; -using System.Text.Json.Serialization; - -namespace Content.Server.Github.Requests; - -/// -/// Interface for all github api requests. -/// -/// -/// WARNING: You must add this JsonDerivedType for all requests that have json otherwise they will not parse properly! -/// -[JsonPolymorphic(UnknownDerivedTypeHandling = JsonUnknownDerivedTypeHandling.FailSerialization)] -[JsonDerivedType(typeof(CreateIssueRequest))] -[JsonDerivedType(typeof(InstallationsRequest))] -[JsonDerivedType(typeof(TokenRequest))] -public interface IGithubRequest -{ - /// - /// The kind of request method for the request. - /// - [JsonIgnore] - public HttpMethod RequestMethod { get; } - - /// - /// There are different types of authentication methods depending on which endpoint you are working with. - /// E.g. the app api endpoint mostly uses JWTs, while stuff like issue creation uses Tokens - /// - [JsonIgnore] - public GithubAuthMethod AuthenticationMethod { get; } - - /// - /// Location of the api endpoint for this request. - /// - /// Owner of the repository. - /// The repository to make the request. - /// The api location for this request. - public string GetLocation(string owner, string repository); -} - -public enum GithubAuthMethod -{ - JWT, - Token, -} diff --git a/Content.Server/Github/Requests/InstallationsRequest.cs b/Content.Server/Github/Requests/InstallationsRequest.cs deleted file mode 100644 index 4e75bbdc383..00000000000 --- a/Content.Server/Github/Requests/InstallationsRequest.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System.Net.Http; - -namespace Content.Server.Github.Requests; - -/// -/// > -/// -public sealed class InstallationsRequest : IGithubRequest -{ - public HttpMethod RequestMethod => HttpMethod.Get; - - public GithubAuthMethod AuthenticationMethod => GithubAuthMethod.JWT; - - public string GetLocation(string owner, string repository) - { - return "app/installations"; - } -} diff --git a/Content.Server/Github/Requests/TokenRequest.cs b/Content.Server/Github/Requests/TokenRequest.cs deleted file mode 100644 index f07764cdf01..00000000000 --- a/Content.Server/Github/Requests/TokenRequest.cs +++ /dev/null @@ -1,22 +0,0 @@ -using System.Net.Http; -using System.Text.Json.Serialization; - -namespace Content.Server.Github.Requests; - -/// -/// > -/// -public sealed class TokenRequest : IGithubRequest -{ - public HttpMethod RequestMethod => HttpMethod.Post; - - public GithubAuthMethod AuthenticationMethod => GithubAuthMethod.JWT; - - [JsonPropertyName("id")] - public required int InstallationId; - - public string GetLocation(string owner, string repository) - { - return $"/app/installations/{InstallationId}/access_tokens"; - } -} diff --git a/Content.Server/Github/Responses/InstallationResponse.cs b/Content.Server/Github/Responses/InstallationResponse.cs deleted file mode 100644 index ffc84a6f0ca..00000000000 --- a/Content.Server/Github/Responses/InstallationResponse.cs +++ /dev/null @@ -1,21 +0,0 @@ -using System.Text.Json.Serialization; - -namespace Content.Server.Github.Responses; - -/// -/// Not all fields are filled out - only the necessary ones. If you need more just add them. -/// > -/// -public sealed class InstallationResponse -{ - public required int Id { get; set; } - - public required GithubInstallationAccount Account { get; set; } -} - -/// -public sealed class GithubInstallationAccount -{ - public required string Login { get; set; } -} - diff --git a/Content.Server/Github/Responses/TokenResponse.cs b/Content.Server/Github/Responses/TokenResponse.cs deleted file mode 100644 index 5b3748219cb..00000000000 --- a/Content.Server/Github/Responses/TokenResponse.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System.Text.Json.Serialization; - -namespace Content.Server.Github.Responses; - -/// -/// Not all fields are filled out - only the necessary ones. If you need more just add them. -/// > -/// -public sealed class TokenResponse -{ - public required string Token { get; set; } - - [JsonPropertyName("expires_at")] - public required DateTime ExpiresAt { get; set; } -} diff --git a/Content.Server/Github/RetryHttpHandler.cs b/Content.Server/Github/RetryHttpHandler.cs deleted file mode 100644 index 28dcff643bb..00000000000 --- a/Content.Server/Github/RetryHttpHandler.cs +++ /dev/null @@ -1,100 +0,0 @@ -using System.Net.Http; -using System.Threading.Tasks; -using System.Threading; -using System.Net; - -namespace Content.Server.Github; - -/// -/// Basic rate limiter for the GitHub api! Will ensure there is only ever one outgoing request at a time and all -/// requests respect the rate limit the best they can. -///
-///
Links to the api for more information: -///
Best practices -///
Rate limit information -///
-/// This was designed for the 2022-11-28 version of the API. -public sealed class RetryHandler(HttpMessageHandler innerHandler, int maxRetries, ISawmill sawmill) : DelegatingHandler(innerHandler) -{ - private const int MaxWaitSeconds = 32; - - /// Extra buffer time (In seconds) after getting rate limited we don't make the request exactly when we get more credits. - private const long ExtraBufferTime = 1L; - - #region Headers - - private const string RetryAfterHeader = "retry-after"; - - private const string RemainingHeader = "x-ratelimit-remaining"; - private const string RateLimitResetHeader = "x-ratelimit-reset"; - - #endregion - - protected override async Task SendAsync( - HttpRequestMessage request, - CancellationToken cancellationToken - ) - { - HttpResponseMessage response; - var i = 0; - do - { - response = await base.SendAsync(request, cancellationToken); - if (response.IsSuccessStatusCode) - return response; - - i++; - if (i < maxRetries) - { - var waitTime = CalculateNextRequestTime(response, i); - await Task.Delay(waitTime, cancellationToken); - } - } while (!response.IsSuccessStatusCode && i < maxRetries); - - return response; - } - - /// - /// Follows these guidelines but also has a small buffer so you should never quite hit zero: - ///
- /// - ///
- /// The last response from the API. - /// Number of current call attempt. - /// The amount of time to wait until the next request. - private TimeSpan CalculateNextRequestTime(HttpResponseMessage response, int attempt) - { - var headers = response.Headers; - var statusCode = response.StatusCode; - - // Specific checks for rate limits. - if (statusCode is HttpStatusCode.Forbidden or HttpStatusCode.TooManyRequests) - { - // Retry after header - if (GithubClient.TryGetHeaderAsLong(headers, RetryAfterHeader, out var retryAfterSeconds)) - return TimeSpan.FromSeconds(retryAfterSeconds.Value + ExtraBufferTime); - - // Reset header (Tells us when we get more api credits) - if (GithubClient.TryGetHeaderAsLong(headers, RemainingHeader, out var remainingRequests) - && GithubClient.TryGetHeaderAsLong(headers, RateLimitResetHeader, out var resetTime) - && remainingRequests == 0) - { - var delayTime = resetTime.Value - DateTimeOffset.UtcNow.ToUnixTimeSeconds(); - sawmill.Warning( - "github returned '{status}' status, have to wait until limit reset - in '{delay}' seconds", - response.StatusCode, - delayTime - ); - return TimeSpan.FromSeconds(delayTime + ExtraBufferTime); - } - } - - // If the status code is not the expected one or the rate limit checks are failing, just do an exponential backoff. - return ExponentialBackoff(attempt); - } - - private static TimeSpan ExponentialBackoff(int i) - { - return TimeSpan.FromSeconds(Math.Min(MaxWaitSeconds, Math.Pow(2, i))); - } -} diff --git a/Content.Server/IoC/ServerContentIoC.cs b/Content.Server/IoC/ServerContentIoC.cs index ba98b7ea7be..7132b40420c 100644 --- a/Content.Server/IoC/ServerContentIoC.cs +++ b/Content.Server/IoC/ServerContentIoC.cs @@ -3,7 +3,6 @@ using Content.Server.Administration.Logs; using Content.Server.Administration.Managers; using Content.Server.Administration.Notes; using Content.Server.Afk; -using Content.Server.BugReports; using Content.Server.Chat.Managers; using Content.Server.Connection; using Content.Server.Database; @@ -13,7 +12,6 @@ using Content.Server.Discord.DiscordLink; using Content.Server.Discord.WebhookMessages; using Content.Server.EUI; using Content.Server.GhostKick; -using Content.Server.Github; using Content.Server.Info; using Content.Server.Mapping; using Content.Server.Maps; @@ -62,7 +60,6 @@ namespace Content.Server.IoC IoCManager.Register(); IoCManager.Register(); IoCManager.Register(); - IoCManager.Register(); IoCManager.Register(); IoCManager.Register(); IoCManager.Register(); @@ -81,11 +78,9 @@ namespace Content.Server.IoC IoCManager.Register(); IoCManager.Register(); IoCManager.Register(); + IoCManager.Register(); IoCManager.Register(); - IoCManager.Register(); - IoCManager.Register(); - IoCManager.Register(); } } } diff --git a/Content.Shared.Database/LogType.cs b/Content.Shared.Database/LogType.cs index 48d763230c9..fa2304dc87d 100644 --- a/Content.Shared.Database/LogType.cs +++ b/Content.Shared.Database/LogType.cs @@ -467,7 +467,6 @@ public enum LogType /// Logs related to botany, such as planting and harvesting crops ///
Botany = 100, - /// /// Artifact node got activated. /// @@ -482,9 +481,4 @@ public enum LogType /// Events relating to midi playback. ///
[DataField, AutoNetworkedField] - public ProtoId SpillImmuneTag = "MessyDrinkerImmune"; + public ProtoId? SpillImmuneTag = "MessyDrinkerImmune"; [DataField, AutoNetworkedField] public LocId? SpillMessagePopup; diff --git a/Content.Shared/Nutrition/EntitySystems/MessyDrinkerSystem.cs b/Content.Shared/Nutrition/EntitySystems/MessyDrinkerSystem.cs index d75e7bf0188..7bfb7a5633d 100644 --- a/Content.Shared/Nutrition/EntitySystems/MessyDrinkerSystem.cs +++ b/Content.Shared/Nutrition/EntitySystems/MessyDrinkerSystem.cs @@ -25,7 +25,7 @@ public sealed class MessyDrinkerSystem : EntitySystem private void OnIngested(Entity ent, ref IngestingEvent ev) { - if (_tag.HasTag(ev.Food, ent.Comp.SpillImmuneTag)) + if (ent.Comp.SpillImmuneTag != null && _tag.HasTag(ev.Food, ent.Comp.SpillImmuneTag.Value)) return; // Cannot spill if you're being forced to drink. From e25bef7fa1f091a16f393b5e45775ffb0f142fe5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C4=81da?= Date: Sat, 30 Aug 2025 13:10:34 -0500 Subject: [PATCH 285/340] Clown bags squeak when inserting items (#39931) squeak! Co-authored-by: iaada --- .../Entities/Clothing/Back/backpacks.yml | 6 ++++++ .../Prototypes/Entities/Clothing/Back/duffel.yml | 16 +++++++++++----- .../Entities/Clothing/Back/satchel.yml | 6 ++++++ 3 files changed, 23 insertions(+), 5 deletions(-) diff --git a/Resources/Prototypes/Entities/Clothing/Back/backpacks.yml b/Resources/Prototypes/Entities/Clothing/Back/backpacks.yml index 20838e17393..bf97c1e2f77 100644 --- a/Resources/Prototypes/Entities/Clothing/Back/backpacks.yml +++ b/Resources/Prototypes/Entities/Clothing/Back/backpacks.yml @@ -47,6 +47,12 @@ - type: Storage storageOpenSound: collection: BikeHorn + params: + variation: 0.125 + storageInsertSound: + collection: FootstepClown + params: + variation: 0.125 - type: entity parent: ClothingBackpack diff --git a/Resources/Prototypes/Entities/Clothing/Back/duffel.yml b/Resources/Prototypes/Entities/Clothing/Back/duffel.yml index 4435324a5a8..e8eed669899 100644 --- a/Resources/Prototypes/Entities/Clothing/Back/duffel.yml +++ b/Resources/Prototypes/Entities/Clothing/Back/duffel.yml @@ -57,11 +57,17 @@ name: clown duffel bag description: A large duffel bag for holding extra honk goods. components: - - type: Sprite - sprite: Clothing/Back/Duffels/clown.rsi - - type: Storage - storageOpenSound: - collection: BikeHorn + - type: Sprite + sprite: Clothing/Back/Duffels/clown.rsi + - type: Storage + storageOpenSound: + collection: BikeHorn + params: + variation: 0.125 + storageInsertSound: + collection: FootstepClown + params: + variation: 0.125 - type: entity parent: [ClothingBackpackDuffel, BaseSecurityContraband] diff --git a/Resources/Prototypes/Entities/Clothing/Back/satchel.yml b/Resources/Prototypes/Entities/Clothing/Back/satchel.yml index c99bf247531..bb142e48173 100644 --- a/Resources/Prototypes/Entities/Clothing/Back/satchel.yml +++ b/Resources/Prototypes/Entities/Clothing/Back/satchel.yml @@ -50,6 +50,12 @@ - type: Storage storageOpenSound: collection: BikeHorn + params: + variation: 0.125 + storageInsertSound: + collection: FootstepClown + params: + variation: 0.125 - type: entity parent: ClothingBackpackSatchel From f45213f5ffea1c024dc6d6e9304934c602e54a04 Mon Sep 17 00:00:00 2001 From: ToastEnjoyer Date: Sun, 31 Aug 2025 02:19:39 -0500 Subject: [PATCH 286/340] Removed unused asset from devmap (#39974) --- Resources/Maps/Test/dev_map.yml | 571 +++++++++++++++++++++----------- 1 file changed, 380 insertions(+), 191 deletions(-) diff --git a/Resources/Maps/Test/dev_map.yml b/Resources/Maps/Test/dev_map.yml index a50bf22fe16..738940ac716 100644 --- a/Resources/Maps/Test/dev_map.yml +++ b/Resources/Maps/Test/dev_map.yml @@ -1,6 +1,19 @@ meta: - format: 6 - postmapinit: false + format: 7 + category: Map + engineVersion: 266.0.0 + forkId: "" + forkVersion: "" + time: 08/31/2025 05:06:28 + entityCount: 3156 +maps: +- 23 +grids: +- 1 +- 2709 +- 2869 +orphans: [] +nullspace: [] tilemap: 0: Space 24: FloorAstroGrass @@ -53,120 +66,120 @@ entities: chunks: 0,0: ind: 0,0 - tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAkwAAAAAA - version: 6 + tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAAJMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJkAAAAAAACTAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACZAAAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAAJMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAAJkAAAAAAACZAAAAAAAAmQAAAAAAAJkAAAAAAACZAAAAAAAAmQAAAAAAAJkAAAAAAACZAAAAAAAAmQAAAAAAAJkAAAAAAACTAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACZAAAAAAAAkwAAAAAAAA== + version: 7 0,1: ind: 0,1 - tiles: mQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - version: 6 + tiles: mQAAAAAAAJkAAAAAAACZAAAAAAAAmQAAAAAAAJkAAAAAAACZAAAAAAAAmQAAAAAAAJkAAAAAAACZAAAAAAAAmQAAAAAAAJkAAAAAAACZAAAAAAAAmQAAAAAAAJkAAAAAAACZAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACZAAAAAAAAmQAAAAAAAJkAAAAAAACZAAAAAAAAmQAAAAAAAJkAAAAAAACZAAAAAAAAmQAAAAAAAJkAAAAAAACZAAAAAAAAmQAAAAAAAJkAAAAAAACZAAAAAAAAmQAAAAAAAJkAAAAAAACTAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAAJkAAAAAAACZAAAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACZAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACZAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACZAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACZAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA== + version: 7 0,2: ind: 0,2 - tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - version: 6 + tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACZAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAAJkAAAAAAACZAAAAAAAAmQAAAAAAAJkAAAAAAACZAAAAAAAAmQAAAAAAAJkAAAAAAACZAAAAAAAAmQAAAAAAAJkAAAAAAACZAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA== + version: 7 1,0: ind: 1,0 - tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAAAAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAAAAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAAAAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAAQAAAAADAQAAAAACAQAAAAACmQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAkwAAAAAAAQAAAAAAAgAAAAACAgAAAAAC - version: 6 + tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACZAAAAAAAAAAAAAAAAAAAAAAAAAACZAAAAAAAAmQAAAAAAAJkAAAAAAAAAAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAmQAAAAAAAJkAAAAAAACZAAAAAAAAmQAAAAAAAJkAAAAAAACZAAAAAAAAAAAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJkAAAAAAAAAAAAAAAAAAAAAAAAAAJkAAAAAAACZAAAAAAAAmQAAAAAAAAAAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACZAAAAAAAAmQAAAAAAAJkAAAAAAACZAAAAAAAAmQAAAAAAAJkAAAAAAACZAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAAQAAAAADAAEAAAAAAgABAAAAAAIAmQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAAJkAAAAAAACZAAAAAAAAmQAAAAAAAJkAAAAAAACZAAAAAAAAkwAAAAAAAAEAAAAAAAACAAAAAAIAAgAAAAACAA== + version: 7 1,1: ind: 1,1 - tiles: mQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAAwAAAAAAAQAAAAABAgAAAAABAgAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAAwAAAAAAAQAAAAAAAgAAAAABAgAAAAADmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAAwAAAAADAQAAAAABAgAAAAABAgAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAmQAAAAAAkwAAAAAAAQAAAAACAQAAAAABAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAkwAAAAAABAAAAAACBAAAAAAABAAAAAACBAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAkwAAAAAABAAAAAACBAAAAAACBAAAAAABBgAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAkwAAAAAABAAAAAADBQAAAAAABAAAAAADBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAkwAAAAAABAAAAAABBAAAAAADBAAAAAACBQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAkwAAAAAAkwAAAAAAkwAAAAAABAAAAAAABAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAA - version: 6 + tiles: mQAAAAAAAJkAAAAAAACZAAAAAAAAmQAAAAAAAJkAAAAAAACZAAAAAAAAmQAAAAAAAJkAAAAAAACZAAAAAAAAmQAAAAAAAJkAAAAAAACZAAAAAAAAAwAAAAAAAAEAAAAAAQACAAAAAAEAAgAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAAMAAAAAAAABAAAAAAAAAgAAAAABAAIAAAAAAwCZAAAAAAAAmQAAAAAAAJkAAAAAAACZAAAAAAAAmQAAAAAAAJkAAAAAAACZAAAAAAAAmQAAAAAAAJkAAAAAAACZAAAAAAAAmQAAAAAAAJkAAAAAAAADAAAAAAMAAQAAAAABAAIAAAAAAQACAAAAAAAAmQAAAAAAAJkAAAAAAACZAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJkAAAAAAACZAAAAAAAAkwAAAAAAAAEAAAAAAgABAAAAAAEAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACZAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAAJMAAAAAAAAEAAAAAAIABAAAAAAAAAQAAAAAAgAEAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJkAAAAAAACTAAAAAAAABAAAAAACAAQAAAAAAgAEAAAAAAEABgAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACZAAAAAAAAkwAAAAAAAAQAAAAAAwAFAAAAAAAABAAAAAADAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAAJMAAAAAAAAEAAAAAAEABAAAAAADAAQAAAAAAgAFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJkAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAAAEAAAAAAAABAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACZAAAAAAAAAAAAAAAAAAAAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACTAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACZAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACZAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAAA== + version: 7 1,2: ind: 1,2 - tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAABwAAAAAABwAAAAAABwAAAAAAkwAAAAAACAAAAAAACAAAAAAACAAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAABwAAAAAABwAAAAAABwAAAAAABwAAAAAACAAAAAAACAAAAAAACAAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAABwAAAAAABwAAAAAABwAAAAAAkwAAAAAACAAAAAAACAAAAAAACAAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAACAAAAAAACAAAAAAACAAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAAAAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAAQAAAAADAQAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAAQAAAAACAQAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAACQAAAAAACQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAkwAAAAAAAwAAAAABAgAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAkwAAAAAAAgAAAAAB - version: 6 + tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACZAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJkAAAAAAACZAAAAAAAAmQAAAAAAAJkAAAAAAACZAAAAAAAAmQAAAAAAAJkAAAAAAACZAAAAAAAAmQAAAAAAAJkAAAAAAACZAAAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACTAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJMAAAAAAAAHAAAAAAAABwAAAAAAAAcAAAAAAACTAAAAAAAACAAAAAAAAAgAAAAAAAAIAAAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACTAAAAAAAABwAAAAAAAAcAAAAAAAAHAAAAAAAABwAAAAAAAAgAAAAAAAAIAAAAAAAACAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAAAcAAAAAAAAHAAAAAAAABwAAAAAAAJMAAAAAAAAIAAAAAAAACAAAAAAAAAgAAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAACAAAAAAAAAgAAAAAAAAIAAAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJkAAAAAAAAAAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACZAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAAAEAAAAAAwABAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJMAAAAAAAABAAAAAAIAAQAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACTAAAAAAAACQAAAAAAAAkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJkAAAAAAACZAAAAAAAAmQAAAAAAAJkAAAAAAACZAAAAAAAAkwAAAAAAAAMAAAAAAQACAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJMAAAAAAACTAAAAAAAAAgAAAAABAA== + version: 7 2,0: ind: 2,0 - tiles: kwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAAQAAAAADAQAAAAAAAQAAAAACAQAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAAQAAAAADAQAAAAABAQAAAAAAAQAAAAACkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAAQAAAAADAQAAAAABAQAAAAADAQAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAAQAAAAADAQAAAAABAQAAAAADAQAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAAQAAAAACAQAAAAACAQAAAAADAQAAAAABkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAAQAAAAAAAQAAAAAAAQAAAAADAQAAAAACkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAAQAAAAADAQAAAAACAQAAAAADAQAAAAABkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAAQAAAAAAAQAAAAAAAQAAAAABAQAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAAQAAAAADAQAAAAACAQAAAAADAQAAAAABkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAAQAAAAADAQAAAAADAQAAAAAAAQAAAAABkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAAQAAAAABAQAAAAACAQAAAAABAQAAAAABkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAAwAAAAABAQAAAAAAAQAAAAAAAQAAAAADAQAAAAABkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAAQAAAAABAQAAAAAAAQAAAAABAQAAAAACAQAAAAACkwAAAAAAAQAAAAAAAQAAAAACAQAAAAADAQAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAAQAAAAABAgAAAAADAQAAAAAAAgAAAAABAgAAAAACAQAAAAACkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - version: 6 + tiles: kwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAAEAAAAAAwABAAAAAAAAAQAAAAACAAEAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAAABAAAAAAMAAQAAAAABAAEAAAAAAAABAAAAAAIAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAAQAAAAADAAEAAAAAAQABAAAAAAMAAQAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAAEAAAAAAwABAAAAAAEAAQAAAAADAAEAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAAABAAAAAAIAAQAAAAACAAEAAAAAAwABAAAAAAEAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAMAAQAAAAACAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAAEAAAAAAwABAAAAAAIAAQAAAAADAAEAAAAAAQCTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAQABAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAAQAAAAADAAEAAAAAAgABAAAAAAMAAQAAAAABAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAAEAAAAAAwABAAAAAAMAAQAAAAAAAAEAAAAAAQCTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAAABAAAAAAEAAQAAAAACAAEAAAAAAQABAAAAAAEAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAAADAAAAAAEAAQAAAAAAAAEAAAAAAAABAAAAAAMAAQAAAAABAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAAEAAAAAAQABAAAAAAAAAQAAAAABAAEAAAAAAgABAAAAAAIAkwAAAAAAAAEAAAAAAAABAAAAAAIAAQAAAAADAAEAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAAQAAAAABAAIAAAAAAwABAAAAAAAAAgAAAAABAAIAAAAAAgABAAAAAAIAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACZAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA== + version: 7 2,1: ind: 2,1 - tiles: AQAAAAAAAgAAAAACAQAAAAAAAgAAAAABAgAAAAAAAQAAAAABkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAADAgAAAAABAQAAAAADAgAAAAADAgAAAAAAAQAAAAABkwAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAACAgAAAAABAQAAAAADAgAAAAADAgAAAAABAQAAAAACkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAgAAAAAAAQAAAAACAQAAAAABAQAAAAABkwAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACgAAAAABCgAAAAACCgAAAAACkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAACBAAAAAAABAAAAAACBAAAAAABBAAAAAACBAAAAAAABAAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABgAAAAAABgAAAAAABgAAAAACBgAAAAACBAAAAAAABAAAAAADBAAAAAABkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAABAAAAAABBAAAAAADBAAAAAABBAAAAAADBQAAAAAABAAAAAAAkwAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAABAAAAAADBQAAAAAABAAAAAADBQAAAAAABAAAAAABBAAAAAABBAAAAAACkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAADBAAAAAAABAAAAAADBAAAAAADBAAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAACBAAAAAABBAAAAAACkwAAAAAAkwAAAAAAkwAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAABAAAAAACBQAAAAAABAAAAAADkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAACBAAAAAABBAAAAAADkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAAAAAAAAAAAAAAAAA - version: 6 + tiles: AQAAAAAAAAIAAAAAAgABAAAAAAAAAgAAAAABAAIAAAAAAAABAAAAAAEAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACZAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAwACAAAAAAEAAQAAAAADAAIAAAAAAwACAAAAAAAAAQAAAAABAJMAAAAAAACZAAAAAAAAmQAAAAAAAJkAAAAAAACZAAAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAIAAgAAAAABAAEAAAAAAwACAAAAAAMAAgAAAAABAAEAAAAAAgCTAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAIAAAAAAAABAAAAAAIAAQAAAAABAAEAAAAAAQCTAAAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAoAAAAAAQAKAAAAAAIACgAAAAACAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAIABAAAAAAAAAQAAAAAAgAEAAAAAAEABAAAAAACAAQAAAAAAAAEAAAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABgAAAAAAAAYAAAAAAAAGAAAAAAIABgAAAAACAAQAAAAAAAAEAAAAAAMABAAAAAABAJMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAEAAAAAAEABAAAAAADAAQAAAAAAQAEAAAAAAMABQAAAAAAAAQAAAAAAACTAAAAAAAAmQAAAAAAAJkAAAAAAACZAAAAAAAAmQAAAAAAAJkAAAAAAACZAAAAAAAAmQAAAAAAAJkAAAAAAAAEAAAAAAMABQAAAAAAAAQAAAAAAwAFAAAAAAAABAAAAAABAAQAAAAAAQAEAAAAAAIAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAADAAQAAAAAAAAEAAAAAAMABAAAAAADAAQAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAgAEAAAAAAEABAAAAAACAJMAAAAAAACTAAAAAAAAkwAAAAAAAJkAAAAAAACZAAAAAAAAmQAAAAAAAJkAAAAAAACZAAAAAAAAmQAAAAAAAJkAAAAAAACZAAAAAAAAmQAAAAAAAJkAAAAAAAAEAAAAAAIABQAAAAAAAAQAAAAAAwCTAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAACAAQAAAAAAQAEAAAAAAMAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACZAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACZAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAAAAAAAAAAAAAAAAAAAAAA== + version: 7 3,0: ind: 3,0 - tiles: kwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAAQAAAAABAQAAAAADAQAAAAACAQAAAAACAQAAAAABAQAAAAACAQAAAAADAQAAAAABAQAAAAAAAQAAAAACAQAAAAADAQAAAAAAAQAAAAACAQAAAAABAQAAAAABkwAAAAAAAQAAAAAAAQAAAAAAAQAAAAACAQAAAAABAQAAAAABAQAAAAABAQAAAAADAQAAAAABAQAAAAADAQAAAAADAQAAAAAAAQAAAAABAQAAAAAAAQAAAAADAQAAAAADkwAAAAAAAQAAAAADAQAAAAAAAQAAAAADAQAAAAADAQAAAAACAQAAAAADAQAAAAACAQAAAAACAQAAAAAAAQAAAAABAQAAAAADAQAAAAAAAQAAAAAAAQAAAAACAQAAAAAAkwAAAAAAAQAAAAADAQAAAAABAQAAAAAAAQAAAAAAAQAAAAACAQAAAAABAQAAAAACAQAAAAADAQAAAAAAAQAAAAACAQAAAAABAQAAAAADAQAAAAAAAQAAAAADAQAAAAABkwAAAAAAAQAAAAABAQAAAAABAQAAAAAAAQAAAAACAQAAAAAAAQAAAAADAQAAAAAAAQAAAAADAQAAAAABAQAAAAABAQAAAAAAAQAAAAABAQAAAAACAQAAAAAAAQAAAAAAkwAAAAAAAQAAAAABAQAAAAABAQAAAAADAQAAAAADAQAAAAABAQAAAAACAQAAAAAAAQAAAAABAQAAAAABAQAAAAADAQAAAAAAAQAAAAAAAQAAAAACAQAAAAADAQAAAAACkwAAAAAAAQAAAAABAQAAAAAAAQAAAAADAQAAAAAAAQAAAAAAAQAAAAADAQAAAAABAQAAAAABAQAAAAABAQAAAAABAQAAAAADAQAAAAAAAQAAAAACAQAAAAADAQAAAAABkwAAAAAAAQAAAAACAQAAAAACAQAAAAACAQAAAAAAAQAAAAAAAQAAAAABAQAAAAADAQAAAAADAQAAAAAAAQAAAAAAAQAAAAADAQAAAAADAQAAAAADAQAAAAACAQAAAAACkwAAAAAAAQAAAAACAQAAAAACAQAAAAABAQAAAAACAQAAAAABAQAAAAADAQAAAAACAQAAAAACAQAAAAADAQAAAAABAQAAAAABAQAAAAAAAQAAAAADAQAAAAADAQAAAAAAkwAAAAAAAQAAAAABAQAAAAAAAQAAAAAAAQAAAAAAAQAAAAACAQAAAAACAQAAAAAAAQAAAAADAQAAAAADAQAAAAABAQAAAAAAAQAAAAAAAQAAAAABAQAAAAACAQAAAAAAkwAAAAAAAQAAAAAAAQAAAAAAAQAAAAADAQAAAAAAAQAAAAAAAQAAAAACAQAAAAACAQAAAAAAAQAAAAABAQAAAAABAQAAAAADAQAAAAABAQAAAAADAQAAAAADAQAAAAABkwAAAAAAAQAAAAADAQAAAAABAQAAAAABAQAAAAADAQAAAAABAQAAAAADAQAAAAACAQAAAAADAQAAAAACAQAAAAACAQAAAAACAQAAAAABAQAAAAAAAQAAAAAAAQAAAAAAkwAAAAAAAQAAAAABAQAAAAABAQAAAAABAQAAAAAAAQAAAAACAQAAAAACAQAAAAADAQAAAAACAQAAAAABAQAAAAAAAQAAAAAAAQAAAAABAQAAAAABAQAAAAACAQAAAAADkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - version: 6 + tiles: kwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAAEAAAAAAQABAAAAAAMAAQAAAAACAAEAAAAAAgABAAAAAAEAAQAAAAACAAEAAAAAAwABAAAAAAEAAQAAAAAAAAEAAAAAAgABAAAAAAMAAQAAAAAAAAEAAAAAAgABAAAAAAEAAQAAAAABAJMAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAgABAAAAAAEAAQAAAAABAAEAAAAAAQABAAAAAAMAAQAAAAABAAEAAAAAAwABAAAAAAMAAQAAAAAAAAEAAAAAAQABAAAAAAAAAQAAAAADAAEAAAAAAwCTAAAAAAAAAQAAAAADAAEAAAAAAAABAAAAAAMAAQAAAAADAAEAAAAAAgABAAAAAAMAAQAAAAACAAEAAAAAAgABAAAAAAAAAQAAAAABAAEAAAAAAwABAAAAAAAAAQAAAAAAAAEAAAAAAgABAAAAAAAAkwAAAAAAAAEAAAAAAwABAAAAAAEAAQAAAAAAAAEAAAAAAAABAAAAAAIAAQAAAAABAAEAAAAAAgABAAAAAAMAAQAAAAAAAAEAAAAAAgABAAAAAAEAAQAAAAADAAEAAAAAAAABAAAAAAMAAQAAAAABAJMAAAAAAAABAAAAAAEAAQAAAAABAAEAAAAAAAABAAAAAAIAAQAAAAAAAAEAAAAAAwABAAAAAAAAAQAAAAADAAEAAAAAAQABAAAAAAEAAQAAAAAAAAEAAAAAAQABAAAAAAIAAQAAAAAAAAEAAAAAAACTAAAAAAAAAQAAAAABAAEAAAAAAQABAAAAAAMAAQAAAAADAAEAAAAAAQABAAAAAAIAAQAAAAAAAAEAAAAAAQABAAAAAAEAAQAAAAADAAEAAAAAAAABAAAAAAAAAQAAAAACAAEAAAAAAwABAAAAAAIAkwAAAAAAAAEAAAAAAQABAAAAAAAAAQAAAAADAAEAAAAAAAABAAAAAAAAAQAAAAADAAEAAAAAAQABAAAAAAEAAQAAAAABAAEAAAAAAQABAAAAAAMAAQAAAAAAAAEAAAAAAgABAAAAAAMAAQAAAAABAJMAAAAAAAABAAAAAAIAAQAAAAACAAEAAAAAAgABAAAAAAAAAQAAAAAAAAEAAAAAAQABAAAAAAMAAQAAAAADAAEAAAAAAAABAAAAAAAAAQAAAAADAAEAAAAAAwABAAAAAAMAAQAAAAACAAEAAAAAAgCTAAAAAAAAAQAAAAACAAEAAAAAAgABAAAAAAEAAQAAAAACAAEAAAAAAQABAAAAAAMAAQAAAAACAAEAAAAAAgABAAAAAAMAAQAAAAABAAEAAAAAAQABAAAAAAAAAQAAAAADAAEAAAAAAwABAAAAAAAAkwAAAAAAAAEAAAAAAQABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAIAAQAAAAACAAEAAAAAAAABAAAAAAMAAQAAAAADAAEAAAAAAQABAAAAAAAAAQAAAAAAAAEAAAAAAQABAAAAAAIAAQAAAAAAAJMAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAwABAAAAAAAAAQAAAAAAAAEAAAAAAgABAAAAAAIAAQAAAAAAAAEAAAAAAQABAAAAAAEAAQAAAAADAAEAAAAAAQABAAAAAAMAAQAAAAADAAEAAAAAAQCTAAAAAAAAAQAAAAADAAEAAAAAAQABAAAAAAEAAQAAAAADAAEAAAAAAQABAAAAAAMAAQAAAAACAAEAAAAAAwABAAAAAAIAAQAAAAACAAEAAAAAAgABAAAAAAEAAQAAAAAAAAEAAAAAAAABAAAAAAAAkwAAAAAAAAEAAAAAAQABAAAAAAEAAQAAAAABAAEAAAAAAAABAAAAAAIAAQAAAAACAAEAAAAAAwABAAAAAAIAAQAAAAABAAEAAAAAAAABAAAAAAAAAQAAAAABAAEAAAAAAQABAAAAAAIAAQAAAAADAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACZAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA== + version: 7 3,1: ind: 3,1 - tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAkwAAAAAAAQAAAAABAQAAAAADkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAADwAAAAABDwAAAAADkwAAAAAAkwAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAkwAAAAAAAQAAAAABAgAAAAADAgAAAAACkwAAAAAADgAAAAAADgAAAAAADgAAAAAAkwAAAAAAEAAAAAACEAAAAAACDwAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAkwAAAAAAAQAAAAABAQAAAAACkwAAAAAADgAAAAAABQAAAAAADgAAAAAAkwAAAAAAEAAAAAACEAAAAAAADwAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAAQAAAAABkwAAAAAADgAAAAAADgAAAAAADgAAAAAAkwAAAAAAEQAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAACwAAAAADCwAAAAABCwAAAAACCwAAAAADCwAAAAACCwAAAAADCwAAAAADCwAAAAABCwAAAAACCwAAAAACkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAACwAAAAADDAAAAAACDAAAAAAACwAAAAABCwAAAAAACwAAAAADCwAAAAABDQAAAAADkwAAAAAACwAAAAADkwAAAAAAEgAAAAAAEgAAAAAAEgAAAAAAEgAAAAAAkwAAAAAACwAAAAABDAAAAAACDAAAAAADCwAAAAADCwAAAAAACwAAAAADCwAAAAABCwAAAAAACwAAAAACCwAAAAAAEgAAAAAAEgAAAAAAEgAAAAAAEgAAAAAAEgAAAAAAkwAAAAAACwAAAAAACwAAAAACCwAAAAACCwAAAAACCwAAAAADCwAAAAAACwAAAAACDQAAAAADkwAAAAAACwAAAAAAkwAAAAAAEgAAAAAAEgAAAAAAEgAAAAAAEgAAAAAAkwAAAAAAkwAAAAAACwAAAAABCwAAAAADDQAAAAACAQAAAAAAAQAAAAAAAQAAAAADCwAAAAAACwAAAAABCwAAAAABkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAAAAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAAQAAAAACAQAAAAACAQAAAAADkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - version: 6 + tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACZAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACZAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJMAAAAAAACTAAAAAAAAAQAAAAABAAEAAAAAAwCTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAA8AAAAAAQAPAAAAAAMAkwAAAAAAAJMAAAAAAACZAAAAAAAAmQAAAAAAAJkAAAAAAACTAAAAAAAAAQAAAAABAAIAAAAAAwACAAAAAAIAkwAAAAAAAA4AAAAAAAAOAAAAAAAADgAAAAAAAJMAAAAAAAAQAAAAAAIAEAAAAAACAA8AAAAAAACTAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAAJMAAAAAAAABAAAAAAEAAQAAAAACAJMAAAAAAAAOAAAAAAAABQAAAAAAAA4AAAAAAACTAAAAAAAAEAAAAAACABAAAAAAAAAPAAAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAAEAAAAAAQCTAAAAAAAADgAAAAAAAA4AAAAAAAAOAAAAAAAAkwAAAAAAABEAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACTAAAAAAAACwAAAAADAAsAAAAAAQALAAAAAAIACwAAAAADAAsAAAAAAgALAAAAAAMACwAAAAADAAsAAAAAAQALAAAAAAIACwAAAAACAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAAsAAAAAAwAMAAAAAAIADAAAAAAAAAsAAAAAAQALAAAAAAAACwAAAAADAAsAAAAAAQANAAAAAAMAkwAAAAAAAAsAAAAAAwCTAAAAAAAAEgAAAAAAABIAAAAAAAASAAAAAAAAEgAAAAAAAJMAAAAAAAALAAAAAAEADAAAAAACAAwAAAAAAwALAAAAAAMACwAAAAAAAAsAAAAAAwALAAAAAAEACwAAAAAAAAsAAAAAAgALAAAAAAAAEgAAAAAAABIAAAAAAAASAAAAAAAAEgAAAAAAABIAAAAAAACTAAAAAAAACwAAAAAAAAsAAAAAAgALAAAAAAIACwAAAAACAAsAAAAAAwALAAAAAAAACwAAAAACAA0AAAAAAwCTAAAAAAAACwAAAAAAAJMAAAAAAAASAAAAAAAAEgAAAAAAABIAAAAAAAASAAAAAAAAkwAAAAAAAJMAAAAAAAALAAAAAAEACwAAAAADAA0AAAAAAgABAAAAAAAAAQAAAAAAAAEAAAAAAwALAAAAAAAACwAAAAABAAsAAAAAAQCTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAAAAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAAQAAAAACAAEAAAAAAgABAAAAAAMAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACZAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA== + version: 7 4,1: ind: 4,1 - tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAAQAAAAACAgAAAAACAgAAAAACAgAAAAACAQAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAAQAAAAADAgAAAAABAgAAAAADAgAAAAABAQAAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAAgAAAAAAAgAAAAADAgAAAAACkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAAQAAAAABkwAAAAAAkwAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAmQAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAmQAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - version: 6 + tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAAABAAAAAAIAAgAAAAACAAIAAAAAAgACAAAAAAIAAQAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAAQAAAAADAAIAAAAAAQACAAAAAAMAAgAAAAABAAEAAAAAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAAACAAAAAAAAAgAAAAADAAIAAAAAAgCTAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAAEAAAAAAQCTAAAAAAAAkwAAAAAAAJkAAAAAAACZAAAAAAAAmQAAAAAAAJkAAAAAAACZAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJkAAAAAAACZAAAAAAAAmQAAAAAAAJkAAAAAAACZAAAAAAAAmQAAAAAAAJkAAAAAAACZAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAmQAAAAAAAJMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJkAAAAAAACTAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACZAAAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAAJMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACZAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJkAAAAAAAAAAAAAAAAAAAAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA== + version: 7 3,2: ind: 3,2 - tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAABQAAAAAABQAAAAAABQAAAAAAkwAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAkwAAAAAADgAAAAAADgAAAAAADgAAAAAAkwAAAAAABQAAAAAABQAAAAAABQAAAAAABQAAAAAAkwAAAAAAmQAAAAAAmQAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAADgAAAAAABQAAAAAADgAAAAAAkwAAAAAAkwAAAAAABQAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAAAAAAAAAAAAAAAAACwAAAAACCwAAAAACCwAAAAABkwAAAAAAkwAAAAAADgAAAAAADgAAAAAADgAAAAAAkwAAAAAAkwAAAAAACwAAAAADCwAAAAADCwAAAAADkwAAAAAAAAAAAAAAAAAAAAAACwAAAAACDQAAAAACCwAAAAABCwAAAAADCwAAAAABCwAAAAADEwAAAAACCwAAAAACCwAAAAAACwAAAAADFQAAAAACFQAAAAACFQAAAAACkwAAAAAAAAAAAAAAAAAAAAAAEwAAAAABEwAAAAABEwAAAAACEwAAAAADEwAAAAABEwAAAAAAEwAAAAABEwAAAAACEwAAAAACEwAAAAACFQAAAAABDQAAAAABFQAAAAACkwAAAAAAAAAAAAAAAAAAAAAACwAAAAACCwAAAAABCwAAAAAACwAAAAACCwAAAAAACwAAAAACEwAAAAABCwAAAAABCwAAAAAACwAAAAAAFQAAAAACFQAAAAADFQAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAwAAAAADAQAAAAADAQAAAAADkwAAAAAACwAAAAABCwAAAAACCwAAAAACCwAAAAACCwAAAAACkwAAAAAACwAAAAAACwAAAAADCwAAAAAAkwAAAAAAmQAAAAAAmQAAAAAAAQAAAAAAFAAAAAAAAQAAAAACkwAAAAAACwAAAAACEwAAAAACEwAAAAADEwAAAAABCwAAAAABkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAACwAAAAAAEgAAAAAAEgAAAAAAEgAAAAAACwAAAAACkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAACwAAAAAAEgAAAAAAEgAAAAAAEgAAAAAACwAAAAABkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - version: 6 + tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACZAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACZAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAAAFAAAAAAAABQAAAAAAAAUAAAAAAACTAAAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJkAAAAAAAAAAAAAAAAAAAAAAAAAAJMAAAAAAAAOAAAAAAAADgAAAAAAAA4AAAAAAACTAAAAAAAABQAAAAAAAAUAAAAAAAAFAAAAAAAABQAAAAAAAJMAAAAAAACZAAAAAAAAmQAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAADgAAAAAAAAUAAAAAAAAOAAAAAAAAkwAAAAAAAJMAAAAAAAAFAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAAAAAAAAAAAAAAAAAAAALAAAAAAIACwAAAAACAAsAAAAAAQCTAAAAAAAAkwAAAAAAAA4AAAAAAAAOAAAAAAAADgAAAAAAAJMAAAAAAACTAAAAAAAACwAAAAADAAsAAAAAAwALAAAAAAMAkwAAAAAAAAAAAAAAAAAAAAAAAAAACwAAAAACAA0AAAAAAgALAAAAAAEACwAAAAADAAsAAAAAAQALAAAAAAMAEwAAAAACAAsAAAAAAgALAAAAAAAACwAAAAADABUAAAAAAgAVAAAAAAIAFQAAAAACAJMAAAAAAAAAAAAAAAAAAAAAAAAAABMAAAAAAQATAAAAAAEAEwAAAAACABMAAAAAAwATAAAAAAEAEwAAAAAAABMAAAAAAQATAAAAAAIAEwAAAAACABMAAAAAAgAVAAAAAAEADQAAAAABABUAAAAAAgCTAAAAAAAAAAAAAAAAAAAAAAAAAAALAAAAAAIACwAAAAABAAsAAAAAAAALAAAAAAIACwAAAAAAAAsAAAAAAgATAAAAAAEACwAAAAABAAsAAAAAAAALAAAAAAAAFQAAAAACABUAAAAAAwAVAAAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAwAAAAADAAEAAAAAAwABAAAAAAMAkwAAAAAAAAsAAAAAAQALAAAAAAIACwAAAAACAAsAAAAAAgALAAAAAAIAkwAAAAAAAAsAAAAAAAALAAAAAAMACwAAAAAAAJMAAAAAAACZAAAAAAAAmQAAAAAAAAEAAAAAAAAUAAAAAAAAAQAAAAACAJMAAAAAAAALAAAAAAIAEwAAAAACABMAAAAAAwATAAAAAAEACwAAAAABAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAAAAAAAAAAAAAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAACwAAAAAAABIAAAAAAAASAAAAAAAAEgAAAAAAAAsAAAAAAgCTAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAAAsAAAAAAAASAAAAAAAAEgAAAAAAABIAAAAAAAALAAAAAAEAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACZAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA== + version: 7 2,2: ind: 2,2 - tiles: AAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADgAAAAAADgAAAAAADgAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADgAAAAAABQAAAAAADgAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAADgAAAAAADgAAAAAADgAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAAQAAAAADAgAAAAABAQAAAAACDwAAAAACDwAAAAABDwAAAAAADwAAAAACkwAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAADgAAAAAADgAAAAAAAQAAAAAAAgAAAAADAQAAAAABEAAAAAACEAAAAAAAEAAAAAADEAAAAAABDwAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAADgAAAAAADgAAAAAAAQAAAAABAgAAAAACAQAAAAABEAAAAAAAEAAAAAAAEAAAAAACEAAAAAAADwAAAAABkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAADgAAAAAADgAAAAAAAQAAAAACAgAAAAACAQAAAAAADwAAAAADDwAAAAACDwAAAAACDwAAAAACkwAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAAwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAkwAAAAAAAQAAAAACCQAAAAAAAQAAAAACAQAAAAAAAQAAAAADkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAAQAAAAADCQAAAAAAAQAAAAACAQAAAAADAQAAAAABkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACQAAAAAACQAAAAAACQAAAAAACQAAAAAACQAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwAAAAACCQAAAAAAAwAAAAABAgAAAAADAwAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwAAAAAACQAAAAAAAwAAAAACAgAAAAACkwAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - version: 6 + tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAAAAAAAAAAAAAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADgAAAAAAAA4AAAAAAAAOAAAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACZAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA4AAAAAAAAFAAAAAAAADgAAAAAAAJMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJMAAAAAAAAOAAAAAAAADgAAAAAAAA4AAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJkAAAAAAACZAAAAAAAAmQAAAAAAAJkAAAAAAACZAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAAQAAAAADAAIAAAAAAQABAAAAAAIADwAAAAACAA8AAAAAAQAPAAAAAAAADwAAAAACAJMAAAAAAACTAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJMAAAAAAAAOAAAAAAAADgAAAAAAAAEAAAAAAAACAAAAAAMAAQAAAAABABAAAAAAAgAQAAAAAAAAEAAAAAADABAAAAAAAQAPAAAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACTAAAAAAAADgAAAAAAAA4AAAAAAAABAAAAAAEAAgAAAAACAAEAAAAAAQAQAAAAAAAAEAAAAAAAABAAAAAAAgAQAAAAAAAADwAAAAABAJMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAAA4AAAAAAAAOAAAAAAAAAQAAAAACAAIAAAAAAgABAAAAAAAADwAAAAADAA8AAAAAAgAPAAAAAAIADwAAAAACAJMAAAAAAACTAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAAADAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAmQAAAAAAAJkAAAAAAACZAAAAAAAAmQAAAAAAAJkAAAAAAACZAAAAAAAAmQAAAAAAAJMAAAAAAAABAAAAAAIACQAAAAAAAAEAAAAAAgABAAAAAAAAAQAAAAADAJMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACTAAAAAAAAAQAAAAADAAkAAAAAAAABAAAAAAIAAQAAAAADAAEAAAAAAQCTAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACZAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkAAAAAAAAJAAAAAAAACQAAAAAAAAkAAAAAAAAJAAAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAAAAAAIACQAAAAAAAAMAAAAAAQACAAAAAAMAAwAAAAAAAJMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwAAAAAAAAkAAAAAAAADAAAAAAIAAgAAAAACAJMAAAAAAACTAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACZAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA== + version: 7 1,3: ind: 1,3 - tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - version: 6 + tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACTAAAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA== + version: 7 2,3: ind: 2,3 - tiles: kwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAADgAAAAAADgAAAAAADgAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAADgAAAAAABQAAAAAADgAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAADgAAAAAADgAAAAAADgAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAACgAAAAAACgAAAAAACgAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAACgAAAAAACgAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAACgAAAAAACgAAAAAACgAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAACgAAAAAACgAAAAAACgAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAACgAAAAAACgAAAAAACgAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAkwAAAAAAFgAAAAAAFgAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAACgAAAAAACgAAAAAAkwAAAAAA - version: 6 + tiles: kwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJMAAAAAAAAOAAAAAAAADgAAAAAAAA4AAAAAAACTAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACZAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACTAAAAAAAADgAAAAAAAAUAAAAAAAAOAAAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAA4AAAAAAAAOAAAAAAAADgAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAAAAAAAAAAAAAAAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAACgAAAAAAAAoAAAAAAAAKAAAAAAAAAAAAAAAAAAAAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAACgAAAAAAAAoAAAAAAAAAAAAAAAAAAAAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAAAAAAAAAAAAAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAAoAAAAAAAAKAAAAAAAACgAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAAAAAAAAAAAAAAAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAACgAAAAAAAAoAAAAAAAAKAAAAAAAAAAAAAAAAAAAAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAAAKAAAAAAAACgAAAAAAAAoAAAAAAAAAAAAAAAAAAAAAAAAAAJMAAAAAAACTAAAAAAAAFgAAAAAAABYAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAAAAAAAAAAAAAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAAoAAAAAAAAKAAAAAAAAkwAAAAAAAA== + version: 7 4,0: ind: 4,0 - tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAADgAAAAAADgAAAAAADgAAAAAAkwAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAADgAAAAAABQAAAAAADgAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAADgAAAAAADgAAAAAADgAAAAAAkwAAAAAA - version: 6 + tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJkAAAAAAACZAAAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACZAAAAAAAAmQAAAAAAAJkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAAJkAAAAAAACZAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJkAAAAAAACZAAAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACZAAAAAAAAmQAAAAAAAJkAAAAAAACZAAAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAAJkAAAAAAACZAAAAAAAAmQAAAAAAAJkAAAAAAACZAAAAAAAAmQAAAAAAAJkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJkAAAAAAACZAAAAAAAAmQAAAAAAAJkAAAAAAACZAAAAAAAAmQAAAAAAAJkAAAAAAACZAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACZAAAAAAAAmQAAAAAAAJkAAAAAAACZAAAAAAAAmQAAAAAAAJkAAAAAAACZAAAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAAJkAAAAAAACZAAAAAAAAmQAAAAAAAJkAAAAAAACZAAAAAAAAmQAAAAAAAJkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJkAAAAAAACZAAAAAAAAmQAAAAAAAJkAAAAAAACZAAAAAAAAmQAAAAAAAJkAAAAAAACZAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACZAAAAAAAAmQAAAAAAAJkAAAAAAACZAAAAAAAAmQAAAAAAAJkAAAAAAACZAAAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAAJkAAAAAAACZAAAAAAAAmQAAAAAAAJkAAAAAAACZAAAAAAAAmQAAAAAAAJkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJkAAAAAAACZAAAAAAAAmQAAAAAAAJkAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAA4AAAAAAAAOAAAAAAAADgAAAAAAAJMAAAAAAACZAAAAAAAAmQAAAAAAAJkAAAAAAACZAAAAAAAAmQAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAAAOAAAAAAAABQAAAAAAAA4AAAAAAACTAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAADgAAAAAAAA4AAAAAAAAOAAAAAAAAkwAAAAAAAA== + version: 7 5,1: ind: 5,1 - tiles: kwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAA - version: 6 + tiles: kwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACZAAAAAAAAAAAAAAAAAAAAAAAAAACZAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJkAAAAAAACZAAAAAAAAmQAAAAAAAJkAAAAAAACZAAAAAAAAmQAAAAAAAJkAAAAAAACZAAAAAAAAmQAAAAAAAA== + version: 7 5,0: ind: 5,0 - tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAmQAAAAAAmQAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAAAAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAmQAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAmQAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAmQAAAAAAmQAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAA - version: 6 + tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACZAAAAAAAAmQAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAAAAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAmQAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJkAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJkAAAAAAACZAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJkAAAAAAACZAAAAAAAAmQAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACZAAAAAAAAmQAAAAAAAJkAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAmQAAAAAAAJkAAAAAAACZAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAA== + version: 7 6,0: ind: 6,0 - tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - version: 6 + tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAAJMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJMAAAAAAACTAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACTAAAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAAJMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA== + version: 7 6,1: ind: 6,1 - tiles: kwAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - version: 6 + tiles: kwAAAAAAAJMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJMAAAAAAACTAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACTAAAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAAJMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJMAAAAAAACTAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACTAAAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAAJMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJMAAAAAAACTAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACTAAAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAAJMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJMAAAAAAACTAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACTAAAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAAJMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJMAAAAAAACTAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA== + version: 7 5,2: ind: 5,2 - tiles: AAAAAAAAAAAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - version: 6 + tiles: AAAAAAAAAAAAAAAAAACZAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAAAAAAAAAAAAAAAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAAAAAAAAAAAAAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAAAAAAAAAAAAAAAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAAAAAAAAAAAAAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAAAAAAAAAAAAAAAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAAAAAAAAAAAAAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA== + version: 7 4,2: ind: 4,2 - tiles: AAAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAkwAAAAAADgAAAAAADgAAAAAADgAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAkwAAAAAADgAAAAAABQAAAAAADgAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAADgAAAAAADgAAAAAADgAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAmQAAAAAAkwAAAAAAAQAAAAAAAQAAAAABAgAAAAABAQAAAAAAAQAAAAAAAQAAAAACAgAAAAADAQAAAAAAAQAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAAAAAAAAAkwAAAAAAAQAAAAADAQAAAAACAgAAAAACAQAAAAADAQAAAAADAQAAAAABAgAAAAADAQAAAAAAAQAAAAABkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAAAAAAAAAkwAAAAAAAQAAAAADAQAAAAADAgAAAAAAAQAAAAABAQAAAAABAQAAAAACAgAAAAADAQAAAAACAQAAAAABkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAAAAAAAAAkwAAAAAAAQAAAAADAQAAAAADAgAAAAABAQAAAAAAAQAAAAACAQAAAAABAgAAAAAAAQAAAAACAQAAAAABkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAAAAAAAAAkwAAAAAAAQAAAAADAQAAAAADAgAAAAAAAQAAAAACAQAAAAABAQAAAAADAgAAAAACAQAAAAACAQAAAAABkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAAAAAAAAAkwAAAAAAAQAAAAACAQAAAAADAgAAAAAAAQAAAAADAQAAAAACAQAAAAADAgAAAAADAQAAAAACAQAAAAADkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAmQAAAAAAkwAAAAAAAQAAAAAAAQAAAAABAgAAAAABAQAAAAABAQAAAAACAQAAAAADAgAAAAACAQAAAAADAQAAAAABkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAAAAAAAAAkwAAAAAAAgAAAAAAAgAAAAADAgAAAAADAgAAAAACAgAAAAACAgAAAAAAAgAAAAADAgAAAAABAgAAAAADkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAAAAAAAAAkwAAAAAAAQAAAAADAQAAAAADAQAAAAACAQAAAAADAQAAAAACAQAAAAACAQAAAAABAQAAAAADAQAAAAADkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAAAAAAAAAkwAAAAAAAQAAAAABAQAAAAABAQAAAAABAQAAAAAAAQAAAAAAAQAAAAADAQAAAAADAQAAAAADAQAAAAACkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAAAAAAAAAkwAAAAAAAQAAAAACAQAAAAAAAQAAAAACAQAAAAACAQAAAAADAQAAAAABAQAAAAAAAQAAAAACAQAAAAABkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAAAAAAAAAkwAAAAAAkwAAAAAAAQAAAAABAQAAAAADAQAAAAACAQAAAAACAQAAAAAAAQAAAAACAQAAAAABkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAAQAAAAAAAQAAAAAAAQAAAAACAQAAAAABAQAAAAAAAQAAAAACAQAAAAACkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - version: 6 + tiles: AAAAAAAAAJkAAAAAAAAAAAAAAAAAAAAAAAAAAJMAAAAAAAAOAAAAAAAADgAAAAAAAA4AAAAAAACTAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACZAAAAAAAAAAAAAAAAAAAAAAAAAACTAAAAAAAADgAAAAAAAAUAAAAAAAAOAAAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAA4AAAAAAAAOAAAAAAAADgAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAmQAAAAAAAJMAAAAAAAABAAAAAAAAAQAAAAABAAIAAAAAAQABAAAAAAAAAQAAAAAAAAEAAAAAAgACAAAAAAMAAQAAAAAAAAEAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAAAAAAAAAACTAAAAAAAAAQAAAAADAAEAAAAAAgACAAAAAAIAAQAAAAADAAEAAAAAAwABAAAAAAEAAgAAAAADAAEAAAAAAAABAAAAAAEAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAAAAAAAAAAAAkwAAAAAAAAEAAAAAAwABAAAAAAMAAgAAAAAAAAEAAAAAAQABAAAAAAEAAQAAAAACAAIAAAAAAwABAAAAAAIAAQAAAAABAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAAAAAAAAAAJMAAAAAAAABAAAAAAMAAQAAAAADAAIAAAAAAQABAAAAAAAAAQAAAAACAAEAAAAAAQACAAAAAAAAAQAAAAACAAEAAAAAAQCTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAAAAAAAAAACTAAAAAAAAAQAAAAADAAEAAAAAAwACAAAAAAAAAQAAAAACAAEAAAAAAQABAAAAAAMAAgAAAAACAAEAAAAAAgABAAAAAAEAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAAAAAAAAAAAAkwAAAAAAAAEAAAAAAgABAAAAAAMAAgAAAAAAAAEAAAAAAwABAAAAAAIAAQAAAAADAAIAAAAAAwABAAAAAAIAAQAAAAADAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAmQAAAAAAAJMAAAAAAAABAAAAAAAAAQAAAAABAAIAAAAAAQABAAAAAAEAAQAAAAACAAEAAAAAAwACAAAAAAIAAQAAAAADAAEAAAAAAQCTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAAAAAAAAAACTAAAAAAAAAgAAAAAAAAIAAAAAAwACAAAAAAMAAgAAAAACAAIAAAAAAgACAAAAAAAAAgAAAAADAAIAAAAAAQACAAAAAAMAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAAAAAAAAAAAAkwAAAAAAAAEAAAAAAwABAAAAAAMAAQAAAAACAAEAAAAAAwABAAAAAAIAAQAAAAACAAEAAAAAAQABAAAAAAMAAQAAAAADAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAAAAAAAAAAJMAAAAAAAABAAAAAAEAAQAAAAABAAEAAAAAAQABAAAAAAAAAQAAAAAAAAEAAAAAAwABAAAAAAMAAQAAAAADAAEAAAAAAgCTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAAAAAAAAAACTAAAAAAAAAQAAAAACAAEAAAAAAAABAAAAAAIAAQAAAAACAAEAAAAAAwABAAAAAAEAAQAAAAAAAAEAAAAAAgABAAAAAAEAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAAAAAAAAAAAAkwAAAAAAAJMAAAAAAAABAAAAAAEAAQAAAAADAAEAAAAAAgABAAAAAAIAAQAAAAAAAAEAAAAAAgABAAAAAAEAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAAAAAAAAAAAAAAAAAAACTAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAIAAQAAAAABAAEAAAAAAAABAAAAAAIAAQAAAAACAJMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA== + version: 7 4,3: ind: 4,3 - tiles: AAAAAAAAAAAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAAQAAAAACAQAAAAACAQAAAAADkwAAAAAAkwAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - version: 6 + tiles: AAAAAAAAAAAAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAAABAAAAAAIAAQAAAAACAAEAAAAAAwCTAAAAAAAAkwAAAAAAAJMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA== + version: 7 6,2: ind: 6,2 - tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - version: 6 + tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACTAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACTAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACTAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA== + version: 7 2,4: ind: 2,4 - tiles: AAAAAAAAAAAAAAAAkwAAAAAAkwAAAAAAFwAAAAAEFwAAAAAGkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAkwAAAAAAGAAAAAADGQAAAAAAGgAAAAAAGwAAAAAAHQAAAAAAHwAAAAAAIAAAAAADIQAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAHAAAAAAAHgAAAAACkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - version: 6 + tiles: AAAAAAAAAAAAAAAAAACTAAAAAAAAkwAAAAAAABcAAAAABAAXAAAAAAYAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAAAAAAAAAAAAAAAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAAAAAAAAAAAAAAAAAAACTAAAAAAAAkwAAAAAAABgAAAAAAwAZAAAAAAAAGgAAAAAAABsAAAAAAAAdAAAAAAAAHwAAAAAAACAAAAAAAwAhAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAAAcAAAAAAAAHgAAAAACAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAAAAAAAAAAAAAAAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA== + version: 7 3,3: ind: 3,3 - tiles: AAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACgAAAAAACgAAAAAACgAAAAAAkwAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACgAAAAAACgAAAAAACgAAAAAAkwAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACgAAAAAACgAAAAAACgAAAAAAkwAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACgAAAAAACgAAAAAACgAAAAAAkwAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAACgAAAAAACgAAAAAAkwAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAACgAAAAAACgAAAAAAkwAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - version: 6 + tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACZAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKAAAAAAAACgAAAAAAAAoAAAAAAACTAAAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAoAAAAAAAAKAAAAAAAACgAAAAAAAJMAAAAAAACTAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACgAAAAAAAAoAAAAAAAAKAAAAAAAAkwAAAAAAAJMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKAAAAAAAACgAAAAAAAAoAAAAAAACTAAAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJMAAAAAAAAKAAAAAAAACgAAAAAAAJMAAAAAAACTAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAAAoAAAAAAAAKAAAAAAAAkwAAAAAAAJMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA== + version: 7 3,4: ind: 3,4 - tiles: kwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - version: 6 + tiles: kwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA== + version: 7 4,-1: ind: 4,-1 - tiles: AAAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAAAAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAAAAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAAAAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAAAAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAAAAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAAAAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAAAAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAAAAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAAAAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAAAAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAAAAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAAAAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAAAAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAAAAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAAAAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAAAAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAAAAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAAAAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAAAAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAAAAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAAAAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAAAAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAAAAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAAAAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - version: 6 + tiles: AAAAAAAAAJkAAAAAAACZAAAAAAAAmQAAAAAAAJkAAAAAAACZAAAAAAAAAAAAAAAAAJkAAAAAAACZAAAAAAAAmQAAAAAAAAAAAAAAAACZAAAAAAAAmQAAAAAAAJkAAAAAAACZAAAAAAAAmQAAAAAAAAAAAAAAAACZAAAAAAAAmQAAAAAAAJkAAAAAAACZAAAAAAAAmQAAAAAAAJkAAAAAAACZAAAAAAAAmQAAAAAAAJkAAAAAAACZAAAAAAAAmQAAAAAAAJkAAAAAAACZAAAAAAAAmQAAAAAAAJkAAAAAAAAAAAAAAAAAmQAAAAAAAJkAAAAAAACZAAAAAAAAmQAAAAAAAJkAAAAAAAAAAAAAAAAAmQAAAAAAAJkAAAAAAACZAAAAAAAAAAAAAAAAAJkAAAAAAACZAAAAAAAAmQAAAAAAAJkAAAAAAACZAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJkAAAAAAACZAAAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACZAAAAAAAAmQAAAAAAAJkAAAAAAACZAAAAAAAAmQAAAAAAAAAAAAAAAACZAAAAAAAAmQAAAAAAAJkAAAAAAAAAAAAAAAAAmQAAAAAAAJkAAAAAAACZAAAAAAAAmQAAAAAAAJkAAAAAAAAAAAAAAAAAmQAAAAAAAJkAAAAAAACZAAAAAAAAmQAAAAAAAJkAAAAAAACZAAAAAAAAmQAAAAAAAJkAAAAAAACZAAAAAAAAmQAAAAAAAJkAAAAAAACZAAAAAAAAmQAAAAAAAJkAAAAAAACZAAAAAAAAAAAAAAAAAJkAAAAAAACZAAAAAAAAmQAAAAAAAJkAAAAAAACZAAAAAAAAAAAAAAAAAJkAAAAAAACZAAAAAAAAmQAAAAAAAAAAAAAAAACZAAAAAAAAmQAAAAAAAJkAAAAAAACZAAAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACZAAAAAAAAmQAAAAAAAJkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAAJkAAAAAAACZAAAAAAAAmQAAAAAAAJkAAAAAAAAAAAAAAAAAmQAAAAAAAJkAAAAAAACZAAAAAAAAAAAAAAAAAJkAAAAAAACZAAAAAAAAmQAAAAAAAJkAAAAAAACZAAAAAAAAAAAAAAAAAJkAAAAAAACZAAAAAAAAmQAAAAAAAJkAAAAAAACZAAAAAAAAmQAAAAAAAJkAAAAAAACZAAAAAAAAmQAAAAAAAJkAAAAAAACZAAAAAAAAmQAAAAAAAJkAAAAAAACZAAAAAAAAmQAAAAAAAAAAAAAAAACZAAAAAAAAmQAAAAAAAJkAAAAAAACZAAAAAAAAmQAAAAAAAAAAAAAAAACZAAAAAAAAmQAAAAAAAJkAAAAAAAAAAAAAAAAAmQAAAAAAAJkAAAAAAACZAAAAAAAAmQAAAAAAAJkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAAJkAAAAAAACZAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJkAAAAAAACZAAAAAAAAmQAAAAAAAJkAAAAAAACZAAAAAAAAAAAAAAAAAJkAAAAAAACZAAAAAAAAmQAAAAAAAAAAAAAAAACZAAAAAAAAmQAAAAAAAJkAAAAAAACZAAAAAAAAmQAAAAAAAAAAAAAAAACZAAAAAAAAmQAAAAAAAJkAAAAAAACZAAAAAAAAmQAAAAAAAJkAAAAAAACZAAAAAAAAmQAAAAAAAJkAAAAAAACZAAAAAAAAmQAAAAAAAJkAAAAAAACZAAAAAAAAmQAAAAAAAJkAAAAAAAAAAAAAAAAAmQAAAAAAAJkAAAAAAACZAAAAAAAAmQAAAAAAAJkAAAAAAAAAAAAAAAAAmQAAAAAAAJkAAAAAAACZAAAAAAAAAAAAAAAAAJkAAAAAAACZAAAAAAAAmQAAAAAAAJkAAAAAAACZAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJkAAAAAAACZAAAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA== + version: 7 4,-2: ind: 4,-2 - tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - version: 6 + tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACZAAAAAAAAmQAAAAAAAJkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAAJkAAAAAAACZAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJkAAAAAAACZAAAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA== + version: 7 - type: Broadphase - type: Physics bodyStatus: InAir @@ -979,6 +992,7 @@ entities: 368: 39.592293,65.77571 - type: OccluderTree - type: Shuttle + dampingModifier: 0.25 - type: GridPathfinding - type: SpreaderGrid - type: GravityShake @@ -1702,6 +1716,7 @@ entities: chunkSize: 4 - type: BecomesStation id: Dev + - type: ImplicitRoof - uid: 23 components: - type: MetaData @@ -1712,7 +1727,6 @@ entities: - type: GridTree - type: Broadphase - type: OccluderTree - - type: LoadedMap - uid: 2709 components: - type: MetaData @@ -1725,20 +1739,20 @@ entities: chunks: 0,0: ind: 0,0 - tiles: kwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAAAAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAkwAAAAAAAAAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - version: 6 + tiles: kwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAAAAAAAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACTAAAAAAAAkwAAAAAAAAAAAAAAAACZAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAAJMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJMAAAAAAACZAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA== + version: 7 0,-1: ind: 0,-1 - tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAkwAAAAAAAAAAAAAAmQAAAAAAmQAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - version: 6 + tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACTAAAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAAJMAAAAAAAAAAAAAAAAAmQAAAAAAAJkAAAAAAACTAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA== + version: 7 -1,0: ind: -1,0 - tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAAAAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAAAAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - version: 6 + tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAAAAAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAAAAAAAAAAACTAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA== + version: 7 -1,-1: ind: -1,-1 - tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAmQAAAAAAmQAAAAAAAAAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAAkwAAAAAA - version: 6 + tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACTAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACTAAAAAAAAmQAAAAAAAJkAAAAAAAAAAAAAAAAAkwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJkAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACTAAAAAAAAkwAAAAAAAJMAAAAAAACTAAAAAAAAkwAAAAAAAA== + version: 7 - type: Broadphase - type: Physics bodyStatus: InAir @@ -1751,6 +1765,7 @@ entities: - type: OccluderTree - type: SpreaderGrid - type: Shuttle + dampingModifier: 0.25 - type: GridPathfinding - type: Gravity gravityShakeSound: !type:SoundPathSpecifier @@ -1824,6 +1839,7 @@ entities: chunkSize: 4 - type: GasTileOverlay - type: RadiationGridResistance + - type: ImplicitRoof - uid: 2869 components: - type: MetaData @@ -1835,8 +1851,8 @@ entities: chunks: 1,1: ind: 1,1 - tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAmQAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - version: 6 + tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACZAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACZAAAAAAAAmQAAAAAAAJkAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACZAAAAAAAAmQAAAAAAAJkAAAAAAACZAAAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJkAAAAAAACZAAAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA== + version: 7 - type: Broadphase - type: Physics bodyStatus: InAir @@ -1849,6 +1865,7 @@ entities: - type: OccluderTree - type: SpreaderGrid - type: Shuttle + dampingModifier: 0.25 - type: GridPathfinding - type: Gravity gravityShakeSound: !type:SoundPathSpecifier @@ -1864,6 +1881,7 @@ entities: - type: GasTileOverlay - type: IFF flags: HideLabel + - type: ImplicitRoof - proto: AirAlarm entities: - uid: 1270 @@ -1876,6 +1894,8 @@ entities: devices: - 1269 - 1167 + - type: Fixtures + fixtures: {} - uid: 1539 components: - type: Transform @@ -1885,6 +1905,8 @@ entities: - type: DeviceList devices: - 1538 + - type: Fixtures + fixtures: {} - uid: 1680 components: - type: Transform @@ -1894,6 +1916,8 @@ entities: - type: DeviceList devices: - 1712 + - type: Fixtures + fixtures: {} - proto: AirCanister entities: - uid: 1111 @@ -2041,6 +2065,8 @@ entities: rot: 3.141592653589793 rad pos: 77.5,8.5 parent: 1 + - type: Fixtures + fixtures: {} - proto: APCHyperCapacity entities: - uid: 456 @@ -2048,51 +2074,69 @@ entities: - type: Transform pos: 53.5,14.5 parent: 1 + - type: Fixtures + fixtures: {} - uid: 458 components: - type: Transform pos: 33.5,14.5 parent: 1 + - type: Fixtures + fixtures: {} - uid: 619 components: - type: Transform rot: -1.5707963267948966 rad pos: 38.5,16.5 parent: 1 + - type: Fixtures + fixtures: {} - uid: 863 components: - type: Transform rot: 3.141592653589793 rad pos: 52.5,23.5 parent: 1 + - type: Fixtures + fixtures: {} - uid: 1068 components: - type: Transform pos: 33.5,48.5 parent: 1 + - type: Fixtures + fixtures: {} - uid: 1220 components: - type: Transform rot: 3.141592653589793 rad pos: 51.5,37.5 parent: 1 + - type: Fixtures + fixtures: {} - uid: 1394 components: - type: Transform pos: 75.5,18.5 parent: 1 + - type: Fixtures + fixtures: {} - uid: 2295 components: - type: Transform rot: 3.141592653589793 rad pos: 73.5,34.5 parent: 1 + - type: Fixtures + fixtures: {} - uid: 2601 components: - type: Transform rot: 3.141592653589793 rad pos: 43.5,48.5 parent: 1 + - type: Fixtures + fixtures: {} - proto: AtmosDeviceFanDirectional entities: - uid: 574 @@ -3018,6 +3062,8 @@ entities: - type: Transform pos: 37.5,42.5 parent: 1 + - type: Fixtures + fixtures: {} - proto: BaseBallBat entities: - uid: 2686 @@ -8925,6 +8971,25 @@ entities: - type: Transform pos: 56.75264,43.50025 parent: 1 +- proto: ChemistryBottleRobustHarvest + entities: + - uid: 1058 + components: + - type: Transform + pos: 30.295897,44.102787 + parent: 1 +- proto: ChemistryBottleUnstableMutagen + entities: + - uid: 1056 + components: + - type: Transform + pos: 30.637724,44.013588 + parent: 1 + - uid: 1057 + components: + - type: Transform + pos: 30.726896,43.86493 + parent: 1 - proto: ChemistryHotplate entities: - uid: 1129 @@ -8999,6 +9064,8 @@ entities: rot: 1.5707963267948966 rad pos: -3.5,-1.5 parent: 2709 + - type: Fixtures + fixtures: {} - proto: ClosetWallMixed entities: - uid: 829 @@ -9007,6 +9074,8 @@ entities: rot: -1.5707963267948966 rad pos: 52.5,21.5 parent: 1 + - type: Fixtures + fixtures: {} - proto: ClothingBackpackDuffelSurgeryFilled entities: - uid: 1218 @@ -9084,7 +9153,8 @@ entities: - type: DeviceLinkSource linkedPorts: 844: - - ArtifactAnalyzerSender: ArtifactAnalyzerReceiver + - - ArtifactAnalyzerSender + - ArtifactAnalyzerReceiver - uid: 2616 components: - type: Transform @@ -9131,13 +9201,6 @@ entities: - type: Transform pos: 47.5,55.5 parent: 1 -- proto: ComputerCargoShuttle - entities: - - uid: 2637 - components: - - type: Transform - pos: 49.5,55.5 - parent: 1 - proto: ComputerCloningConsole entities: - uid: 1183 @@ -9149,9 +9212,11 @@ entities: - type: DeviceLinkSource linkedPorts: 1185: - - MedicalScannerSender: MedicalScannerReceiver + - - MedicalScannerSender + - MedicalScannerReceiver 1184: - - CloningPodSender: CloningPodReceiver + - - CloningPodSender + - CloningPodReceiver - uid: 2620 components: - type: Transform @@ -9299,6 +9364,11 @@ entities: - type: Transform pos: 50.5,55.5 parent: 1 + - uid: 2637 + components: + - type: Transform + pos: 49.5,55.5 + parent: 1 - proto: ComputerShuttleSyndie entities: - uid: 2630 @@ -9619,7 +9689,6 @@ entities: showEnts: False occludes: True ents: - - 2115 - 2114 - 2113 - 2112 @@ -9861,6 +9930,8 @@ entities: - type: Transform pos: -0.5,1.5 parent: 2709 + - type: Fixtures + fixtures: {} - proto: DebugGenerator entities: - uid: 2256 @@ -9931,12 +10002,16 @@ entities: rot: 3.141592653589793 rad pos: 47.5,37.5 parent: 1 + - type: Fixtures + fixtures: {} - uid: 1910 components: - type: Transform rot: -1.5707963267948966 rad pos: 61.5,40.5 parent: 1 + - type: Fixtures + fixtures: {} - proto: DogBed entities: - uid: 780 @@ -10019,30 +10094,40 @@ entities: rot: 3.141592653589793 rad pos: 56.5,23.5 parent: 1 + - type: Fixtures + fixtures: {} - uid: 1008 components: - type: Transform rot: 1.5707963267948966 rad pos: 23.5,39.5 parent: 1 + - type: Fixtures + fixtures: {} - uid: 1907 components: - type: Transform rot: -1.5707963267948966 rad pos: 79.5,18.5 parent: 1 + - type: Fixtures + fixtures: {} - uid: 1908 components: - type: Transform rot: -1.5707963267948966 rad pos: 72.5,34.5 parent: 1 + - type: Fixtures + fixtures: {} - uid: 1909 components: - type: Transform rot: -1.5707963267948966 rad pos: 56.5,37.5 parent: 1 + - type: Fixtures + fixtures: {} - proto: FireAxeCabinetFilled entities: - uid: 1633 @@ -10051,12 +10136,16 @@ entities: rot: 1.5707963267948966 rad pos: 28.5,15.5 parent: 1 + - type: Fixtures + fixtures: {} - uid: 3074 components: - type: Transform rot: 1.5707963267948966 rad pos: 80.5,20.5 parent: 1 + - type: Fixtures + fixtures: {} - proto: FireExtinguisher entities: - uid: 425 @@ -10332,6 +10421,8 @@ entities: rot: 1.5707963267948966 rad pos: 51.5,43.5 parent: 1 + - type: Fixtures + fixtures: {} - proto: GasAnalyzer entities: - uid: 1258 @@ -12105,15 +12196,6 @@ entities: - type: Physics canCollide: False - type: InsideEntityStorage -- proto: MagazineLightRifleMaxim - entities: - - uid: 2115 - components: - - type: Transform - parent: 2107 - - type: Physics - canCollide: False - - type: InsideEntityStorage - proto: MagazineLightRiflePractice entities: - uid: 2110 @@ -12958,6 +13040,8 @@ entities: rot: 3.141592653589793 rad pos: 94.5,11.5 parent: 1 + - type: Fixtures + fixtures: {} - proto: PosterLegitJustAWeekAway entities: - uid: 3144 @@ -12965,6 +13049,8 @@ entities: - type: Transform pos: 61.5,39.5 parent: 1 + - type: Fixtures + fixtures: {} - proto: PottedPlant21 entities: - uid: 928 @@ -14354,13 +14440,6 @@ entities: - type: Transform pos: 50.542976,20.508951 parent: 1 -- proto: RobustHarvestChemistryBottle - entities: - - uid: 1058 - components: - - type: Transform - pos: 30.295897,44.102787 - parent: 1 - proto: SalvageMagnet entities: - uid: 2678 @@ -14770,6 +14849,8 @@ entities: parent: 1 - type: Lock locked: False + - type: Fixtures + fixtures: {} - proto: ShotGunCabinetFilled entities: - uid: 1906 @@ -14778,6 +14859,8 @@ entities: rot: 1.5707963267948966 rad pos: 28.5,19.5 parent: 1 + - type: Fixtures + fixtures: {} - proto: ShuttleGunDuster entities: - uid: 2781 @@ -14875,27 +14958,40 @@ entities: - type: DeviceLinkSource linkedPorts: 585: - - Pressed: Toggle + - - Pressed + - Toggle 586: - - Pressed: Toggle + - - Pressed + - Toggle 587: - - Pressed: Toggle + - - Pressed + - Toggle 588: - - Pressed: Toggle + - - Pressed + - Toggle 589: - - Pressed: Toggle + - - Pressed + - Toggle 590: - - Pressed: Toggle + - - Pressed + - Toggle 591: - - Pressed: Toggle + - - Pressed + - Toggle 592: - - Pressed: Toggle + - - Pressed + - Toggle 593: - - Pressed: Toggle + - - Pressed + - Toggle 584: - - Pressed: Toggle + - - Pressed + - Toggle 608: - - Pressed: Toggle + - - Pressed + - Toggle + - type: Fixtures + fixtures: {} - uid: 740 components: - type: MetaData @@ -14906,27 +15002,40 @@ entities: - type: DeviceLinkSource linkedPorts: 598: - - Pressed: Toggle + - - Pressed + - Toggle 599: - - Pressed: Toggle + - - Pressed + - Toggle 607: - - Pressed: Toggle + - - Pressed + - Toggle 606: - - Pressed: Toggle + - - Pressed + - Toggle 605: - - Pressed: Toggle + - - Pressed + - Toggle 604: - - Pressed: Toggle + - - Pressed + - Toggle 603: - - Pressed: Toggle + - - Pressed + - Toggle 602: - - Pressed: Toggle + - - Pressed + - Toggle 601: - - Pressed: Toggle + - - Pressed + - Toggle 600: - - Pressed: Toggle + - - Pressed + - Toggle 609: - - Pressed: Toggle + - - Pressed + - Toggle + - type: Fixtures + fixtures: {} - uid: 753 components: - type: MetaData @@ -14938,11 +15047,16 @@ entities: - type: DeviceLinkSource linkedPorts: 596: - - Pressed: Toggle + - - Pressed + - Toggle 852: - - Pressed: Toggle + - - Pressed + - Toggle 853: - - Pressed: Toggle + - - Pressed + - Toggle + - type: Fixtures + fixtures: {} - uid: 1593 components: - type: MetaData @@ -14954,7 +15068,10 @@ entities: - type: DeviceLinkSource linkedPorts: 1597: - - Pressed: Trigger + - - Pressed + - Trigger + - type: Fixtures + fixtures: {} - uid: 1594 components: - type: MetaData @@ -14966,7 +15083,10 @@ entities: - type: DeviceLinkSource linkedPorts: 1579: - - Pressed: Toggle + - - Pressed + - Toggle + - type: Fixtures + fixtures: {} - uid: 2794 components: - type: MetaData @@ -14978,17 +15098,27 @@ entities: - type: DeviceLinkSource linkedPorts: 2783: - - Pressed: Toggle - - Pressed: Trigger + - - Pressed + - Toggle + - - Pressed + - Trigger 2782: - - Pressed: Toggle - - Pressed: Trigger + - - Pressed + - Toggle + - - Pressed + - Trigger 2781: - - Pressed: Toggle - - Pressed: Trigger + - - Pressed + - Toggle + - - Pressed + - Trigger 2784: - - Pressed: Toggle - - Pressed: Trigger + - - Pressed + - Toggle + - - Pressed + - Trigger + - type: Fixtures + fixtures: {} - uid: 2795 components: - type: MetaData @@ -15000,7 +15130,10 @@ entities: - type: DeviceLinkSource linkedPorts: 2779: - - Pressed: Toggle + - - Pressed + - Toggle + - type: Fixtures + fixtures: {} - uid: 2796 components: - type: Transform @@ -15009,8 +15142,12 @@ entities: - type: DeviceLinkSource linkedPorts: 2781: - - Pressed: Toggle - - Pressed: Trigger + - - Pressed + - Toggle + - - Pressed + - Trigger + - type: Fixtures + fixtures: {} - uid: 2797 components: - type: Transform @@ -15019,8 +15156,12 @@ entities: - type: DeviceLinkSource linkedPorts: 2784: - - Pressed: Toggle - - Pressed: Trigger + - - Pressed + - Toggle + - - Pressed + - Trigger + - type: Fixtures + fixtures: {} - uid: 2798 components: - type: Transform @@ -15029,8 +15170,12 @@ entities: - type: DeviceLinkSource linkedPorts: 2783: - - Pressed: Toggle - - Pressed: Trigger + - - Pressed + - Toggle + - - Pressed + - Trigger + - type: Fixtures + fixtures: {} - uid: 2799 components: - type: Transform @@ -15039,8 +15184,12 @@ entities: - type: DeviceLinkSource linkedPorts: 2782: - - Pressed: Toggle - - Pressed: Trigger + - - Pressed + - Toggle + - - Pressed + - Trigger + - type: Fixtures + fixtures: {} - proto: SignalButtonDirectional entities: - uid: 2642 @@ -15054,7 +15203,10 @@ entities: - type: DeviceLinkSource linkedPorts: 2641: - - Pressed: Toggle + - - Pressed + - Toggle + - type: Fixtures + fixtures: {} - proto: SignalTrigger entities: - uid: 2863 @@ -15725,6 +15877,8 @@ entities: - type: Transform pos: 45.5,65.5 parent: 1 + - type: Fixtures + fixtures: {} - proto: StationMapBroken entities: - uid: 1911 @@ -15732,6 +15886,8 @@ entities: - type: Transform pos: 46.5,65.5 parent: 1 + - type: Fixtures + fixtures: {} - proto: Stunbaton entities: - uid: 2683 @@ -16144,6 +16300,7 @@ entities: - type: Transform pos: 82.5,21.5 parent: 1 + - type: Conveyed - uid: 2881 components: - type: Transform @@ -16302,53 +16459,89 @@ entities: - type: DeviceLinkSource linkedPorts: 2850: - - Left: Forward - - Right: Reverse - - Middle: Off + - - Left + - Forward + - - Right + - Reverse + - - Middle + - Off 2848: - - Left: Forward - - Right: Reverse - - Middle: Off + - - Left + - Forward + - - Right + - Reverse + - - Middle + - Off 2847: - - Left: Forward - - Right: Reverse - - Middle: Off + - - Left + - Forward + - - Right + - Reverse + - - Middle + - Off 2626: - - Left: Forward - - Right: Reverse - - Middle: Off + - - Left + - Forward + - - Right + - Reverse + - - Middle + - Off 2844: - - Left: Forward - - Right: Reverse - - Middle: Off + - - Left + - Forward + - - Right + - Reverse + - - Middle + - Off 2621: - - Left: Forward - - Right: Reverse - - Middle: Off + - - Left + - Forward + - - Right + - Reverse + - - Middle + - Off 432: - - Left: Forward - - Right: Reverse - - Middle: Off + - - Left + - Forward + - - Right + - Reverse + - - Middle + - Off 2615: - - Left: Forward - - Right: Reverse - - Middle: Off + - - Left + - Forward + - - Right + - Reverse + - - Middle + - Off 2213: - - Left: Forward - - Right: Reverse - - Middle: Off + - - Left + - Forward + - - Right + - Reverse + - - Middle + - Off 2849: - - Left: Forward - - Right: Reverse - - Middle: Off + - - Left + - Forward + - - Right + - Reverse + - - Middle + - Off 2852: - - Left: Forward - - Right: Reverse - - Middle: Off + - - Left + - Forward + - - Right + - Reverse + - - Middle + - Off 2851: - - Left: Forward - - Right: Reverse - - Middle: Off + - - Left + - Forward + - - Right + - Reverse + - - Middle + - Off - proto: UniformPrinter entities: - uid: 428 @@ -16356,18 +16549,12 @@ entities: - type: Transform pos: 37.5,18.5 parent: 1 -- proto: UnstableMutagenChemistryBottle - entities: - - uid: 1056 - components: - - type: Transform - pos: 30.637724,44.013588 - parent: 1 - - uid: 1057 - components: - - type: Transform - pos: 30.726896,43.86493 - parent: 1 + - type: TechnologyDatabase + supportedDisciplines: + - Industrial + - Arsenal + - Experimental + - CivilianServices - proto: UraniumReinforcedWindowDirectional entities: - uid: 748 @@ -16531,6 +16718,8 @@ entities: - type: Transform pos: 57.5,41.5 parent: 1 + - type: Fixtures + fixtures: {} - proto: VendingMachineYouTool entities: - uid: 1292 From 7d6a8426c5c31dc646f70fd3cec88691ca3f4aca Mon Sep 17 00:00:00 2001 From: AndrewFenriz <78079974+AndrewFenriz@users.noreply.github.com> Date: Sun, 31 Aug 2025 15:54:45 +0300 Subject: [PATCH 287/340] Migrate all mechs to PartAssembly and remove legacy MechAssemblySystem (#39027) * Removed the old MechAssembly system and component. Converted all mechs to use the unified PartAssembly system. Removed dismantling mechs during assembly logic to simplify the code. * Delete Chassis via migration --- .../Mech/Components/MechAssemblyComponent.cs | 50 ------ .../Mech/Systems/MechAssemblySystem.cs | 67 -------- Resources/Locale/en-US/mech/mech.ftl | 4 +- Resources/Migrations/migration.yml | 6 + .../Specific/Mech/mech_construction.yml | 152 ++++++------------ .../Graphs/mechs/hamtr_construction.yml | 3 + .../Graphs/mechs/honker_construction.yml | 3 + .../Graphs/mechs/ripley_construction.yml | 3 + .../Graphs/mechs/vim_construction.yml | 3 + 9 files changed, 71 insertions(+), 220 deletions(-) delete mode 100644 Content.Server/Mech/Components/MechAssemblyComponent.cs delete mode 100644 Content.Server/Mech/Systems/MechAssemblySystem.cs diff --git a/Content.Server/Mech/Components/MechAssemblyComponent.cs b/Content.Server/Mech/Components/MechAssemblyComponent.cs deleted file mode 100644 index 2d352cbf15c..00000000000 --- a/Content.Server/Mech/Components/MechAssemblyComponent.cs +++ /dev/null @@ -1,50 +0,0 @@ -using Content.Shared.Storage.Components; -using Content.Shared.Tag; -using Content.Shared.Tools; -using Robust.Shared.Containers; -using Robust.Shared.Prototypes; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.Dictionary; - -namespace Content.Server.Mech.Components; - -/// -/// A component used to create a mech chassis -/// after the correct parts have been placed inside -/// of it. -/// -/// -/// The actual visualization of the parts being inserted is -/// done via -/// -[RegisterComponent] -public sealed partial class MechAssemblyComponent : Component -{ - /// - /// The parts needed to be placed within the assembly, - /// stored as a tag and a bool tracking whether or not - /// they're present. - /// - [DataField("requiredParts", required: true, customTypeSerializer: typeof(PrototypeIdDictionarySerializer))] - public Dictionary RequiredParts = new(); - - /// - /// The prototype spawned when the assembly is finished - /// - [DataField("finishedPrototype", required: true, customTypeSerializer: typeof(PrototypeIdSerializer))] - public string FinishedPrototype = default!; - - /// - /// The container that stores all of the parts when - /// they're being assembled. - /// - [ViewVariables] - public Container PartsContainer = default!; - - /// - /// The quality of tool needed to remove all the parts - /// from the parts container. - /// - [DataField("qualityNeeded", customTypeSerializer: typeof(PrototypeIdSerializer))] - public string QualityNeeded = "Prying"; -} diff --git a/Content.Server/Mech/Systems/MechAssemblySystem.cs b/Content.Server/Mech/Systems/MechAssemblySystem.cs deleted file mode 100644 index bfd88d53b9c..00000000000 --- a/Content.Server/Mech/Systems/MechAssemblySystem.cs +++ /dev/null @@ -1,67 +0,0 @@ -using Content.Server.Mech.Components; -using Content.Shared.Interaction; -using Content.Shared.Tag; -using Content.Shared.Tools.Components; -using Content.Shared.Tools.Systems; -using Robust.Server.Containers; -using Robust.Shared.Containers; - -namespace Content.Server.Mech.Systems; - -/// -/// Handles and the insertion -/// and removal of parts from the assembly. -/// -public sealed class MechAssemblySystem : EntitySystem -{ - [Dependency] private readonly ContainerSystem _container = default!; - [Dependency] private readonly TagSystem _tag = default!; - [Dependency] private readonly SharedToolSystem _toolSystem = default!; - - /// - public override void Initialize() - { - SubscribeLocalEvent(OnInit); - SubscribeLocalEvent(OnInteractUsing); - } - - private void OnInit(EntityUid uid, MechAssemblyComponent component, ComponentInit args) - { - component.PartsContainer = _container.EnsureContainer(uid, "mech-assembly-container"); - } - - private void OnInteractUsing(EntityUid uid, MechAssemblyComponent component, InteractUsingEvent args) - { - if (_toolSystem.HasQuality(args.Used, component.QualityNeeded)) - { - foreach (var tag in component.RequiredParts.Keys) - { - component.RequiredParts[tag] = false; - } - _container.EmptyContainer(component.PartsContainer); - return; - } - - if (!TryComp(args.Used, out var tagComp)) - return; - - foreach (var (tag, val) in component.RequiredParts) - { - if (!val && _tag.HasTag(tagComp, tag)) - { - component.RequiredParts[tag] = true; - _container.Insert(args.Used, component.PartsContainer); - break; - } - } - - //check to see if we have all the parts - foreach (var val in component.RequiredParts.Values) - { - if (!val) - return; - } - Spawn(component.FinishedPrototype, Transform(uid).Coordinates); - Del(uid); - } -} diff --git a/Resources/Locale/en-US/mech/mech.ftl b/Resources/Locale/en-US/mech/mech.ftl index 7fac0387edb..95bb7f6ab0b 100644 --- a/Resources/Locale/en-US/mech/mech.ftl +++ b/Resources/Locale/en-US/mech/mech.ftl @@ -18,4 +18,6 @@ mech-slot-display = Open Slots: {$amount} mech-no-enter = You cannot pilot this. -mech-eject-pilot-alert = {$user} is pulling the pilot out of the {$item}! \ No newline at end of file +mech-eject-pilot-alert = {$user} is pulling the pilot out of the {$item}! + +mech-construction-guide-string = All mech parts must be attached to the harness. diff --git a/Resources/Migrations/migration.yml b/Resources/Migrations/migration.yml index 214a6e4b466..66fc06c2e5c 100644 --- a/Resources/Migrations/migration.yml +++ b/Resources/Migrations/migration.yml @@ -653,6 +653,12 @@ BarSignWhiskeyEchoesAlignTile: BarSignWhiskeyEchoes # 2025-06-21 ClothingNeckHeadphones: ClothingMultipleHeadphones +# 2025-07-17 +RipleyChassis: null +HonkerChassis: null +HamtrChassis: null +VimChassis: null + # 2025-08-01 FoodDonutJellySlugcat: FoodDonutJellyScurret diff --git a/Resources/Prototypes/Entities/Objects/Specific/Mech/mech_construction.yml b/Resources/Prototypes/Entities/Objects/Specific/Mech/mech_construction.yml index c40073c659d..2731c6909f9 100644 --- a/Resources/Prototypes/Entities/Objects/Specific/Mech/mech_construction.yml +++ b/Resources/Prototypes/Entities/Objects/Specific/Mech/mech_construction.yml @@ -75,16 +75,23 @@ - type: ContainerContainer containers: mech-assembly-container: !type:Container - - type: MechAssembly - finishedPrototype: RipleyChassis - requiredParts: - RipleyLArm: false - RipleyRArm: false - RipleyLLeg: false - RipleyRLeg: false + battery-container: !type:Container + - type: MechAssemblyVisuals + statePrefix: ripley - type: Sprite state: ripley_harness+o noRot: true + - type: PartAssembly + parts: + Ripley: + - RipleyLArm + - RipleyRArm + - RipleyLLeg + - RipleyRLeg + containerId: mech-assembly-container + - type: Construction + graph: Ripley + node: start - type: entity parent: BaseRipleyPartItem @@ -134,26 +141,6 @@ tags: - RipleyRArm -- type: entity - id: RipleyChassis - parent: BaseRipleyPart - name: ripley chassis - description: An in-progress construction of the Ripley APLU mech. - components: - - type: Appearance - - type: ContainerContainer - containers: - battery-container: !type:Container - - type: MechAssemblyVisuals - statePrefix: ripley - - type: Sprite - noRot: true - state: ripley0 - - type: Construction - graph: Ripley - node: start - defaultTarget: ripley - # H.O.N.K. - type: entity @@ -203,16 +190,23 @@ - type: ContainerContainer containers: mech-assembly-container: !type:Container - - type: MechAssembly - finishedPrototype: HonkerChassis - requiredParts: - HonkerLArm: false - HonkerRArm: false - HonkerLLeg: false - HonkerRLeg: false + battery-container: !type:Container + - type: MechAssemblyVisuals + statePrefix: honker - type: Sprite state: honker_harness+o noRot: true + - type: PartAssembly + parts: + Honker: + - HonkerLArm + - HonkerRArm + - HonkerLLeg + - HonkerRLeg + containerId: mech-assembly-container + - type: Construction + graph: Honker + node: start - type: entity parent: BaseHonkerPartItem @@ -262,26 +256,6 @@ tags: - HonkerRArm -- type: entity - id: HonkerChassis - parent: BaseHonkerPart - name: H.O.N.K. chassis - description: An in-progress construction of a H.O.N.K. mech. Contains chuckle unit, bananium core and honk support systems. - components: - - type: Appearance - - type: ContainerContainer - containers: - battery-container: !type:Container - - type: MechAssemblyVisuals - statePrefix: honker - - type: Sprite - noRot: true - state: honker0 - - type: Construction - graph: Honker - node: start - defaultTarget: honker - # H.A.M.T.R. - type: entity @@ -331,16 +305,23 @@ - type: ContainerContainer containers: mech-assembly-container: !type:Container - - type: MechAssembly - finishedPrototype: HamtrChassis - requiredParts: - HamtrLArm: false - HamtrRArm: false - HamtrLLeg: false - HamtrRLeg: false + battery-container: !type:Container + - type: MechAssemblyVisuals + statePrefix: hamtr - type: Sprite state: hamtr_harness+o noRot: true + - type: PartAssembly + parts: + Hamtr: + - HamtrLArm + - HamtrRArm + - HamtrLLeg + - HamtrRLeg + containerId: mech-assembly-container + - type: Construction + graph: Hamtr + node: start - type: entity parent: BaseHamtrPartItem @@ -390,26 +371,6 @@ tags: - HamtrRArm -- type: entity - id: HamtrChassis - parent: BaseHamtrPart - name: HAMTR chassis - description: An in-progress construction of the HAMTR mech. - components: - - type: Appearance - - type: ContainerContainer - containers: - battery-container: !type:Container - - type: MechAssemblyVisuals - statePrefix: hamtr - - type: Sprite - noRot: true - state: hamtr0 - - type: Construction - graph: Hamtr - node: start - defaultTarget: hamtr - # Vim!!!!!! - type: entity @@ -455,30 +416,17 @@ - type: ContainerContainer containers: mech-assembly-container: !type:Container - - type: MechAssembly - finishedPrototype: VimChassis - requiredParts: - HelmetEVA: false - BorgLeg: false + battery-container: !type:Container + - type: PartAssembly + parts: + Vim: + - HelmetEVA + - BorgLeg + - BorgLeg + containerId: mech-assembly-container - type: Sprite state: harness noRot: true - -- type: entity - id: VimChassis - parent: BaseVimPart - name: vim chassis - description: An in-progress construction of the Vim exosuit. - components: - - type: Appearance - - type: ContainerContainer - containers: - battery-container: !type:Container - - type: MechAssemblyVisuals - statePrefix: vim - - type: Sprite - noRot: true - state: vim0 - type: Construction graph: Vim node: start diff --git a/Resources/Prototypes/Recipes/Construction/Graphs/mechs/hamtr_construction.yml b/Resources/Prototypes/Recipes/Construction/Graphs/mechs/hamtr_construction.yml index 687d72f390c..a71846755f9 100644 --- a/Resources/Prototypes/Recipes/Construction/Graphs/mechs/hamtr_construction.yml +++ b/Resources/Prototypes/Recipes/Construction/Graphs/mechs/hamtr_construction.yml @@ -6,6 +6,9 @@ edges: - to: hamtr steps: + - assemblyId: Hamtr + guideString: mech-construction-guide-string + - tool: Anchoring doAfter: 1 completed: diff --git a/Resources/Prototypes/Recipes/Construction/Graphs/mechs/honker_construction.yml b/Resources/Prototypes/Recipes/Construction/Graphs/mechs/honker_construction.yml index 8274c4c0d13..a821cf18a20 100644 --- a/Resources/Prototypes/Recipes/Construction/Graphs/mechs/honker_construction.yml +++ b/Resources/Prototypes/Recipes/Construction/Graphs/mechs/honker_construction.yml @@ -6,6 +6,9 @@ edges: - to: honker steps: + - assemblyId: Honker + guideString: mech-construction-guide-string + - tool: Honking doAfter: 1 completed: diff --git a/Resources/Prototypes/Recipes/Construction/Graphs/mechs/ripley_construction.yml b/Resources/Prototypes/Recipes/Construction/Graphs/mechs/ripley_construction.yml index db45cbc4f1a..f9e54518491 100644 --- a/Resources/Prototypes/Recipes/Construction/Graphs/mechs/ripley_construction.yml +++ b/Resources/Prototypes/Recipes/Construction/Graphs/mechs/ripley_construction.yml @@ -6,6 +6,9 @@ edges: - to: ripley steps: + - assemblyId: Ripley + guideString: mech-construction-guide-string + - tool: Anchoring doAfter: 1 completed: diff --git a/Resources/Prototypes/Recipes/Construction/Graphs/mechs/vim_construction.yml b/Resources/Prototypes/Recipes/Construction/Graphs/mechs/vim_construction.yml index 7feed88cc5e..5a1c614550f 100644 --- a/Resources/Prototypes/Recipes/Construction/Graphs/mechs/vim_construction.yml +++ b/Resources/Prototypes/Recipes/Construction/Graphs/mechs/vim_construction.yml @@ -6,6 +6,9 @@ edges: - to: vim steps: + - assemblyId: Vim + guideString: mech-construction-guide-string + - tag: VoiceTrigger name: construction-graph-tag-voice-trigger icon: From 4ade77bba91486a4e2f9e5010c003c065f8b29b4 Mon Sep 17 00:00:00 2001 From: slarticodefast <161409025+slarticodefast@users.noreply.github.com> Date: Sun, 31 Aug 2025 20:50:37 +0200 Subject: [PATCH 288/340] improve spawnpoint error logging (#40021) --- .../Components/SpawnPointComponent.cs | 6 +++- .../EntitySystems/SpawnPointSystem.cs | 9 ++--- Resources/Maps/Test/empty.yml | 33 +++++++++++++++---- .../Entities/Markers/Spawners/jobs.yml | 11 +++++++ 4 files changed, 48 insertions(+), 11 deletions(-) diff --git a/Content.Server/Spawners/Components/SpawnPointComponent.cs b/Content.Server/Spawners/Components/SpawnPointComponent.cs index c6d14dfeb31..c48b7ec5985 100644 --- a/Content.Server/Spawners/Components/SpawnPointComponent.cs +++ b/Content.Server/Spawners/Components/SpawnPointComponent.cs @@ -6,11 +6,15 @@ namespace Content.Server.Spawners.Components; [RegisterComponent] public sealed partial class SpawnPointComponent : Component, ISpawnPoint { + /// + /// The job this spawn point is valid for. + /// Null will allow all jobs to spawn here. + /// [DataField("job_id")] public ProtoId? Job; /// - /// The type of spawn point + /// The type of spawn point. /// [DataField("spawn_type"), ViewVariables(VVAccess.ReadWrite)] public SpawnPointType SpawnType { get; set; } = SpawnPointType.Unset; diff --git a/Content.Server/Spawners/EntitySystems/SpawnPointSystem.cs b/Content.Server/Spawners/EntitySystems/SpawnPointSystem.cs index 2a29b833d88..b6b001bf0e4 100644 --- a/Content.Server/Spawners/EntitySystems/SpawnPointSystem.cs +++ b/Content.Server/Spawners/EntitySystems/SpawnPointSystem.cs @@ -27,7 +27,7 @@ public sealed class SpawnPointSystem : EntitySystem var points = EntityQueryEnumerator(); var possiblePositions = new List(); - while ( points.MoveNext(out var uid, out var spawnPoint, out var xform)) + while (points.MoveNext(out var uid, out var spawnPoint, out var xform)) { if (args.Station != null && _stationSystem.GetOwningStation(uid, xform) != args.Station) continue; @@ -57,7 +57,7 @@ public sealed class SpawnPointSystem : EntitySystem if (_gameTicker.RunLevel != GameRunLevel.InRound && spawnPoint.SpawnType == SpawnPointType.Job && - (args.Job == null || spawnPoint.Job == args.Job)) + (args.Job == null || spawnPoint.Job == null || spawnPoint.Job == args.Job)) { possiblePositions.Add(xform.Coordinates); } @@ -69,13 +69,14 @@ public sealed class SpawnPointSystem : EntitySystem // TODO: Refactor gameticker spawning code so we don't have to do this! var points2 = EntityQueryEnumerator(); - if (points2.MoveNext(out var spawnPoint, out var xform)) + if (points2.MoveNext(out _, out var xform)) { + Log.Error($"Unable to pick a valid spawn point, picking random spawner as a backup.\nRunLevel: {_gameTicker.RunLevel} Station: {ToPrettyString(args.Station)} Job: {args.Job}"); possiblePositions.Add(xform.Coordinates); } else { - Log.Error("No spawn points were available!"); + Log.Error($"No spawn points were available!\nRunLevel: {_gameTicker.RunLevel} Station: {ToPrettyString(args.Station)} Job: {args.Job}"); return; } } diff --git a/Resources/Maps/Test/empty.yml b/Resources/Maps/Test/empty.yml index 000b91ea438..e54a18422b4 100644 --- a/Resources/Maps/Test/empty.yml +++ b/Resources/Maps/Test/empty.yml @@ -1,6 +1,17 @@ meta: - format: 6 - postmapinit: false + format: 7 + category: Map + engineVersion: 266.0.0 + forkId: "" + forkVersion: "" + time: 08/31/2025 14:22:33 + entityCount: 4 +maps: +- 3 +grids: +- 2 +orphans: [] +nullspace: [] tilemap: 0: Space 89: FloorSteel @@ -16,8 +27,8 @@ entities: chunks: -1,-1: ind: -1,-1 - tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWQAAAAAA - version: 6 + tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWQAAAAAAAA== + version: 7 - type: Broadphase - type: Physics bodyStatus: InAir @@ -31,6 +42,7 @@ entities: id: Empty - type: OccluderTree - type: Shuttle + dampingModifier: 0.25 - type: GridPathfinding - type: Gravity gravityShakeSound: !type:SoundPathSpecifier @@ -40,20 +52,29 @@ entities: version: 2 nodes: [] - type: SpreaderGrid + - type: ImplicitRoof - uid: 3 components: - type: MetaData name: map 89 - type: Transform - type: Map + mapPaused: True - type: GridTree - type: Broadphase - type: OccluderTree +- proto: SpawnPointAnyJob + entities: + - uid: 4 + components: + - type: Transform + pos: -0.5,-0.5 + parent: 2 - proto: SpawnPointLatejoin entities: - uid: 1 components: - type: Transform - anchored: False - parent: 3 + pos: -0.5,-0.5 + parent: 2 ... diff --git a/Resources/Prototypes/Entities/Markers/Spawners/jobs.yml b/Resources/Prototypes/Entities/Markers/Spawners/jobs.yml index 359ccf9efa3..2deffd32baa 100644 --- a/Resources/Prototypes/Entities/Markers/Spawners/jobs.yml +++ b/Resources/Prototypes/Entities/Markers/Spawners/jobs.yml @@ -36,6 +36,17 @@ - type: SpawnPoint spawn_type: LateJoin +- type: entity + name: any job spawn point + id: SpawnPointAnyJob # used for integration tests so we don't need to map every single job spawner on the test map + parent: SpawnPointJobBase + components: + - type: Sprite + state: green + - type: SpawnPoint + spawn_type: Job + job_id: null # any job can spawn here + # Logistics - type: entity From 473e3f7fa7003de665ca51a5fbd52666f02dac7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C4=81da?= Date: Sun, 31 Aug 2025 13:54:15 -0500 Subject: [PATCH 289/340] TriggerOnMeleeHit and more (#39826) Co-authored-by: iaada Co-authored-by: slarticodefast <161409025+slarticodefast@users.noreply.github.com> --- .../Triggers/TriggerOnMeleeHitComponent.cs | 25 ++++++++ .../Triggers/TriggerOnMeleeMissComponent.cs | 10 ++++ .../Triggers/TriggerOnMeleeSwingComponent.cs | 18 ++++++ .../Trigger/Systems/MeleeTriggerSystem.cs | 58 +++++++++++++++++++ 4 files changed, 111 insertions(+) create mode 100644 Content.Shared/Trigger/Components/Triggers/TriggerOnMeleeHitComponent.cs create mode 100644 Content.Shared/Trigger/Components/Triggers/TriggerOnMeleeMissComponent.cs create mode 100644 Content.Shared/Trigger/Components/Triggers/TriggerOnMeleeSwingComponent.cs create mode 100644 Content.Shared/Trigger/Systems/MeleeTriggerSystem.cs diff --git a/Content.Shared/Trigger/Components/Triggers/TriggerOnMeleeHitComponent.cs b/Content.Shared/Trigger/Components/Triggers/TriggerOnMeleeHitComponent.cs new file mode 100644 index 00000000000..42779412275 --- /dev/null +++ b/Content.Shared/Trigger/Components/Triggers/TriggerOnMeleeHitComponent.cs @@ -0,0 +1,25 @@ +using Robust.Shared.GameStates; + +namespace Content.Shared.Trigger.Components.Triggers; + +/// +/// Triggers when this entity is swung as a melee weapon and hits at least one target. +/// +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +public sealed partial class TriggerOnMeleeHitComponent : BaseTriggerOnXComponent +{ + /// + /// If true, this trigger will activate individually for each entity hit. + /// If false, this trigger will always activate only once. + /// + [DataField, AutoNetworkedField] + public bool TriggerEveryHit; + + /// + /// If true, the "user" of the trigger is the entity hit by the melee. + /// If false, user is the entity which attacked with the melee weapon. + /// + /// If TriggerEveryHit is false, the user is randomly chosen from hit entities. + [DataField, AutoNetworkedField] + public bool TargetIsUser; +} diff --git a/Content.Shared/Trigger/Components/Triggers/TriggerOnMeleeMissComponent.cs b/Content.Shared/Trigger/Components/Triggers/TriggerOnMeleeMissComponent.cs new file mode 100644 index 00000000000..ea175fa0911 --- /dev/null +++ b/Content.Shared/Trigger/Components/Triggers/TriggerOnMeleeMissComponent.cs @@ -0,0 +1,10 @@ +using Robust.Shared.GameStates; + +namespace Content.Shared.Trigger.Components.Triggers; + +/// +/// Triggers when this entity is swung as a melee weapon and hits nothing. +/// The user is the entity swinging the weapon. +/// +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +public sealed partial class TriggerOnMeleeMissComponent : BaseTriggerOnXComponent; diff --git a/Content.Shared/Trigger/Components/Triggers/TriggerOnMeleeSwingComponent.cs b/Content.Shared/Trigger/Components/Triggers/TriggerOnMeleeSwingComponent.cs new file mode 100644 index 00000000000..b035c20b10d --- /dev/null +++ b/Content.Shared/Trigger/Components/Triggers/TriggerOnMeleeSwingComponent.cs @@ -0,0 +1,18 @@ +using Robust.Shared.GameStates; + +namespace Content.Shared.Trigger.Components.Triggers; + +/// +/// Triggers when this entity is swung as a melee weapon, regardless of whether it hits something. +/// +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +public sealed partial class TriggerOnMeleeSwingComponent : BaseTriggerOnXComponent +{ + /// + /// If true, the "user" of the trigger is the entity hit by the melee. User is null if nothing is hit. + /// If false, user is the entity which attacked with the melee weapon. + /// + /// If true and multiple targets are hit, the user is randomly chosen from hit entities. + [DataField, AutoNetworkedField] + public bool TargetIsUser; +} diff --git a/Content.Shared/Trigger/Systems/MeleeTriggerSystem.cs b/Content.Shared/Trigger/Systems/MeleeTriggerSystem.cs new file mode 100644 index 00000000000..b7433a29876 --- /dev/null +++ b/Content.Shared/Trigger/Systems/MeleeTriggerSystem.cs @@ -0,0 +1,58 @@ +using Content.Shared.Trigger.Components.Triggers; +using Content.Shared.Weapons.Melee.Events; + +namespace Content.Shared.Trigger.Systems; + +/// +/// Trigger system for melee related triggers. +/// +public sealed class MeleeTriggerSystem : EntitySystem +{ + [Dependency] private readonly TriggerSystem _trigger = default!; + + /// + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnMissTrigger); + SubscribeLocalEvent(OnSwingTrigger); + SubscribeLocalEvent(OnHitTrigger); + } + + private void OnMissTrigger(Entity ent, ref MeleeHitEvent args) + { + if (args.HitEntities.Count == 0) + _trigger.Trigger(ent.Owner, args.User, ent.Comp.KeyOut); + } + + private void OnSwingTrigger(Entity ent, ref MeleeHitEvent args) + { + EntityUid? target; + if (args.HitEntities.Count == 0) + target = ent.Comp.TargetIsUser ? null : args.User; + else + target = ent.Comp.TargetIsUser ? args.HitEntities[0] : args.User; + + _trigger.Trigger(ent.Owner, target, ent.Comp.KeyOut); + } + + private void OnHitTrigger(Entity ent, ref MeleeHitEvent args) + { + if (args.HitEntities.Count == 0) + return; + + if (!ent.Comp.TriggerEveryHit) + { + var target = ent.Comp.TargetIsUser ? args.HitEntities[0] : args.User; + _trigger.Trigger(ent.Owner, target, ent.Comp.KeyOut); + return; + } + + // if TriggerEveryHit + foreach (var target in args.HitEntities) + { + _trigger.Trigger(ent.Owner, ent.Comp.TargetIsUser ? target : args.User, ent.Comp.KeyOut); + } + } +} From 76c54acfd2930257a02c253c3dd0d79efecb0e89 Mon Sep 17 00:00:00 2001 From: Travis Reid <86178026+Travis-G-Reid@users.noreply.github.com> Date: Sun, 31 Aug 2025 19:32:59 -0500 Subject: [PATCH 290/340] Fix docstring typo starts -> stops (#40031) --- Content.Shared/Movement/Pulling/Events/PullStoppedMessage.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Content.Shared/Movement/Pulling/Events/PullStoppedMessage.cs b/Content.Shared/Movement/Pulling/Events/PullStoppedMessage.cs index 6df4d174839..7c367f29514 100644 --- a/Content.Shared/Movement/Pulling/Events/PullStoppedMessage.cs +++ b/Content.Shared/Movement/Pulling/Events/PullStoppedMessage.cs @@ -1,6 +1,6 @@ -namespace Content.Shared.Movement.Pulling.Events; +namespace Content.Shared.Movement.Pulling.Events; /// -/// Event raised directed BOTH at the puller and pulled entity when a pull starts. +/// Event raised directed BOTH at the puller and pulled entity when a pull stops. /// public sealed class PullStoppedMessage(EntityUid pullerUid, EntityUid pulledUid) : PullMessage(pullerUid, pulledUid); From e72cf44abd488bd7211c82cddf02d8c54edea62c Mon Sep 17 00:00:00 2001 From: SlamBamActionman <83650252+SlamBamActionman@users.noreply.github.com> Date: Mon, 1 Sep 2025 17:27:21 +0200 Subject: [PATCH 291/340] Fix incorrect bullet & cartridge names (#39993) * Fix conflicting names * zero zeroes --- .../Weapons/Guns/Ammunition/Cartridges/heavy_rifle.yml | 2 +- .../Weapons/Guns/Ammunition/Projectiles/heavy_rifle.yml | 2 +- .../Weapons/Guns/Ammunition/Projectiles/light_rifle.yml | 8 ++++---- .../Objects/Weapons/Guns/Ammunition/Projectiles/rifle.yml | 8 ++++---- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Cartridges/heavy_rifle.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Cartridges/heavy_rifle.yml index 2054fa78849..51bf0fea54d 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Cartridges/heavy_rifle.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Cartridges/heavy_rifle.yml @@ -1,6 +1,6 @@ - type: entity id: BaseCartridgeHeavyRifle - name: cartridge (.20 rifle) + name: cartridge (.10 rifle) parent: [ BaseCartridge, BaseSecurityContraband ] abstract: true components: diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Projectiles/heavy_rifle.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Projectiles/heavy_rifle.yml index d37555c3443..eebccf32a0c 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Projectiles/heavy_rifle.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Projectiles/heavy_rifle.yml @@ -1,6 +1,6 @@ - type: entity id: BulletHeavyRifle - name: bullet (.20 rifle) + name: bullet (.10 rifle) parent: BaseBullet categories: [ HideSpawnMenu ] components: diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Projectiles/light_rifle.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Projectiles/light_rifle.yml index 7eac4b53d09..43427c1dac7 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Projectiles/light_rifle.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Projectiles/light_rifle.yml @@ -1,6 +1,6 @@ - type: entity id: BulletLightRifle - name: bullet (.20 rifle) + name: bullet (.30 rifle) parent: BaseBullet categories: [ HideSpawnMenu ] components: @@ -11,7 +11,7 @@ - type: entity id: BulletLightRiflePractice - name: bullet (.20 rifle practice) + name: bullet (.30 rifle practice) parent: BaseBulletPractice categories: [ HideSpawnMenu ] components: @@ -23,7 +23,7 @@ - type: entity id: BulletLightRifleIncendiary parent: BaseBulletIncendiary - name: bullet (.20 rifle incendiary) + name: bullet (.30 rifle incendiary) categories: [ HideSpawnMenu ] components: - type: Projectile @@ -35,7 +35,7 @@ - type: entity id: BulletLightRifleUranium parent: BaseBulletUranium - name: bullet (.20 rifle uranium) + name: bullet (.30 rifle uranium) categories: [ HideSpawnMenu ] components: - type: Projectile diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Projectiles/rifle.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Projectiles/rifle.yml index 030f6fc4958..6f328c25832 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Projectiles/rifle.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Projectiles/rifle.yml @@ -1,6 +1,6 @@ - type: entity id: BulletRifle - name: bullet (0.20 rifle) + name: bullet (.20 rifle) parent: BaseBullet categories: [ HideSpawnMenu ] components: @@ -11,7 +11,7 @@ - type: entity id: BulletRiflePractice - name: bullet (0.20 rifle practice) + name: bullet (.20 rifle practice) parent: BaseBulletPractice categories: [ HideSpawnMenu ] components: @@ -23,7 +23,7 @@ - type: entity id: BulletRifleIncendiary parent: BaseBulletIncendiary - name: bullet (0.20 rifle incendiary) + name: bullet (.20 rifle incendiary) categories: [ HideSpawnMenu ] components: - type: Projectile @@ -35,7 +35,7 @@ - type: entity id: BulletRifleUranium parent: BaseBulletUranium - name: bullet (0.20 rifle uranium) + name: bullet (.20 rifle uranium) categories: [ HideSpawnMenu ] components: - type: Projectile From 2019485bfee67e00741149cf82a1deb434b50d61 Mon Sep 17 00:00:00 2001 From: InsoPL Date: Mon, 1 Sep 2025 17:31:11 +0200 Subject: [PATCH 292/340] Texture Scaling for clothing (#39714) scale --- Content.Client/Clothing/ClientClothingSystem.cs | 4 +--- Content.Shared/Clothing/Components/ClothingComponent.cs | 8 ++++++++ 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/Content.Client/Clothing/ClientClothingSystem.cs b/Content.Client/Clothing/ClientClothingSystem.cs index 958bab343a6..b06ec8f8e3c 100644 --- a/Content.Client/Clothing/ClientClothingSystem.cs +++ b/Content.Client/Clothing/ClientClothingSystem.cs @@ -1,13 +1,11 @@ using System.Diagnostics.CodeAnalysis; using System.Linq; -using System.Numerics; using Content.Client.DisplacementMap; using Content.Client.Inventory; using Content.Shared._DV.Silicon.IPC; // DeltaV - IPC Snouts using Content.Shared.Clothing; using Content.Shared.Clothing.Components; using Content.Shared.Clothing.EntitySystems; -using Content.Shared.DisplacementMap; using Content.Shared.Humanoid; using Content.Shared.Inventory; using Content.Shared.Inventory.Events; @@ -15,7 +13,6 @@ using Content.Shared.Item; using Robust.Client.GameObjects; using Robust.Client.Graphics; using Robust.Client.ResourceManagement; -using Robust.Shared.Serialization.Manager; using Robust.Shared.Serialization.TypeSerializers.Implementations; using Robust.Shared.Utility; using static Robust.Client.GameObjects.SpriteComponent; @@ -185,6 +182,7 @@ public sealed class ClientClothingSystem : ClothingSystem var layer = new PrototypeLayerData(); layer.RsiPath = rsi.Path.ToString(); layer.State = state; + layer.Scale = clothing.Scale; layers = new() { layer }; return true; diff --git a/Content.Shared/Clothing/Components/ClothingComponent.cs b/Content.Shared/Clothing/Components/ClothingComponent.cs index ff1d422189f..2d576637a60 100644 --- a/Content.Shared/Clothing/Components/ClothingComponent.cs +++ b/Content.Shared/Clothing/Components/ClothingComponent.cs @@ -1,4 +1,5 @@ using System.Diagnostics.CodeAnalysis; +using System.Numerics; using Content.Shared.Clothing.EntitySystems; using Content.Shared.DoAfter; using Content.Shared.Inventory; @@ -92,6 +93,13 @@ public sealed partial class ClothingComponent : Component /// [DataField] public TimeSpan StripDelay = TimeSpan.Zero; + + /// + /// A scale applied to all layers. + /// + /// + [DataField] + public Vector2 Scale = Vector2.One; } public enum ClothingMask : byte From fdc8301b05389434e24c7e771496c23ed5d6bbc4 Mon Sep 17 00:00:00 2001 From: Hannah Giovanna Dawson Date: Mon, 1 Sep 2025 17:16:12 +0100 Subject: [PATCH 293/340] Lizard Tails Can Be Hidden By Clothing (#40026) Taken from @TiniestShark's PR. --- Resources/Prototypes/Entities/Mobs/Species/reptilian.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/Resources/Prototypes/Entities/Mobs/Species/reptilian.yml b/Resources/Prototypes/Entities/Mobs/Species/reptilian.yml index 5293063f76b..a50c0345155 100644 --- a/Resources/Prototypes/Entities/Mobs/Species/reptilian.yml +++ b/Resources/Prototypes/Entities/Mobs/Species/reptilian.yml @@ -12,6 +12,7 @@ - Snout - HeadTop - HeadSide + - Tail undergarmentBottom: UndergarmentBottomBoxersReptilian - type: Hunger - type: Puller From 471a90c8f1b6e541d78156e35de79644d2afcbfc Mon Sep 17 00:00:00 2001 From: SlamBamActionman <83650252+SlamBamActionman@users.noreply.github.com> Date: Mon, 1 Sep 2025 17:07:43 +0200 Subject: [PATCH 294/340] Moths cannot eject items from military boots (#40049) --- .../Prototypes/Entities/Clothing/Shoes/base_clothingshoes.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/Resources/Prototypes/Entities/Clothing/Shoes/base_clothingshoes.yml b/Resources/Prototypes/Entities/Clothing/Shoes/base_clothingshoes.yml index cf7c053946c..33bafddc325 100644 --- a/Resources/Prototypes/Entities/Clothing/Shoes/base_clothingshoes.yml +++ b/Resources/Prototypes/Entities/Clothing/Shoes/base_clothingshoes.yml @@ -55,6 +55,7 @@ tags: - Knife - ConcealCarry # DeltaV - replace Sidearm tag + priority: 4 - type: entity abstract: true From 9d978dc7f97b66587901f593e17c8abcedced226 Mon Sep 17 00:00:00 2001 From: slarticodefast <161409025+slarticodefast@users.noreply.github.com> Date: Mon, 1 Sep 2025 17:24:37 +0200 Subject: [PATCH 295/340] Fix NF belt metadata file caused by git assuming that was the file to put it in --- .../Chemistry/EntitySystems/InjectorSystem.cs | 4 +- .../Chemistry/UI/InjectorStatusControl.cs | 6 +- .../Chemistry/EntitySystems/InjectorSystem.cs | 432 +--------------- .../Forensics/Systems/ForensicsSystem.cs | 10 +- .../Chemistry/Components/InjectorComponent.cs | 51 +- .../EntitySystems/SharedInjectorSystem.cs | 480 ++++++++++++++++-- .../Fluids/SharedPuddleSystem.Spillable.cs | 2 + .../Systems/SharedForensicsSystem.cs | 9 + .../components/injector-component.ftl | 12 +- Resources/Migrations/migration.yml | 3 + .../Entities/Objects/Specific/chemistry.yml | 33 +- .../_NF/Clothing/Belt/pilot.rsi/meta.json | 32 +- 12 files changed, 530 insertions(+), 544 deletions(-) diff --git a/Content.Client/Chemistry/EntitySystems/InjectorSystem.cs b/Content.Client/Chemistry/EntitySystems/InjectorSystem.cs index 0131a283c8c..58cb5330a2d 100644 --- a/Content.Client/Chemistry/EntitySystems/InjectorSystem.cs +++ b/Content.Client/Chemistry/EntitySystems/InjectorSystem.cs @@ -2,7 +2,6 @@ using Content.Client.Chemistry.UI; using Content.Client.Items; using Content.Shared.Chemistry.Components; using Content.Shared.Chemistry.EntitySystems; -using Robust.Shared.GameStates; namespace Content.Client.Chemistry.EntitySystems; @@ -11,6 +10,7 @@ public sealed class InjectorSystem : SharedInjectorSystem public override void Initialize() { base.Initialize(); - Subs.ItemStatus(ent => new InjectorStatusControl(ent, SolutionContainers)); + + Subs.ItemStatus(ent => new InjectorStatusControl(ent, SolutionContainer)); } } diff --git a/Content.Client/Chemistry/UI/InjectorStatusControl.cs b/Content.Client/Chemistry/UI/InjectorStatusControl.cs index f9b0d90e205..0358876b76e 100644 --- a/Content.Client/Chemistry/UI/InjectorStatusControl.cs +++ b/Content.Client/Chemistry/UI/InjectorStatusControl.cs @@ -38,13 +38,13 @@ public sealed class InjectorStatusControl : Control // only updates the UI if any of the details are different than they previously were if (PrevVolume == solution.Volume && PrevMaxVolume == solution.MaxVolume - && PrevTransferAmount == _parent.Comp.TransferAmount + && PrevTransferAmount == _parent.Comp.CurrentTransferAmount && PrevToggleState == _parent.Comp.ToggleState) return; PrevVolume = solution.Volume; PrevMaxVolume = solution.MaxVolume; - PrevTransferAmount = _parent.Comp.TransferAmount; + PrevTransferAmount = _parent.Comp.CurrentTransferAmount; PrevToggleState = _parent.Comp.ToggleState; // Update current volume and injector state @@ -59,6 +59,6 @@ public sealed class InjectorStatusControl : Control ("currentVolume", solution.Volume), ("totalVolume", solution.MaxVolume), ("modeString", modeStringLocalized), - ("transferVolume", _parent.Comp.TransferAmount))); + ("transferVolume", _parent.Comp.CurrentTransferAmount))); } } diff --git a/Content.Server/Chemistry/EntitySystems/InjectorSystem.cs b/Content.Server/Chemistry/EntitySystems/InjectorSystem.cs index d320bc3b486..45578a17649 100644 --- a/Content.Server/Chemistry/EntitySystems/InjectorSystem.cs +++ b/Content.Server/Chemistry/EntitySystems/InjectorSystem.cs @@ -1,435 +1,5 @@ -using System.Linq; // DeltaV -using Content.Server.Body.Components; -using Content.Server.Body.Systems; -using Content.Shared._DV.Chemistry.Components; // DeltaV -using Content.Shared.Chemistry; -using Content.Shared.Chemistry.Components; -using Content.Shared.Chemistry.Components.SolutionManager; using Content.Shared.Chemistry.EntitySystems; -using Content.Shared.Body.Components; -using Content.Shared.Database; -using Content.Shared.DoAfter; -using Content.Shared.FixedPoint; -using Content.Shared.Forensics; -using Content.Shared.IdentityManagement; -using Content.Shared.Interaction; -using Content.Shared.Mobs.Components; -using Content.Shared.Stacks; -using Content.Shared.Nutrition.EntitySystems; namespace Content.Server.Chemistry.EntitySystems; -public sealed class InjectorSystem : SharedInjectorSystem -{ - [Dependency] private readonly BloodstreamSystem _blood = default!; - [Dependency] private readonly ReactiveSystem _reactiveSystem = default!; - [Dependency] private readonly OpenableSystem _openable = default!; - - public override void Initialize() - { - base.Initialize(); - - SubscribeLocalEvent(OnInjectDoAfter); - SubscribeLocalEvent(OnInjectorAfterInteract); - } - - private bool TryUseInjector(Entity injector, EntityUid target, EntityUid user) - { - var isOpenOrIgnored = injector.Comp.IgnoreClosed || !_openable.IsClosed(target); - // Handle injecting/drawing for solutions - if (injector.Comp.ToggleState == InjectorToggleMode.Inject) - { - if (isOpenOrIgnored && SolutionContainers.TryGetInjectableSolution(target, out var injectableSolution, out _)) - return TryInject(injector, target, injectableSolution.Value, user, false); - - if (isOpenOrIgnored && SolutionContainers.TryGetRefillableSolution(target, out var refillableSolution, out _)) - return TryInject(injector, target, refillableSolution.Value, user, true); - - if (TryComp(target, out var bloodstream)) - return TryInjectIntoBloodstream(injector, (target, bloodstream), user); - - Popup.PopupEntity(Loc.GetString("injector-component-cannot-transfer-message", - ("target", Identity.Entity(target, EntityManager))), injector, user); - return false; - } - - if (injector.Comp.ToggleState == InjectorToggleMode.Draw) - { - // Draw from a bloodstream, if the target has that - if (TryComp(target, out var stream) && - SolutionContainers.ResolveSolution(target, stream.BloodSolutionName, ref stream.BloodSolution)) - { - return TryDraw(injector, (target, stream), stream.BloodSolution.Value, user); - } - - // Draw from an object (food, beaker, etc) - if (isOpenOrIgnored && SolutionContainers.TryGetDrawableSolution(target, out var drawableSolution, out _)) - return TryDraw(injector, target, drawableSolution.Value, user); - - Popup.PopupEntity(Loc.GetString("injector-component-cannot-draw-message", - ("target", Identity.Entity(target, EntityManager))), injector.Owner, user); - return false; - } - return false; - } - - private void OnInjectDoAfter(Entity entity, ref InjectorDoAfterEvent args) - { - if (args.Cancelled || args.Handled || args.Args.Target == null) - return; - - args.Handled = TryUseInjector(entity, args.Args.Target.Value, args.Args.User); - } - - private void OnInjectorAfterInteract(Entity entity, ref AfterInteractEvent args) - { - if (args.Handled || !args.CanReach) - return; - - //Make sure we have the attacking entity - if (args.Target is not { Valid: true } target || !HasComp(entity)) - return; - - // Is the target a mob? If yes, use a do-after to give them time to respond. - if (HasComp(target) || HasComp(target)) - { - // Are use using an injector capable of targeting a mob? - if (entity.Comp.IgnoreMobs) - return; - - InjectDoAfter(entity, target, args.User); - args.Handled = true; - return; - } - - args.Handled = TryUseInjector(entity, target, args.User); - } - - /// - /// Send informative pop-up messages and wait for a do-after to complete. - /// - private void InjectDoAfter(Entity injector, EntityUid target, EntityUid user) - { - if (HasComp(target)) // DeltaV - { - Popup.PopupEntity(Loc.GetString("injector-component-deny-user"), target, user); - return; - } - - // Create a pop-up for the user - if (injector.Comp.ToggleState == InjectorToggleMode.Draw) - { - Popup.PopupEntity(Loc.GetString("injector-component-drawing-user"), target, user); - } - else - { - Popup.PopupEntity(Loc.GetString("injector-component-injecting-user"), target, user); - } - - if (!SolutionContainers.TryGetSolution(injector.Owner, injector.Comp.SolutionName, out _, out var solution)) - return; - - var actualDelay = injector.Comp.Delay; - FixedPoint2 amountToInject; - if (injector.Comp.ToggleState == InjectorToggleMode.Draw) - { - // additional delay is based on actual volume left to draw in syringe when smaller than transfer amount - amountToInject = FixedPoint2.Min(injector.Comp.TransferAmount, (solution.MaxVolume - solution.Volume)); - } - else - { - // additional delay is based on actual volume left to inject in syringe when smaller than transfer amount - amountToInject = FixedPoint2.Min(injector.Comp.TransferAmount, solution.Volume); - } - - // Injections take 0.5 seconds longer per 5u of possible space/content - // First 5u(MinimumTransferAmount) doesn't incur delay - actualDelay += injector.Comp.DelayPerVolume * FixedPoint2.Max(0, amountToInject - injector.Comp.MinimumTransferAmount).Double(); - - // Ensure that minimum delay before incapacitation checks is 1 seconds - actualDelay = MathHelper.Max(actualDelay, TimeSpan.FromSeconds(1)); - - - var isTarget = user != target; - - if (isTarget) - { - // Create a pop-up for the target - var userName = Identity.Entity(user, EntityManager); - if (injector.Comp.ToggleState == InjectorToggleMode.Draw) - { - Popup.PopupEntity(Loc.GetString("injector-component-drawing-target", - ("user", userName)), user, target); - } - else - { - Popup.PopupEntity(Loc.GetString("injector-component-injecting-target", - ("user", userName)), user, target); - } - - - // Check if the target is incapacitated or in combat mode and modify time accordingly. - if (MobState.IsIncapacitated(target)) - { - actualDelay /= 2.5f; - } - else if (Combat.IsInCombatMode(target)) - { - // Slightly increase the delay when the target is in combat mode. Helps prevents cheese injections in - // combat with fast syringes & lag. - actualDelay += TimeSpan.FromSeconds(1); - } - - // Add an admin log, using the "force feed" log type. It's not quite feeding, but the effect is the same. - if (injector.Comp.ToggleState == InjectorToggleMode.Inject) - { - AdminLogger.Add(LogType.ForceFeed, - $"{ToPrettyString(user):user} is attempting to inject {ToPrettyString(target):target} with a solution {SharedSolutionContainerSystem.ToPrettyString(solution):solution}"); - } - else - { - AdminLogger.Add(LogType.ForceFeed, - $"{ToPrettyString(user):user} is attempting to draw {injector.Comp.TransferAmount.ToString()} units from {ToPrettyString(target):target}"); - } - } - else - { - // Self-injections take half as long. - actualDelay /= 2; - - if (injector.Comp.ToggleState == InjectorToggleMode.Inject) - { - AdminLogger.Add(LogType.Ingestion, - $"{ToPrettyString(user):user} is attempting to inject themselves with a solution {SharedSolutionContainerSystem.ToPrettyString(solution):solution}."); - } - else - { - AdminLogger.Add(LogType.ForceFeed, - $"{ToPrettyString(user):user} is attempting to draw {injector.Comp.TransferAmount.ToString()} units from themselves."); - } - } - - DoAfter.TryStartDoAfter(new DoAfterArgs(EntityManager, user, actualDelay, new InjectorDoAfterEvent(), injector.Owner, target: target, used: injector.Owner) - { - BreakOnMove = true, - BreakOnWeightlessMove = false, - BreakOnDamage = true, - NeedHand = injector.Comp.NeedHand, - BreakOnHandChange = injector.Comp.BreakOnHandChange, - MovementThreshold = injector.Comp.MovementThreshold, - }); - } - - private bool TryInjectIntoBloodstream(Entity injector, Entity target, - EntityUid user) - { - // Get transfer amount. May be smaller than _transferAmount if not enough room - if (!SolutionContainers.ResolveSolution(target.Owner, target.Comp.ChemicalSolutionName, - ref target.Comp.ChemicalSolution, out var chemSolution)) - { - Popup.PopupEntity( - Loc.GetString("injector-component-cannot-inject-message", - ("target", Identity.Entity(target, EntityManager))), injector.Owner, user); - return false; - } - - var realTransferAmount = FixedPoint2.Min(injector.Comp.TransferAmount, chemSolution.AvailableVolume); - if (realTransferAmount <= 0) - { - Popup.PopupEntity( - Loc.GetString("injector-component-cannot-inject-message", - ("target", Identity.Entity(target, EntityManager))), injector.Owner, user); - return false; - } - - // Move units from attackSolution to targetSolution - var removedSolution = SolutionContainers.SplitSolution(target.Comp.ChemicalSolution.Value, realTransferAmount); - - _blood.TryAddToChemicals(target.AsNullable(), removedSolution); - - _reactiveSystem.DoEntityReaction(target, removedSolution, ReactionMethod.Injection); - - Popup.PopupEntity(Loc.GetString("injector-component-inject-success-message", - ("amount", removedSolution.Volume), - ("target", Identity.Entity(target, EntityManager))), injector.Owner, user); - - Dirty(injector); - AfterInject(injector, target); - return true; - } - - private bool TryInject(Entity injector, EntityUid targetEntity, - Entity targetSolution, EntityUid user, bool asRefill) - { - if (HasComp(targetEntity)) // DeltaV - return false; - - if (!SolutionContainers.TryGetSolution(injector.Owner, injector.Comp.SolutionName, out var soln, - out var solution) || solution.Volume == 0) - return false; - - // Get transfer amount. May be smaller than _transferAmount if not enough room - var realTransferAmount = - FixedPoint2.Min(injector.Comp.TransferAmount, targetSolution.Comp.Solution.AvailableVolume); - - if (realTransferAmount <= 0) - { - Popup.PopupEntity( - Loc.GetString("injector-component-target-already-full-message", - ("target", Identity.Entity(targetEntity, EntityManager))), - injector.Owner, user); - return false; - } - - // Move units from attackSolution to targetSolution - Solution removedSolution; - if (TryComp(targetEntity, out var stack)) - removedSolution = SolutionContainers.SplitStackSolution(soln.Value, realTransferAmount, stack.Count); - else - removedSolution = SolutionContainers.SplitSolution(soln.Value, realTransferAmount); - - _reactiveSystem.DoEntityReaction(targetEntity, removedSolution, ReactionMethod.Injection); - - if (!asRefill) - SolutionContainers.Inject(targetEntity, targetSolution, removedSolution); - else - SolutionContainers.Refill(targetEntity, targetSolution, removedSolution); - - Popup.PopupEntity(Loc.GetString("injector-component-transfer-success-message", - ("amount", removedSolution.Volume), - ("target", Identity.Entity(targetEntity, EntityManager))), injector.Owner, user); - - Dirty(injector); - AfterInject(injector, targetEntity); - return true; - } - - private void AfterInject(Entity injector, EntityUid target) - { - // Automatically set syringe to draw after completely draining it. - if (SolutionContainers.TryGetSolution(injector.Owner, injector.Comp.SolutionName, out _, - out var solution) && solution.Volume == 0) - { - SetMode(injector, InjectorToggleMode.Draw); - } - - // Leave some DNA from the injectee on it - var ev = new TransferDnaEvent { Donor = target, Recipient = injector }; - RaiseLocalEvent(target, ref ev); - } - - private void AfterDraw(Entity injector, EntityUid target) - { - // Automatically set syringe to inject after completely filling it. - if (SolutionContainers.TryGetSolution(injector.Owner, injector.Comp.SolutionName, out _, - out var solution) && solution.AvailableVolume == 0) - { - SetMode(injector, InjectorToggleMode.Inject); - } - - // Leave some DNA from the drawee on it - var ev = new TransferDnaEvent { Donor = target, Recipient = injector }; - RaiseLocalEvent(target, ref ev); - } - - private bool TryDraw(Entity injector, Entity target, - Entity targetSolution, EntityUid user) - { - if (!SolutionContainers.TryGetSolution(injector.Owner, injector.Comp.SolutionName, out var soln, - out var solution) || solution.AvailableVolume == 0) - { - return false; - } - - var applicableTargetSolution = targetSolution.Comp.Solution; - // If a whitelist exists, remove all non-whitelisted reagents from the target solution temporarily - var temporarilyRemovedSolution = new Solution(); - if (injector.Comp.ReagentWhitelist is { } reagentWhitelist) - { - string[] reagentPrototypeWhitelistArray = new string[reagentWhitelist.Count]; - var i = 0; - foreach (var reagent in reagentWhitelist) - { - reagentPrototypeWhitelistArray[i] = reagent; - ++i; - } - temporarilyRemovedSolution = applicableTargetSolution.SplitSolutionWithout(applicableTargetSolution.Volume, reagentPrototypeWhitelistArray); - } - // Begin DeltaV Additions - skimmer functionality - else if (injector.Comp.TargetSmallest) - { - if (applicableTargetSolution.Count() > 0 && applicableTargetSolution.MinBy(soln => soln.Quantity) is {} smallest) - { - temporarilyRemovedSolution = applicableTargetSolution.SplitSolutionWithout(applicableTargetSolution.Volume, new string[] { smallest.Reagent.Prototype }); - } - } - // End DeltaV Additions - skimmer functionality - - // Get transfer amount. May be smaller than _transferAmount if not enough room, also make sure there's room in the injector - var realTransferAmount = FixedPoint2.Min(injector.Comp.TransferAmount, applicableTargetSolution.Volume, - solution.AvailableVolume); - - if (realTransferAmount <= 0) - { - Popup.PopupEntity( - Loc.GetString("injector-component-target-is-empty-message", - ("target", Identity.Entity(target, EntityManager))), - injector.Owner, user); - return false; - } - - // We have some snowflaked behavior for streams. - if (target.Comp != null) - { - DrawFromBlood(injector, (target.Owner, target.Comp), soln.Value, realTransferAmount, user); - return true; - } - - // Move units from attackSolution to targetSolution - var removedSolution = SolutionContainers.Draw(target.Owner, targetSolution, realTransferAmount); - - // Add back non-whitelisted reagents to the target solution - SolutionContainers.TryAddSolution(targetSolution, temporarilyRemovedSolution); // DeltaV - fix bug with visualization for skimmers - - if (!SolutionContainers.TryAddSolution(soln.Value, removedSolution)) - { - return false; - } - - Popup.PopupEntity(Loc.GetString("injector-component-draw-success-message", - ("amount", removedSolution.Volume), - ("target", Identity.Entity(target, EntityManager))), injector.Owner, user); - - Dirty(injector); - AfterDraw(injector, target); - return true; - } - - private void DrawFromBlood(Entity injector, Entity target, - Entity injectorSolution, FixedPoint2 transferAmount, EntityUid user) - { - var drawAmount = (float) transferAmount; - - if (SolutionContainers.ResolveSolution(target.Owner, target.Comp.ChemicalSolutionName, - ref target.Comp.ChemicalSolution)) - { - var chemTemp = SolutionContainers.SplitSolution(target.Comp.ChemicalSolution.Value, drawAmount * 0.15f); - SolutionContainers.TryAddSolution(injectorSolution, chemTemp); - drawAmount -= (float) chemTemp.Volume; - } - - if (SolutionContainers.ResolveSolution(target.Owner, target.Comp.BloodSolutionName, - ref target.Comp.BloodSolution)) - { - var bloodTemp = SolutionContainers.SplitSolution(target.Comp.BloodSolution.Value, drawAmount); - SolutionContainers.TryAddSolution(injectorSolution, bloodTemp); - } - - Popup.PopupEntity(Loc.GetString("injector-component-draw-success-message", - ("amount", transferAmount), - ("target", Identity.Entity(target, EntityManager))), injector.Owner, user); - - Dirty(injector); - AfterDraw(injector, target); - } -} +public sealed class InjectorSystem : SharedInjectorSystem; diff --git a/Content.Server/Forensics/Systems/ForensicsSystem.cs b/Content.Server/Forensics/Systems/ForensicsSystem.cs index 96e4fb3152b..f0f8fc2541d 100644 --- a/Content.Server/Forensics/Systems/ForensicsSystem.cs +++ b/Content.Server/Forensics/Systems/ForensicsSystem.cs @@ -332,6 +332,8 @@ namespace Content.Server.Forensics component.Fingerprints.Add(fingerprint.Fingerprint ?? ""); } + // TODO: Delete this. A lot of systems are manually raising this method event instead of calling the identical method. + // According to our code conventions we should not use method events. private void OnTransferDnaEvent(EntityUid uid, DnaComponent component, ref TransferDnaEvent args) { if (component.DNA == null) @@ -364,13 +366,7 @@ namespace Content.Server.Forensics Dirty(ent); } - /// - /// Transfer DNA from one entity onto the forensics of another - /// - /// The entity receiving the DNA - /// The entity applying its DNA - /// If this DNA be cleaned off of the recipient. e.g. cleaning a knife vs cleaning a puddle of blood - public void TransferDna(EntityUid recipient, EntityUid donor, bool canDnaBeCleaned = true) + public override void TransferDna(EntityUid recipient, EntityUid donor, bool canDnaBeCleaned = true) { if (TryComp(donor, out var donorComp) && donorComp.DNA != null) { diff --git a/Content.Shared/Chemistry/Components/InjectorComponent.cs b/Content.Shared/Chemistry/Components/InjectorComponent.cs index bbb8b8d89b0..8b003db2997 100644 --- a/Content.Shared/Chemistry/Components/InjectorComponent.cs +++ b/Content.Shared/Chemistry/Components/InjectorComponent.cs @@ -8,11 +8,6 @@ using Robust.Shared.Serialization; namespace Content.Shared.Chemistry.Components; -[Serializable, NetSerializable] -public sealed partial class InjectorDoAfterEvent : SimpleDoAfterEvent -{ -} - /// /// Implements draw/inject behavior for droppers and syringes. /// @@ -26,9 +21,18 @@ public sealed partial class InjectorDoAfterEvent : SimpleDoAfterEvent [RegisterComponent, NetworkedComponent, AutoGenerateComponentState] public sealed partial class InjectorComponent : Component { + /// + /// The solution to draw into or inject from. + /// [DataField] public string SolutionName = "injector"; + /// + /// A cached reference to the solution. + /// + [ViewVariables] + public Entity? Solution = null; + /// /// Whether or not the injector is able to draw from containers or if it's a single use /// device that can only inject. @@ -37,42 +41,35 @@ public sealed partial class InjectorComponent : Component public bool InjectOnly; /// - /// Whether or not the injector is able to draw from or inject from mobs + /// Whether or not the injector is able to draw from or inject from mobs. /// /// - /// for example: droppers would ignore mobs + /// For example: droppers would ignore mobs. /// [DataField] public bool IgnoreMobs; /// - /// Whether or not the injector is able to draw from or inject into containers that are closed/sealed + /// Whether or not the injector is able to draw from or inject into containers that are closed/sealed. /// /// - /// for example: droppers can not inject into cans, but syringes can + /// For example: droppers can not inject into cans, but syringes can. /// [DataField] public bool IgnoreClosed = true; /// - /// The minimum amount of solution that can be transferred at once from this solution. + /// The transfer amounts for the set-transfer verb. /// - [DataField("minTransferAmount")] - public FixedPoint2 MinimumTransferAmount = FixedPoint2.New(5); - - /// - /// The maximum amount of solution that can be transferred at once from this solution. - /// - [DataField("maxTransferAmount")] - public FixedPoint2 MaximumTransferAmount = FixedPoint2.New(15); + [DataField] + public List TransferAmounts = new() { 1, 5, 10, 15 }; /// /// Amount to inject or draw on each usage. If the injector is inject only, it will /// attempt to inject it's entire contents upon use. /// - [DataField] - [AutoNetworkedField] - public FixedPoint2 TransferAmount = FixedPoint2.New(5); + [DataField, AutoNetworkedField] + public FixedPoint2 CurrentTransferAmount = FixedPoint2.New(5); /// /// Injection delay (seconds) when the target is a mob. @@ -95,8 +92,7 @@ public sealed partial class InjectorComponent : Component /// right SolutionCaps to support injection/drawing. For InjectOnly injectors this should /// only ever be set to Inject /// - [AutoNetworkedField] - [DataField] + [DataField, AutoNetworkedField] public InjectorToggleMode ToggleState = InjectorToggleMode.Draw; /// @@ -134,6 +130,7 @@ public sealed partial class InjectorComponent : Component /// /// Possible modes for an . /// +[Serializable, NetSerializable] public enum InjectorToggleMode : byte { /// @@ -144,5 +141,11 @@ public enum InjectorToggleMode : byte /// /// The injector will try to draw reagent from things. /// - Draw + Draw, } + +/// +/// Raised on the injector when the doafter has finished. +/// +[Serializable, NetSerializable] +public sealed partial class InjectorDoAfterEvent : SimpleDoAfterEvent; diff --git a/Content.Shared/Chemistry/EntitySystems/SharedInjectorSystem.cs b/Content.Shared/Chemistry/EntitySystems/SharedInjectorSystem.cs index 1620344652c..2fac241bd7d 100644 --- a/Content.Shared/Chemistry/EntitySystems/SharedInjectorSystem.cs +++ b/Content.Shared/Chemistry/EntitySystems/SharedInjectorSystem.cs @@ -1,48 +1,61 @@ +using System.Linq; +using Content.Shared._DV.Chemistry.Components; // DeltaV using Content.Shared.Administration.Logs; +using Content.Shared.Body.Components; +using Content.Shared.Body.Systems; using Content.Shared.Chemistry.Components; +using Content.Shared.Chemistry.Components.SolutionManager; using Content.Shared.CombatMode; +using Content.Shared.Database; using Content.Shared.DoAfter; using Content.Shared.FixedPoint; +using Content.Shared.Forensics.Systems; +using Content.Shared.IdentityManagement; +using Content.Shared.Interaction; using Content.Shared.Interaction.Events; +using Content.Shared.Mobs.Components; using Content.Shared.Mobs.Systems; +using Content.Shared.Nutrition.EntitySystems; using Content.Shared.Popups; +using Content.Shared.Stacks; using Content.Shared.Verbs; -using Robust.Shared.Player; namespace Content.Shared.Chemistry.EntitySystems; public abstract class SharedInjectorSystem : EntitySystem { - /// - /// Default transfer amounts for the set-transfer verb. - /// - public static readonly FixedPoint2[] TransferAmounts = { 1, 5, 10, 15 }; - - [Dependency] protected readonly SharedPopupSystem Popup = default!; - [Dependency] protected readonly SharedSolutionContainerSystem SolutionContainers = default!; - [Dependency] protected readonly MobStateSystem MobState = default!; - [Dependency] protected readonly SharedCombatModeSystem Combat = default!; - [Dependency] protected readonly SharedDoAfterSystem DoAfter = default!; - [Dependency] protected readonly ISharedAdminLogManager AdminLogger = default!; + [Dependency] private readonly SharedBloodstreamSystem _blood = default!; + [Dependency] private readonly ISharedAdminLogManager _adminLogger = default!; + [Dependency] private readonly MobStateSystem _mobState = default!; + [Dependency] private readonly OpenableSystem _openable = default!; + [Dependency] private readonly ReactiveSystem _reactiveSystem = default!; + [Dependency] private readonly SharedCombatModeSystem _combatMode = default!; + [Dependency] private readonly SharedDoAfterSystem _doAfter = default!; + [Dependency] private readonly SharedPopupSystem _popup = default!; + [Dependency] private readonly SharedForensicsSystem _forensics = default!; + [Dependency] protected readonly SharedSolutionContainerSystem SolutionContainer = default!; public override void Initialize() { SubscribeLocalEvent>(AddSetTransferVerbs); - SubscribeLocalEvent(OnInjectorStartup); SubscribeLocalEvent(OnInjectorUse); + SubscribeLocalEvent(OnInjectorAfterInteract); + SubscribeLocalEvent(OnInjectDoAfter); } - private void AddSetTransferVerbs(Entity entity, ref GetVerbsEvent args) + private void AddSetTransferVerbs(Entity ent, ref GetVerbsEvent args) { if (!args.CanAccess || !args.CanInteract || args.Hands == null) return; - var user = args.User; - var (_, component) = entity; + if (ent.Comp.TransferAmounts.Count <= 1) + return; // No options to cycle between - var min = component.MinimumTransferAmount; - var max = component.MaximumTransferAmount; - var cur = component.TransferAmount; + var user = args.User; + + var min = ent.Comp.TransferAmounts.Min(); + var max = ent.Comp.TransferAmounts.Max(); + var cur = ent.Comp.CurrentTransferAmount; var toggleAmount = cur == max ? min : max; var priority = 0; @@ -52,9 +65,9 @@ public abstract class SharedInjectorSystem : EntitySystem Category = VerbCategory.SetTransferAmount, Act = () => { - component.TransferAmount = toggleAmount; - Popup.PopupClient(Loc.GetString("comp-solution-transfer-set-amount", ("amount", toggleAmount)), user, user); - Dirty(entity); + ent.Comp.CurrentTransferAmount = toggleAmount; + _popup.PopupClient(Loc.GetString("comp-solution-transfer-set-amount", ("amount", toggleAmount)), user, user); + Dirty(ent); }, Priority = priority @@ -63,21 +76,18 @@ public abstract class SharedInjectorSystem : EntitySystem priority -= 1; - // Add specific transfer verbs according to the container's size - foreach (var amount in TransferAmounts) + // Add specific transfer verbs for amounts defined in the component + foreach (var amount in ent.Comp.TransferAmounts) { - if (amount < component.MinimumTransferAmount || amount > component.MaximumTransferAmount) - continue; - AlternativeVerb verb = new() { Text = Loc.GetString("comp-solution-transfer-verb-amount", ("amount", amount)), Category = VerbCategory.SetTransferAmount, Act = () => { - component.TransferAmount = amount; - Popup.PopupClient(Loc.GetString("comp-solution-transfer-set-amount", ("amount", amount)), user, user); - Dirty(entity); + ent.Comp.CurrentTransferAmount = amount; + _popup.PopupClient(Loc.GetString("comp-solution-transfer-set-amount", ("amount", amount)), user, user); + Dirty(ent); }, // we want to sort by size, not alphabetically by the verb text. @@ -90,30 +100,413 @@ public abstract class SharedInjectorSystem : EntitySystem } } - private void OnInjectorStartup(Entity entity, ref ComponentStartup args) - { - // ???? why ????? - Dirty(entity); - } - - private void OnInjectorUse(Entity entity, ref UseInHandEvent args) + private void OnInjectorUse(Entity ent, ref UseInHandEvent args) { if (args.Handled) return; - Toggle(entity, args.User); + Toggle(ent, args.User); args.Handled = true; } + private void OnInjectorAfterInteract(Entity ent, ref AfterInteractEvent args) + { + if (args.Handled || !args.CanReach) + return; + + //Make sure we have the attacking entity + if (args.Target is not { Valid: true } target || !HasComp(ent)) + return; + + // Is the target a mob? If yes, use a do-after to give them time to respond. + if (HasComp(target) || HasComp(target)) + { + // Are use using an injector capable of targeting a mob? + if (ent.Comp.IgnoreMobs) + return; + + InjectDoAfter(ent, target, args.User); + args.Handled = true; + return; + } + + // Instantly draw from or inject into jugs, bottles etc. + args.Handled = TryUseInjector(ent, target, args.User); + } + + private void OnInjectDoAfter(Entity ent, ref InjectorDoAfterEvent args) + { + if (args.Cancelled || args.Handled || args.Args.Target == null) + return; + + args.Handled = TryUseInjector(ent, args.Args.Target.Value, args.Args.User); + } + /// - /// Toggle between draw/inject state if applicable + /// Send informative pop-up messages and wait for a do-after to complete. /// - private void Toggle(Entity injector, EntityUid user) + private void InjectDoAfter(Entity injector, EntityUid target, EntityUid user) + { + if (HasComp(target)) // DeltaV + { + _popup.PopupClient(Loc.GetString("injector-component-deny-user"), target, user); + return; + } + + // Create a pop-up for the user + if (injector.Comp.ToggleState == InjectorToggleMode.Draw) + { + _popup.PopupClient(Loc.GetString("injector-component-drawing-user"), target, user); + } + else + { + _popup.PopupClient(Loc.GetString("injector-component-injecting-user"), target, user); + } + + if (!SolutionContainer.ResolveSolution(injector.Owner, injector.Comp.SolutionName, ref injector.Comp.Solution, out var solution)) + return; + + var actualDelay = injector.Comp.Delay; + FixedPoint2 amountToInject; + if (injector.Comp.ToggleState == InjectorToggleMode.Draw) + { + // additional delay is based on actual volume left to draw in syringe when smaller than transfer amount + amountToInject = FixedPoint2.Min(injector.Comp.CurrentTransferAmount, solution.MaxVolume - solution.Volume); + } + else + { + // additional delay is based on actual volume left to inject in syringe when smaller than transfer amount + amountToInject = FixedPoint2.Min(injector.Comp.CurrentTransferAmount, solution.Volume); + } + + // Injections take 0.5 seconds longer per 5u of possible space/content + // First 5u(MinimumTransferAmount) doesn't incur delay + actualDelay += injector.Comp.DelayPerVolume * FixedPoint2.Max(0, amountToInject - injector.Comp.TransferAmounts.Min()).Double(); + + // Ensure that minimum delay before incapacitation checks is 1 seconds + actualDelay = MathHelper.Max(actualDelay, TimeSpan.FromSeconds(1)); + + if (user != target) // injecting someone else + { + // Create a pop-up for the target + var userName = Identity.Entity(user, EntityManager); + if (injector.Comp.ToggleState == InjectorToggleMode.Draw) + { + _popup.PopupEntity(Loc.GetString("injector-component-drawing-target", + ("user", userName)), user, target); + } + else + { + _popup.PopupEntity(Loc.GetString("injector-component-injecting-target", + ("user", userName)), user, target); + } + + + // Check if the target is incapacitated or in combat mode and modify time accordingly. + if (_mobState.IsIncapacitated(target)) + { + actualDelay /= 2.5f; + } + else if (_combatMode.IsInCombatMode(target)) + { + // Slightly increase the delay when the target is in combat mode. Helps prevents cheese injections in + // combat with fast syringes & lag. + actualDelay += TimeSpan.FromSeconds(1); + } + + // Add an admin log, using the "force feed" log type. It's not quite feeding, but the effect is the same. + if (injector.Comp.ToggleState == InjectorToggleMode.Inject) + { + _adminLogger.Add(LogType.ForceFeed, + $"{ToPrettyString(user):user} is attempting to inject {ToPrettyString(target):target} with a solution {SharedSolutionContainerSystem.ToPrettyString(solution):solution}"); + } + else + { + _adminLogger.Add(LogType.ForceFeed, + $"{ToPrettyString(user):user} is attempting to draw {injector.Comp.CurrentTransferAmount.ToString()} units from {ToPrettyString(target):target}"); + } + } + else // injecting yourself + { + // Self-injections take half as long. + actualDelay /= 2; + + if (injector.Comp.ToggleState == InjectorToggleMode.Inject) + { + _adminLogger.Add(LogType.Ingestion, + $"{ToPrettyString(user):user} is attempting to inject themselves with a solution {SharedSolutionContainerSystem.ToPrettyString(solution):solution}."); + } + else + { + _adminLogger.Add(LogType.ForceFeed, + $"{ToPrettyString(user):user} is attempting to draw {injector.Comp.CurrentTransferAmount.ToString()} units from themselves."); + } + } + + _doAfter.TryStartDoAfter(new DoAfterArgs(EntityManager, user, actualDelay, new InjectorDoAfterEvent(), injector.Owner, target: target, used: injector.Owner) + { + BreakOnMove = true, + BreakOnWeightlessMove = false, + BreakOnDamage = true, + NeedHand = injector.Comp.NeedHand, + BreakOnHandChange = injector.Comp.BreakOnHandChange, + MovementThreshold = injector.Comp.MovementThreshold, + }); + } + + private bool TryUseInjector(Entity injector, EntityUid target, EntityUid user) + { + var isOpenOrIgnored = injector.Comp.IgnoreClosed || !_openable.IsClosed(target); + // Handle injecting/drawing for solutions + if (injector.Comp.ToggleState == InjectorToggleMode.Inject) + { + if (isOpenOrIgnored && SolutionContainer.TryGetInjectableSolution(target, out var injectableSolution, out _)) + return TryInject(injector, target, injectableSolution.Value, user, false); + + if (isOpenOrIgnored && SolutionContainer.TryGetRefillableSolution(target, out var refillableSolution, out _)) + return TryInject(injector, target, refillableSolution.Value, user, true); + + if (TryComp(target, out var bloodstream)) + return TryInjectIntoBloodstream(injector, (target, bloodstream), user); + + LocId msg = target == user ? "injector-component-cannot-transfer-message-self" : "injector-component-cannot-transfer-message"; + _popup.PopupClient(Loc.GetString(msg, ("target", Identity.Entity(target, EntityManager))), injector, user); + } + else if (injector.Comp.ToggleState == InjectorToggleMode.Draw) + { + // Draw from a bloodstream, if the target has that + if (TryComp(target, out var stream) && + SolutionContainer.ResolveSolution(target, stream.BloodSolutionName, ref stream.BloodSolution)) + { + return TryDraw(injector, (target, stream), stream.BloodSolution.Value, user); + } + + // Draw from an object (food, beaker, etc) + if (isOpenOrIgnored && SolutionContainer.TryGetDrawableSolution(target, out var drawableSolution, out _)) + return TryDraw(injector, target, drawableSolution.Value, user); + + LocId msg = target == user ? "injector-component-cannot-draw-message-self" : "injector-component-cannot-draw-message"; + _popup.PopupClient(Loc.GetString(msg, ("target", Identity.Entity(target, EntityManager))), injector.Owner, user); + } + return false; + } + + private bool TryInject(Entity injector, EntityUid target, + Entity targetSolution, EntityUid user, bool asRefill) + { + if (!SolutionContainer.ResolveSolution(injector.Owner, injector.Comp.SolutionName, ref injector.Comp.Solution, + out var solution) || solution.Volume == 0) + return false; + + // Get transfer amount. May be smaller than _transferAmount if not enough room + var realTransferAmount = + FixedPoint2.Min(injector.Comp.CurrentTransferAmount, targetSolution.Comp.Solution.AvailableVolume); + + if (realTransferAmount <= 0) + { + LocId msg = target == user ? "injector-component-target-already-full-message-self" : "injector-component-target-already-full-message"; + _popup.PopupClient( + Loc.GetString(msg, + ("target", Identity.Entity(target, EntityManager))), + injector.Owner, + user); + return false; + } + + // Move units from attackSolution to targetSolution + Solution removedSolution; + if (TryComp(target, out var stack)) + removedSolution = SolutionContainer.SplitStackSolution(injector.Comp.Solution.Value, realTransferAmount, stack.Count); + else + removedSolution = SolutionContainer.SplitSolution(injector.Comp.Solution.Value, realTransferAmount); + + _reactiveSystem.DoEntityReaction(target, removedSolution, ReactionMethod.Injection); + + if (!asRefill) + SolutionContainer.Inject(target, targetSolution, removedSolution); + else + SolutionContainer.Refill(target, targetSolution, removedSolution); + + LocId msgSuccess = target == user ? "injector-component-transfer-success-message-self" : "injector-component-transfer-success-message"; + _popup.PopupClient( + Loc.GetString(msgSuccess, + ("amount", removedSolution.Volume), + ("target", Identity.Entity(target, EntityManager))), + injector.Owner, user); + + AfterInject(injector, target); + return true; + } + + private bool TryInjectIntoBloodstream(Entity injector, Entity target, + EntityUid user) + { + // Get transfer amount. May be smaller than _transferAmount if not enough room + if (!SolutionContainer.ResolveSolution(target.Owner, target.Comp.ChemicalSolutionName, + ref target.Comp.ChemicalSolution, out var chemSolution)) + { + LocId msg = target.Owner == user ? "injector-component-cannot-inject-message-self" : "injector-component-cannot-inject-message"; + _popup.PopupClient( + Loc.GetString(msg, + ("target", Identity.Entity(target, EntityManager))), + injector.Owner, user); + return false; + } + + var realTransferAmount = FixedPoint2.Min(injector.Comp.CurrentTransferAmount, chemSolution.AvailableVolume); + if (realTransferAmount <= 0) + { + LocId msg = target.Owner == user ? "injector-component-cannot-inject-message-self" : "injector-component-cannot-inject-message"; + _popup.PopupClient( + Loc.GetString(msg, + ("target", Identity.Entity(target, EntityManager))), + injector.Owner, user); + return false; + } + + // Move units from attackSolution to targetSolution + var removedSolution = SolutionContainer.SplitSolution(target.Comp.ChemicalSolution.Value, realTransferAmount); + + _blood.TryAddToChemicals(target.AsNullable(), removedSolution); + + _reactiveSystem.DoEntityReaction(target, removedSolution, ReactionMethod.Injection); + + LocId msgSuccess = target.Owner == user ? "injector-component-inject-success-message-self" : "injector-component-inject-success-message"; + _popup.PopupClient( + Loc.GetString(msgSuccess, + ("amount", removedSolution.Volume), + ("target", Identity.Entity(target, EntityManager))), + injector.Owner, user); + + AfterInject(injector, target); + return true; + } + + private bool TryDraw(Entity injector, Entity target, + Entity targetSolution, EntityUid user) + { + if (!SolutionContainer.ResolveSolution(injector.Owner, injector.Comp.SolutionName, ref injector.Comp.Solution, + out var solution) || solution.AvailableVolume == 0) + { + return false; + } + + var applicableTargetSolution = targetSolution.Comp.Solution; + // If a whitelist exists, remove all non-whitelisted reagents from the target solution temporarily + var temporarilyRemovedSolution = new Solution(); + if (injector.Comp.ReagentWhitelist is { } reagentWhitelist) + { + temporarilyRemovedSolution = applicableTargetSolution.SplitSolutionWithout(applicableTargetSolution.Volume, reagentWhitelist.ToArray()); + } + + // Get transfer amount. May be smaller than _transferAmount if not enough room, also make sure there's room in the injector + var realTransferAmount = FixedPoint2.Min(injector.Comp.CurrentTransferAmount, applicableTargetSolution.Volume, + solution.AvailableVolume); + + if (realTransferAmount <= 0) + { + LocId msg = target.Owner == user ? "injector-component-target-is-empty-message-self" : "injector-component-target-is-empty-message"; + _popup.PopupClient( + Loc.GetString(msg, + ("target", Identity.Entity(target, EntityManager))), + injector.Owner, user); + return false; + } + + // We have some snowflaked behavior for streams. + if (target.Comp != null) + { + DrawFromBlood(injector, (target.Owner, target.Comp), injector.Comp.Solution.Value, realTransferAmount, user); + return true; + } + + // Move units from attackSolution to targetSolution + var removedSolution = SolutionContainer.Draw(target.Owner, targetSolution, realTransferAmount); + + // Add back non-whitelisted reagents to the target solution + SolutionContainer.TryAddSolution(targetSolution, temporarilyRemovedSolution); + + if (!SolutionContainer.TryAddSolution(injector.Comp.Solution.Value, removedSolution)) + { + return false; + } + + LocId msgSuccess = target.Owner == user ? "injector-component-draw-success-message-self" : "injector-component-draw-success-message"; + _popup.PopupClient( + Loc.GetString(msgSuccess, + ("amount", removedSolution.Volume), + ("target", Identity.Entity(target, EntityManager))), + injector.Owner, user); + + AfterDraw(injector, target); + return true; + } + + private void DrawFromBlood(Entity injector, Entity target, + Entity injectorSolution, FixedPoint2 transferAmount, EntityUid user) + { + var drawAmount = (float)transferAmount; + + if (SolutionContainer.ResolveSolution(target.Owner, target.Comp.ChemicalSolutionName, + ref target.Comp.ChemicalSolution)) + { + var chemTemp = SolutionContainer.SplitSolution(target.Comp.ChemicalSolution.Value, drawAmount * 0.15f); + SolutionContainer.TryAddSolution(injectorSolution, chemTemp); + drawAmount -= (float)chemTemp.Volume; + } + + if (SolutionContainer.ResolveSolution(target.Owner, target.Comp.BloodSolutionName, + ref target.Comp.BloodSolution)) + { + var bloodTemp = SolutionContainer.SplitSolution(target.Comp.BloodSolution.Value, drawAmount); + SolutionContainer.TryAddSolution(injectorSolution, bloodTemp); + } + + LocId msg = target.Owner == user ? "injector-component-draw-success-message-self" : "injector-component-draw-success-message"; + _popup.PopupClient( + Loc.GetString(msg, + ("amount", transferAmount), + ("target", Identity.Entity(target, EntityManager))), + injector.Owner, user); + + AfterDraw(injector, target); + } + + private void AfterInject(Entity injector, EntityUid target) + { + // Automatically set syringe to draw after completely draining it. + if (SolutionContainer.ResolveSolution(injector.Owner, injector.Comp.SolutionName, ref injector.Comp.Solution, + out var solution) && solution.Volume == 0) + { + SetMode(injector, InjectorToggleMode.Draw); + } + + // Leave some DNA from the injectee on it + _forensics.TransferDna(injector, target); + } + + private void AfterDraw(Entity injector, EntityUid target) + { + // Automatically set syringe to inject after completely filling it. + if (SolutionContainer.ResolveSolution(injector.Owner, injector.Comp.SolutionName, ref injector.Comp.Solution, + out var solution) && solution.AvailableVolume == 0) + { + SetMode(injector, InjectorToggleMode.Inject); + } + + // Leave some DNA from the drawee on it + _forensics.TransferDna(injector, target); + } + + /// + /// Toggle the injector between draw/inject state if applicable. + /// + public void Toggle(Entity injector, EntityUid user) { if (injector.Comp.InjectOnly) return; - if (!SolutionContainers.TryGetSolution(injector.Owner, injector.Comp.SolutionName, out var solEnt, out var solution)) + if (!SolutionContainer.ResolveSolution(injector.Owner, injector.Comp.SolutionName, ref injector.Comp.Solution, out var solution)) return; string msg; @@ -146,9 +539,12 @@ public abstract class SharedInjectorSystem : EntitySystem throw new ArgumentOutOfRangeException(); } - Popup.PopupClient(Loc.GetString(msg), injector, user); + _popup.PopupClient(Loc.GetString(msg), injector, user); } + /// + /// Set the mode of the injector to draw or inject. + /// public void SetMode(Entity injector, InjectorToggleMode mode) { injector.Comp.ToggleState = mode; diff --git a/Content.Shared/Fluids/SharedPuddleSystem.Spillable.cs b/Content.Shared/Fluids/SharedPuddleSystem.Spillable.cs index 2ce008da262..7d65dd24245 100644 --- a/Content.Shared/Fluids/SharedPuddleSystem.Spillable.cs +++ b/Content.Shared/Fluids/SharedPuddleSystem.Spillable.cs @@ -60,6 +60,8 @@ public abstract partial class SharedPuddleSystem var puddleSolution = _solutionContainerSystem.SplitSolution(soln.Value, solution.Volume); TrySpillAt(Transform(target).Coordinates, puddleSolution, out _); + // TODO: Make this an event subscription once spilling puddles is predicted. + // Injectors should not be hardcoded here. if (TryComp(entity, out var injectorComp)) { injectorComp.ToggleState = InjectorToggleMode.Draw; diff --git a/Content.Shared/Forensics/Systems/SharedForensicsSystem.cs b/Content.Shared/Forensics/Systems/SharedForensicsSystem.cs index 1220b75fffe..be26fd6fd01 100644 --- a/Content.Shared/Forensics/Systems/SharedForensicsSystem.cs +++ b/Content.Shared/Forensics/Systems/SharedForensicsSystem.cs @@ -15,4 +15,13 @@ public abstract class SharedForensicsSystem : EntitySystem /// Does nothing if it does not have the FingerprintComponent. /// public virtual void RandomizeFingerprint(Entity ent) { } + + /// + /// Transfer DNA from one entity onto the forensics of another. + /// + /// The entity receiving the DNA. + /// The entity applying its DNA. + /// If this DNA be cleaned off of the recipient. e.g. cleaning a knife vs cleaning a puddle of blood. + public virtual void TransferDna(EntityUid recipient, EntityUid donor, bool canDnaBeCleaned = true) { } + } diff --git a/Resources/Locale/en-US/chemistry/components/injector-component.ftl b/Resources/Locale/en-US/chemistry/components/injector-component.ftl index 40737f021d5..db98d1ca1bf 100644 --- a/Resources/Locale/en-US/chemistry/components/injector-component.ftl +++ b/Resources/Locale/en-US/chemistry/components/injector-component.ftl @@ -10,14 +10,22 @@ injector-volume-label = Volume: [color=white]{$currentVolume}/{$totalVolume}[/co injector-component-drawing-text = Now drawing injector-component-injecting-text = Now injecting -injector-component-cannot-transfer-message = You aren't able to transfer to {THE($target)}! +injector-component-cannot-transfer-message = You aren't able to transfer into {THE($target)}! +injector-component-cannot-transfer-message-self = You aren't able to transfer into yourself! injector-component-cannot-draw-message = You aren't able to draw from {THE($target)}! -injector-component-cannot-inject-message = You aren't able to inject to {THE($target)}! +injector-component-cannot-draw-message-self = You aren't able to draw from yourself! +injector-component-cannot-inject-message = You aren't able to inject into {THE($target)}! +injector-component-cannot-inject-message-self = You aren't able to inject into yourself! injector-component-inject-success-message = You inject {$amount}u into {THE($target)}! +injector-component-inject-success-message-self = You inject {$amount}u into yourself! injector-component-transfer-success-message = You transfer {$amount}u into {THE($target)}. +injector-component-transfer-success-message-self = You transfer {$amount}u into yourself. injector-component-draw-success-message = You draw {$amount}u from {THE($target)}. +injector-component-draw-success-message-self = You draw {$amount}u from youself. injector-component-target-already-full-message = {CAPITALIZE(THE($target))} is already full! +injector-component-target-already-full-message-self = You are already full! injector-component-target-is-empty-message = {CAPITALIZE(THE($target))} is empty! +injector-component-target-is-empty-message-self = You are empty! injector-component-cannot-toggle-draw-message = Too full to draw! injector-component-cannot-toggle-inject-message = Nothing to inject! diff --git a/Resources/Migrations/migration.yml b/Resources/Migrations/migration.yml index 66fc06c2e5c..987088aa619 100644 --- a/Resources/Migrations/migration.yml +++ b/Resources/Migrations/migration.yml @@ -662,6 +662,9 @@ VimChassis: null # 2025-08-01 FoodDonutJellySlugcat: FoodDonutJellyScurret +# 2025-08-29 +PrefilledSyringe: Syringe + # 2025-10-01 SimpleXenoArtifact: ComplexXenoArtifact MediumXenoArtifact: ComplexXenoArtifact diff --git a/Resources/Prototypes/Entities/Objects/Specific/chemistry.yml b/Resources/Prototypes/Entities/Objects/Specific/chemistry.yml index 50a144e8afe..7d1a85e4b82 100644 --- a/Resources/Prototypes/Entities/Objects/Specific/chemistry.yml +++ b/Resources/Prototypes/Entities/Objects/Specific/chemistry.yml @@ -291,10 +291,13 @@ injectOnly: false ignoreMobs: true ignoreClosed: false - minTransferAmount: 1 - maxTransferAmount: 5 - transferAmount: 1 - toggleState: 1 # draw + transferAmounts: + - 1 + - 2 + - 3 + - 4 + - 5 + currentTransferAmount: 1 - type: ExaminableSolution solution: dropper exactVolume: true @@ -390,8 +393,7 @@ id: Syringe components: - type: Injector - transferAmount: 15 - toggleState: Draw + currentTransferAmount: 15 - type: Tag tags: - Syringe @@ -415,9 +417,13 @@ injector: maxVol: 5 - type: Injector - minTransferAmount: 1 - maxTransferAmount: 5 - transferAmount: 5 + transferAmounts: + - 1 + - 2 + - 3 + - 4 + - 5 + currentTransferAmount: 5 - type: SolutionContainerVisuals maxFillLevels: 3 fillBaseName: minisyringe @@ -466,6 +472,7 @@ - SyringeGunAmmo - type: entity + abstract: true parent: BaseSyringe id: PrefilledSyringe components: @@ -530,15 +537,15 @@ canReact: false - type: Injector injectOnly: false - minTransferAmount: 5 - maxTransferAmount: 10 - transferAmount: 10 + transferAmounts: + - 5 + - 10 + currentTransferAmount: 10 - type: Tag tags: - Syringe - Trash - - type: entity name: pill parent: BaseItem diff --git a/Resources/Textures/_NF/Clothing/Belt/pilot.rsi/meta.json b/Resources/Textures/_NF/Clothing/Belt/pilot.rsi/meta.json index 7d0706ed599..f1e5b934a3c 100644 --- a/Resources/Textures/_NF/Clothing/Belt/pilot.rsi/meta.json +++ b/Resources/Textures/_NF/Clothing/Belt/pilot.rsi/meta.json @@ -10,25 +10,17 @@ { "name": "icon" }, - "states": [ - { - "name": "icon" - }, - { - "name": "equipped-BELT", - "directions": 4 - }, - { - "name": "equipped-BACKPACK", - "directions": 4 - }, - { - "name": "inhand-left", - "directions": 4 - }, - { - "name": "inhand-right", - "directions": 4 - } + { + "name": "equipped-BELT", + "directions": 4 + }, + { + "name": "inhand-left", + "directions": 4 + }, + { + "name": "inhand-right", + "directions": 4 + } ] } From 0040cd56f7d740554377d5c142a1d5e63fcf4e76 Mon Sep 17 00:00:00 2001 From: Southbridge <7013162+southbridge-fur@users.noreply.github.com> Date: Mon, 1 Sep 2025 19:13:52 -0400 Subject: [PATCH 296/340] Event Shuttle Fixes (#40059) --- .../Maps/Shuttles/ShuttleEvent/cryptid.yml | 88 +++++++++++-------- 1 file changed, 51 insertions(+), 37 deletions(-) diff --git a/Resources/Maps/Shuttles/ShuttleEvent/cryptid.yml b/Resources/Maps/Shuttles/ShuttleEvent/cryptid.yml index 055d5a8c737..23f91957105 100644 --- a/Resources/Maps/Shuttles/ShuttleEvent/cryptid.yml +++ b/Resources/Maps/Shuttles/ShuttleEvent/cryptid.yml @@ -1,6 +1,17 @@ meta: - format: 6 - postmapinit: false + format: 7 + category: Grid + engineVersion: 266.0.0 + forkId: "" + forkVersion: "" + time: 09/01/2025 20:37:26 + entityCount: 564 +maps: [] +grids: +- 1 +orphans: +- 1 +nullspace: [] tilemap: 0: Space 1: FloorMetalDiamond @@ -25,20 +36,20 @@ entities: chunks: 0,0: ind: 0,0 - tiles: fQAAAAACfQAAAAABfQAAAAACfQAAAAABfQAAAAADfQAAAAADgQAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAfQAAAAAAfQAAAAAAgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAfQAAAAABfQAAAAAAfQAAAAAAfQAAAAABfQAAAAACfQAAAAABgQAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAfQAAAAAAfQAAAAAAgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAfQAAAAABfQAAAAAAfQAAAAACfQAAAAACfQAAAAACfQAAAAACgQAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAfQAAAAAAfQAAAAAAgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAfQAAAAAAfQAAAAACfQAAAAACfQAAAAAAfQAAAAACgQAAAAAAgQAAAAAAgAAAAAAAgAAAAAAAgQAAAAAAfQAAAAAAfQAAAAAAgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAfQAAAAACfQAAAAADfQAAAAABfQAAAAAAfQAAAAACgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAgQAAAAAAgQAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAfQAAAAACfQAAAAACfQAAAAABfQAAAAAAgQAAAAAAgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAfQAAAAABfQAAAAACfQAAAAADfQAAAAADgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAfQAAAAADfQAAAAABfQAAAAADgQAAAAAAgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAfQAAAAACfQAAAAACgQAAAAAAgQAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAgQAAAAAAgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - version: 6 + tiles: fQAAAAACAH0AAAAAAQB9AAAAAAIAfQAAAAABAH0AAAAAAwB9AAAAAAMAgQAAAAAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAAH0AAAAAAAB9AAAAAAAAgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH0AAAAAAQB9AAAAAAAAfQAAAAAAAH0AAAAAAQB9AAAAAAIAfQAAAAABAIEAAAAAAAAAAAAAAAAAAAAAAAAAAIEAAAAAAAB9AAAAAAAAfQAAAAAAAIEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB9AAAAAAEAfQAAAAAAAH0AAAAAAgB9AAAAAAIAfQAAAAACAH0AAAAAAgCBAAAAAAAAAAAAAAAAAAAAAAAAAACBAAAAAAAAfQAAAAAAAH0AAAAAAACBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAfQAAAAAAAH0AAAAAAgB9AAAAAAIAfQAAAAAAAH0AAAAAAgCBAAAAAAAAgQAAAAAAAIAAAAAAAACAAAAAAAAAgQAAAAAAAH0AAAAAAAB9AAAAAAAAgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH0AAAAAAgB9AAAAAAMAfQAAAAABAH0AAAAAAAB9AAAAAAIAgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAACBAAAAAAAAgQAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB9AAAAAAIAfQAAAAACAH0AAAAAAQB9AAAAAAAAgQAAAAAAAIEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAfQAAAAABAH0AAAAAAgB9AAAAAAMAfQAAAAADAIEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH0AAAAAAwB9AAAAAAEAfQAAAAADAIEAAAAAAACBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB9AAAAAAIAfQAAAAACAIEAAAAAAACBAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA== + version: 7 -1,0: ind: -1,0 - tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAfQAAAAADfQAAAAABfQAAAAACfQAAAAACfQAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAfQAAAAADfQAAAAADfQAAAAAAfQAAAAADfQAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAfQAAAAACfQAAAAADfQAAAAADfQAAAAAAfQAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAgQAAAAAAfQAAAAADfQAAAAAAfQAAAAABfQAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAfQAAAAABfQAAAAADfQAAAAAAfQAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAgQAAAAAAfQAAAAACfQAAAAABfQAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAfQAAAAADfQAAAAABfQAAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAgQAAAAAAfQAAAAACfQAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAgQAAAAAAgQAAAAAAfQAAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - version: 6 + tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIEAAAAAAAB9AAAAAAMAfQAAAAABAH0AAAAAAgB9AAAAAAIAfQAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACBAAAAAAAAfQAAAAADAH0AAAAAAwB9AAAAAAAAfQAAAAADAH0AAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAAH0AAAAAAgB9AAAAAAMAfQAAAAADAH0AAAAAAAB9AAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIEAAAAAAACBAAAAAAAAfQAAAAADAH0AAAAAAAB9AAAAAAEAfQAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAAH0AAAAAAQB9AAAAAAMAfQAAAAAAAH0AAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIEAAAAAAACBAAAAAAAAfQAAAAACAH0AAAAAAQB9AAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAAH0AAAAAAwB9AAAAAAEAfQAAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIEAAAAAAACBAAAAAAAAfQAAAAACAH0AAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAgQAAAAAAAIEAAAAAAAB9AAAAAAMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACBAAAAAAAAgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA== + version: 7 -1,-1: ind: -1,-1 - tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAgQAAAAAAfQAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAgQAAAAAAfQAAAAADfQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAfQAAAAAAfQAAAAABfQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAgQAAAAAAfQAAAAADfQAAAAABfQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAfQAAAAADfQAAAAACfQAAAAAAfQAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAgQAAAAAAfQAAAAAAfQAAAAACfQAAAAAAfQAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAfQAAAAAAfQAAAAAAfQAAAAAAfQAAAAADfQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAfQAAAAABfQAAAAABfQAAAAADfQAAAAAAfQAAAAAB - version: 6 + tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAAIEAAAAAAAB9AAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAAIEAAAAAAAB9AAAAAAMAfQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIEAAAAAAAB9AAAAAAAAfQAAAAABAH0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIEAAAAAAACBAAAAAAAAfQAAAAADAH0AAAAAAQB9AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACBAAAAAAAAfQAAAAADAH0AAAAAAgB9AAAAAAAAfQAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACBAAAAAAAAgQAAAAAAAH0AAAAAAAB9AAAAAAIAfQAAAAAAAH0AAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAAH0AAAAAAAB9AAAAAAAAfQAAAAAAAH0AAAAAAwB9AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIEAAAAAAAB9AAAAAAEAfQAAAAABAH0AAAAAAwB9AAAAAAAAfQAAAAABAA== + version: 7 0,-1: ind: 0,-1 - tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAAQAAAAAAgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAfQAAAAADfQAAAAABgQAAAAAAgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAfQAAAAAAfQAAAAAAfQAAAAACgQAAAAAAgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAfQAAAAACfQAAAAACfQAAAAADfQAAAAABgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAgQAAAAAAgQAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAfQAAAAACfQAAAAABfQAAAAABfQAAAAAAgQAAAAAAgQAAAAAAgQAAAAAAgQAAAAAAgQAAAAAAgQAAAAAAgQAAAAAAgQAAAAAAgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAfQAAAAABfQAAAAADfQAAAAADfQAAAAADfQAAAAADbwAAAAAAcAAAAAAAcAAAAAAAcAAAAAAAbwAAAAAAcQAAAAADgQAAAAAAgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAfQAAAAAAfQAAAAADfQAAAAACfQAAAAABfQAAAAAAgQAAAAAAgQAAAAAAAQAAAAAAgQAAAAAAgQAAAAAAcQAAAAAAgQAAAAAAgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAfQAAAAAAfQAAAAAAfQAAAAACfQAAAAABfQAAAAAAfQAAAAABgQAAAAAAgAAAAAAAgAAAAAAAgQAAAAAAcQAAAAACgQAAAAAAgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAfQAAAAABfQAAAAADfQAAAAACfQAAAAABfQAAAAABfQAAAAADgQAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAbwAAAAAAgQAAAAAAgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - version: 6 + tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIEAAAAAAAABAAAAAAAAgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB9AAAAAAMAfQAAAAABAIEAAAAAAACBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAfQAAAAAAAH0AAAAAAAB9AAAAAAIAgQAAAAAAAIEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH0AAAAAAgB9AAAAAAIAfQAAAAADAH0AAAAAAQCBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAACBAAAAAAAAgQAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB9AAAAAAIAfQAAAAABAH0AAAAAAQB9AAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAfQAAAAABAH0AAAAAAwB9AAAAAAMAfQAAAAADAH0AAAAAAwBvAAAAAAAAcAAAAAAAAHAAAAAAAABwAAAAAAAAbwAAAAAAAHEAAAAAAwCBAAAAAAAAgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAH0AAAAAAAB9AAAAAAMAfQAAAAACAH0AAAAAAQB9AAAAAAAAgQAAAAAAAIEAAAAAAAABAAAAAAAAgQAAAAAAAIEAAAAAAABxAAAAAAAAgQAAAAAAAIEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB9AAAAAAAAfQAAAAAAAH0AAAAAAgB9AAAAAAEAfQAAAAAAAH0AAAAAAQCBAAAAAAAAgAAAAAAAAIAAAAAAAACBAAAAAAAAcQAAAAACAIEAAAAAAACBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAfQAAAAABAH0AAAAAAwB9AAAAAAIAfQAAAAABAH0AAAAAAQB9AAAAAAMAgQAAAAAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAAG8AAAAAAACBAAAAAAAAgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA== + version: 7 - type: Broadphase - type: Physics bodyStatus: InAir @@ -51,6 +62,7 @@ entities: - type: OccluderTree - type: SpreaderGrid - type: Shuttle + dampingModifier: 0.25 - type: GridPathfinding - type: Gravity gravityShakeSound: !type:SoundPathSpecifier @@ -351,6 +363,7 @@ entities: chunkSize: 4 - type: GasTileOverlay - type: RadiationGridResistance + - type: ImplicitRoof - proto: AirCanister entities: - uid: 551 @@ -404,6 +417,8 @@ entities: - type: Transform pos: 6.5,-2.5 parent: 1 + - type: Fixtures + fixtures: {} - proto: AtmosDeviceFanDirectional entities: - uid: 305 @@ -1387,8 +1402,7 @@ entities: - uid: 304 components: - type: Transform - rot: -1.5707963267948966 rad - pos: 11.432869,2.2409668 + pos: 11.192277,2.7941139 parent: 1 - proto: CarpetBlack entities: @@ -2041,13 +2055,6 @@ entities: - type: Transform pos: 4.3126225,4.8620963 parent: 1 -- proto: DrinkWatermelonJuice - entities: - - uid: 548 - components: - - type: Transform - pos: 11.787036,2.772217 - parent: 1 - proto: FaxMachineBase entities: - uid: 262 @@ -2083,19 +2090,12 @@ entities: - type: Transform pos: 5.5,2.5 parent: 1 -- proto: FoodBurgerChicken +- proto: FoodPlatePlastic entities: - uid: 554 components: - type: Transform - pos: 11.422453,2.6368003 - parent: 1 -- proto: FoodPlateSmallPlastic - entities: - - uid: 547 - components: - - type: Transform - pos: 11.401619,2.6368003 + pos: 11.484088,2.5300417 parent: 1 - proto: GasPassiveVent entities: @@ -3056,6 +3056,20 @@ entities: - type: Transform pos: 8.5,-3.5 parent: 1 +- proto: RandomDrinkSoda + entities: + - uid: 547 + components: + - type: Transform + pos: 11.5,2.5 + parent: 1 +- proto: RandomFoodSingle + entities: + - uid: 548 + components: + - type: Transform + pos: 11.5,2.5 + parent: 1 - proto: ShuttleWindow entities: - uid: 15 @@ -3200,6 +3214,8 @@ entities: - type: Transform pos: 0.5,-8.5 parent: 1 + - type: Fixtures + fixtures: {} - proto: SMESBasic entities: - uid: 302 @@ -3379,7 +3395,7 @@ entities: - uid: 553 components: - type: Transform - pos: 11.776619,2.4701335 + pos: 11.685576,2.9053025 parent: 1 - proto: ToyFigurineRatServant entities: @@ -3697,6 +3713,12 @@ entities: rot: 3.141592653589793 rad pos: 12.5,-0.5 parent: 1 + - uid: 94 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 11.5,-0.5 + parent: 1 - uid: 97 components: - type: Transform @@ -3749,14 +3771,6 @@ entities: rot: 3.141592653589793 rad pos: 11.5,-6.5 parent: 1 -- proto: WallShuttleInterior - entities: - - uid: 94 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 11.5,-0.5 - parent: 1 - proto: WindoorSecure entities: - uid: 78 From bfa2c65c7c335e7751abe89258b5136eadac672b Mon Sep 17 00:00:00 2001 From: IProduceWidgets <107586145+IProduceWidgets@users.noreply.github.com> Date: Mon, 1 Sep 2025 19:39:18 -0400 Subject: [PATCH 297/340] Update 4 visitor shuttles & nanomed inventories (#39718) --- .../Maps/Shuttles/ShuttleEvent/cruiser.yml | 188 ++-- .../Maps/Shuttles/ShuttleEvent/flatline.yml | 181 ++-- .../Shuttles/ShuttleEvent/incorporation.yml | 249 +++-- .../Maps/Shuttles/ShuttleEvent/instigator.yml | 226 ++++- .../VendingMachines/Inventories/medical.yml | 63 ++ .../VendingMachines/Inventories/wallmed.yml | 10 - .../Service/vending_machine_restock.yml | 2 + .../Objects/Specific/chemistry-bottles.yml | 879 +++++++++++++++++- .../Structures/Machines/vending_machines.yml | 82 +- .../VendingMachines/medical.rsi/meta.json | 5 +- .../medical.rsi/off-civilian.png | Bin 0 -> 491 bytes .../VendingMachines/wallmed.rsi/meta.json | 5 +- .../wallmed.rsi/off-civilian.png | Bin 0 -> 229 bytes 13 files changed, 1523 insertions(+), 367 deletions(-) delete mode 100644 Resources/Prototypes/Catalog/VendingMachines/Inventories/wallmed.yml create mode 100644 Resources/Textures/Structures/Machines/VendingMachines/medical.rsi/off-civilian.png create mode 100644 Resources/Textures/Structures/Machines/VendingMachines/wallmed.rsi/off-civilian.png diff --git a/Resources/Maps/Shuttles/ShuttleEvent/cruiser.yml b/Resources/Maps/Shuttles/ShuttleEvent/cruiser.yml index 45e7558d71c..d779c5f7c33 100644 --- a/Resources/Maps/Shuttles/ShuttleEvent/cruiser.yml +++ b/Resources/Maps/Shuttles/ShuttleEvent/cruiser.yml @@ -1,6 +1,17 @@ meta: - format: 6 - postmapinit: false + format: 7 + category: Grid + engineVersion: 266.0.0 + forkId: "" + forkVersion: "" + time: 08/17/2025 23:21:08 + entityCount: 566 +maps: [] +grids: +- 1 +orphans: +- 1 +nullspace: [] tilemap: 0: Space 32: FloorDark @@ -26,28 +37,28 @@ entities: chunks: 0,0: ind: 0,0 - tiles: bwAAAAAAgQAAAAAAgQAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAgQAAAAAAgQAAAAAAgQAAAAAAgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAcwAAAAADYAAAAAADgQAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAgQAAAAAAgQAAAAAAgQAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAcwAAAAACYAAAAAAAgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAcwAAAAACYAAAAAADgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAcwAAAAADYAAAAAAAgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAbwAAAAAAgQAAAAAAgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYAAAAAACYAAAAAADgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYAAAAAABYAAAAAACgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYAAAAAABYAAAAAAAgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYAAAAAACYAAAAAACgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAbwAAAAAAgQAAAAAAgQAAAAAAgQAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAACIAAAAAABIAAAAAABIAAAAAACgQAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAADIAAAAAACIAAAAAACIAAAAAACIAAAAAACgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAACIAAAAAACIAAAAAABIAAAAAAAIAAAAAACgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAADbwAAAAAAIAAAAAADIAAAAAACIAAAAAADgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAbwAAAAAAIAAAAAADIAAAAAACgQAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - version: 6 + tiles: bwAAAAAAAIEAAAAAAACBAAAAAAAAAAAAAAAAAAAAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHMAAAAAAwBgAAAAAAMAgQAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABzAAAAAAIAYAAAAAAAAIEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAcwAAAAACAGAAAAAAAwCBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHMAAAAAAwBgAAAAAAAAgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABvAAAAAAAAgQAAAAAAAIEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYAAAAAACAGAAAAAAAwCBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGAAAAAAAQBgAAAAAAIAgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABgAAAAAAEAYAAAAAAAAIEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYAAAAAACAGAAAAAAAgCBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAG8AAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAIAIAAAAAABACAAAAAAAQAgAAAAAAAAgQAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAADACAAAAAAAgAgAAAAAAAAIAAAAAAAACAAAAAAAACBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAgAgAAAAAAIAIAAAAAAAACAAAAAAAAAgAAAAAAAAgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAMAbwAAAAAAACAAAAAAAAAgAAAAAAAAIAAAAAAAAIEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAG8AAAAAAAAgAAAAAAAAIAAAAAAAAIEAAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA== + version: 7 0,-1: ind: 0,-1 - tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAgQAAAAAAgQAAAAAAgQAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAgQAAAAAAgQAAAAAAgQAAAAAAgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAgQAAAAAAgQAAAAAAgQAAAAAAgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAAQAAAAAAgQAAAAAAAAAAAAAAgAAAAAAAgQAAAAAAgQAAAAAAcQAAAAABcQAAAAADgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAbwAAAAAAbwAAAAAAgQAAAAAAgQAAAAAAgQAAAAAAcQAAAAAAcQAAAAADcQAAAAAAcQAAAAAAgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJgAAAAAAJgAAAAAAYAAAAAACYAAAAAABgQAAAAAAgQAAAAAAbwAAAAAAgQAAAAAAgQAAAAAAgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJgAAAAAAJgAAAAAAYAAAAAABYAAAAAABbwAAAAAAYAAAAAABYAAAAAABYAAAAAACgQAAAAAAgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJgAAAAAAJgAAAAAAYAAAAAACYAAAAAACbwAAAAAAYAAAAAAAYAAAAAACYAAAAAABbwAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYAAAAAACYAAAAAACYAAAAAABgQAAAAAAgQAAAAAAYAAAAAABYAAAAAABYAAAAAACbwAAAAAAgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYAAAAAACYAAAAAADgQAAAAAAgAAAAAAAAAAAAAAAgQAAAAAAYAAAAAADYAAAAAABbwAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - version: 6 + tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAAAEAAAAAAACBAAAAAAAAAAAAAAAAAIAAAAAAAACBAAAAAAAAgQAAAAAAAHEAAAAAAQBxAAAAAAMAgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAG8AAAAAAABvAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAAcQAAAAAAAHEAAAAAAwBxAAAAAAAAcQAAAAAAAIEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAmAAAAAAAAJgAAAAAAAGAAAAAAAgBgAAAAAAEAgQAAAAAAAIEAAAAAAABvAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJgAAAAAAACYAAAAAAABgAAAAAAEAYAAAAAABAG8AAAAAAABgAAAAAAEAYAAAAAABAGAAAAAAAgCBAAAAAAAAgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACYAAAAAAAAmAAAAAAAAYAAAAAACAGAAAAAAAgBvAAAAAAAAYAAAAAAAAGAAAAAAAgBgAAAAAAEAbwAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABgAAAAAAIAYAAAAAACAGAAAAAAAQCBAAAAAAAAgQAAAAAAAGAAAAAAAQBgAAAAAAEAYAAAAAACAG8AAAAAAACBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYAAAAAACAGAAAAAAAwCBAAAAAAAAgAAAAAAAAAAAAAAAAACBAAAAAAAAYAAAAAADAGAAAAAAAQBvAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA== + version: 7 -1,0: ind: -1,0 - tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAgQAAAAAAgQAAAAAAgQAAAAAAgQAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAgQAAAAAAgQAAAAAAgQAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAYAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAYAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAYAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAYAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAYAAAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAYAAAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAgQAAAAAAgQAAAAAAgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAgQAAAAAAIAAAAAACIAAAAAADIAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAIAAAAAADIAAAAAAAIAAAAAABIAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAIAAAAAACIAAAAAAAIAAAAAADIAAAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAIAAAAAAAIAAAAAABIAAAAAADbwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAgQAAAAAAIAAAAAADIAAAAAABbwAAAAAA - version: 6 + tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAAAAAAAAAAAAAAAAAAAACBAAAAAAAAgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAAGAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIEAAAAAAABgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACBAAAAAAAAYAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAAGAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIEAAAAAAACBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACBAAAAAAAAYAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAAGAAAAAAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIEAAAAAAABgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACBAAAAAAAAYAAAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAACBAAAAAAAAIAAAAAAAACAAAAAAAAAgAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACBAAAAAAAAIAAAAAAAACAAAAAAAAAgAAAAAAEAIAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAACAAAAAAAAAgAAAAAAAAIAAAAAAAACAAAAAAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIEAAAAAAAAgAAAAAAAAIAAAAAAAACAAAAAAAABvAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAgQAAAAAAACAAAAAAAAAgAAAAAAAAbwAAAAAAAA== + version: 7 -1,-1: ind: -1,-1 - tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAgQAAAAAAgQAAAAAAgQAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAgQAAAAAAgQAAAAAAgQAAAAAAgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAgQAAAAAAgQAAAAAAgQAAAAAAgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAcQAAAAAAcQAAAAADgQAAAAAAgQAAAAAAgAAAAAAAAAAAAAAAgQAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAcQAAAAABcQAAAAADcQAAAAACcQAAAAADgQAAAAAAgQAAAAAAgQAAAAAAbwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAgQAAAAAAgQAAAAAAbwAAAAAAgQAAAAAAgQAAAAAAYAAAAAABYAAAAAABJgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAgQAAAAAAYAAAAAABYAAAAAABYAAAAAADbwAAAAAAYAAAAAADYAAAAAAAJgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAbwAAAAAAYAAAAAADYAAAAAACYAAAAAADbwAAAAAAYAAAAAADYAAAAAABJgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAbwAAAAAAYAAAAAABYAAAAAACYAAAAAABgQAAAAAAgQAAAAAAYAAAAAADYAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAbwAAAAAAYAAAAAACYAAAAAAAgQAAAAAAAAAAAAAAgAAAAAAAgQAAAAAAYAAAAAAD - version: 6 + tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIEAAAAAAABxAAAAAAAAcQAAAAADAIEAAAAAAACBAAAAAAAAgAAAAAAAAAAAAAAAAACBAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACBAAAAAAAAcQAAAAABAHEAAAAAAwBxAAAAAAIAcQAAAAADAIEAAAAAAACBAAAAAAAAgQAAAAAAAG8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAAbwAAAAAAAIEAAAAAAACBAAAAAAAAYAAAAAABAGAAAAAAAQAmAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIEAAAAAAACBAAAAAAAAYAAAAAABAGAAAAAAAQBgAAAAAAMAbwAAAAAAAGAAAAAAAwBgAAAAAAAAJgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAbwAAAAAAAGAAAAAAAwBgAAAAAAIAYAAAAAADAG8AAAAAAABgAAAAAAMAYAAAAAABACYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAAG8AAAAAAABgAAAAAAEAYAAAAAACAGAAAAAAAQCBAAAAAAAAgQAAAAAAAGAAAAAAAwBgAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAABvAAAAAAAAYAAAAAACAGAAAAAAAACBAAAAAAAAAAAAAAAAAIAAAAAAAACBAAAAAAAAYAAAAAADAA== + version: 7 -1,1: ind: -1,1 - tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAgQAAAAAAIAAAAAABbwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAgQAAAAAAgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - version: 6 + tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAIEAAAAAAAAgAAAAAAAAbwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA== + version: 7 0,1: ind: 0,1 - tiles: gQAAAAAAbwAAAAAAIAAAAAABgQAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAgQAAAAAAgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - version: 6 + tiles: gQAAAAAAAG8AAAAAAAAgAAAAAAAAgQAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA== + version: 7 - type: Broadphase - type: Physics bodyStatus: InAir @@ -60,6 +71,7 @@ entities: - type: OccluderTree - type: SpreaderGrid - type: Shuttle + dampingModifier: 0.25 - type: GridPathfinding - type: Gravity gravityShakeSound: !type:SoundPathSpecifier @@ -409,6 +421,7 @@ entities: chunkSize: 4 - type: GasTileOverlay - type: RadiationGridResistance + - type: ImplicitRoof - proto: AirAlarm entities: - uid: 502 @@ -420,6 +433,8 @@ entities: devices: - 494 - 493 + - type: Fixtures + fixtures: {} - uid: 506 components: - type: Transform @@ -429,6 +444,8 @@ entities: - type: DeviceList devices: - 505 + - type: Fixtures + fixtures: {} - uid: 507 components: - type: Transform @@ -437,6 +454,17 @@ entities: - type: DeviceList devices: - 504 + - type: Fixtures + fixtures: {} +- proto: AirAlarmVox + entities: + - uid: 566 + components: + - type: Transform + pos: -2.5,-1.5 + parent: 1 + - type: Fixtures + fixtures: {} - proto: AirCanister entities: - uid: 500 @@ -457,7 +485,7 @@ entities: bodyType: Static - proto: Airlock entities: - - uid: 227 + - uid: 166 components: - type: Transform pos: 0.5,10.5 @@ -594,11 +622,15 @@ entities: rot: 3.141592653589793 rad pos: 1.5,10.5 parent: 1 + - type: Fixtures + fixtures: {} - uid: 503 components: - type: Transform pos: -1.5,-0.5 parent: 1 + - type: Fixtures + fixtures: {} - proto: AtmosDeviceFanDirectional entities: - uid: 555 @@ -1509,26 +1541,29 @@ entities: - type: Transform pos: -0.5,13.5 parent: 1 -- proto: ComputerSurveillanceWirelessCameraMonitor - entities: - - uid: 166 + - uid: 178 components: - type: Transform rot: 1.5707963267948966 rad pos: -3.5,14.5 parent: 1 - - uid: 178 + - uid: 227 components: - type: Transform rot: -1.5707963267948966 rad pos: 4.5,14.5 parent: 1 -- proto: CrateEngineeringElectricalSupplies +- proto: CrateFilledSpawner entities: - - uid: 533 + - uid: 534 components: - type: Transform - pos: 1.5,-2.5 + pos: -0.5,-4.5 + parent: 1 + - uid: 536 + components: + - type: Transform + pos: -0.5,-2.5 parent: 1 - proto: CrateFunArtSupplies entities: @@ -1537,26 +1572,12 @@ entities: - type: Transform pos: 0.5,-3.5 parent: 1 -- proto: CrateServiceBooks +- proto: CratePermaEscapeSpawner entities: - - uid: 534 + - uid: 565 components: - type: Transform - pos: -0.5,-4.5 - parent: 1 -- proto: CrateVendingMachineRestockDinnerwareFilled - entities: - - uid: 537 - components: - - type: Transform - pos: -0.5,-2.5 - parent: 1 -- proto: CrateVendingMachineRestockHotDrinksFilled - entities: - - uid: 536 - components: - - type: Transform - pos: 0.5,-2.5 + pos: 1.5,-4.5 parent: 1 - proto: DefibrillatorCabinetFilled entities: @@ -1565,6 +1586,8 @@ entities: - type: Transform pos: 1.5,5.5 parent: 1 + - type: Fixtures + fixtures: {} - proto: EncryptionKeyFreelance entities: - uid: 550 @@ -2645,6 +2668,13 @@ entities: - type: Transform pos: 1.3176541,4.7092643 parent: 1 +- proto: LootSpawnerRandomCrateEngineering + entities: + - uid: 533 + components: + - type: Transform + pos: 1.5,-2.5 + parent: 1 - proto: MedicalBed entities: - uid: 196 @@ -2854,6 +2884,13 @@ entities: - type: Transform pos: 3.5,11.5 parent: 1 +- proto: SalvageMaterialCrateSpawner + entities: + - uid: 537 + components: + - type: Transform + pos: 0.5,-2.5 + parent: 1 - proto: SecurityVisitorSpawner entities: - uid: 546 @@ -2883,6 +2920,10 @@ entities: showEnts: False occludes: True ent: 162 + cell_slot: !type:ContainerSlot + showEnts: False + occludes: True + ent: null - proto: ShuttleWindow entities: - uid: 2 @@ -3022,11 +3063,16 @@ entities: - type: DeviceLinkSource linkedPorts: 375: - - Pressed: Toggle + - - Pressed + - Toggle 376: - - Pressed: Toggle + - - Pressed + - Toggle 377: - - Pressed: Toggle + - - Pressed + - Toggle + - type: Fixtures + fixtures: {} - uid: 382 components: - type: Transform @@ -3035,11 +3081,16 @@ entities: - type: DeviceLinkSource linkedPorts: 378: - - Pressed: Toggle + - - Pressed + - Toggle 379: - - Pressed: Toggle + - - Pressed + - Toggle 380: - - Pressed: Toggle + - - Pressed + - Toggle + - type: Fixtures + fixtures: {} - uid: 385 components: - type: Transform @@ -3049,11 +3100,16 @@ entities: - type: DeviceLinkSource linkedPorts: 358: - - Pressed: Toggle + - - Pressed + - Toggle 357: - - Pressed: Toggle + - - Pressed + - Toggle 356: - - Pressed: Toggle + - - Pressed + - Toggle + - type: Fixtures + fixtures: {} - proto: SMESBasic entities: - uid: 323 @@ -3183,6 +3239,20 @@ entities: - type: Transform pos: 1.6926541,4.5530143 parent: 1 +- proto: Table + entities: + - uid: 562 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: -0.5,-0.5 + parent: 1 + - uid: 563 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 1.5,-0.5 + parent: 1 - proto: TableGlass entities: - uid: 198 @@ -3298,6 +3368,13 @@ entities: - type: Transform pos: -5.5,1.5 parent: 1 +- proto: ToolboxMechanicalFilledAllTools + entities: + - uid: 564 + components: + - type: Transform + pos: -0.5382964,-0.35850996 + parent: 1 - proto: TwoWayLever entities: - uid: 191 @@ -3310,11 +3387,16 @@ entities: - type: DeviceLinkSource linkedPorts: 161: - - Left: On - - Left: Trigger - - Right: On - - Right: Trigger - - Middle: Off + - - Left + - On + - - Left + - Trigger + - - Right + - On + - - Right + - Trigger + - - Middle + - Off - proto: VendingMachineCigs entities: - uid: 517 diff --git a/Resources/Maps/Shuttles/ShuttleEvent/flatline.yml b/Resources/Maps/Shuttles/ShuttleEvent/flatline.yml index b623ec68131..0008654ea3a 100644 --- a/Resources/Maps/Shuttles/ShuttleEvent/flatline.yml +++ b/Resources/Maps/Shuttles/ShuttleEvent/flatline.yml @@ -1,6 +1,17 @@ meta: - format: 6 - postmapinit: false + format: 7 + category: Grid + engineVersion: 266.0.0 + forkId: "" + forkVersion: "" + time: 08/18/2025 00:22:49 + entityCount: 232 +maps: [] +grids: +- 1 +orphans: +- 1 +nullspace: [] tilemap: 0: Space 1: FloorMetalDiamond @@ -24,20 +35,20 @@ entities: chunks: 0,0: ind: 0,0 - tiles: gQAAAAAAgQAAAAAAgQAAAAAAgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAcQAAAAAAgQAAAAAAgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAbwAAAAAAcQAAAAACgQAAAAAAgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAcQAAAAABgQAAAAAAgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAgQAAAAAAgQAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - version: 6 + tiles: gQAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIEAAAAAAABxAAAAAAAAgQAAAAAAAIEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABvAAAAAAAAcQAAAAACAIEAAAAAAACBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAAHEAAAAAAQCBAAAAAAAAgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA== + version: 7 -1,0: ind: -1,0 - tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAgQAAAAAAbwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAdQAAAAAAdQAAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAdQAAAAADdQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAdQAAAAABdQAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAdQAAAAACdQAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAgQAAAAAAgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - version: 6 + tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAACBAAAAAAAAbwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACBAAAAAAAAdQAAAAAAAHUAAAAAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAAHUAAAAAAwB1AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIEAAAAAAAB1AAAAAAEAdQAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACBAAAAAAAAdQAAAAACAHUAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAIEAAAAAAACBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA== + version: 7 -1,-1: ind: -1,-1 - tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAgQAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAgQAAAAAAdwAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAdwAAAAAAdwAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAdwAAAAAAdwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAgQAAAAAAdwAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAQAAAAAAdwAAAAAC - version: 6 + tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAgQAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAIEAAAAAAAB3AAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIEAAAAAAAB3AAAAAAAAdwAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACBAAAAAAAAdwAAAAAAAHcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAIEAAAAAAAB3AAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAABAAAAAAAAdwAAAAACAA== + version: 7 0,-1: ind: 0,-1 - tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAAQAAAAAAgQAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAdwAAAAABdwAAAAADgQAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAdwAAAAACdwAAAAACdwAAAAADgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAdwAAAAABdwAAAAABgQAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAdwAAAAACdwAAAAACgQAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAgQAAAAAAgQAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - version: 6 + tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIEAAAAAAAABAAAAAAAAgQAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB3AAAAAAEAdwAAAAADAIEAAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAdwAAAAACAHcAAAAAAgB3AAAAAAMAgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHcAAAAAAQB3AAAAAAEAgQAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB3AAAAAAIAdwAAAAACAIEAAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA== + version: 7 - type: Broadphase - type: Physics bodyStatus: InAir @@ -50,6 +61,7 @@ entities: - type: OccluderTree - type: SpreaderGrid - type: Shuttle + dampingModifier: 0.25 - type: GridPathfinding - type: Gravity gravityShakeSound: !type:SoundPathSpecifier @@ -300,6 +312,7 @@ entities: chunkSize: 4 - type: GasTileOverlay - type: RadiationGridResistance + - type: ImplicitRoof - proto: AirCanister entities: - uid: 98 @@ -360,6 +373,8 @@ entities: - type: Transform pos: 1.5,-0.49999997 parent: 1 + - type: Fixtures + fixtures: {} - proto: AtmosDeviceFanDirectional entities: - uid: 104 @@ -387,37 +402,17 @@ entities: parent: 1 - proto: Bloodpack entities: - - uid: 112 - components: - - type: Transform - pos: 0.53517246,-1.2409748 - parent: 1 - - uid: 113 - components: - - type: Transform - pos: 0.56642246,-1.449308 - parent: 1 - uid: 114 components: - type: Transform - pos: 0.81642246,-1.2409748 - parent: 1 - - uid: 115 - components: - - type: Transform - pos: 0.8685057,-1.3763914 + pos: 1.1232822,-1.2575787 parent: 1 - proto: Brutepack entities: - - uid: 235 - components: - - type: Transform - pos: 1.8104452,-1.8881177 - parent: 1 - uid: 236 components: - type: Transform - pos: 1.8104452,-2.0756176 + pos: 1.3732822,-2.3513286 parent: 1 - proto: ButtonFrameCaution entities: @@ -758,6 +753,13 @@ entities: rot: 3.141592653589793 rad pos: -0.49999997,3.5 parent: 1 +- proto: ChemistryBottleEpinephrine + entities: + - uid: 124 + components: + - type: Transform + pos: 1.3524488,-1.965912 + parent: 1 - proto: ClosetWallEmergencyFilledRandom entities: - uid: 204 @@ -800,6 +802,8 @@ entities: - 212 - 213 - 215 + - type: Fixtures + fixtures: {} - proto: ClothingEyesHudMedical entities: - uid: 233 @@ -906,6 +910,8 @@ entities: rot: 1.5707963267948966 rad pos: -1.5,-1.5 parent: 1 + - type: Fixtures + fixtures: {} - proto: DoubleEmergencyOxygenTankFilled entities: - uid: 209 @@ -932,18 +938,6 @@ entities: - type: Transform pos: -1.6332935,-3.5610697 parent: 1 -- proto: EpinephrineChemistryBottle - entities: - - uid: 124 - components: - - type: Transform - pos: 1.3126785,-1.980415 - parent: 1 - - uid: 125 - components: - - type: Transform - pos: 1.3458732,-1.7341763 - parent: 1 - proto: ExtinguisherCabinetFilled entities: - uid: 232 @@ -952,6 +946,8 @@ entities: rot: 1.5707963267948966 rad pos: 2.5,-2.5 parent: 1 + - type: Fixtures + fixtures: {} - proto: FloorDrain entities: - uid: 198 @@ -1162,20 +1158,10 @@ entities: color: '#FF1212FF' - proto: Gauze entities: - - uid: 116 - components: - - type: Transform - pos: 1.6271232,-1.2133429 - parent: 1 - - uid: 117 - components: - - type: Transform - pos: 1.4083732,-1.3175095 - parent: 1 - uid: 118 components: - type: Transform - pos: 1.76254,-1.4529263 + pos: 0.8107822,-1.528412 parent: 1 - proto: GeneratorBasic15kW entities: @@ -1270,10 +1256,11 @@ entities: parent: 1 - proto: HandheldHealthAnalyzerUnpowered entities: - - uid: 132 + - uid: 112 components: - type: Transform - pos: 1.7501786,-2.5637481 + rot: -1.5707963267948966 rad + pos: 0.7066155,-1.2992454 parent: 1 - proto: IntercomMedical entities: @@ -1283,6 +1270,8 @@ entities: rot: -1.5707963267948966 rad pos: 0.5,-0.49999997 parent: 1 + - type: Fixtures + fixtures: {} - proto: LightBulb entities: - uid: 217 @@ -1376,12 +1365,7 @@ entities: - uid: 130 components: - type: Transform - pos: 1.4041953,-1.6485344 - parent: 1 - - uid: 237 - components: - - type: Transform - pos: 1.6750284,-1.7527012 + pos: 1.2795322,-1.6429952 parent: 1 - proto: OxygenTankFilled entities: @@ -1548,11 +1532,11 @@ entities: parent: 1 - proto: Scalpel entities: - - uid: 199 + - uid: 115 components: - type: Transform rot: -1.5707963267948966 rad - pos: 1.0872557,-1.386808 + pos: 0.4357822,-1.3825787 parent: 1 - proto: ShuttleWindow entities: @@ -1624,19 +1608,28 @@ entities: - type: DeviceLinkSource linkedPorts: 216: - - Pressed: Toggle + - - Pressed + - Toggle 227: - - Pressed: Toggle + - - Pressed + - Toggle 218: - - Pressed: Toggle + - - Pressed + - Toggle 229: - - Pressed: Toggle + - - Pressed + - Toggle 223: - - Pressed: Toggle + - - Pressed + - Toggle 225: - - Pressed: Toggle + - - Pressed + - Toggle 220: - - Pressed: Toggle + - - Pressed + - Toggle + - type: Fixtures + fixtures: {} - proto: SMESBasic entities: - uid: 43 @@ -1663,28 +1656,35 @@ entities: - uid: 120 components: - type: Transform - pos: 1.41879,-2.1404262 + pos: 1.5920322,-1.559662 parent: 1 - proto: SyringeDermaline entities: - uid: 121 components: - type: Transform - pos: 1.66879,-2.119593 + pos: 1.5607822,-2.111745 parent: 1 - proto: SyringeInaprovaline entities: - - uid: 123 + - uid: 116 components: - type: Transform - pos: 1.3979566,-2.4112594 + pos: 1.6441156,-1.7575787 + parent: 1 +- proto: SyringeSigynate + entities: + - uid: 117 + components: + - type: Transform + pos: 1.6753656,-2.5492454 parent: 1 - proto: SyringeTranexamicAcid entities: - - uid: 122 + - uid: 113 components: - type: Transform - pos: 1.8042066,-2.1925094 + pos: 1.6336988,-2.3513286 parent: 1 - proto: TableReinforced entities: @@ -1747,16 +1747,29 @@ entities: parent: 1 - proto: Tourniquet entities: - - uid: 133 - components: - - type: Transform - pos: 1.9146119,-1.4193677 - parent: 1 - uid: 134 components: - type: Transform - pos: 1.8625284,-1.221451 + pos: 1.5086988,-1.2367454 parent: 1 +- proto: VendingMachineWallMedicalCivilian + entities: + - uid: 122 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: -1.5,-4.5 + parent: 1 + - type: Fixtures + fixtures: {} + - uid: 123 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 2.5,-4.5 + parent: 1 + - type: Fixtures + fixtures: {} - proto: VisitorParamedicSpawner entities: - uid: 214 diff --git a/Resources/Maps/Shuttles/ShuttleEvent/incorporation.yml b/Resources/Maps/Shuttles/ShuttleEvent/incorporation.yml index bbcef8f9330..63e2c7f6f31 100644 --- a/Resources/Maps/Shuttles/ShuttleEvent/incorporation.yml +++ b/Resources/Maps/Shuttles/ShuttleEvent/incorporation.yml @@ -1,6 +1,17 @@ meta: - format: 6 - postmapinit: false + format: 7 + category: Grid + engineVersion: 266.0.0 + forkId: "" + forkVersion: "" + time: 08/18/2025 04:40:53 + entityCount: 876 +maps: [] +grids: +- 1 +orphans: +- 1 +nullspace: [] tilemap: 0: Space 32: FloorDark @@ -32,28 +43,28 @@ entities: chunks: 0,0: ind: 0,0 - tiles: gQAAAAAAgQAAAAAAgQAAAAAAbwAAAAAAgQAAAAAAfQAAAAABfQAAAAADfQAAAAADgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYAAAAAAAYAAAAAACYAAAAAACYAAAAAABgQAAAAAAfQAAAAABfQAAAAAAfQAAAAABgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYAAAAAACYAAAAAABYAAAAAACYAAAAAAAgQAAAAAAfQAAAAAAfQAAAAABgQAAAAAAgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAABIAAAAAABIAAAAAADIAAAAAADbwAAAAAAfQAAAAABfQAAAAACgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAIAAAAAABIAAAAAADIAAAAAADgQAAAAAAfwAAAAABgQAAAAAAgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAABIAAAAAABIAAAAAAAIAAAAAADgQAAAAAAfQAAAAAAgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAIAAAAAABIAAAAAACIAAAAAABgQAAAAAAgQAAAAAAgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAIAAAAAADgQAAAAAAgQAAAAAAgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAgQAAAAAAgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - version: 6 + tiles: gQAAAAAAAIEAAAAAAACBAAAAAAAAbwAAAAAAAIEAAAAAAAB9AAAAAAEAfQAAAAADAH0AAAAAAwCBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGAAAAAAAABgAAAAAAIAYAAAAAACAGAAAAAAAQCBAAAAAAAAfQAAAAABAH0AAAAAAAB9AAAAAAEAgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABgAAAAAAIAYAAAAAABAGAAAAAAAgBgAAAAAAAAgQAAAAAAAH0AAAAAAAB9AAAAAAEAgQAAAAAAAIEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAABACAAAAAAAQAgAAAAAAMAIAAAAAADAG8AAAAAAAB9AAAAAAEAfQAAAAACAIEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAgAAAAAAEAIAAAAAADACAAAAAAAwCBAAAAAAAAfwAAAAABAIEAAAAAAACBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAEAIAAAAAABACAAAAAAAAAgAAAAAAMAgQAAAAAAAH0AAAAAAACBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAACAAAAAAAQAgAAAAAAIAIAAAAAABAIEAAAAAAACBAAAAAAAAgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAgAAAAAAMAgQAAAAAAAIEAAAAAAACBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA== + version: 7 -1,0: ind: -1,0 - tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAbwAAAAAAYAAAAAACYAAAAAAAYAAAAAACgQAAAAAAgQAAAAAAgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAbwAAAAAAbwAAAAAAYAAAAAACYAAAAAADYAAAAAADbwAAAAAAYAAAAAACYAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAgQAAAAAAgQAAAAAAbwAAAAAAgQAAAAAAYAAAAAACYAAAAAADYAAAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAcQAAAAAAcQAAAAADgQAAAAAAYAAAAAACYAAAAAAAIAAAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAgQAAAAAAcQAAAAAAgQAAAAAAIAAAAAAAIAAAAAABIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAcQAAAAABgQAAAAAAIAAAAAADIAAAAAACIAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAgQAAAAAAgQAAAAAAIAAAAAACIAAAAAACIAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAgQAAAAAAgQAAAAAAIAAAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - version: 6 + tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACBAAAAAAAAbwAAAAAAAGAAAAAAAgBgAAAAAAAAYAAAAAACAIEAAAAAAACBAAAAAAAAgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAbwAAAAAAAG8AAAAAAABgAAAAAAIAYAAAAAADAGAAAAAAAwBvAAAAAAAAYAAAAAACAGAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAAG8AAAAAAACBAAAAAAAAYAAAAAACAGAAAAAAAwBgAAAAAAMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAAHEAAAAAAABxAAAAAAMAgQAAAAAAAGAAAAAAAgBgAAAAAAAAIAAAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIEAAAAAAACBAAAAAAAAcQAAAAAAAIEAAAAAAAAgAAAAAAAAIAAAAAABACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAAHEAAAAAAQCBAAAAAAAAIAAAAAADACAAAAAAAgAgAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAACAAAAAAAgAgAAAAAAIAIAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAACAAAAAAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIEAAAAAAACBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA== + version: 7 0,-1: ind: 0,-1 - tiles: awAAAAADYAAAAAAAYAAAAAABbwAAAAAAYAAAAAADYAAAAAADYAAAAAABYAAAAAABgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAawAAAAABYAAAAAABYAAAAAACgQAAAAAAYAAAAAABYAAAAAADYAAAAAAAYAAAAAADgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAawAAAAADcQAAAAAAgQAAAAAAgQAAAAAAgQAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAbwAAAAAAgQAAAAAAgQAAAAAAAAAAAAAAgQAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAgQAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAgQAAAAAAgAAAAAAAgQAAAAAAgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAgQAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAgQAAAAAAgQAAAAAAgQAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAbwAAAAAAgQAAAAAAgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYAAAAAAAbwAAAAAAgQAAAAAAgQAAAAAAgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYAAAAAABYAAAAAAAgQAAAAAAcwAAAAAAgQAAAAAAgQAAAAAAgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYAAAAAACYAAAAAADcwAAAAABcwAAAAADcwAAAAAAcwAAAAACgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYAAAAAABYAAAAAACgQAAAAAAcwAAAAACdwAAAAABdwAAAAADgQAAAAAAgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAbwAAAAAAgQAAAAAAgQAAAAAAcwAAAAABdwAAAAACdwAAAAABcwAAAAADgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUwAAAAAAUwAAAAAAgQAAAAAAcwAAAAAAcwAAAAADgQAAAAAAgQAAAAAAgQAAAAAAgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUwAAAAAAUwAAAAAAgQAAAAAAcwAAAAABgQAAAAAAgQAAAAAAfQAAAAADfQAAAAAAgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - version: 6 + tiles: awAAAAADAGAAAAAAAABgAAAAAAEAbwAAAAAAAGAAAAAAAwBgAAAAAAMAYAAAAAABAGAAAAAAAQCBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGsAAAAAAQBgAAAAAAEAYAAAAAACAIEAAAAAAABgAAAAAAEAYAAAAAADAGAAAAAAAABgAAAAAAMAgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABrAAAAAAMAcQAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAAFIAAAAAAABSAAAAAAAAUgAAAAAAAIEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAbwAAAAAAAIEAAAAAAACBAAAAAAAAAAAAAAAAAIEAAAAAAABSAAAAAAAAUgAAAAAAAFIAAAAAAACBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIEAAAAAAACBAAAAAAAAAAAAAAAAAAAAAAAAAACBAAAAAAAAgQAAAAAAAIAAAAAAAACBAAAAAAAAgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACBAAAAAAAAgQAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAAIEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAgAAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIEAAAAAAACBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABvAAAAAAAAgQAAAAAAAIEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYAAAAAAAAG8AAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGAAAAAAAQBgAAAAAAAAgQAAAAAAAHMAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABgAAAAAAIAYAAAAAADAHMAAAAAAQBzAAAAAAMAcwAAAAAAAHMAAAAAAgCBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYAAAAAABAGAAAAAAAgCBAAAAAAAAcwAAAAACAHcAAAAAAQB3AAAAAAMAgQAAAAAAAIEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAG8AAAAAAACBAAAAAAAAgQAAAAAAAHMAAAAAAQB3AAAAAAIAdwAAAAABAHMAAAAAAwCBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABTAAAAAAAAUwAAAAAAAIEAAAAAAABzAAAAAAAAcwAAAAADAIEAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUwAAAAAAAFMAAAAAAACBAAAAAAAAcwAAAAABAIEAAAAAAACBAAAAAAAAfQAAAAADAH0AAAAAAACBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA== + version: 7 -1,-1: ind: -1,-1 - tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAYAAAAAAAYAAAAAABYAAAAAACYAAAAAADbwAAAAAAYAAAAAAAYAAAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAYAAAAAADYAAAAAADYAAAAAACYAAAAAAAgQAAAAAAYAAAAAAAYAAAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAgQAAAAAAgQAAAAAAgQAAAAAAcQAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAgQAAAAAAAAAAAAAAgQAAAAAAgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAgQAAAAAAgAAAAAAAgQAAAAAAgQAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAgQAAAAAAgQAAAAAAgQAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAgQAAAAAAgQAAAAAAbwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAgQAAAAAAbwAAAAAAbwAAAAAAbwAAAAAAYAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAbwAAAAAAYAAAAAACYAAAAAACYAAAAAACYAAAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAbwAAAAAAYAAAAAABYAAAAAACYAAAAAAAYAAAAAACYAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAbwAAAAAAYAAAAAACYAAAAAACbwAAAAAAgQAAAAAAbwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAgQAAAAAAbwAAAAAAYAAAAAABYAAAAAABgQAAAAAAUwAAAAAAUwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAbwAAAAAAbwAAAAAAYAAAAAADYAAAAAACYAAAAAAAgQAAAAAAUwAAAAAAUwAAAAAA - version: 6 + tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACBAAAAAAAAYAAAAAAAAGAAAAAAAQBgAAAAAAIAYAAAAAADAG8AAAAAAABgAAAAAAAAYAAAAAADAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAAGAAAAAAAwBgAAAAAAMAYAAAAAACAGAAAAAAAACBAAAAAAAAYAAAAAAAAGAAAAAAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIEAAAAAAABSAAAAAAAAUgAAAAAAAFIAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAABxAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACBAAAAAAAAUgAAAAAAAFIAAAAAAABSAAAAAAAAgQAAAAAAAAAAAAAAAACBAAAAAAAAgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAAIEAAAAAAACAAAAAAAAAgQAAAAAAAIEAAAAAAAAAAAAAAAAAAAAAAAAAAIEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAACBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAIAAAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIEAAAAAAACBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAAbwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACBAAAAAAAAgQAAAAAAAG8AAAAAAABvAAAAAAAAbwAAAAAAAGAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAAG8AAAAAAABgAAAAAAIAYAAAAAACAGAAAAAAAgBgAAAAAAMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAAG8AAAAAAABgAAAAAAEAYAAAAAACAGAAAAAAAABgAAAAAAIAYAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIEAAAAAAABvAAAAAAAAYAAAAAACAGAAAAAAAgBvAAAAAAAAgQAAAAAAAG8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIEAAAAAAACBAAAAAAAAbwAAAAAAAGAAAAAAAQBgAAAAAAEAgQAAAAAAAFMAAAAAAABTAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABvAAAAAAAAbwAAAAAAAGAAAAAAAwBgAAAAAAIAYAAAAAAAAIEAAAAAAABTAAAAAAAAUwAAAAAAAA== + version: 7 -1,-2: ind: -1,-2 - tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAgQAAAAAAgQAAAAAAgQAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAgQAAAAAAgQAAAAAAgQAAAAAAgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAgQAAAAAAcAAAAAAAgQAAAAAAgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAcAAAAAAAcAAAAAAAcAAAAAAAgQAAAAAAgQAAAAAAAAAAAAAAgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAYAAAAAABYAAAAAAAYAAAAAABYAAAAAACgQAAAAAAgQAAAAAAgQAAAAAA - version: 6 + tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAACAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAAIEAAAAAAABwAAAAAAAAgQAAAAAAAIEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIEAAAAAAABwAAAAAAAAcAAAAAAAAHAAAAAAAACBAAAAAAAAgQAAAAAAAAAAAAAAAACBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACBAAAAAAAAYAAAAAABAGAAAAAAAABgAAAAAAEAYAAAAAACAIEAAAAAAACBAAAAAAAAgQAAAAAAAA== + version: 7 0,-2: ind: 0,-2 - tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAgAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAgQAAAAAAgQAAAAAAgQAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAgQAAAAAAgQAAAAAAgQAAAAAAgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAgQAAAAAAcAAAAAAAgQAAAAAAgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAgQAAAAAAAAAAAAAAgQAAAAAAgQAAAAAAcAAAAAAAcAAAAAAAcAAAAAAAgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAbwAAAAAAgQAAAAAAgQAAAAAAgQAAAAAAYAAAAAABYAAAAAAAYAAAAAAAYAAAAAABgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - version: 6 + tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAIAAAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACBAAAAAAAAgQAAAAAAAHAAAAAAAACBAAAAAAAAgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAgQAAAAAAAAAAAAAAAACBAAAAAAAAgQAAAAAAAHAAAAAAAABwAAAAAAAAcAAAAAAAAIEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAbwAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAAGAAAAAAAQBgAAAAAAAAYAAAAAAAAGAAAAAAAQCBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA== + version: 7 - type: Broadphase - type: Physics bodyStatus: InAir @@ -66,6 +77,7 @@ entities: - type: OccluderTree - type: SpreaderGrid - type: Shuttle + dampingModifier: 0.25 - type: GridPathfinding - type: Gravity gravityShakeSound: !type:SoundPathSpecifier @@ -582,6 +594,7 @@ entities: chunkSize: 4 - type: GasTileOverlay - type: RadiationGridResistance + - type: ImplicitRoof - proto: AirAlarm entities: - uid: 855 @@ -594,6 +607,8 @@ entities: - 854 - 703 - 704 + - type: Fixtures + fixtures: {} - uid: 856 components: - type: Transform @@ -606,6 +621,8 @@ entities: - 619 - 616 - 618 + - type: Fixtures + fixtures: {} - uid: 857 components: - type: Transform @@ -620,6 +637,8 @@ entities: - 811 - 659 - 660 + - type: Fixtures + fixtures: {} - uid: 858 components: - type: Transform @@ -631,6 +650,8 @@ entities: - 853 - 611 - 626 + - type: Fixtures + fixtures: {} - proto: AirCanister entities: - uid: 770 @@ -789,11 +810,15 @@ entities: rot: 3.141592653589793 rad pos: -0.5,-16.5 parent: 1 + - type: Fixtures + fixtures: {} - uid: 456 components: - type: Transform pos: -1.5,-2.5 parent: 1 + - type: Fixtures + fixtures: {} - proto: AtmosDeviceFanDirectional entities: - uid: 733 @@ -925,27 +950,6 @@ entities: hard: True restitution: 0 friction: 0.4 -- proto: BorgModuleClowning - entities: - - uid: 779 - components: - - type: Transform - pos: -4.5,-17.5 - parent: 1 -- proto: BorgModuleService - entities: - - uid: 869 - components: - - type: Transform - pos: -4.5,-17.5 - parent: 1 -- proto: BorgModuleTool - entities: - - uid: 868 - components: - - type: Transform - pos: -4.5,-17.5 - parent: 1 - proto: BoxBeaker entities: - uid: 679 @@ -2402,20 +2406,26 @@ entities: rot: -1.5707963267948966 rad pos: 7.5,-15.5 parent: 1 + - type: AnalysisConsole + analyzerEntity: 398 - type: DeviceLinkSource linkedPorts: - 272: - - ArtifactAnalyzerSender: ArtifactAnalyzerReceiver + 398: + - - ArtifactAnalyzerSender + - ArtifactAnalyzerReceiver - uid: 784 components: - type: Transform rot: 1.5707963267948966 rad pos: -6.5,-15.5 parent: 1 + - type: AnalysisConsole + analyzerEntity: 272 - type: DeviceLinkSource linkedPorts: - 398: - - ArtifactAnalyzerSender: ArtifactAnalyzerReceiver + 272: + - - ArtifactAnalyzerSender + - ArtifactAnalyzerReceiver - proto: ComputerComms entities: - uid: 67 @@ -2480,54 +2490,25 @@ entities: - proto: CrateArtifactContainer entities: - uid: 766 - components: - - type: Transform - pos: 7.5,-16.5 - parent: 1 - - type: Lock - locked: False - - type: ContainerContainer - containers: - entity_storage: !type:Container - showEnts: False - occludes: True - ents: - - 767 - paper_label: !type:ContainerSlot - showEnts: False - occludes: True - ent: null - - uid: 768 components: - type: Transform pos: -6.5,-16.5 parent: 1 - type: Lock locked: False - - type: ContainerContainer - containers: - entity_storage: !type:Container - showEnts: False - occludes: True - ents: - - 769 - paper_label: !type:ContainerSlot - showEnts: False - occludes: True - ent: null -- proto: CrateMaterialGlass - entities: - - uid: 765 + - uid: 768 components: - type: Transform - pos: -6.496111,-14.5 + pos: 7.5,-16.5 parent: 1 -- proto: CrateMaterialPlastic + - type: Lock + locked: False +- proto: CrateFilledSpawner entities: - - uid: 785 + - uid: 779 components: - type: Transform - pos: 7.501801,-14.5 + pos: -1.5,-14.5 parent: 1 - proto: CrateMaterialSteel entities: @@ -2536,6 +2517,13 @@ entities: - type: Transform pos: -4.5,4.5 parent: 1 +- proto: CratePermaEscapeSpawner + entities: + - uid: 230 + components: + - type: Transform + pos: 2.5,-14.5 + parent: 1 - proto: CrowbarRed entities: - uid: 875 @@ -2557,6 +2545,8 @@ entities: - type: Transform pos: 5.5,-1.5 parent: 1 + - type: Fixtures + fixtures: {} - proto: DresserCaptainFilled entities: - uid: 410 @@ -2611,12 +2601,16 @@ entities: rot: 1.5707963267948966 rad pos: -2.5,-16.5 parent: 1 + - type: Fixtures + fixtures: {} - uid: 777 components: - type: Transform rot: -1.5707963267948966 rad pos: 3.5,-16.5 parent: 1 + - type: Fixtures + fixtures: {} - proto: FaxMachineCaptain entities: - uid: 743 @@ -4282,19 +4276,13 @@ entities: - uid: 272 components: - type: Transform - pos: 6.5,-12.5 + pos: -5.5,-12.5 parent: 1 - - type: ItemPlacer - placedEntities: - - 789 - uid: 398 components: - type: Transform - pos: -5.5,-12.5 + pos: 6.5,-12.5 parent: 1 - - type: ItemPlacer - placedEntities: - - 788 - proto: MedicalBed entities: - uid: 422 @@ -4309,16 +4297,16 @@ entities: parent: 1 - proto: NetworkConfigurator entities: + - uid: 785 + components: + - type: Transform + pos: -3.7083337,-14.34175 + parent: 1 - uid: 809 components: - type: Transform pos: 4.2934732,-14.35611 parent: 1 - - uid: 810 - components: - - type: Transform - pos: -3.716944,-14.345694 - parent: 1 - proto: PaperCaptainsThoughts entities: - uid: 744 @@ -4595,6 +4583,18 @@ entities: rot: -1.5707963267948966 rad pos: -2.5,-14.5 parent: 1 +- proto: SalvageMaterialCrateSpawner + entities: + - uid: 418 + components: + - type: Transform + pos: 7.5,-14.5 + parent: 1 + - uid: 765 + components: + - type: Transform + pos: -6.5,-14.5 + parent: 1 - proto: SecurityVisitorSpawner entities: - uid: 871 @@ -4859,9 +4859,13 @@ entities: - type: DeviceLinkSource linkedPorts: 289: - - Pressed: Toggle + - - Pressed + - Toggle 278: - - Pressed: DoorBolt + - - Pressed + - DoorBolt + - type: Fixtures + fixtures: {} - uid: 298 components: - type: Transform @@ -4871,7 +4875,10 @@ entities: - type: DeviceLinkSource linkedPorts: 261: - - Pressed: Toggle + - - Pressed + - Toggle + - type: Fixtures + fixtures: {} - uid: 308 components: - type: MetaData @@ -4882,9 +4889,13 @@ entities: - type: DeviceLinkSource linkedPorts: 307: - - Pressed: Toggle + - - Pressed + - Toggle 277: - - Pressed: DoorBolt + - - Pressed + - DoorBolt + - type: Fixtures + fixtures: {} - uid: 560 components: - type: Transform @@ -4894,7 +4905,10 @@ entities: - type: DeviceLinkSource linkedPorts: 562: - - Pressed: Toggle + - - Pressed + - Toggle + - type: Fixtures + fixtures: {} - uid: 795 components: - type: Transform @@ -4903,11 +4917,16 @@ entities: - type: DeviceLinkSource linkedPorts: 571: - - Pressed: Toggle + - - Pressed + - Toggle 443: - - Pressed: Toggle + - - Pressed + - Toggle 438: - - Pressed: Toggle + - - Pressed + - Toggle + - type: Fixtures + fixtures: {} - proto: SinkStemlessWater entities: - uid: 687 @@ -5286,48 +5305,18 @@ entities: - type: Transform pos: 5.5,-14.5 parent: 1 -- proto: VariedXenoArtifactItem +- proto: VendingMachineMedicalBase entities: - uid: 767 components: - type: Transform - parent: 766 - - type: XenoArtifact - - type: Physics - canCollide: False - - type: InsideEntityStorage + pos: 6.5,-2.5 + parent: 1 - uid: 769 - components: - - type: Transform - parent: 768 - - type: XenoArtifact - - type: Physics - canCollide: False - - type: InsideEntityStorage - - uid: 788 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: -5.5242987,-12.5 - parent: 1 - - uid: 789 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 6.506952,-12.5 - parent: 1 -- proto: VendingMachineMedical - entities: - - uid: 230 components: - type: Transform pos: 3.5,-5.5 parent: 1 - - uid: 418 - components: - - type: Transform - pos: 6.5,-2.5 - parent: 1 - proto: VendingMachineTankDispenserEVA entities: - uid: 28 diff --git a/Resources/Maps/Shuttles/ShuttleEvent/instigator.yml b/Resources/Maps/Shuttles/ShuttleEvent/instigator.yml index dd004830172..b67960cab4c 100644 --- a/Resources/Maps/Shuttles/ShuttleEvent/instigator.yml +++ b/Resources/Maps/Shuttles/ShuttleEvent/instigator.yml @@ -1,6 +1,17 @@ meta: - format: 6 - postmapinit: false + format: 7 + category: Grid + engineVersion: 266.0.0 + forkId: "" + forkVersion: "" + time: 08/18/2025 00:34:06 + entityCount: 541 +maps: [] +grids: +- 1 +orphans: +- 1 +nullspace: [] tilemap: 0: Space 86: FloorShuttleBlack @@ -23,20 +34,20 @@ entities: chunks: 0,0: ind: 0,0 - tiles: WwAAAAADWwAAAAABWwAAAAABgQAAAAAAgQAAAAAAWwAAAAADVgAAAAAAcAAAAAAAcQAAAAADcQAAAAAAgQAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWwAAAAABWwAAAAADWwAAAAACVgAAAAADgQAAAAAAgQAAAAAAVgAAAAACgQAAAAAAgQAAAAAAgQAAAAAAgQAAAAAAgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWwAAAAABWwAAAAAAWwAAAAADgQAAAAAAgQAAAAAAgQAAAAAAVgAAAAAAWwAAAAAAgQAAAAAAVgAAAAAAVgAAAAADcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWwAAAAAAWwAAAAAAWwAAAAAAgQAAAAAAgQAAAAAAgQAAAAAAVgAAAAABVgAAAAAAVgAAAAACVgAAAAAAVgAAAAABgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWwAAAAABWwAAAAABgQAAAAAAgQAAAAAAAAAAAAAAgAAAAAAAgQAAAAAAVgAAAAACVgAAAAADVgAAAAACVgAAAAACcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAgQAAAAAAgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAgQAAAAAAgQAAAAAAVgAAAAAAgQAAAAAAgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAgQAAAAAAVgAAAAACVgAAAAABVgAAAAAAgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAgQAAAAAAVgAAAAACVgAAAAABVgAAAAACgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAVgAAAAAAVgAAAAACVgAAAAABgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAVgAAAAABVgAAAAACgQAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAVgAAAAACVgAAAAACgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAVgAAAAAAVgAAAAADgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAgQAAAAAAgQAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - version: 6 + tiles: WwAAAAADAFsAAAAAAQBbAAAAAAEAgQAAAAAAAIEAAAAAAABbAAAAAAMAVgAAAAAAAHAAAAAAAABxAAAAAAMAcQAAAAAAAIEAAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFsAAAAAAQBbAAAAAAMAWwAAAAACAFYAAAAAAwCBAAAAAAAAgQAAAAAAAFYAAAAAAgCBAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABbAAAAAAEAWwAAAAAAAFsAAAAAAwCBAAAAAAAAgQAAAAAAAIEAAAAAAABWAAAAAAAAWwAAAAAAAIEAAAAAAABWAAAAAAAAVgAAAAADAHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWwAAAAAAAFsAAAAAAABbAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAAVgAAAAABAFYAAAAAAABWAAAAAAIAVgAAAAAAAFYAAAAAAQCBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFsAAAAAAQBbAAAAAAEAgQAAAAAAAIEAAAAAAAAAAAAAAAAAgAAAAAAAAIEAAAAAAABWAAAAAAIAVgAAAAADAFYAAAAAAgBWAAAAAAIAcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAABWAAAAAAAAgQAAAAAAAIEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAAIEAAAAAAABWAAAAAAIAVgAAAAABAFYAAAAAAACBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAACBAAAAAAAAVgAAAAACAFYAAAAAAQBWAAAAAAIAgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAAFYAAAAAAABWAAAAAAIAVgAAAAABAIEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIEAAAAAAABWAAAAAAEAVgAAAAACAIEAAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACBAAAAAAAAVgAAAAACAFYAAAAAAgCBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAFYAAAAAAABWAAAAAAMAgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAACBAAAAAAAAgQAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAAIEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIEAAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA== + version: 7 0,-1: ind: 0,-1 - tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAgQAAAAAAgQAAAAAAgQAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAVgAAAAABVgAAAAAAgQAAAAAAgQAAAAAAgQAAAAAAgQAAAAAAgQAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAVgAAAAADVgAAAAADVgAAAAABVgAAAAACVgAAAAACVgAAAAABVgAAAAADgQAAAAAAgQAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWwAAAAACWwAAAAABWwAAAAABVgAAAAAAVgAAAAADVgAAAAAAVgAAAAAAgQAAAAAAcQAAAAAAgQAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - version: 6 + tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFYAAAAAAQBWAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABWAAAAAAMAVgAAAAADAFYAAAAAAQBWAAAAAAIAVgAAAAACAFYAAAAAAQBWAAAAAAMAgQAAAAAAAIEAAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWwAAAAACAFsAAAAAAQBbAAAAAAEAVgAAAAAAAFYAAAAAAwBWAAAAAAAAVgAAAAAAAIEAAAAAAABxAAAAAAAAgQAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA== + version: 7 -1,0: ind: -1,0 - tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAgQAAAAAAcQAAAAABcQAAAAAAcAAAAAAAVgAAAAACWwAAAAACgQAAAAAAgQAAAAAAWwAAAAAAWwAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAgQAAAAAAgQAAAAAAgQAAAAAAgQAAAAAAVgAAAAAAgQAAAAAAgQAAAAAAVgAAAAAAWwAAAAABWwAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAcAAAAAAAVgAAAAAAVgAAAAABgQAAAAAAWwAAAAAAVgAAAAADgQAAAAAAgQAAAAAAgQAAAAAAWwAAAAAAWwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAVgAAAAAAVgAAAAADVgAAAAADVgAAAAACVgAAAAACgQAAAAAAgQAAAAAAgQAAAAAAWwAAAAAAWwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAcAAAAAAAVgAAAAABVgAAAAAAVgAAAAAAVgAAAAADgQAAAAAAgAAAAAAAAAAAAAAAgQAAAAAAgQAAAAAAWwAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAgQAAAAAAVgAAAAABgQAAAAAAgQAAAAAAgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAVgAAAAAAVgAAAAACVgAAAAADgQAAAAAAgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAVgAAAAADVgAAAAABVgAAAAAAgQAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAVgAAAAABVgAAAAABVgAAAAABgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAgQAAAAAAVgAAAAAAVgAAAAACgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAVgAAAAABVgAAAAADgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAVgAAAAAAVgAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAgQAAAAAAgQAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - version: 6 + tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAgQAAAAAAAHEAAAAAAQBxAAAAAAAAcAAAAAAAAFYAAAAAAgBbAAAAAAIAgQAAAAAAAIEAAAAAAABbAAAAAAAAWwAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAABWAAAAAAAAgQAAAAAAAIEAAAAAAABWAAAAAAAAWwAAAAABAFsAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHAAAAAAAABWAAAAAAAAVgAAAAABAIEAAAAAAABbAAAAAAAAVgAAAAADAIEAAAAAAACBAAAAAAAAgQAAAAAAAFsAAAAAAABbAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACBAAAAAAAAVgAAAAAAAFYAAAAAAwBWAAAAAAMAVgAAAAACAFYAAAAAAgCBAAAAAAAAgQAAAAAAAIEAAAAAAABbAAAAAAAAWwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAcAAAAAAAAFYAAAAAAQBWAAAAAAAAVgAAAAAAAFYAAAAAAwCBAAAAAAAAgAAAAAAAAAAAAAAAAACBAAAAAAAAgQAAAAAAAFsAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIEAAAAAAACBAAAAAAAAVgAAAAABAIEAAAAAAACBAAAAAAAAgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIEAAAAAAACBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACBAAAAAAAAVgAAAAAAAFYAAAAAAgBWAAAAAAMAgQAAAAAAAIEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgQAAAAAAAFYAAAAAAwBWAAAAAAEAVgAAAAAAAIEAAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIEAAAAAAABWAAAAAAEAVgAAAAABAFYAAAAAAQCBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAgQAAAAAAAFYAAAAAAABWAAAAAAIAgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIEAAAAAAABWAAAAAAEAVgAAAAADAIEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACBAAAAAAAAVgAAAAAAAFYAAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAIEAAAAAAACBAAAAAAAAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACBAAAAAAAAgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAIEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA== + version: 7 -1,-1: ind: -1,-1 - tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAgQAAAAAAgQAAAAAAgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAgQAAAAAAgQAAAAAAgQAAAAAAgQAAAAAAgQAAAAAAVgAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAgQAAAAAAgQAAAAAAVgAAAAAAVgAAAAAAVgAAAAACVgAAAAACVgAAAAADVgAAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAgQAAAAAAcQAAAAABgQAAAAAAVgAAAAAAVgAAAAACVgAAAAAAVgAAAAACWwAAAAACWwAAAAAC - version: 6 + tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAACBAAAAAAAAgQAAAAAAAIEAAAAAAACBAAAAAAAAgQAAAAAAAFYAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAIEAAAAAAACBAAAAAAAAVgAAAAAAAFYAAAAAAABWAAAAAAIAVgAAAAACAFYAAAAAAwBWAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAIEAAAAAAABxAAAAAAEAgQAAAAAAAFYAAAAAAABWAAAAAAIAVgAAAAAAAFYAAAAAAgBbAAAAAAIAWwAAAAACAA== + version: 7 - type: Broadphase - type: Physics bodyStatus: InAir @@ -49,6 +60,7 @@ entities: - type: OccluderTree - type: SpreaderGrid - type: Shuttle + dampingModifier: 0.25 - type: GridPathfinding - type: Gravity gravityShakeSound: !type:SoundPathSpecifier @@ -433,6 +445,29 @@ entities: chunkSize: 4 - type: GasTileOverlay - type: RadiationGridResistance + - type: ImplicitRoof +- proto: ActionToggleInternals + entities: + - uid: 495 + mapInit: true + paused: true + components: + - type: Transform + parent: 493 + - type: Action + originalIconColor: '#FFFFFFFF' + container: 493 +- proto: ActionToggleJetpack + entities: + - uid: 494 + mapInit: true + paused: true + components: + - type: Transform + parent: 493 + - type: Action + originalIconColor: '#FFFFFFFF' + container: 493 - proto: AirCanister entities: - uid: 441 @@ -460,7 +495,8 @@ entities: - type: DeviceLinkSource linkedPorts: 127: - - DoorStatus: DoorBolt + - - DoorStatus + - DoorBolt - uid: 126 components: - type: Transform @@ -476,7 +512,8 @@ entities: - type: DeviceLinkSource linkedPorts: 128: - - DoorStatus: DoorBolt + - - DoorStatus + - DoorBolt - uid: 127 components: - type: Transform @@ -492,7 +529,8 @@ entities: - type: DeviceLinkSource linkedPorts: 125: - - DoorStatus: DoorBolt + - - DoorStatus + - DoorBolt - uid: 128 components: - type: Transform @@ -508,7 +546,8 @@ entities: - type: DeviceLinkSource linkedPorts: 126: - - DoorStatus: DoorBolt + - - DoorStatus + - DoorBolt - proto: AirlockMaint entities: - uid: 43 @@ -568,6 +607,8 @@ entities: - type: Transform pos: -2.5,0.5 parent: 1 + - type: Fixtures + fixtures: {} - proto: AtmosDeviceFanDirectional entities: - uid: 87 @@ -770,12 +811,12 @@ entities: - uid: 463 components: - type: Transform - pos: -7.332144,10.686393 + pos: -7.396112,7.4312053 parent: 1 - uid: 464 components: - type: Transform - pos: -7.311311,7.5718102 + pos: -7.271112,7.639539 parent: 1 - proto: ButtonFrameExit entities: @@ -1748,11 +1789,47 @@ entities: - type: Transform pos: -7.5,9.5 parent: 1 + - type: EntityStorage + air: + volume: 200 + immutable: False + temperature: 293.14673 + moles: + - 1.7459903 + - 6.568249 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 - uid: 460 components: - type: Transform pos: -7.5,8.5 parent: 1 + - type: EntityStorage + air: + volume: 200 + immutable: False + temperature: 293.14673 + moles: + - 1.7459903 + - 6.568249 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 - proto: CyberPen entities: - uid: 328 @@ -1765,7 +1842,7 @@ entities: - uid: 496 components: - type: Transform - pos: 8.55729,9.557987 + pos: 8.469106,9.509953 parent: 1 - proto: FaxMachineSyndie entities: @@ -2708,13 +2785,31 @@ entities: - type: Transform pos: 0.5,-2.5 parent: 1 +- proto: HandheldHealthAnalyzer + entities: + - uid: 540 + components: + - type: Transform + pos: -7.6773615,10.327039 + parent: 1 - proto: JetpackMiniFilled entities: - uid: 493 components: - type: Transform - pos: 8.505206,10.057987 + pos: 8.489939,10.312036 parent: 1 + - type: GasTank + toggleActionEntity: 495 + - type: Jetpack + toggleActionEntity: 494 + - type: ActionsContainer + - type: ContainerContainer + containers: + actions: !type:Container + ents: + - 494 + - 495 - proto: LockerSyndicate entities: - uid: 471 @@ -2770,6 +2865,34 @@ entities: showEnts: False occludes: True ent: null +- proto: MedkitAdvancedFilled + entities: + - uid: 538 + components: + - type: Transform + pos: -7.6565285,10.806205 + parent: 1 +- proto: MedkitBruteFilled + entities: + - uid: 537 + components: + - type: Transform + pos: -7.250519,10.341591 + parent: 1 +- proto: MedkitCombatFilled + entities: + - uid: 539 + components: + - type: Transform + pos: 8.510773,9.89537 + parent: 1 +- proto: MedkitFilled + entities: + - uid: 541 + components: + - type: Transform + pos: -7.2296853,10.747841 + parent: 1 - proto: PhoneInstrumentSyndicate entities: - uid: 498 @@ -2869,6 +2992,13 @@ entities: rot: 1.5707963267948966 rad pos: 3.5,3.5 parent: 1 +- proto: PowerCellRecharger + entities: + - uid: 536 + components: + - type: Transform + pos: 8.5,10.5 + parent: 1 - proto: PoweredlightRed entities: - uid: 432 @@ -2974,11 +3104,16 @@ entities: - type: DeviceLinkSource linkedPorts: 208: - - Pressed: Toggle + - - Pressed + - Toggle 209: - - Pressed: Toggle + - - Pressed + - Toggle 210: - - Pressed: Toggle + - - Pressed + - Toggle + - type: Fixtures + fixtures: {} - uid: 330 components: - type: MetaData @@ -2990,11 +3125,16 @@ entities: - type: DeviceLinkSource linkedPorts: 211: - - Pressed: Toggle + - - Pressed + - Toggle 212: - - Pressed: Toggle + - - Pressed + - Toggle 213: - - Pressed: Toggle + - - Pressed + - Toggle + - type: Fixtures + fixtures: {} - proto: SMESBasic entities: - uid: 198 @@ -3109,11 +3249,15 @@ entities: - type: Transform pos: -2.5,2.5 parent: 1 + - type: Fixtures + fixtures: {} - uid: 469 components: - type: Transform pos: 3.5,2.5 parent: 1 + - type: Fixtures + fixtures: {} - proto: SyndieHandyFlag entities: - uid: 466 @@ -3259,17 +3403,27 @@ entities: - type: DeviceLinkSource linkedPorts: 129: - - Left: On - - Left: Trigger - - Right: On - - Right: Trigger - - Middle: Off + - - Left + - On + - - Left + - Trigger + - - Right + - On + - - Right + - Trigger + - - Middle + - Off 132: - - Left: On - - Left: Trigger - - Right: On - - Right: Trigger - - Middle: Off + - - Left + - On + - - Left + - Trigger + - - Right + - On + - - Right + - Trigger + - - Middle + - Off - proto: VendingMachineClothing entities: - uid: 465 @@ -4015,11 +4169,11 @@ entities: - uid: 461 components: - type: Transform - pos: -7.4571443,7.4884768 + pos: -7.5419455,7.639539 parent: 1 - uid: 462 components: - type: Transform - pos: -7.4154773,10.488477 + pos: -7.6356955,7.483289 parent: 1 ... diff --git a/Resources/Prototypes/Catalog/VendingMachines/Inventories/medical.yml b/Resources/Prototypes/Catalog/VendingMachines/Inventories/medical.yml index d28f4c00318..dff2c16a441 100644 --- a/Resources/Prototypes/Catalog/VendingMachines/Inventories/medical.yml +++ b/Resources/Prototypes/Catalog/VendingMachines/Inventories/medical.yml @@ -1,15 +1,78 @@ +- type: vendingMachineInventory + id: NanoMedInventory + startingInventory: + HandheldHealthAnalyzer: 1 + Gauze: 3 + Brutepack: 3 + Ointment: 3 + Bloodpack: 3 + ChemistryBottleEpinephrine: 3 + Syringe: 3 + PillCanisterTricordrazine: 2 + contrabandInventory: + PillCanisterRandom: 1 + PowerCellSmall: 2 + +- type: vendingMachineInventory + id: NanoMedCivilianWallInventory + startingInventory: + HandheldHealthAnalyzer: 1 + AloeCream: 2 + Gauze: 3 + Brutepack: 3 + Ointment: 2 + Bloodpack: 3 + ChemistryBottleEpinephrine: 3 + Syringe: 3 + PillCanisterTricordrazine: 2 + contrabandInventory: + PillCanisterRandom: 1 + PowerCellSmall: 2 + - type: vendingMachineInventory id: NanoMedPlusInventory startingInventory: HandheldHealthAnalyzer: 3 + Gauze: 5 Brutepack: 5 Ointment: 5 Bloodpack: 5 + Tourniquet: 2 ChemistryBottleEpinephrine: 3 Syringe: 8 # DeltaV - was 5 BoxBottle: 4 # DeltaV - was 3 Portafib: 1 # DeltaV - Add Portafibs, see Prototypes/_DV/Entities/Objects/Devices/Medical/portafib.yml ClothingEyesHudMedical: 3 # DeltaV - was 2 + ChemistryBottleBicaridine: 1 + PillCanisterTricordrazine: 3 + PillCanisterIron: 1 + PillCanisterCopper: 1 + PillCanisterPotassiumIodide: 1 + SyringeIpecac: 1 ClothingEyesEyepatchHudMedical: 2 contrabandInventory: + PillCanisterRandom: 3 + PillSpaceDrugs: 3 + FoodApple: 1 + +- type: vendingMachineInventory + id: NanoMedCivilianInventory + startingInventory: + HandheldHealthAnalyzer: 3 + AloeCream: 3 + Gauze: 5 + Brutepack: 5 + Ointment: 4 + Bloodpack: 5 + Tourniquet: 1 + ChemistryBottleEpinephrine: 3 + Syringe: 5 + BoxBottle: 3 + PillCanisterTricordrazine: 2 + PillCanisterIron: 1 + PillCanisterCopper: 1 + PillCanisterPotassiumIodide: 1 + contrabandInventory: + PillCanisterRandom: 1 + PillSpaceDrugs: 3 FoodApple: 1 diff --git a/Resources/Prototypes/Catalog/VendingMachines/Inventories/wallmed.yml b/Resources/Prototypes/Catalog/VendingMachines/Inventories/wallmed.yml deleted file mode 100644 index 327c17269af..00000000000 --- a/Resources/Prototypes/Catalog/VendingMachines/Inventories/wallmed.yml +++ /dev/null @@ -1,10 +0,0 @@ -- type: vendingMachineInventory - id: NanoMedInventory - startingInventory: - Brutepack: 3 - Ointment: 3 - Bloodpack: 3 - ChemistryBottleEpinephrine: 3 - Syringe: 3 - contrabandInventory: - PowerCellSmall: 2 diff --git a/Resources/Prototypes/Entities/Objects/Specific/Service/vending_machine_restock.yml b/Resources/Prototypes/Entities/Objects/Specific/Service/vending_machine_restock.yml index 24678a6f947..4a6491043fa 100644 --- a/Resources/Prototypes/Entities/Objects/Specific/Service/vending_machine_restock.yml +++ b/Resources/Prototypes/Entities/Objects/Specific/Service/vending_machine_restock.yml @@ -285,6 +285,8 @@ canRestock: - NanoMedInventory - NanoMedPlusInventory + - NanoMedCivilianInventory + - NanoMedCivilianWallInventory - type: Sprite layers: - state: base diff --git a/Resources/Prototypes/Entities/Objects/Specific/chemistry-bottles.yml b/Resources/Prototypes/Entities/Objects/Specific/chemistry-bottles.yml index 5d74717c95c..3f9e10a94c1 100644 --- a/Resources/Prototypes/Entities/Objects/Specific/chemistry-bottles.yml +++ b/Resources/Prototypes/Entities/Objects/Specific/chemistry-bottles.yml @@ -148,6 +148,263 @@ tags: - Bottle +# Medicine bottles + +- type: entity + id: ChemistryBottleAloxadone + suffix: aloxadone + parent: BaseChemistryBottleFilled + components: + - type: Label + currentLabel: reagent-aloxadone + - type: SolutionContainerManager + solutions: + drink: + maxVol: 30 + reagents: + - ReagentId: Aloxadone + Quantity: 30 + +- type: entity + id: ChemistryBottleAmbuzol + suffix: ambuzol + parent: BaseChemistryBottleFilled + components: + - type: Label + currentLabel: reagent-ambuzol + - type: SolutionContainerManager + solutions: + drink: + maxVol: 30 + reagents: + - ReagentId: Ambuzol + Quantity: 30 + +- type: entity + id: ChemistryBottleAmbuzolPlus + suffix: ambuzol+ + parent: BaseChemistryBottleFilled + components: + - type: Label + currentLabel: reagent-ambuzol-plus + - type: SolutionContainerManager + solutions: + drink: + maxVol: 30 + reagents: + - ReagentId: AmbuzolPlus + Quantity: 30 + +- type: entity + id: ChemistryBottleArithrazine + suffix: arithrazine + parent: BaseChemistryBottleFilled + components: + - type: Label + currentLabel: reagent-name-arithrazine + - type: SolutionContainerManager + solutions: + drink: + maxVol: 30 + reagents: + - ReagentId: Arithrazine + Quantity: 30 + +- type: entity + id: ChemistryBottleBarozine + suffix: barozine + parent: BaseChemistryBottleFilled + components: + - type: Label + currentLabel: reagent-barozine + - type: SolutionContainerManager + solutions: + drink: + maxVol: 30 + reagents: + - ReagentId: Barozine + Quantity: 30 + +- type: entity + id: ChemistryBottleBicaridine + suffix: bicaridine + parent: BaseChemistryBottleFilled + components: + - type: Label + currentLabel: reagent-name-bicaridine + - type: SolutionContainerManager + solutions: + drink: # This solution name and target volume is hard-coded in ChemMasterComponent + maxVol: 30 + reagents: + - ReagentId: Bicaridine + Quantity: 30 + +- type: entity + id: ChemistryBottleBruizine + suffix: bruizine + parent: BaseChemistryBottleFilled + components: + - type: Label + currentLabel: reagent-bruizine + - type: SolutionContainerManager + solutions: + drink: + maxVol: 30 + reagents: + - ReagentId: Bruizine + Quantity: 30 + +- type: entity + id: ChemistryBottleCognizine + suffix: cognizine + parent: BaseChemistryBottleFilled + components: + - type: Label + currentLabel: reagent-cognizine + - type: SolutionContainerManager + solutions: + drink: + maxVol: 30 + reagents: + - ReagentId: Cognizine + Quantity: 30 + +- type: entity + id: ChemistryBottleCryoxadone + suffix: cryoxadone + parent: BaseChemistryBottleFilled + components: + - type: Label + currentLabel: reagent-name-cryoxadone + - type: SolutionContainerManager + solutions: + drink: + maxVol: 30 + reagents: + - ReagentId: Cryoxadone + Quantity: 30 + +- type: entity + id: ChemistryBottleCryptobiolin + suffix: cryptobiolin + parent: BaseChemistryBottleFilled + components: + - type: Label + currentLabel: reagent-name-cryptobiolin + - type: SolutionContainerManager + solutions: + drink: + maxVol: 30 + reagents: + - ReagentId: Cryptobiolin + Quantity: 30 + +- type: entity + id: ChemistryBottleDermaline + suffix: dermaline + parent: BaseChemistryBottleFilled + components: + - type: Label + currentLabel: reagent-name-dermaline + - type: SolutionContainerManager + solutions: + drink: + maxVol: 30 + reagents: + - ReagentId: Dermaline + Quantity: 30 + +- type: entity + id: ChemistryBottleDexalin + suffix: dex + parent: BaseChemistryBottleFilled + components: + - type: Label + currentLabel: reagent-name-dexalin + - type: SolutionContainerManager + solutions: + drink: + maxVol: 30 + reagents: + - ReagentId: Dexalin + Quantity: 30 + +- type: entity + id: ChemistryBottleDexalinPlus + suffix: dex+ + parent: BaseChemistryBottleFilled + components: + - type: Label + currentLabel: reagent-name-dexalin-plus + - type: SolutionContainerManager + solutions: + drink: + maxVol: 30 + reagents: + - ReagentId: DexalinPlus + Quantity: 30 + +- type: entity + id: ChemistryBottleDiphenhydramine + suffix: diphenhydramine + parent: BaseChemistryBottleFilled + components: + - type: Label + currentLabel: reagent-name-diphenhydramine + - type: SolutionContainerManager + solutions: + drink: + maxVol: 30 + reagents: + - ReagentId: Diphenhydramine + Quantity: 30 + +- type: entity + id: ChemistryBottleDiphenylmethylamine + suffix: meth + parent: BaseChemistryBottleFilled + components: + - type: Label + currentLabel: reagent-name-diphenylmethylamine + - type: SolutionContainerManager + solutions: + drink: + maxVol: 30 + reagents: + - ReagentId: Diphenylmethylamine + Quantity: 30 + +- type: entity + id: ChemistryBottleDoxarubixadone + suffix: doxarubixadone + parent: BaseChemistryBottleFilled + components: + - type: Label + currentLabel: reagent-name-doxarubixadone + - type: SolutionContainerManager + solutions: + drink: + maxVol: 30 + reagents: + - ReagentId: Doxarubixadone + Quantity: 30 + +- type: entity + id: ChemistryBottleDylovene + suffix: dylovene + parent: BaseChemistryBottleFilled + components: + - type: Label + currentLabel: reagent-name-dylovene + - type: SolutionContainerManager + solutions: + drink: + maxVol: 30 + reagents: + - ReagentId: Dylovene + Quantity: 30 + - type: entity id: ChemistryBottleEpinephrine suffix: epinephrine @@ -157,12 +414,494 @@ currentLabel: reagent-name-epinephrine - type: SolutionContainerManager solutions: - drink: # This solution name and target volume is hard-coded in ChemMasterComponent + drink: maxVol: 30 reagents: - ReagentId: Epinephrine Quantity: 30 +- type: entity + id: ChemistryBottleEthyloxyephedrine + suffix: ethyloxyephedrine + parent: BaseChemistryBottleFilled + components: + - type: Label + currentLabel: reagent-name-ethyloxyephedrine + - type: SolutionContainerManager + solutions: + drink: + maxVol: 30 + reagents: + - ReagentId: Ethyloxyephedrine + Quantity: 30 + +- type: entity + id: ChemistryBottleEthylredoxrazine + suffix: ethylredoxrazine + parent: BaseChemistryBottleFilled + components: + - type: Label + currentLabel: reagent-name-ethylredoxrazine + - type: SolutionContainerManager + solutions: + drink: + maxVol: 30 + reagents: + - ReagentId: Ethylredoxrazine + Quantity: 30 + +- type: entity + id: ChemistryBottleHaloperidol + suffix: haloperidol + parent: BaseChemistryBottleFilled + components: + - type: Label + currentLabel: reagent-name-haloperidol + - type: SolutionContainerManager + solutions: + drink: + maxVol: 30 + reagents: + - ReagentId: Haloperidol + Quantity: 30 + +- type: entity + id: ChemistryBottleHolywater + suffix: holy water + parent: BaseChemistryBottleFilled + components: + - type: Label + currentLabel: reagent-name-holy-water + - type: SolutionContainerManager + solutions: + drink: + maxVol: 30 + reagents: + - ReagentId: Holywater + Quantity: 30 + +- type: entity + id: ChemistryBottleHyronalin + suffix: hyronalin + parent: BaseChemistryBottleFilled + components: + - type: Label + currentLabel: reagent-name-hyronalin + - type: SolutionContainerManager + solutions: + drink: + maxVol: 30 + reagents: + - ReagentId: Hyronalin + Quantity: 30 + +- type: entity + id: ChemistryBottleInaprovaline + suffix: inaprovaline + parent: BaseChemistryBottleFilled + components: + - type: Label + currentLabel: reagent-name-inaprovaline + - type: SolutionContainerManager + solutions: + drink: + maxVol: 30 + reagents: + - ReagentId: Inaprovaline + Quantity: 30 + +- type: entity + id: ChemistryBottleInsuzine + suffix: insuzine + parent: BaseChemistryBottleFilled + components: + - type: Label + currentLabel: reagent-name-insuzine + - type: SolutionContainerManager + solutions: + drink: + maxVol: 30 + reagents: + - ReagentId: Insuzine + Quantity: 30 + +- type: entity + id: ChemistryBottleIpecac + suffix: ipecac + parent: BaseChemistryBottleFilled + components: + - type: Label + currentLabel: reagent-name-ipecac + - type: SolutionContainerManager + solutions: + drink: + maxVol: 30 + reagents: + - ReagentId: Ipecac + Quantity: 30 + +- type: entity + id: ChemistryBottleKelotane + suffix: kelotane + parent: BaseChemistryBottleFilled + components: + - type: Label + currentLabel: reagent-name-kelotane + - type: SolutionContainerManager + solutions: + drink: + maxVol: 30 + reagents: + - ReagentId: Kelotane + Quantity: 30 + +- type: entity + id: ChemistryBottleLacerinol + suffix: lacerinol + parent: BaseChemistryBottleFilled + components: + - type: Label + currentLabel: reagent-name-lacerinol + - type: SolutionContainerManager + solutions: + drink: + maxVol: 30 + reagents: + - ReagentId: Lacerinol + Quantity: 30 + +- type: entity + id: ChemistryBottleLeporazine + suffix: leporazine + parent: BaseChemistryBottleFilled + components: + - type: Label + currentLabel: reagent-name-leporazine + - type: SolutionContainerManager + solutions: + drink: + maxVol: 30 + reagents: + - ReagentId: Leporazine + Quantity: 30 + +- type: entity + id: ChemistryBottleLipozine + suffix: lipozine + parent: BaseChemistryBottleFilled + components: + - type: Label + currentLabel: reagent-name-lipozine + - type: SolutionContainerManager + solutions: + drink: + maxVol: 30 + reagents: + - ReagentId: Lipozine + Quantity: 30 + +- type: entity + id: ChemistryBottleMannitol + suffix: mannitol + parent: BaseChemistryBottleFilled + components: + - type: Label + currentLabel: reagent-name-mannitol + - type: SolutionContainerManager + solutions: + drink: + maxVol: 30 + reagents: + - ReagentId: Mannitol + Quantity: 30 + +- type: entity + id: ChemistryBottleNecrosol + suffix: necrosol + parent: BaseChemistryBottleFilled + components: + - type: Label + currentLabel: reagent-name-necrosol + - type: SolutionContainerManager + solutions: + drink: + maxVol: 30 + reagents: + - ReagentId: Necrosol + Quantity: 30 + +- type: entity + id: ChemistryBottleOculine + suffix: oculine + parent: BaseChemistryBottleFilled + components: + - type: Label + currentLabel: reagent-oculine + - type: SolutionContainerManager + solutions: + drink: + maxVol: 30 + reagents: + - ReagentId: Oculine + Quantity: 30 + +- type: entity + id: ChemistryBottleOmnizine + suffix: omnizine + parent: BaseChemistryBottleFilled + components: + - type: Label + currentLabel: reagent-name-omnizine + - type: SolutionContainerManager + solutions: + drink: + maxVol: 30 + reagents: + - ReagentId: Omnizine + Quantity: 30 + +- type: entity + id: ChemistryBottleOpporozidone + suffix: opporozidone + parent: BaseChemistryBottleFilled + components: + - type: Label + currentLabel: reagent-opporozidone + - type: SolutionContainerManager + solutions: + drink: + maxVol: 30 + reagents: + - ReagentId: Opporozidone + Quantity: 30 + +- type: entity + id: ChemistryBottlePhalanximine + suffix: phalanximine + parent: BaseChemistryBottleFilled + components: + - type: Label + currentLabel: reagent-name-phalanximine + - type: SolutionContainerManager + solutions: + drink: + maxVol: 30 + reagents: + - ReagentId: Phalanximine + Quantity: 30 + +- type: entity + id: ChemistryBottlePolypyryliumOligomers + suffix: poly-oli + parent: BaseChemistryBottleFilled + components: + - type: Label + currentLabel: reagent-name-polypyrylium-oligomers + - type: SolutionContainerManager + solutions: + drink: + maxVol: 30 + reagents: + - ReagentId: PolypyryliumOligomers + Quantity: 30 + +- type: entity + id: ChemistryBottlePotassiumIodide + suffix: iodide + parent: BaseChemistryBottleFilled + components: + - type: Label + currentLabel: reagent-name-potassium-iodide + - type: SolutionContainerManager + solutions: + drink: + maxVol: 30 + reagents: + - ReagentId: PotassiumIodide + Quantity: 30 + +- type: entity + id: ChemistryBottlePsicodine + suffix: psicodine + parent: BaseChemistryBottleFilled + components: + - type: Label + currentLabel: reagent-name-psicodine + - type: SolutionContainerManager + solutions: + drink: + maxVol: 30 + reagents: + - ReagentId: Psicodine + Quantity: 30 + +- type: entity + id: ChemistryBottlePulpedBananaPeel + suffix: pulped-banana-peel + parent: BaseChemistryBottleFilled + components: + - type: Label + currentLabel: reagent-name-pulped-banana-peel + - type: SolutionContainerManager + solutions: + drink: + maxVol: 30 + reagents: + - ReagentId: PulpedBananaPeel + Quantity: 30 + +- type: entity + id: ChemistryBottlePuncturase + suffix: puncturase + parent: BaseChemistryBottleFilled + components: + - type: Label + currentLabel: reagent-name-puncturase + - type: SolutionContainerManager + solutions: + drink: + maxVol: 30 + reagents: + - ReagentId: Puncturase + Quantity: 30 + +- type: entity + id: ChemistryBottlePyrazine + suffix: pyrazine + parent: BaseChemistryBottleFilled + components: + - type: Label + currentLabel: reagent-name-pyrazine + - type: SolutionContainerManager + solutions: + drink: + maxVol: 30 + reagents: + - ReagentId: Pyrazine + Quantity: 30 + +- type: entity + id: ChemistryBottleSaline + suffix: saline + parent: BaseChemistryBottleFilled + components: + - type: Label + currentLabel: reagent-name-saline + - type: SolutionContainerManager + solutions: + drink: + maxVol: 30 + reagents: + - ReagentId: Saline + Quantity: 30 + +- type: entity + id: ChemistryBottleSiderlac + suffix: siderlac + parent: BaseChemistryBottleFilled + components: + - type: Label + currentLabel: reagent-name-siderlac + - type: SolutionContainerManager + solutions: + drink: + maxVol: 30 + reagents: + - ReagentId: Siderlac + Quantity: 30 + +- type: entity + id: ChemistryBottleSigynate + suffix: sigynate + parent: BaseChemistryBottleFilled + components: + - type: Label + currentLabel: reagent-name-sigynate + - type: SolutionContainerManager + solutions: + drink: + maxVol: 30 + reagents: + - ReagentId: Sigynate + Quantity: 30 + +- type: entity + id: ChemistryBottleStellibinin + suffix: stellibinin + parent: BaseChemistryBottleFilled + components: + - type: Label + currentLabel: reagent-name-stellibinin + - type: SolutionContainerManager + solutions: + drink: + maxVol: 30 + reagents: + - ReagentId: Stellibinin + Quantity: 30 + +- type: entity + id: ChemistryBottleSynaptizine + suffix: synaptizine + parent: BaseChemistryBottleFilled + components: + - type: Label + currentLabel: reagent-name-synaptizine + - type: SolutionContainerManager + solutions: + drink: + maxVol: 30 + reagents: + - ReagentId: Synaptizine + Quantity: 30 + +- type: entity + id: ChemistryBottleTranexamicAcid + suffix: tranexamic acid + parent: BaseChemistryBottleFilled + components: + - type: Label + currentLabel: reagent-tranexamic-acid + - type: SolutionContainerManager + solutions: + drink: + maxVol: 30 + reagents: + - ReagentId: TranexamicAcid + Quantity: 30 + +- type: entity + id: ChemistryBottleTricordrazine + suffix: tricordrazine + parent: BaseChemistryBottleFilled + components: + - type: Label + currentLabel: reagent-name-tricordrazine + - type: SolutionContainerManager + solutions: + drink: + maxVol: 30 + reagents: + - ReagentId: Tricordrazine + Quantity: 30 + +- type: entity + id: ChemistryBottleUltravasculine + suffix: ultravasculine + parent: BaseChemistryBottleFilled + components: + - type: Label + currentLabel: reagent-name-ultravasculine + - type: SolutionContainerManager + solutions: + drink: + maxVol: 30 + reagents: + - ReagentId: Ultravasculine + Quantity: 30 + +# Other bottles + - type: entity id: ChemistryBottleRobustHarvest suffix: robust harvest @@ -253,36 +992,6 @@ - ReagentId: Ephedrine Quantity: 30 -- type: entity - id: ChemistryBottleOmnizine - suffix: omnizine - parent: BaseChemistryBottleFilled - components: - - type: Label - currentLabel: reagent-name-omnizine - - type: SolutionContainerManager - solutions: - drink: - maxVol: 30 - reagents: - - ReagentId: Omnizine - Quantity: 30 - -- type: entity - parent: BaseChemistryBottleFilled - id: ChemistryBottleCognizine - suffix: cognizine - components: - - type: Label - currentLabel: reagent-name-cognizine - - type: SolutionContainerManager - solutions: - drink: - maxVol: 30 - reagents: - - ReagentId: Cognizine - Quantity: 30 - - type: entity id: ChemistryBottlePax suffix: pax @@ -643,3 +1352,111 @@ reagents: - ReagentId: Sulfur Quantity: 30 + +# Entity tables +- type: entityTable + id: BasicReagentBottlesTable + table: !type:GroupSelector + children: + - id: ChemistryBottleAluminium + - id: ChemistryBottleCarbon + - id: ChemistryBottleChlorine + - id: ChemistryBottleCopper + - id: ChemistryBottleEthanol + - id: ChemistryBottleFluorine + - id: ChemistryBottleHydrogen + - id: ChemistryBottleIodine + - id: ChemistryBottleIron + - id: ChemistryBottleLithium + - id: ChemistryBottleMercury + - id: ChemistryBottleNitrogen + - id: ChemistryBottleOxygen + - id: ChemistryBottlePhosphorus + - id: ChemistryBottlePotassium + - id: ChemistryBottleRadium + - id: ChemistryBottleSilicon + - id: ChemistryBottleSodium + - id: ChemistryBottleSugar + - id: ChemistryBottleSulfur + +- type: entityTable + id: CoreMedicineReagentBottleTable + table: !type:GroupSelector + children: + - id: ChemistryBottleBicaridine + - id: ChemistryBottleKelotane + - id: ChemistryBottleDermaline + - id: ChemistryBottleDylovene + - id: ChemistryBottleInaprovaline + - id: ChemistryBottleDexalin + - id: ChemistryBottleDexalinPlus + - id: ChemistryBottleSaline + - id: ChemistryBottleTricordrazine + +- type: entityTable + id: SpecialtyMedicineReagentBottleTable + table: !type:GroupSelector + children: + - id: ChemistryBottleCryoxadone + - id: ChemistryBottleEpinephrine + - id: ChemistryBottleHyronalin + - id: ChemistryBottleArithrazine + - id: ChemistryBottlePhalanximine + - id: ChemistryBottleTricordrazine + - id: ChemistryBottleTranexamicAcid + - id: ChemistryBottleOculine + +- type: entityTable + id: AllMedicineReagentBottlesTable + table: !type:GroupSelector + children: + - id: ChemistryBottleAloxadone + - id: ChemistryBottleAmbuzol + - id: ChemistryBottleAmbuzolPlus + - id: ChemistryBottleArithrazine + - id: ChemistryBottleBarozine + - id: ChemistryBottleBicaridine + - id: ChemistryBottleBruizine + - id: ChemistryBottleCognizine + - id: ChemistryBottleCryoxadone + - id: ChemistryBottleCryptobiolin + - id: ChemistryBottleDermaline + - id: ChemistryBottleDexalin + - id: ChemistryBottleDexalinPlus + - id: ChemistryBottleDiphenhydramine + - id: ChemistryBottleDiphenylmethylamine + - id: ChemistryBottleDoxarubixadone + - id: ChemistryBottleDylovene + - id: ChemistryBottleEpinephrine + - id: ChemistryBottleEthyloxyephedrine + - id: ChemistryBottleEthylredoxrazine + - id: ChemistryBottleHaloperidol + - id: ChemistryBottleHolywater + - id: ChemistryBottleHyronalin + - id: ChemistryBottleInaprovaline + - id: ChemistryBottleInsuzine + - id: ChemistryBottleIpecac + - id: ChemistryBottleKelotane + - id: ChemistryBottleLacerinol + - id: ChemistryBottleLeporazine + - id: ChemistryBottleLipozine + - id: ChemistryBottleMannitol + - id: ChemistryBottleNecrosol + - id: ChemistryBottleOculine + - id: ChemistryBottleOmnizine + - id: ChemistryBottleOpporozidone + - id: ChemistryBottlePhalanximine + - id: ChemistryBottlePolypyryliumOligomers + - id: ChemistryBottlePotassiumIodide + - id: ChemistryBottlePsicodine + - id: ChemistryBottlePulpedBananaPeel + - id: ChemistryBottlePuncturase + - id: ChemistryBottlePyrazine + - id: ChemistryBottleSaline + - id: ChemistryBottleSiderlac + - id: ChemistryBottleSigynate + - id: ChemistryBottleStellibinin + - id: ChemistryBottleSynaptizine + - id: ChemistryBottleTranexamicAcid + - id: ChemistryBottleTricordrazine + - id: ChemistryBottleUltravasculine diff --git a/Resources/Prototypes/Entities/Structures/Machines/vending_machines.yml b/Resources/Prototypes/Entities/Structures/Machines/vending_machines.yml index e6784c1daa2..732bbb38be8 100644 --- a/Resources/Prototypes/Entities/Structures/Machines/vending_machines.yml +++ b/Resources/Prototypes/Entities/Structures/Machines/vending_machines.yml @@ -911,13 +911,13 @@ - type: entity parent: VendingMachine - id: VendingMachineMedical - name: NanoMed Plus + id: VendingMachineMedicalBase + name: NanoMed Civilian description: It's a medical drug dispenser. Natural chemicals only! components: - type: VendingMachine - pack: NanoMedPlusInventory - offState: off + pack: NanoMedCivilianInventory + offState: off-civilian brokenState: broken normalState: normal-unshaded ejectState: eject-unshaded @@ -927,6 +927,33 @@ dataset: NanoMedAds - type: SpeakOnUIClosed pack: GenericVendGoodbyes + - type: Sprite + sprite: Structures/Machines/VendingMachines/medical.rsi + layers: + - state: "off-civilian" + map: ["enum.VendingMachineVisualLayers.Base"] + - state: "off-civilian" + map: ["enum.VendingMachineVisualLayers.BaseUnshaded"] + shader: unshaded + - state: panel + map: ["enum.WiresVisualLayers.MaintenancePanel"] + - type: PointLight + radius: 1.5 + energy: 1.6 + color: "#9dc5c9" + - type: GuideHelp + guides: + - MedicalDoctor + +- type: entity + parent: VendingMachineMedicalBase + id: VendingMachineMedical + name: NanoMed Plus + description: It's a medical drug dispenser. Natural chemicals only! + components: + - type: VendingMachine + pack: NanoMedPlusInventory + offState: off - type: Sprite sprite: Structures/Machines/VendingMachines/medical.rsi layers: @@ -939,13 +966,6 @@ map: ["enum.WiresVisualLayers.MaintenancePanel"] - type: AccessReader access: [["Medical"]] - - type: PointLight - radius: 1.5 - energy: 1.6 - color: "#9dc5c9" - - type: GuideHelp - guides: - - MedicalDoctor - type: entity parent: VendingMachine @@ -2258,6 +2278,36 @@ # wallmount - type: entity parent: VendingMachineWallmount + id: VendingMachineWallMedicalCivilian + name: NanoMed band-aid + description: "It's a wall-mounted medical equipment dispenser. Natural chemicals only!" + components: + - type: VendingMachine + pack: NanoMedCivilianWallInventory + offState: off-civilian + brokenState: broken + normalState: normal-unshaded + denyState: deny-unshaded + - type: Sprite + sprite: Structures/Machines/VendingMachines/wallmed.rsi + layers: + - state: "off-civilian" + map: ["enum.VendingMachineVisualLayers.Base"] + - state: "off-civilian" + map: ["enum.VendingMachineVisualLayers.BaseUnshaded"] + shader: unshaded + - texture: Structures/Machines/VendingMachines/maintenance_panel.png + map: ["enum.WiresVisualLayers.MaintenancePanel"] + - type: PointLight + radius: 1.3 + energy: 1.6 + color: "#43ccb5" + - type: GuideHelp + guides: + - Medical + +- type: entity + parent: VendingMachineWallMedicalCivilian id: VendingMachineWallMedical name: NanoMed description: "It's a wall-mounted medical equipment dispenser. Natural chemicals only!" @@ -2265,9 +2315,6 @@ - type: VendingMachine pack: NanoMedInventory offState: off - brokenState: broken - normalState: normal-unshaded - denyState: deny-unshaded - type: Sprite sprite: Structures/Machines/VendingMachines/wallmed.rsi layers: @@ -2278,12 +2325,5 @@ shader: unshaded - texture: Structures/Machines/VendingMachines/maintenance_panel.png map: ["enum.WiresVisualLayers.MaintenancePanel"] - - type: PointLight - radius: 1.3 - energy: 1.6 - color: "#43ccb5" - type: AccessReader access: [["Medical"]] - - type: GuideHelp - guides: - - Medical diff --git a/Resources/Textures/Structures/Machines/VendingMachines/medical.rsi/meta.json b/Resources/Textures/Structures/Machines/VendingMachines/medical.rsi/meta.json index 3035a0a0c83..17fd7bcc2d8 100644 --- a/Resources/Textures/Structures/Machines/VendingMachines/medical.rsi/meta.json +++ b/Resources/Textures/Structures/Machines/VendingMachines/medical.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at https://github.com/tgstation/tgstation/commit/1516a728931b4985c1e86f0c5995a5aa1554a1ad and modified by Swept", + "copyright": "Taken from tgstation at https://github.com/tgstation/tgstation/commit/1516a728931b4985c1e86f0c5995a5aa1554a1ad and modified by Swept & IproduceWidgets (github)", "size": { "x": 32, "y": 32 @@ -31,6 +31,9 @@ { "name": "off" }, + { + "name": "off-civilian" + }, { "name": "panel" }, diff --git a/Resources/Textures/Structures/Machines/VendingMachines/medical.rsi/off-civilian.png b/Resources/Textures/Structures/Machines/VendingMachines/medical.rsi/off-civilian.png new file mode 100644 index 0000000000000000000000000000000000000000..edd82f66904ca2511134530b63cc3501fec493e1 GIT binary patch literal 491 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=hEVFmCd6aSVw#oSfpobnqSHf5{gt z*WTSZaN+*qh_Yvj+5H;UO=)cWvcH*?DG3ugj^Tl?oMzPG>j+`c+5#TZNKNRj(x&2!M6;VoPu4#QfGpI^pp!VAASlSz9Sj@G2Pio zPmS%0=@nxTHUI(@QE_996|W3!e*EEF{ZnVli7c)?H4-m98>jQXB|GH2d;NNVvgopu$*yHmUC9avrAr!WRJMKzQTWahf`BpAjm{E zb^CA;yI9!|55B3kRqmbckw58ScAOx0*2G(_{_%SfCrlGKc=JM{VhY2~vxZ60krI3n f=JlM1JD3Nv?u6{1-oD!M&MT}&pBtEcj{_fwrrWpYTMdhCV{UaJicB%Ia!@^m7%%0`YoGfjeg9F`6NmY ztYCJNHF(t!$j-BaS;8~mxBa3MeHll!fAI;X+IhZhd|hpC)H3CT;hL8_j~oC3fuKd~ z(>HH$F$wdNvG<)VkP#=-t+->^b0KGsPPxPT&Wb-s^4rJ8vvp&4r_p>B_6rtW?gup_ b7BVncGAOO!T3#0cbT@;itDnm{r-UW|vh!A< literal 0 HcmV?d00001 From 2f768d22b346be7d8d05bf3761592fa4e3605d92 Mon Sep 17 00:00:00 2001 From: M4rchy-S <89603088+M4rchy-S@users.noreply.github.com> Date: Tue, 2 Sep 2025 03:07:37 +0300 Subject: [PATCH 298/340] Fix radiation vomit for dead mobs (#40020) * Fix Radiation Vomit for dead mobs * Update Content.Server/Destructible/Thresholds/Behaviors/VomitBehavior.cs Co-authored-by: lzk <124214523+lzk228@users.noreply.github.com> * Fix Radiation Vomit for dead mobs * Fix Radiation Vomit system for dead mobs * refactors * Adding mobStateSystem for validation * refactor * Unrelated cleanup --------- Co-authored-by: lzk <124214523+lzk228@users.noreply.github.com> Co-authored-by: Princess Cheeseballs <66055347+Pronana@users.noreply.github.com> --- Content.Server/Medical/VomitSystem.cs | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/Content.Server/Medical/VomitSystem.cs b/Content.Server/Medical/VomitSystem.cs index 9fee1dfc85c..235cc173318 100644 --- a/Content.Server/Medical/VomitSystem.cs +++ b/Content.Server/Medical/VomitSystem.cs @@ -8,6 +8,7 @@ using Content.Shared.Chemistry.Components; using Content.Shared.Chemistry.EntitySystems; using Content.Shared.Chemistry.Reagent; using Content.Shared.IdentityManagement; +using Content.Shared.Mobs.Systems; using Content.Shared.Movement.Systems; using Content.Shared.Nutrition.Components; using Content.Shared.Nutrition.EntitySystems; @@ -21,15 +22,16 @@ namespace Content.Server.Medical { [Dependency] private readonly IPrototypeManager _proto = default!; [Dependency] private readonly AudioSystem _audio = default!; + [Dependency] private readonly BloodstreamSystem _bloodstream = default!; [Dependency] private readonly BodySystem _body = default!; + [Dependency] private readonly ForensicsSystem _forensics = default!; [Dependency] private readonly HungerSystem _hunger = default!; + [Dependency] private readonly MobStateSystem _mobstate = default!; + [Dependency] private readonly MovementModStatusSystem _movementMod = default!; [Dependency] private readonly PopupSystem _popup = default!; [Dependency] private readonly PuddleSystem _puddle = default!; [Dependency] private readonly SharedSolutionContainerSystem _solutionContainer = default!; - [Dependency] private readonly MovementModStatusSystem _movementMod = default!; [Dependency] private readonly ThirstSystem _thirst = default!; - [Dependency] private readonly ForensicsSystem _forensics = default!; - [Dependency] private readonly BloodstreamSystem _bloodstream = default!; private static readonly ProtoId VomitCollection = "Vomit"; @@ -39,13 +41,18 @@ namespace Content.Server.Medical /// /// Make an entity vomit, if they have a stomach. /// - public void Vomit(EntityUid uid, float thirstAdded = -40f, float hungerAdded = -40f) + public void Vomit(EntityUid uid, float thirstAdded = -40f, float hungerAdded = -40f, bool force = false) { // Main requirement: You have a stomach var stomachList = _body.GetBodyOrganEntityComps(uid); if (stomachList.Count == 0) return; + // Vomit only if entity is alive + // Ignore condition if force was set to true + if (!force && _mobstate.IsDead(uid)) + return; + // Vomiting makes you hungrier and thirstier if (TryComp(uid, out var hunger)) _hunger.ModifyHunger(uid, hungerAdded, hunger); From de7e8b6a6306a94e8b2f438e36df9c786db7055e Mon Sep 17 00:00:00 2001 From: MilenVolf <63782763+MilenVolf@users.noreply.github.com> Date: Tue, 2 Sep 2025 12:37:45 +0300 Subject: [PATCH 299/340] Remove empty `drink-component.ftl` file (#40064) Probably had to be removed in #39031 --- Resources/Locale/en-US/nutrition/components/drink-component.ftl | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 Resources/Locale/en-US/nutrition/components/drink-component.ftl diff --git a/Resources/Locale/en-US/nutrition/components/drink-component.ftl b/Resources/Locale/en-US/nutrition/components/drink-component.ftl deleted file mode 100644 index e69de29bb2d..00000000000 From c7f086bffcd29f2cb5fb1c042ce6b04fc92a52e3 Mon Sep 17 00:00:00 2001 From: IProduceWidgets <107586145+IProduceWidgets@users.noreply.github.com> Date: Tue, 2 Sep 2025 09:30:11 -0400 Subject: [PATCH 300/340] prevent double-mapping lights (#39939) works? --- .../Prototypes/Entities/Structures/Lighting/base_lighting.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Resources/Prototypes/Entities/Structures/Lighting/base_lighting.yml b/Resources/Prototypes/Entities/Structures/Lighting/base_lighting.yml index 838d8c1ab4b..d02abb99f12 100644 --- a/Resources/Prototypes/Entities/Structures/Lighting/base_lighting.yml +++ b/Resources/Prototypes/Entities/Structures/Lighting/base_lighting.yml @@ -86,6 +86,8 @@ - !type:PlaySoundBehavior sound: collection: GlassBreak + - type: PlacementReplacement + key: lights placement: mode: SnapgridCenter snap: From 9c820b926973daba6d2398a2da66ea614b19e368 Mon Sep 17 00:00:00 2001 From: SolidSyn <220547106+SolidSyn@users.noreply.github.com> Date: Tue, 2 Sep 2025 06:32:18 -0700 Subject: [PATCH 301/340] Adds a secHUD to the noir-tech glasses (#39859) * Adds a SecHUD to the noir-tech glasses * Adds a Security HUD to the noir-tech glasses * Revert "Adds a Security HUD to the noir-tech glasses" This reverts commit 68d7b9b6e190618e44a94df71cf311e056892392. * Adds a security HUD to the noir-tech glasses --- Resources/Prototypes/Entities/Clothing/Eyes/glasses.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Resources/Prototypes/Entities/Clothing/Eyes/glasses.yml b/Resources/Prototypes/Entities/Clothing/Eyes/glasses.yml index f46721f02c0..f7e27c0017e 100644 --- a/Resources/Prototypes/Entities/Clothing/Eyes/glasses.yml +++ b/Resources/Prototypes/Entities/Clothing/Eyes/glasses.yml @@ -266,7 +266,7 @@ - type: FlashImmunity - type: entity - parent: ClothingEyesBase + parent: [ClothingEyesBase, ShowSecurityIcons, BaseSecurityContraband] id: ClothingEyesGlassesNoir name: noir-tech glasses description: A pair of glasses that simulate what the world looked like before the invention of color. From 2d4ffa8f39fd11e1760b999bece37fe72991efd8 Mon Sep 17 00:00:00 2001 From: Partmedia Date: Tue, 2 Sep 2025 15:55:38 -0700 Subject: [PATCH 302/340] Fix benchmark (#40039) --- Content.Benchmarks/MapLoadBenchmark.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Content.Benchmarks/MapLoadBenchmark.cs b/Content.Benchmarks/MapLoadBenchmark.cs index f763ee321e6..126ac99774f 100644 --- a/Content.Benchmarks/MapLoadBenchmark.cs +++ b/Content.Benchmarks/MapLoadBenchmark.cs @@ -47,7 +47,7 @@ public class MapLoadBenchmark PoolManager.Shutdown(); } - public static readonly string[] MapsSource = { "Empty", "Box", "Aspid", "Bagel", "Dev", "CentComm", "Atlas", "Core", "TestTeg", "Saltern", "Packed", "Omega", "Cluster", "Gemini", "Reach", "Origin", "Meta", "Marathon", "Europa", "MeteorArena", "Fland", "Barratry" }; + public static string[] MapsSource { get; } = { "Empty", "Saltern", "Box", "Bagel", "Dev", "CentComm", "Core", "TestTeg", "Packed", "Omega", "Reach", "Meta", "Marathon", "MeteorArena", "Fland", "Oasis", "Convex"}; [ParamsSource(nameof(MapsSource))] public string Map; From 4f221dadc768b6301d568ea3ec1ee4f2813e33ef Mon Sep 17 00:00:00 2001 From: slarticodefast <161409025+slarticodefast@users.noreply.github.com> Date: Wed, 3 Sep 2025 13:09:40 +0200 Subject: [PATCH 303/340] Don't show item dropping popup when wielding. (#40032) silence --- .../Inventory/VirtualItem/SharedVirtualItemSystem.cs | 9 +++++---- Content.Shared/Wieldable/SharedWieldableSystem.cs | 3 ++- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/Content.Shared/Inventory/VirtualItem/SharedVirtualItemSystem.cs b/Content.Shared/Inventory/VirtualItem/SharedVirtualItemSystem.cs index 8842223afcc..db3a4fd95c6 100644 --- a/Content.Shared/Inventory/VirtualItem/SharedVirtualItemSystem.cs +++ b/Content.Shared/Inventory/VirtualItem/SharedVirtualItemSystem.cs @@ -103,13 +103,14 @@ public abstract class SharedVirtualItemSystem : EntitySystem /// The entity we will make a virtual entity copy of /// The entity that we want to insert the virtual entity /// Whether or not to try and drop other items to make space - public bool TrySpawnVirtualItemInHand(EntityUid blockingEnt, EntityUid user, bool dropOthers = false) + /// If true this won't show a popup when dropping other items + public bool TrySpawnVirtualItemInHand(EntityUid blockingEnt, EntityUid user, bool dropOthers = false, bool silent = false) { - return TrySpawnVirtualItemInHand(blockingEnt, user, out _, dropOthers); + return TrySpawnVirtualItemInHand(blockingEnt, user, out _, dropOthers, silent: silent); } /// - public bool TrySpawnVirtualItemInHand(EntityUid blockingEnt, EntityUid user, [NotNullWhen(true)] out EntityUid? virtualItem, bool dropOthers = false, string? empty = null) + public bool TrySpawnVirtualItemInHand(EntityUid blockingEnt, EntityUid user, [NotNullWhen(true)] out EntityUid? virtualItem, bool dropOthers = false, string? empty = null, bool silent = false) { virtualItem = null; if (empty == null && !_handsSystem.TryGetEmptyHand(user, out empty)) @@ -128,7 +129,7 @@ public abstract class SharedVirtualItemSystem : EntitySystem if (!_handsSystem.TryDrop(user, hand)) continue; - if (!TerminatingOrDeleted(held)) + if (!silent && !TerminatingOrDeleted(held)) _popup.PopupClient(Loc.GetString("virtual-item-dropped-other", ("dropped", held)), user, user); empty = hand; diff --git a/Content.Shared/Wieldable/SharedWieldableSystem.cs b/Content.Shared/Wieldable/SharedWieldableSystem.cs index 0a49622f8bd..3b9b8dd8e71 100644 --- a/Content.Shared/Wieldable/SharedWieldableSystem.cs +++ b/Content.Shared/Wieldable/SharedWieldableSystem.cs @@ -314,7 +314,8 @@ public abstract class SharedWieldableSystem : EntitySystem var virtuals = new ValueList(); for (var i = 0; i < component.FreeHandsRequired; i++) { - if (_virtualItem.TrySpawnVirtualItemInHand(used, user, out var virtualItem, true)) + // don't show a popup when dropping items because it will overlap with the popup for wielding + if (_virtualItem.TrySpawnVirtualItemInHand(used, user, out var virtualItem, true, silent: true)) { virtuals.Add(virtualItem.Value); continue; From e0d8ec0e22049d11714e0ea7ebd4f7a4748b94c8 Mon Sep 17 00:00:00 2001 From: Kyle Tyo <36606155+VerinSenpai@users.noreply.github.com> Date: Wed, 3 Sep 2025 06:49:34 -0400 Subject: [PATCH 304/340] Localize, cleanup, and LEC round control commands. (#38812) * commit-progress * commit --- .../GameTicking/Commands/DelayStartCommand.cs | 76 +++++++++---------- .../GameTicking/Commands/EndRoundCommand.cs | 33 ++++---- .../Commands/RestartRoundCommand.cs | 56 ++++++-------- .../GameTicking/Commands/StartRoundCommand.cs | 33 ++++---- .../en-US/commands/delaystart-command.ftl | 7 ++ .../en-US/commands/endround-command.ftl | 2 + .../en-US/commands/restartround-command.ftl | 5 ++ .../en-US/commands/startround-command.ftl | 2 + Resources/Locale/en-US/shell.ftl | 2 + 9 files changed, 106 insertions(+), 110 deletions(-) create mode 100644 Resources/Locale/en-US/commands/delaystart-command.ftl create mode 100644 Resources/Locale/en-US/commands/endround-command.ftl create mode 100644 Resources/Locale/en-US/commands/restartround-command.ftl create mode 100644 Resources/Locale/en-US/commands/startround-command.ftl diff --git a/Content.Server/GameTicking/Commands/DelayStartCommand.cs b/Content.Server/GameTicking/Commands/DelayStartCommand.cs index 6e101d93a32..7c7eb9c7f1f 100644 --- a/Content.Server/GameTicking/Commands/DelayStartCommand.cs +++ b/Content.Server/GameTicking/Commands/DelayStartCommand.cs @@ -2,50 +2,44 @@ using Content.Shared.Administration; using Robust.Shared.Console; -namespace Content.Server.GameTicking.Commands +namespace Content.Server.GameTicking.Commands; + +[AdminCommand(AdminFlags.Round)] +public sealed class DelayStartCommand : LocalizedEntityCommands { - [AdminCommand(AdminFlags.Round)] - sealed class DelayStartCommand : IConsoleCommand + [Dependency] private readonly GameTicker _gameTicker = default!; + + public override string Command => "delaystart"; + + public override void Execute(IConsoleShell shell, string argStr, string[] args) { - [Dependency] private readonly IEntityManager _e = default!; - - public string Command => "delaystart"; - public string Description => "Delays the round start."; - public string Help => $"Usage: {Command} \nPauses/Resumes the countdown if no argument is provided."; - - public void Execute(IConsoleShell shell, string argStr, string[] args) + if (_gameTicker.RunLevel != GameRunLevel.PreRoundLobby) { - var ticker = _e.System(); - if (ticker.RunLevel != GameRunLevel.PreRoundLobby) - { - shell.WriteLine("This can only be executed while the game is in the pre-round lobby."); - return; - } - - if (args.Length == 0) - { - var paused = ticker.TogglePause(); - shell.WriteLine(paused ? "Paused the countdown." : "Resumed the countdown."); - return; - } - - if (args.Length != 1) - { - shell.WriteLine("Need zero or one arguments."); - return; - } - - if (!uint.TryParse(args[0], out var seconds) || seconds == 0) - { - shell.WriteLine($"{args[0]} isn't a valid amount of seconds."); - return; - } - - var time = TimeSpan.FromSeconds(seconds); - if (!ticker.DelayStart(time)) - { - shell.WriteLine("An unknown error has occurred."); - } + shell.WriteLine(Loc.GetString("shell-can-only-run-from-pre-round-lobby")); + return; } + + switch (args.Length) + { + case 0: + var paused = _gameTicker.TogglePause(); + shell.WriteLine(Loc.GetString(paused ? "cmd-delaystart-paused" : "cmd-delaystart-unpaused")); + return; + case 1: + break; + default: + shell.WriteError(Loc.GetString("shell-wrong-arguments-number")); + return; + } + + if (!uint.TryParse(args[0], out var seconds) || seconds == 0) + { + shell.WriteLine(Loc.GetString("cmd-delaystart-invalid-seconds", ("value", args[0]))); + return; + } + + var time = TimeSpan.FromSeconds(seconds); + if (!_gameTicker.DelayStart(time)) + shell.WriteLine(Loc.GetString("cmd-delaystart-too-late")); } } diff --git a/Content.Server/GameTicking/Commands/EndRoundCommand.cs b/Content.Server/GameTicking/Commands/EndRoundCommand.cs index c6a8ddbf537..2f8ca541444 100644 --- a/Content.Server/GameTicking/Commands/EndRoundCommand.cs +++ b/Content.Server/GameTicking/Commands/EndRoundCommand.cs @@ -2,28 +2,23 @@ using Content.Shared.Administration; using Robust.Shared.Console; -namespace Content.Server.GameTicking.Commands +namespace Content.Server.GameTicking.Commands; + +[AdminCommand(AdminFlags.Round)] +public sealed class EndRoundCommand : LocalizedEntityCommands { - [AdminCommand(AdminFlags.Round)] - sealed class EndRoundCommand : IConsoleCommand + [Dependency] private readonly GameTicker _gameTicker = default!; + + public override string Command => "endround"; + + public override void Execute(IConsoleShell shell, string argStr, string[] args) { - [Dependency] private readonly IEntityManager _e = default!; - - public string Command => "endround"; - public string Description => "Ends the round and moves the server to PostRound."; - public string Help => String.Empty; - - public void Execute(IConsoleShell shell, string argStr, string[] args) + if (_gameTicker.RunLevel != GameRunLevel.InRound) { - var ticker = _e.System(); - - if (ticker.RunLevel != GameRunLevel.InRound) - { - shell.WriteLine("This can only be executed while the game is in a round."); - return; - } - - ticker.EndRound(); + shell.WriteLine(Loc.GetString("shell-can-only-run-while-round-is-active")); + return; } + + _gameTicker.EndRound(); } } diff --git a/Content.Server/GameTicking/Commands/RestartRoundCommand.cs b/Content.Server/GameTicking/Commands/RestartRoundCommand.cs index e4ea3fa53c3..6811df4e2e4 100644 --- a/Content.Server/GameTicking/Commands/RestartRoundCommand.cs +++ b/Content.Server/GameTicking/Commands/RestartRoundCommand.cs @@ -3,43 +3,37 @@ using Content.Server.RoundEnd; using Content.Shared.Administration; using Robust.Shared.Console; -namespace Content.Server.GameTicking.Commands +namespace Content.Server.GameTicking.Commands; + +[AdminCommand(AdminFlags.Round)] +public sealed class RestartRoundCommand : LocalizedEntityCommands { - [AdminCommand(AdminFlags.Round)] - public sealed class RestartRoundCommand : IConsoleCommand + [Dependency] private readonly GameTicker _gameTicker = default!; + [Dependency] private readonly RoundEndSystem _roundEndSystem = default!; + + public override string Command => "restartround"; + + public override void Execute(IConsoleShell shell, string argStr, string[] args) { - [Dependency] private readonly IEntityManager _e = default!; - - public string Command => "restartround"; - public string Description => "Ends the current round and starts the countdown for the next lobby."; - public string Help => string.Empty; - - public void Execute(IConsoleShell shell, string argStr, string[] args) + if (_gameTicker.RunLevel != GameRunLevel.InRound) { - var ticker = _e.System(); - - if (ticker.RunLevel != GameRunLevel.InRound) - { - shell.WriteLine("This can only be executed while the game is in a round - try restartroundnow"); - return; - } - - _e.System().EndRound(); + shell.WriteLine(Loc.GetString("shell-can-only-run-while-round-is-active")); + return; } - } - [AdminCommand(AdminFlags.Round)] - public sealed class RestartRoundNowCommand : IConsoleCommand - { - [Dependency] private readonly IEntityManager _e = default!; + _roundEndSystem.EndRound(); + } +} + +[AdminCommand(AdminFlags.Round)] +public sealed class RestartRoundNowCommand : LocalizedEntityCommands +{ + [Dependency] private readonly GameTicker _gameTicker = default!; - public string Command => "restartroundnow"; - public string Description => "Moves the server from PostRound to a new PreRoundLobby."; - public string Help => String.Empty; + public override string Command => "restartroundnow"; - public void Execute(IConsoleShell shell, string argStr, string[] args) - { - _e.System().RestartRound(); - } + public override void Execute(IConsoleShell shell, string argStr, string[] args) + { + _gameTicker.RestartRound(); } } diff --git a/Content.Server/GameTicking/Commands/StartRoundCommand.cs b/Content.Server/GameTicking/Commands/StartRoundCommand.cs index 432cdd23e35..6579800ca35 100644 --- a/Content.Server/GameTicking/Commands/StartRoundCommand.cs +++ b/Content.Server/GameTicking/Commands/StartRoundCommand.cs @@ -2,28 +2,23 @@ using Content.Shared.Administration; using Robust.Shared.Console; -namespace Content.Server.GameTicking.Commands +namespace Content.Server.GameTicking.Commands; + +[AdminCommand(AdminFlags.Round)] +public sealed class StartRoundCommand : LocalizedEntityCommands { - [AdminCommand(AdminFlags.Round)] - sealed class StartRoundCommand : IConsoleCommand + [Dependency] private readonly GameTicker _gameTicker = default!; + + public override string Command => "startround"; + + public override void Execute(IConsoleShell shell, string argStr, string[] args) { - [Dependency] private readonly IEntityManager _e = default!; - - public string Command => "startround"; - public string Description => "Ends PreRoundLobby state and starts the round."; - public string Help => String.Empty; - - public void Execute(IConsoleShell shell, string argStr, string[] args) + if (_gameTicker.RunLevel != GameRunLevel.PreRoundLobby) { - var ticker = _e.System(); - - if (ticker.RunLevel != GameRunLevel.PreRoundLobby) - { - shell.WriteLine("This can only be executed while the game is in the pre-round lobby."); - return; - } - - ticker.StartRound(); + shell.WriteLine(Loc.GetString("shell-can-only-run-from-pre-round-lobby")); + return; } + + _gameTicker.StartRound(); } } diff --git a/Resources/Locale/en-US/commands/delaystart-command.ftl b/Resources/Locale/en-US/commands/delaystart-command.ftl new file mode 100644 index 00000000000..e5189a7822f --- /dev/null +++ b/Resources/Locale/en-US/commands/delaystart-command.ftl @@ -0,0 +1,7 @@ +cmd-delaystart-desc = Delays the round start. +cmd-delaystart-help = Usage: delaystart [seconds] + If no arguments are passed, the round will be paused or resumed accordingly. +cmd-delaystart-invalid-seconds = {$value} isn't a valid amount of seconds. +cmd-delaystart-paused = Paused the countdown. +cmd-delaystart-unpaused = Resumed the countdown. +cmd-delaystart-too-late = Round start could not be delayed in time! diff --git a/Resources/Locale/en-US/commands/endround-command.ftl b/Resources/Locale/en-US/commands/endround-command.ftl new file mode 100644 index 00000000000..3b322b59df2 --- /dev/null +++ b/Resources/Locale/en-US/commands/endround-command.ftl @@ -0,0 +1,2 @@ +cmd-endround-desc = Ends the round and moves the server to PostRound. +cmd-endround-help = Usage: endround diff --git a/Resources/Locale/en-US/commands/restartround-command.ftl b/Resources/Locale/en-US/commands/restartround-command.ftl new file mode 100644 index 00000000000..22bf0744520 --- /dev/null +++ b/Resources/Locale/en-US/commands/restartround-command.ftl @@ -0,0 +1,5 @@ +cmd-restartround-desc = Ends the current round and starts the countdown for the next lobby. +cmd-restartround-help = Usage: restartround + +cmd-restartroundnow-desc = Moves the server from PostRound to a new PreRoundLobby. +cmd-restartroundnow-help = Usage: restartroundnow diff --git a/Resources/Locale/en-US/commands/startround-command.ftl b/Resources/Locale/en-US/commands/startround-command.ftl new file mode 100644 index 00000000000..51e85e81b7f --- /dev/null +++ b/Resources/Locale/en-US/commands/startround-command.ftl @@ -0,0 +1,2 @@ +cmd-startround-desc = Ends PreRoundLobby state and starts the round. +cmd-startround-help = Usage: startround diff --git a/Resources/Locale/en-US/shell.ftl b/Resources/Locale/en-US/shell.ftl index 3edc43bd748..36bebeae35b 100644 --- a/Resources/Locale/en-US/shell.ftl +++ b/Resources/Locale/en-US/shell.ftl @@ -5,6 +5,8 @@ shell-command-success = Command successful shell-invalid-command = Invalid command. shell-invalid-command-specific = Invalid {$commandName} command. +shell-can-only-run-from-pre-round-lobby = You can only run this command while the game is in the pre-round lobby. +shell-can-only-run-while-round-is-active = You can only run this command while the game is in a round. shell-cannot-run-command-from-server = You cannot run this command from the server. shell-only-players-can-run-this-command = Only players can run this command. shell-must-be-attached-to-entity = You must be attached to an entity to run this command. From ffdb552d1f158015e659be125d800da4cdb15e70 Mon Sep 17 00:00:00 2001 From: Centronias Date: Wed, 3 Sep 2025 04:04:44 -0700 Subject: [PATCH 305/340] Add CVar for disabling loadout item role timers (#36775) --- Content.Client/Lobby/LobbyUIController.cs | 1 + Content.IntegrationTests/PoolManager.Cvars.cs | 1 + Content.Shared/CCVar/CCVars.Game.cs | 6 ++++++ .../Loadouts/Effects/JobRequirementLoadoutEffect.cs | 7 ++++++- Resources/ConfigPresets/Build/development.toml | 4 ++++ 5 files changed, 18 insertions(+), 1 deletion(-) diff --git a/Content.Client/Lobby/LobbyUIController.cs b/Content.Client/Lobby/LobbyUIController.cs index 121e8dbe71f..ec052adea55 100644 --- a/Content.Client/Lobby/LobbyUIController.cs +++ b/Content.Client/Lobby/LobbyUIController.cs @@ -72,6 +72,7 @@ public sealed class LobbyUIController : UIController, IOnStateEntered RefreshProfileEditor()); + _configurationManager.OnValueChanged(CCVars.GameRoleLoadoutTimers, _ => RefreshProfileEditor()); _configurationManager.OnValueChanged(CCVars.GameRoleWhitelist, _ => RefreshProfileEditor()); } diff --git a/Content.IntegrationTests/PoolManager.Cvars.cs b/Content.IntegrationTests/PoolManager.Cvars.cs index 2c51bdbc3a3..8cf2b626dc6 100644 --- a/Content.IntegrationTests/PoolManager.Cvars.cs +++ b/Content.IntegrationTests/PoolManager.Cvars.cs @@ -21,6 +21,7 @@ public static partial class PoolManager (CCVars.NPCMaxUpdates.Name, "999999"), (CVars.ThreadParallelCount.Name, "1"), (CCVars.GameRoleTimers.Name, "false"), + (CCVars.GameRoleLoadoutTimers.Name, "false"), (CCVars.GameRoleWhitelist.Name, "false"), (CCVars.GridFill.Name, "false"), (CCVars.PreloadGrids.Name, "false"), diff --git a/Content.Shared/CCVar/CCVars.Game.cs b/Content.Shared/CCVar/CCVars.Game.cs index 014b720e4e0..849f4f2da32 100644 --- a/Content.Shared/CCVar/CCVars.Game.cs +++ b/Content.Shared/CCVar/CCVars.Game.cs @@ -109,6 +109,12 @@ public sealed partial class CCVars public static readonly CVarDef GameRoleTimers = CVarDef.Create("game.role_timers", true, CVar.SERVER | CVar.REPLICATED); + /// + /// If role loadout items should be restricted based on time. + /// + public static readonly CVarDef + GameRoleLoadoutTimers = CVarDef.Create("game.role_loadout_timers", true, CVar.SERVER | CVar.REPLICATED); + /// /// Override default role requirements using a /// diff --git a/Content.Shared/Preferences/Loadouts/Effects/JobRequirementLoadoutEffect.cs b/Content.Shared/Preferences/Loadouts/Effects/JobRequirementLoadoutEffect.cs index 30d88815bde..56faccc866e 100644 --- a/Content.Shared/Preferences/Loadouts/Effects/JobRequirementLoadoutEffect.cs +++ b/Content.Shared/Preferences/Loadouts/Effects/JobRequirementLoadoutEffect.cs @@ -1,7 +1,9 @@ using System.Diagnostics.CodeAnalysis; using Content.Shared.Players; +using Content.Shared.CCVar; using Content.Shared.Players.PlayTimeTracking; using Content.Shared.Roles; +using Robust.Shared.Configuration; using Robust.Shared.Player; using Robust.Shared.Prototypes; using Robust.Shared.Utility; @@ -18,7 +20,10 @@ public sealed partial class JobRequirementLoadoutEffect : LoadoutEffect public override bool Validate(HumanoidCharacterProfile profile, RoleLoadout loadout, ICommonSession? session, IDependencyCollection collection, [NotNullWhen(false)] out FormattedMessage? reason) { - if (session == null) + var configurationManager = collection.Resolve(); + var timersDisabled = !configurationManager.GetCVar(CCVars.GameRoleLoadoutTimers); + + if (session == null || timersDisabled) { reason = FormattedMessage.Empty; return true; diff --git a/Resources/ConfigPresets/Build/development.toml b/Resources/ConfigPresets/Build/development.toml index e6c0af965a0..0a4be494e3b 100644 --- a/Resources/ConfigPresets/Build/development.toml +++ b/Resources/ConfigPresets/Build/development.toml @@ -4,10 +4,14 @@ lobbyenabled = false # Dev map for faster loading & convenience map = "Dev" role_timers = false +<<<<<<< HEAD contraband_examine = false # DeltaV secret_weight_prototype = "SecretDeltaV" # DeltaV role_timer_override = "DeltaV" # DeltaV showgreentext = false # DeltaV +======= +role_loadout_timers = false +>>>>>>> c709d4d55c (Add CVar for disabling loadout item role timers (#36775)) [events] enabled = false From 0c0421a61a9f9569e1df17ca0960836263722965 Mon Sep 17 00:00:00 2001 From: Mora <46364955+TrixxedHeart@users.noreply.github.com> Date: Wed, 3 Sep 2025 13:05:48 -0500 Subject: [PATCH 306/340] Some more vox customization (#39083) * Added docked and spiked tails, added talisman for vox * Tail Talisman ftl * adjusts talisman to be its own tail to avoid having to deal with other tails at all * vox tail stuff * Added amputated tail (courtesy of flareguy) and split tail * adds TODO regarding marking conditionals * rsi run check pls stop screaming at me * Shelving the talisman for later, keeping the sprites around * Add RSI credits * Remove unnecessary files * renamed amputated to vestigial --- Resources/Locale/en-US/markings/vox.ftl | 11 +++++- .../Mobs/Customization/Markings/vox_parts.yml | 32 +++++++++++++++++- .../Customization/Markings/vox_tattoos.yml | 1 + .../Customization/vox_parts.rsi/meta.json | 14 +++++++- .../vox_parts.rsi/tail_docked.png | Bin 0 -> 319 bytes .../vox_parts.rsi/tail_spikes.png | Bin 0 -> 3072 bytes .../vox_parts.rsi/tail_split.png | Bin 0 -> 372 bytes .../Customization/vox_tattoos.rsi/meta.json | 6 +++- .../vox_tattoos.rsi/tail_talisman.png | Bin 0 -> 2887 bytes 9 files changed, 60 insertions(+), 4 deletions(-) create mode 100644 Resources/Textures/Mobs/Customization/vox_parts.rsi/tail_docked.png create mode 100644 Resources/Textures/Mobs/Customization/vox_parts.rsi/tail_spikes.png create mode 100644 Resources/Textures/Mobs/Customization/vox_parts.rsi/tail_split.png create mode 100644 Resources/Textures/Mobs/Customization/vox_tattoos.rsi/tail_talisman.png diff --git a/Resources/Locale/en-US/markings/vox.ftl b/Resources/Locale/en-US/markings/vox.ftl index 1ae829ebbf1..3cb14df2aa0 100644 --- a/Resources/Locale/en-US/markings/vox.ftl +++ b/Resources/Locale/en-US/markings/vox.ftl @@ -53,4 +53,13 @@ marking-VoxTail-vox_tail = Vox Tail (Medium) marking-VoxTail = Vox Tail (Medium) marking-VoxTailBig-vox_tail_big = Vox Tail (Big) -marking-VoxTailBig = Vox Tail (Big) \ No newline at end of file +marking-VoxTailBig = Vox Tail (Big) + +marking-VoxTailSpikes-vox_tail_spikes = Vox Tail (Spiked) +marking-VoxTailSpikes = Vox Tail (Spiked) + +marking-VoxTailDocked-vox_tail_docked = Vox Tail (Vestigial) +marking-VoxTailDocked = Vox Tail (Vestigial) + +marking-VoxTailSplit-vox_tail_split = Vox Tail (Split) +marking-VoxTailSplit = Vox Tail (Split) diff --git a/Resources/Prototypes/Entities/Mobs/Customization/Markings/vox_parts.yml b/Resources/Prototypes/Entities/Mobs/Customization/Markings/vox_parts.yml index f3c0e5d204c..0643c5cbd45 100644 --- a/Resources/Prototypes/Entities/Mobs/Customization/Markings/vox_parts.yml +++ b/Resources/Prototypes/Entities/Mobs/Customization/Markings/vox_parts.yml @@ -161,4 +161,34 @@ forcedColoring: true sprites: - sprite: Mobs/Customization/vox_parts.rsi - state: tail_big \ No newline at end of file + state: tail_big + +- type: marking + id: VoxTailSpikes + bodyPart: Tail + markingCategory: Tail + speciesRestriction: [Vox] + forcedColoring: true + sprites: + - sprite: Mobs/Customization/vox_parts.rsi + state: tail_spikes + +- type: marking + id: VoxTailDocked + bodyPart: Tail + markingCategory: Tail + speciesRestriction: [Vox] + forcedColoring: true + sprites: + - sprite: Mobs/Customization/vox_parts.rsi + state: tail_docked + +- type: marking + id: VoxTailSplit + bodyPart: Tail + markingCategory: Tail + speciesRestriction: [Vox] + forcedColoring: true + sprites: + - sprite: Mobs/Customization/vox_parts.rsi + state: tail_split \ No newline at end of file diff --git a/Resources/Prototypes/Entities/Mobs/Customization/Markings/vox_tattoos.yml b/Resources/Prototypes/Entities/Mobs/Customization/Markings/vox_tattoos.yml index 567c3b26203..cf350da60d4 100644 --- a/Resources/Prototypes/Entities/Mobs/Customization/Markings/vox_tattoos.yml +++ b/Resources/Prototypes/Entities/Mobs/Customization/Markings/vox_tattoos.yml @@ -56,6 +56,7 @@ - type: marking id: TattooVoxTailRing + # TODO // Looks off on some tails (i.e docked/amputated), if conditionals for markings ever get implemented this needs to be updated to account for those. bodyPart: Tail markingCategory: Overlay speciesRestriction: [Vox] diff --git a/Resources/Textures/Mobs/Customization/vox_parts.rsi/meta.json b/Resources/Textures/Mobs/Customization/vox_parts.rsi/meta.json index 183e3c03380..143710ad9ff 100644 --- a/Resources/Textures/Mobs/Customization/vox_parts.rsi/meta.json +++ b/Resources/Textures/Mobs/Customization/vox_parts.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from https://github.com/vgstation-coders/vgstation13 at 02ff588d59b3c560c685d9ca75e882d32a72d8cb, modified by Bhijn, Errant and Flareguy. tail_big and tail_short modified from tail by Flareguy", + "copyright": "Taken from https://github.com/vgstation-coders/vgstation13 at 02ff588d59b3c560c685d9ca75e882d32a72d8cb, modified by Bhijn, Errant and Flareguy. tail_big tail_short and tail_docked modified from tail by Flareguy, tail_spiked modified from tail by TrixxedHeart", "size": { "x": 32, "y": 32 @@ -58,6 +58,18 @@ { "name": "tail_big", "directions": 4 + }, + { + "name": "tail_spikes", + "directions": 4 + }, + { + "name": "tail_docked", + "directions": 4 + }, + { + "name": "tail_split", + "directions": 4 } ] } diff --git a/Resources/Textures/Mobs/Customization/vox_parts.rsi/tail_docked.png b/Resources/Textures/Mobs/Customization/vox_parts.rsi/tail_docked.png new file mode 100644 index 0000000000000000000000000000000000000000..9850750ff54e675c35ea7bac8b624c7d19364c97 GIT binary patch literal 319 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!7>k44ofy`glX(f`u%tWsIx;Y9 z?C1WI$O`0(2Ka=yPMI?0?AfzVpFaKn|Npvm>wv;Q@H<-oq?^4Y$S)Wu4g?HR-pp=5 zA(?%Jb+hl)OToU=A?GjkR@_5q6 zdD9;7a3~ZgG#qGTV0vE7q*NVg7X5u^*P&H2^#fCP@}?Qgwy%GZ{l{ZPt?`+~2iLc2 zgmKLN?!J*bX5&-uMej8%{{EUD#H?B&&GFB{;FzdyP2A~}xh4KUw=#IT`njxgN@xNA DRt9(K literal 0 HcmV?d00001 diff --git a/Resources/Textures/Mobs/Customization/vox_parts.rsi/tail_spikes.png b/Resources/Textures/Mobs/Customization/vox_parts.rsi/tail_spikes.png new file mode 100644 index 0000000000000000000000000000000000000000..c5af68390951756e8cebb000711b5dc355c676cb GIT binary patch literal 3072 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 C1drSR literal 0 HcmV?d00001 diff --git a/Resources/Textures/Mobs/Customization/vox_tattoos.rsi/meta.json b/Resources/Textures/Mobs/Customization/vox_tattoos.rsi/meta.json index e1d263c9acb..92dbbff751f 100644 --- a/Resources/Textures/Mobs/Customization/vox_tattoos.rsi/meta.json +++ b/Resources/Textures/Mobs/Customization/vox_tattoos.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from Paradise at https://github.com/ParadiseSS13/Paradise/blob/ef7a4d962915cb36b138eeb59663f0053d4906fe/icons/mob/sprite_accessories/vox/vox_body_markings.dmi and modified by Flareguy. eyeshadow & tail_ring states by Flareguy", + "copyright": "Taken from Paradise at https://github.com/ParadiseSS13/Paradise/blob/ef7a4d962915cb36b138eeb59663f0053d4906fe/icons/mob/sprite_accessories/vox/vox_body_markings.dmi and modified by Flareguy. eyeshadow & tail_ring states by Flareguy, tail_talisman by TrixxedHeart", "size": { "x": 32, "y": 32 @@ -23,6 +23,10 @@ "name": "nightling_s", "directions": 4 }, + { + "name": "tail_talisman", + "directions": 4 + }, { "name": "tattoo_eye_vox_r", "directions": 4 diff --git a/Resources/Textures/Mobs/Customization/vox_tattoos.rsi/tail_talisman.png b/Resources/Textures/Mobs/Customization/vox_tattoos.rsi/tail_talisman.png new file mode 100644 index 0000000000000000000000000000000000000000..80fade39b9a1c16a84e0c13847b1e8ed13d4e91e GIT binary patch literal 2887 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 literal 0 HcmV?d00001 From 500209a1c2d4f5d3201960093916588cdc79f05b Mon Sep 17 00:00:00 2001 From: FungiFellow <151778459+FungiFellow@users.noreply.github.com> Date: Wed, 3 Sep 2025 08:00:07 -0400 Subject: [PATCH 307/340] Trimmed Sentience Targets from Corgis Smile and Cockroaches (#39810) * Update animals.yml * Update pets.yml * Removed Sentience Target from corgi * Update random-sentience.ftl * Obliterated Scurret from .ftl --- .../Locale/en-US/station-events/events/random-sentience.ftl | 3 --- Resources/Prototypes/Entities/Mobs/NPCs/animals.yml | 4 ---- Resources/Prototypes/Entities/Mobs/NPCs/pets.yml | 2 -- 3 files changed, 9 deletions(-) diff --git a/Resources/Locale/en-US/station-events/events/random-sentience.ftl b/Resources/Locale/en-US/station-events/events/random-sentience.ftl index 5cf07f4f084..135ec3df5d1 100644 --- a/Resources/Locale/en-US/station-events/events/random-sentience.ftl +++ b/Resources/Locale/en-US/station-events/events/random-sentience.ftl @@ -32,9 +32,6 @@ station-event-random-sentience-role-description = You are a sentient { $name }, # Flavors station-event-random-sentience-flavor-mechanical = mechanical station-event-random-sentience-flavor-organic = organic -station-event-random-sentience-flavor-corgi = corgi station-event-random-sentience-flavor-primate = primate station-event-random-sentience-flavor-kobold = kobold -station-event-random-sentience-flavor-slime = slime station-event-random-sentience-flavor-inanimate = inanimate -station-event-random-sentience-flavor-scurret = scurret diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml b/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml index 4eb6f820720..8807547e0d9 100644 --- a/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml +++ b/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml @@ -430,8 +430,6 @@ gibContents: Skip # Shitmed Change recursive: false - type: NonSpreaderZombie - - type: SentienceTarget - flavorKind: station-event-random-sentience-flavor-organic - type: MeleeWeapon soundHit: path: /Audio/Effects/bite.ogg @@ -3079,8 +3077,6 @@ amount: 2 - type: ReplacementAccent accent: dog - - type: SentienceTarget - flavorKind: station-event-random-sentience-flavor-corgi - type: Tag tags: - VimPilot diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/pets.yml b/Resources/Prototypes/Entities/Mobs/NPCs/pets.yml index d912276bbf7..23849f987fb 100644 --- a/Resources/Prototypes/Entities/Mobs/NPCs/pets.yml +++ b/Resources/Prototypes/Entities/Mobs/NPCs/pets.yml @@ -869,8 +869,6 @@ - type: Item sprite: Mobs/Pets/Smile/smile.rsi size: Huge - - type: SentienceTarget - flavorKind: station-event-random-sentience-flavor-slime - type: MobPrice price: 3000 # it is a truly valuable creature - type: GhostRole From 3c2da3143bbbdf0da264c4dbc2c766e848ff730e Mon Sep 17 00:00:00 2001 From: opl- Date: Wed, 3 Sep 2025 22:49:50 +0200 Subject: [PATCH 308/340] Use a fixed amount of decimal points in gas analyzer window (#40081) This prevents the volume and temperature labels from changing width when the value lands on integer values, making the text easier to read. Co-authored-by: opl <4833621+opl@users.noreply.github.com> --- Content.Client/Atmos/UI/GasAnalyzerWindow.xaml.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Content.Client/Atmos/UI/GasAnalyzerWindow.xaml.cs b/Content.Client/Atmos/UI/GasAnalyzerWindow.xaml.cs index e280523e43e..63b4e6b0c6f 100644 --- a/Content.Client/Atmos/UI/GasAnalyzerWindow.xaml.cs +++ b/Content.Client/Atmos/UI/GasAnalyzerWindow.xaml.cs @@ -208,7 +208,7 @@ namespace Content.Client.Atmos.UI }); presBox.AddChild(new Label { - Text = Loc.GetString("gas-analyzer-window-pressure-val-text", ("pressure", $"{gasMix.Pressure:0.##}")), + Text = Loc.GetString("gas-analyzer-window-pressure-val-text", ("pressure", $"{gasMix.Pressure:0.00}")), Align = Label.AlignMode.Right, HorizontalExpand = true }); @@ -232,8 +232,8 @@ namespace Content.Client.Atmos.UI tempBox.AddChild(new Label { Text = Loc.GetString("gas-analyzer-window-temperature-val-text", - ("tempK", $"{gasMix.Temperature:0.#}"), - ("tempC", $"{TemperatureHelpers.KelvinToCelsius(gasMix.Temperature):0.#}")), + ("tempK", $"{gasMix.Temperature:0.0}"), + ("tempC", $"{TemperatureHelpers.KelvinToCelsius(gasMix.Temperature):0.0}")), Align = Label.AlignMode.Right, HorizontalExpand = true }); From 28f8d6dd225c1e2d3b8a95301fd727d2db420d6b Mon Sep 17 00:00:00 2001 From: breeplayx3 Date: Wed, 3 Sep 2025 17:06:04 -0400 Subject: [PATCH 309/340] Berry Delight recipe edit (#40085) berry delight change --- Resources/Prototypes/Recipes/Cooking/meal_recipes.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Resources/Prototypes/Recipes/Cooking/meal_recipes.yml b/Resources/Prototypes/Recipes/Cooking/meal_recipes.yml index 7e3cca3fa4b..53577fd9995 100644 --- a/Resources/Prototypes/Recipes/Cooking/meal_recipes.yml +++ b/Resources/Prototypes/Recipes/Cooking/meal_recipes.yml @@ -1707,8 +1707,8 @@ time: 5 group: Cake solids: - FoodCakePlain: 1 - FoodBerries: 5 + FoodCakeBlueberry: 1 + FoodBerries: 2 reagents: Milk: 10 From 32f018e80428079be570a52727d877e2a922f213 Mon Sep 17 00:00:00 2001 From: pathetic meowmeow Date: Wed, 3 Sep 2025 17:29:50 -0400 Subject: [PATCH 310/340] Don't enqueue construction events without validation (#39869) --- .../Interaction/EdgeClobbering.cs | 49 +++++++++++++++++++ .../ConstructionSystem.Interactions.cs | 4 ++ 2 files changed, 53 insertions(+) create mode 100644 Content.IntegrationTests/Tests/Construction/Interaction/EdgeClobbering.cs diff --git a/Content.IntegrationTests/Tests/Construction/Interaction/EdgeClobbering.cs b/Content.IntegrationTests/Tests/Construction/Interaction/EdgeClobbering.cs new file mode 100644 index 00000000000..9f578148cfb --- /dev/null +++ b/Content.IntegrationTests/Tests/Construction/Interaction/EdgeClobbering.cs @@ -0,0 +1,49 @@ +using Content.IntegrationTests.Tests.Interaction; +using Content.Server.Construction.Components; +using Content.Shared.Temperature; + +namespace Content.IntegrationTests.Tests.Construction.Interaction; + +public sealed class EdgeClobbering : InteractionTest +{ + [TestPrototypes] + private const string Prototypes = @" +- type: constructionGraph + id: ExampleGraph + start: A + graph: + - node: A + edges: + - to: B + steps: + - tool: Anchoring + doAfter: 1 + - to: C + steps: + - tool: Screwing + doAfter: 1 + - node: B + - node: C + +- type: entity + id: ExampleEntity + components: + - type: Construction + graph: ExampleGraph + node: A + + "; + + [Test] + public async Task EnsureNoEdgeClobbering() + { + await SpawnTarget("ExampleEntity"); + var sTarget = SEntMan.GetEntity(Target!.Value); + + await InteractUsing(Screw, false); + SEntMan.EventBus.RaiseLocalEvent(sTarget, new OnTemperatureChangeEvent(0f, 0f, 0f)); + await AwaitDoAfters(); + + Assert.That(SEntMan.GetComponent(sTarget).Node, Is.EqualTo("C")); + } +} diff --git a/Content.Server/Construction/ConstructionSystem.Interactions.cs b/Content.Server/Construction/ConstructionSystem.Interactions.cs index ffab936019a..e838d7087ed 100644 --- a/Content.Server/Construction/ConstructionSystem.Interactions.cs +++ b/Content.Server/Construction/ConstructionSystem.Interactions.cs @@ -570,6 +570,10 @@ namespace Content.Server.Construction handled.Handled = true; } + // Make sure the event passes validation before enqueuing it + if (HandleEvent(uid, args, true, construction) != HandleResult.Validated) + return; + // Enqueue this event so it'll be handled in the next tick. // This prevents some issues that could occur from entity deletion, component deletion, etc in a handler. construction.InteractionQueue.Enqueue(args); From 3e1d74b1f37515910635cf2126366bda1d97238e Mon Sep 17 00:00:00 2001 From: Tiniest Shark Date: Wed, 3 Sep 2025 15:42:50 -0400 Subject: [PATCH 311/340] Burger Inhands (#39894) burger is in your hands --- .../Objects/Consumable/Food/burger.yml | 317 ++++++++++ .../Food/burger.rsi/alpha-bun-inhand-left.png | Bin 0 -> 381 bytes .../burger.rsi/alpha-bun-inhand-right.png | Bin 0 -> 416 bytes .../burger.rsi/alpha-filling-inhand-left.png | Bin 0 -> 155 bytes .../burger.rsi/alpha-filling-inhand-right.png | Bin 0 -> 156 bytes .../burger.rsi/alpha-patty-inhand-left.png | Bin 0 -> 182 bytes .../burger.rsi/alpha-patty-inhand-right.png | Bin 0 -> 201 bytes .../Food/burger.rsi/bear-inhand-left.png | Bin 0 -> 558 bytes .../Food/burger.rsi/bear-inhand-right.png | Bin 0 -> 579 bytes .../Food/burger.rsi/brain-inhand-left.png | Bin 0 -> 564 bytes .../Food/burger.rsi/brain-inhand-right.png | Bin 0 -> 597 bytes .../Food/burger.rsi/bun-inhand-left.png | Bin 0 -> 464 bytes .../Food/burger.rsi/bun-inhand-right.png | Bin 0 -> 475 bytes .../burger.rsi/burger-big-inhand-left.png | Bin 0 -> 752 bytes .../burger.rsi/burger-big-inhand-right.png | Bin 0 -> 819 bytes .../Food/burger.rsi/burger-inhand-left.png | Bin 0 -> 334 bytes .../Food/burger.rsi/burger-inhand-right.png | Bin 0 -> 333 bytes .../burger.rsi/burger-super-inhand-left.png | Bin 0 -> 896 bytes .../burger.rsi/burger-super-inhand-right.png | Bin 0 -> 942 bytes .../Food/burger.rsi/cat-inhand-left.png | Bin 0 -> 253 bytes .../Food/burger.rsi/cat-inhand-right.png | Bin 0 -> 249 bytes .../Food/burger.rsi/clown-inhand-left.png | Bin 0 -> 804 bytes .../Food/burger.rsi/clown-inhand-right.png | Bin 0 -> 859 bytes .../Food/burger.rsi/crazy-inhand-left.png | Bin 0 -> 1915 bytes .../Food/burger.rsi/crazy-inhand-right.png | Bin 0 -> 1784 bytes .../Food/burger.rsi/dog-inhand-left.png | Bin 0 -> 710 bytes .../Food/burger.rsi/dog-inhand-right.png | Bin 0 -> 760 bytes .../Food/burger.rsi/inhand-left.png | Bin 207 -> 0 bytes .../Food/burger.rsi/inhand-right.png | Bin 212 -> 0 bytes .../Consumable/Food/burger.rsi/meta.json | 572 ++++++++++++------ .../Food/burger.rsi/mime-inhand-left.png | Bin 0 -> 642 bytes .../Food/burger.rsi/mime-inhand-right.png | Bin 0 -> 665 bytes .../Food/burger.rsi/mothroach-inhand-left.png | Bin 0 -> 859 bytes .../burger.rsi/mothroach-inhand-right.png | Bin 0 -> 867 bytes .../Food/burger.rsi/plain-inhand-left.png | Bin 0 -> 625 bytes .../Food/burger.rsi/plain-inhand-right.png | Bin 0 -> 678 bytes .../Food/burger.rsi/plasma-inhand-left.png | Bin 0 -> 924 bytes .../Food/burger.rsi/plasma-inhand-right.png | Bin 0 -> 1000 bytes .../Food/burger.rsi/rat-inhand-left.png | Bin 0 -> 344 bytes .../Food/burger.rsi/rat-inhand-right.png | Bin 0 -> 336 bytes .../Food/burger.rsi/spell-inhand-left.png | Bin 0 -> 770 bytes .../Food/burger.rsi/spell-inhand-right.png | Bin 0 -> 844 bytes 42 files changed, 701 insertions(+), 188 deletions(-) create mode 100644 Resources/Textures/Objects/Consumable/Food/burger.rsi/alpha-bun-inhand-left.png create mode 100644 Resources/Textures/Objects/Consumable/Food/burger.rsi/alpha-bun-inhand-right.png create mode 100644 Resources/Textures/Objects/Consumable/Food/burger.rsi/alpha-filling-inhand-left.png create mode 100644 Resources/Textures/Objects/Consumable/Food/burger.rsi/alpha-filling-inhand-right.png create mode 100644 Resources/Textures/Objects/Consumable/Food/burger.rsi/alpha-patty-inhand-left.png create mode 100644 Resources/Textures/Objects/Consumable/Food/burger.rsi/alpha-patty-inhand-right.png create mode 100644 Resources/Textures/Objects/Consumable/Food/burger.rsi/bear-inhand-left.png create mode 100644 Resources/Textures/Objects/Consumable/Food/burger.rsi/bear-inhand-right.png create mode 100644 Resources/Textures/Objects/Consumable/Food/burger.rsi/brain-inhand-left.png create mode 100644 Resources/Textures/Objects/Consumable/Food/burger.rsi/brain-inhand-right.png create mode 100644 Resources/Textures/Objects/Consumable/Food/burger.rsi/bun-inhand-left.png create mode 100644 Resources/Textures/Objects/Consumable/Food/burger.rsi/bun-inhand-right.png create mode 100644 Resources/Textures/Objects/Consumable/Food/burger.rsi/burger-big-inhand-left.png create mode 100644 Resources/Textures/Objects/Consumable/Food/burger.rsi/burger-big-inhand-right.png create mode 100644 Resources/Textures/Objects/Consumable/Food/burger.rsi/burger-inhand-left.png create mode 100644 Resources/Textures/Objects/Consumable/Food/burger.rsi/burger-inhand-right.png create mode 100644 Resources/Textures/Objects/Consumable/Food/burger.rsi/burger-super-inhand-left.png create mode 100644 Resources/Textures/Objects/Consumable/Food/burger.rsi/burger-super-inhand-right.png create mode 100644 Resources/Textures/Objects/Consumable/Food/burger.rsi/cat-inhand-left.png create mode 100644 Resources/Textures/Objects/Consumable/Food/burger.rsi/cat-inhand-right.png create mode 100644 Resources/Textures/Objects/Consumable/Food/burger.rsi/clown-inhand-left.png create mode 100644 Resources/Textures/Objects/Consumable/Food/burger.rsi/clown-inhand-right.png create mode 100644 Resources/Textures/Objects/Consumable/Food/burger.rsi/crazy-inhand-left.png create mode 100644 Resources/Textures/Objects/Consumable/Food/burger.rsi/crazy-inhand-right.png create mode 100644 Resources/Textures/Objects/Consumable/Food/burger.rsi/dog-inhand-left.png create mode 100644 Resources/Textures/Objects/Consumable/Food/burger.rsi/dog-inhand-right.png delete mode 100644 Resources/Textures/Objects/Consumable/Food/burger.rsi/inhand-left.png delete mode 100644 Resources/Textures/Objects/Consumable/Food/burger.rsi/inhand-right.png create mode 100644 Resources/Textures/Objects/Consumable/Food/burger.rsi/mime-inhand-left.png create mode 100644 Resources/Textures/Objects/Consumable/Food/burger.rsi/mime-inhand-right.png create mode 100644 Resources/Textures/Objects/Consumable/Food/burger.rsi/mothroach-inhand-left.png create mode 100644 Resources/Textures/Objects/Consumable/Food/burger.rsi/mothroach-inhand-right.png create mode 100644 Resources/Textures/Objects/Consumable/Food/burger.rsi/plain-inhand-left.png create mode 100644 Resources/Textures/Objects/Consumable/Food/burger.rsi/plain-inhand-right.png create mode 100644 Resources/Textures/Objects/Consumable/Food/burger.rsi/plasma-inhand-left.png create mode 100644 Resources/Textures/Objects/Consumable/Food/burger.rsi/plasma-inhand-right.png create mode 100644 Resources/Textures/Objects/Consumable/Food/burger.rsi/rat-inhand-left.png create mode 100644 Resources/Textures/Objects/Consumable/Food/burger.rsi/rat-inhand-right.png create mode 100644 Resources/Textures/Objects/Consumable/Food/burger.rsi/spell-inhand-left.png create mode 100644 Resources/Textures/Objects/Consumable/Food/burger.rsi/spell-inhand-right.png diff --git a/Resources/Prototypes/Entities/Objects/Consumable/Food/burger.yml b/Resources/Prototypes/Entities/Objects/Consumable/Food/burger.yml index 9bff344d65e..b3a2be94f61 100644 --- a/Resources/Prototypes/Entities/Objects/Consumable/Food/burger.yml +++ b/Resources/Prototypes/Entities/Objects/Consumable/Food/burger.yml @@ -127,6 +127,20 @@ - state: custburg-filling color: red - state: custburg-top + - type: Item + inhandVisuals: + left: + - state: bun-inhand-left + - state: alpha-patty-inhand-left + color: "#f70000" + - state: alpha-filling-inhand-left + color: "#f70000" + right: + - state: bun-inhand-right + - state: alpha-patty-inhand-right + color: "#f70000" + - state: alpha-filling-inhand-right + color: "#f70000" # Burger @@ -156,6 +170,20 @@ - type: Tag tags: - Meat + - type: Item + inhandVisuals: + left: + - state: bun-inhand-left + - state: alpha-patty-inhand-left + color: "#382010" + - state: alpha-filling-inhand-left + color: "#bd9451" + right: + - state: bun-inhand-right + - state: alpha-patty-inhand-right + color: "#382010" + - state: alpha-filling-inhand-right + color: "#bd9451" # Tastes like bun, grass. - type: entity @@ -182,6 +210,20 @@ - type: Tag tags: - Meat + - type: Item + inhandVisuals: + left: + - state: bun-inhand-left + - state: alpha-patty-inhand-left + color: "#b37659" + - state: alpha-filling-inhand-left + color: "#e8634f" + right: + - state: bun-inhand-right + - state: alpha-patty-inhand-right + color: "#b37659" + - state: alpha-filling-inhand-right + color: "#e8634f" # Tastes like bun, bacon. - type: entity @@ -210,6 +252,16 @@ - type: Tag tags: - Meat + - type: Item + inhandVisuals: + left: + - state: alpha-bun-inhand-left + color: "#f7f7f7" + - state: burger-inhand-left + right: + - state: alpha-bun-inhand-right + color: "#f7f7f7" + - state: burger-inhand-right - type: entity name: bearger @@ -237,6 +289,12 @@ - type: Tag tags: - Meat + - type: Item + inhandVisuals: + left: + - state: bear-inhand-left + right: + - state: bear-inhand-right - type: entity name: big bite burger @@ -265,6 +323,12 @@ - type: Tag tags: - Meat + - type: Item + inhandVisuals: + left: + - state: burger-big-inhand-left + right: + - state: burger-big-inhand-right # Tastes like bun, silver, magic. - type: entity @@ -293,6 +357,12 @@ - type: Tag tags: - Meat + - type: Item + inhandVisuals: + left: + - state: brain-inhand-left + right: + - state: brain-inhand-right # Tastes like bun, brains. - type: entity @@ -322,6 +392,14 @@ - type: Tag tags: - Meat + - type: Item + inhandVisuals: + left: + - state: cat-inhand-left + - state: plain-inhand-left + right: + - state: cat-inhand-right + - state: plain-inhand-right - type: entity name: cheese burger @@ -350,6 +428,12 @@ - type: Tag tags: - Meat + - type: Item + inhandVisuals: + left: + - state: plain-inhand-left + right: + - state: plain-inhand-right # TODO: Make this work. # - type: Sprite # state: plate @@ -388,6 +472,20 @@ - type: Tag tags: - Meat + - type: Item + inhandVisuals: + left: + - state: bun-inhand-left + - state: alpha-filling-inhand-left + color: "#98d966" + - state: alpha-patty-inhand-left + color: "#f7b125" + right: + - state: bun-inhand-right + - state: alpha-filling-inhand-right + color: "#98d966" + - state: alpha-patty-inhand-right + color: "#f7b125" # Tastes like bun, chicken. - type: entity @@ -416,6 +514,12 @@ - type: Tag tags: - Meat + - type: Item + inhandVisuals: + left: + - state: clown-inhand-left + right: + - state: clown-inhand-right - type: entity name: corger #not curger @@ -442,6 +546,12 @@ - type: Tag tags: - Meat + - type: Item + inhandVisuals: + left: + - state: dog-inhand-left + right: + - state: dog-inhand-right - type: entity name: crab burger @@ -469,6 +579,20 @@ - type: Tag tags: - Meat + - type: Item + inhandVisuals: + left: + - state: bun-inhand-left + - state: alpha-filling-inhand-left + color: "#7e1a07" + - state: alpha-patty-inhand-left + color: "#7e1a07" + right: + - state: bun-inhand-right + - state: alpha-filling-inhand-right + color: "#7e1a07" + - state: alpha-patty-inhand-right + color: "#7e1a07" - type: entity name: crazy hamburger # Burger for you euro-cucks @@ -502,6 +626,12 @@ - type: Tag tags: - Meat + - type: Item + inhandVisuals: + left: + - state: crazy-inhand-left + right: + - state: crazy-inhand-right - type: entity name: duck sandwich # Burger for you sick bastards @@ -527,6 +657,20 @@ - type: Tag tags: - Meat + - type: Item + inhandVisuals: + left: + - state: bun-inhand-left + - state: alpha-filling-inhand-left + color: "#98d966" + - state: alpha-patty-inhand-left + color: "#e8b348" + right: + - state: bun-inhand-right + - state: alpha-filling-inhand-right + color: "#98d966" + - state: alpha-patty-inhand-right + color: "#e8b348" # Tastes like bun, duck. - type: entity @@ -550,6 +694,12 @@ Quantity: 8 - ReagentId: Licoxide Quantity: 5 + - type: Item + inhandVisuals: + left: + - state: plasma-inhand-left + right: + - state: plasma-inhand-right # Tastes like bun, pure electricity. - type: entity @@ -567,6 +717,20 @@ - type: Tag tags: - Meat + - type: Item + inhandVisuals: + left: + - state: bun-inhand-left + - state: alpha-filling-inhand-left + color: "#feffba" + - state: alpha-patty-inhand-left + color: "#f4bb53" + right: + - state: bun-inhand-right + - state: alpha-filling-inhand-right + color: "#feffba" + - state: alpha-patty-inhand-right + color: "#f4bb53" # Tastes like bun, fish. - type: entity @@ -599,6 +763,12 @@ - type: Tag tags: - Meat + - type: Item + inhandVisuals: + left: + - state: plain-inhand-left + right: + - state: plain-inhand-right # Tastes like bun, HEAT. @@ -627,6 +797,22 @@ tags: - ClothMade - Meat + - type: Item + inhandVisuals: + left: + - state: alpha-bun-inhand-left + color: "#cededa" + - state: alpha-filling-inhand-left + color: "#6a6281" + - state: alpha-patty-inhand-left + color: "#95a79f" + right: + - state: alpha-bun-inhand-right + color: "#cededa" + - state: alpha-filling-inhand-right + color: "#6a6281" + - state: alpha-patty-inhand-right + color: "#95a79f" # Tastes like bun, ectoplasm. - type: entity @@ -655,6 +841,12 @@ - type: Tag tags: - Meat + - type: Item + inhandVisuals: + left: + - state: plain-inhand-left + right: + - state: plain-inhand-right - type: entity name: McGuffin @@ -682,6 +874,20 @@ - type: Tag tags: - Meat + - type: Item + inhandVisuals: + left: + - state: bun-inhand-left + - state: alpha-filling-inhand-left + color: "#f2efce" + - state: alpha-patty-inhand-left + color: "#e3756d" + right: + - state: bun-inhand-right + - state: alpha-filling-inhand-right + color: "#f2efce" + - state: alpha-patty-inhand-right + color: "#e3756d" - type: entity name: BBQ Rib Sandwich @@ -714,6 +920,20 @@ - type: Tag tags: - Meat + - type: Item + inhandVisuals: + left: + - state: bun-inhand-left + - state: alpha-filling-inhand-left + color: "#899660" + - state: alpha-patty-inhand-left + color: "#a94a31" + right: + - state: bun-inhand-right + - state: alpha-filling-inhand-right + color: "#899660" + - state: alpha-patty-inhand-right + color: "#a94a31" # Tastes like bun, pork patty. - type: entity @@ -741,6 +961,12 @@ Quantity: 4 - ReagentId: Nothing Quantity: 1 + - type: Item + inhandVisuals: + left: + - state: mime-inhand-left + right: + - state: mime-inhand-right # Tastes like . - type: entity @@ -769,6 +995,12 @@ - type: Tag tags: - Meat + - type: Item + inhandVisuals: + left: + - state: plain-inhand-left + right: + - state: plain-inhand-right - type: entity name: rat burger @@ -796,6 +1028,15 @@ - type: Tag tags: - Meat + - type: Item + inhandVisuals: + left: + - state: bun-inhand-left + - state: rat-inhand-left + right: + - state: bun-inhand-right + - state: rat-inhand-right + # Tastes like bun, HEAT. - type: entity @@ -823,6 +1064,22 @@ - type: Tag tags: - Meat + - type: Item + inhandVisuals: + left: + - state: alpha-bun-inhand-left + color: "#7f7f7f" + - state: alpha-patty-inhand-left + color: "#c0c0c0" + - state: alpha-filling-inhand-left + color: "#141414" + right: + - state: alpha-bun-inhand-right + color: "#7f7f7f" + - state: alpha-patty-inhand-right + color: "#c0c0c0" + - state: alpha-filling-inhand-right + color: "#141414" # Tastes like bun, lettuce, sludge. - type: entity @@ -846,6 +1103,20 @@ Quantity: 13 - ReagentId: Vitamin Quantity: 5 + - type: Item + inhandVisuals: + left: + - state: bun-inhand-left + - state: alpha-patty-inhand-left + color: "#91d90b" + - state: alpha-filling-inhand-left + color: "#91d90b" + right: + - state: bun-inhand-right + - state: alpha-patty-inhand-right + color: "#91d90b" + - state: alpha-filling-inhand-right + color: "#91d90b" # Tastes like bun, redditors. - type: entity @@ -871,6 +1142,12 @@ Quantity: 5 - ReagentId: Vitamin Quantity: 10 + - type: Item + inhandVisuals: + left: + - state: spell-inhand-left + right: + - state: spell-inhand-right # Tastes like bun, silver. - type: entity @@ -902,6 +1179,12 @@ - type: Tag tags: - Meat + - type: Item + inhandVisuals: + left: + - state: burger-super-inhand-left + right: + - state: burger-super-inhand-right # Tastes like bun, diabetes. - type: entity @@ -925,6 +1208,20 @@ Quantity: 8 - ReagentId: Protein Quantity: 3 + - type: Item + inhandVisuals: + left: + - state: bun-inhand-left + - state: alpha-patty-inhand-left + color: "#f0d8a1" + - state: alpha-filling-inhand-left + color: "#e5ad29" + right: + - state: bun-inhand-right + - state: alpha-patty-inhand-right + color: "#f0d8a1" + - state: alpha-filling-inhand-right + color: "#e5ad29" # Tastes like bun, tofu. - type: entity @@ -954,6 +1251,20 @@ - type: Tag tags: - Meat + - type: Item + inhandVisuals: + left: + - state: bun-inhand-left + - state: alpha-patty-inhand-left + color: "#00cc33" + - state: alpha-filling-inhand-left + color: "#9900cc" + right: + - state: bun-inhand-right + - state: alpha-patty-inhand-right + color: "#00cc33" + - state: alpha-filling-inhand-right + color: "#9900cc" # Tastes like bun, acid. # Note: I would put a bunch of colored burgers here as listed in the tg .dm but @@ -986,4 +1297,10 @@ - type: Tag tags: - Meat + - type: Item + inhandVisuals: + left: + - state: mothroach-inhand-left + right: + - state: mothroach-inhand-right diff --git a/Resources/Textures/Objects/Consumable/Food/burger.rsi/alpha-bun-inhand-left.png b/Resources/Textures/Objects/Consumable/Food/burger.rsi/alpha-bun-inhand-left.png new file mode 100644 index 0000000000000000000000000000000000000000..e949a52f5adad1179fdfa491f9cc906036705ba2 GIT binary patch literal 381 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=jKx9jP7LeL$-D%z%{^TlLn`LH zy|uTu#Xx}dLHVVl0sOWX+NB*t5;GdQ?l3iGGISp>F_=DQVl!`Ec(Sb6`^gi`5_yi< zU$SF%0fR3#@lma7woa<+f4m}WJJ+?SPD8JrKo^&`#0mCyzLiPeG7ViaU0m?vz3%UE zdxe9fqrMj1mvVLDxX#M(dRNvI*1Gt663xppuVjTCjjHZl^S@54N;RHg@ApS@R=@II znG^n#Ywvq&hJ<<#ivQ>1qJ7r=Yfw^pUdhBT zEmiXp=k|9`Y?S&9SFuaoN*4@y^f9LEg!hTXpK@;tI2|zYWl)&!R`^QxLTT(p#h-5`#XyAZga3`q;uqPL?Z{ME(viV@xxM)NG_hwBOcqplu;%NpK4HK;({xi`oxOm| zB=>(>KbQmrLEz%gl#Q&thDLX@*Dii7+hpkG#3AGalv+B)CFHmG=}s@Pf>%3={pJ+! zmTM`${Y^ADL!#{`Q^WDc8y9un{&a8gx@?9C%QDYx4P`tKrJZ~GU0Lfpzb`_ZiYK=4 z9xHUYUTSejsQcA{PiJp^w`F*=}T{XaVXKZ{=WES&xJuR9Hf zZtJdVGbo%dPKn$$-!s^&v*S!Ud(iV|@k^ftA9K&C`Xjn@%9T>y_qGfVigrFoU#9ZZ ztHST>@^8->85(~7?OUXAY3sAjYgU(|^2O$V%d0dyX{mng)|2-Qq19V+qcyvjQX?1X zcrzS$Tju@C^u{mk%~}tpw5?l}Radr4xdh~-FAMiE-buOrnJxR^QecoXc)I$ztaD0e F0svBCyc+-j literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Consumable/Food/burger.rsi/alpha-filling-inhand-left.png b/Resources/Textures/Objects/Consumable/Food/burger.rsi/alpha-filling-inhand-left.png new file mode 100644 index 0000000000000000000000000000000000000000..23e3dd2248451e0b9aac7568c2cacd40f7c9d0b8 GIT binary patch literal 155 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=jKx9jP7LeL$-D$|LOop^Ln`LH zy>*cDfB_Hl0iL-BZ9396{nq*tt-*5YE{juqrY=w!!-HOx%XfoAC#QV7H#x=c`LEve xgUdIAB!Hk`_w$ddX1z0;T7OcUk%8gIDb_7Z9oO#9+}sV4^>p=fS?83{1OR=DHt+xd literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Consumable/Food/burger.rsi/alpha-filling-inhand-right.png b/Resources/Textures/Objects/Consumable/Food/burger.rsi/alpha-filling-inhand-right.png new file mode 100644 index 0000000000000000000000000000000000000000..2846e579bc3276ebf7f5c39416138e1155fdebf6 GIT binary patch literal 156 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=jKx9jP7LeL$-D$|!aQ9ZLn`LH zy|t0IA%Md*u>D`N;fdLtZ+fJvO)Zx%+{>w&BMnr>P;mWjaOmWeYf;B*c6YOjv4F%F x7(SSLKC7Emzx(B*Kl%Zom+ww~5fr<~*XQs1D5IXu<;} Y{^-X#@vBzy^Me$6y85}Sb4q9e0Ipa-iU0rr literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Consumable/Food/burger.rsi/alpha-patty-inhand-right.png b/Resources/Textures/Objects/Consumable/Food/burger.rsi/alpha-patty-inhand-right.png new file mode 100644 index 0000000000000000000000000000000000000000..07e19d217fca2ca2eee090cb711ddcc61b786b59 GIT binary patch literal 201 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=jKx9jP7LeL$-D$|nmt_{Ln`LH zy}6sW*@1^4!1%DQ6YK7~3Ts$IC*N87KxE<~4bdPCkBar%bnCs`ff^VJ^bb#5aOOPx$=t)FDRCt{2+CPgEQ4|I6qgX9irjXnC2{K9J;-pR_GR0U4TUscwaKTmy7SmhU zrCJSawP>Rjsa$L<{RBdmjZ2haH-AdySh#N)gM~6Tny}{wLlVN=_j2>zH0J>#A|fIp zB69v*@G6ugHHP<(Uw?F~yB4yf#%aIJX}?Y8J>I=u=O5hm*JF6sbP;|$^BzAxi+^4p z?zuK0jNw(U=wg|h&5QsrKbhcYcL%fM31-I=e0urrm+#BSk{Tb}zJkj)Z*YPEWH?QLzkO}5xzubM@rwg3Qh>J@D7 zA0kat2{61!HUxklcMiW-L$sx#O-s802rgyIIeHNi~Hn=E6 zJ1Ej?tKVgq@{{R3007*qoM6N<$g2sLP+yDRo literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Consumable/Food/burger.rsi/bear-inhand-right.png b/Resources/Textures/Objects/Consumable/Food/burger.rsi/bear-inhand-right.png new file mode 100644 index 0000000000000000000000000000000000000000..873ad1bb63b07acebec6a390367d3d8a528b8a91 GIT binary patch literal 579 zcmV-J0=)f+P)Px${YgYYRCt{2+A&BQQ5XmC|CNqP5mAr_rdx+XF1HwR;Fy3l!*voe6sMCe3LTsz zNXhQdL2!_OkSVlFmu9NaK)1TObTSR092yn3@^#P`B5iFn@8MJbKR6P&ypQ+Zm%HWv z03sqHA|fJsc)US>SSe;ie_#8!H}JT7p;FAq@y?ta@63rLTN3928DQA0=x>y5pPt04*)vRxobTc2*b@N2 z_NOy!e*1}5t7T*pQmGW0%_a(k0ve45JkN9I5x_+pZR^~C4rKeIc~iBuf#UIhsh6_i z`#w6Ij+I#YbujTqH18Cpl;}8Gf7*Bv_DAz3YY$ByL(!8nenN|gh=_>Dn%^`y4<$O& R15W?|002ovPDHLkV1h#a2Lb>9 literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Consumable/Food/burger.rsi/brain-inhand-left.png b/Resources/Textures/Objects/Consumable/Food/burger.rsi/brain-inhand-left.png new file mode 100644 index 0000000000000000000000000000000000000000..0d721f98e4447e2da398d2e2a95cc788d73f3976 GIT binary patch literal 564 zcmV-40?Yl0P)Px$?ny*JRCt{2+ObO;VHgJR$681g3PQ0Mw}M+CBn|}~TQWp$aT5FkDv0gar4Ajk zTWF>OAri=#5(r(2l1bfk$?D+X9SI?KxdX?yLp(Ur8?@hhG$GFq0=a{GkM||{zTx=* zA|fIpA|jeSb6SPUR$ij-hplV1x>KQSD%&gqacrX?8)!YuBjqwUi!A& z{n#9RF85T25WPdIUfeT{BBAHQsaFvUd;|j@H;uMNS>U1h&pTPX+}c*F8TZ`e;mU`i zSQ~Hg>ctA2u8TK?b%=Y1OxH!_(;9M%O*uIIZM+_Yo{z9zH7%3KXaEn*iS-^>&8-8$ z5Kh-c_Vo(v<0ed-A0IGqZc;9h(EtFzTj-&6)&b5svAZ4P=8-hu6c`WSuys8bU!iaN zx;tRq35gCjz{HDB>(N`9ZZIx{ujv17qOZf#pF)c#h2YR zEZytGIqP)Px%4@pEpRCt{2+A&BQQ5XmCzeQ*xEeN6FIg|=+fsk_$uA?D?a!aRzP;j~~ZANkE z;E>(HOaUPvWK0pC}sI{*8Cx#29EZ|__ zXL~RF*Oxc3O~SYZdJtq#&-Gwe%ILN|blVce6-C#I1? z^3go(hJ!_Y8RDGbVZ%Z3-4fC>hw}E*$5=fNx@`~5Y7M|lpz$LU&|jRGtH45f8R&Lk zHymhl^C;~fB5sQZfalulu?jRY0T@aGj_X73*75DfxsnO1Hg17#OaK75iRR_?_m&^C z^!aP-st*81$MskjC~}se$99JzA|fIpA|fIpBBHw%%m4QO6lH5Zbg-z;4HV3bq3 zfG6uOF_pC9Q#8xaMOvlHvjeJo^H;UzRmMlq*4R}nLzkW171)(B06^Q=L>?aiKvez` zdaj3Fzcn9)i4y<-r_~ysKJJI;Cqk9$TJylR((jol0mW=i%+(aMIe&5sX@7Ed!@<_Z z5@vsfKR0k)YhJa95^!7R2HZr`@Am%InpZ2-M2p$nUk@cW(Nww{M7_&|3OHy(KTH0~ j!@WB~M?^$KME|G@9xes~XS=>l00000NkvXXu0mjf?nnF+q=8gOUnq@yQK9(8oQQ18G#(MPW-Z>CmjQ@7rt)suI< zymj>8K|Y~NCbF&1FU*r^TJc2m{fFO<3bMb7zE6r#h-Xj&gJ1P+Tew^k71HY8e+pc? zPJEHU1i!snbE`sCI#ZMD!sjGV(?4_t~p_4US(}l`efv<5F&V zhH2J`%RH5{9=`nJwpi!F{6FVjiJUsEon@MP?*8gPi4(srX)q*I{l50|W7YBk_p_>9 z|JF`eE*ZBwKf)%bs&JcIm)HyYPj+G}o-bip5K@uQcK5-@t=amsR_Spu7k)GJaDfB4 z!20v=qJ82lB!1?6FX8@qwe_cFb4Jr;Uo*j-DjQ2)g?@E#{vFLSwc<{i(xbP0l+XkK DauLxN literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Consumable/Food/burger.rsi/bun-inhand-right.png b/Resources/Textures/Objects/Consumable/Food/burger.rsi/bun-inhand-right.png new file mode 100644 index 0000000000000000000000000000000000000000..9327840b23432ecfbd1e6a948d73577bf3f6282f GIT binary patch literal 475 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=jKx9jP7LeL$-D%zr+T_LhE&XX zduyZjVFwYm59=SP=x!Bh*IOqWGi#~9|7I_7^@Arh^JM3`bd~78xaQc^+SIM5m)F#k zx65LOg~g18Q_OM;gyuO*oqbSXCO&J~eSRj%qT_dW@8NzT>)-+g-Ret!B`l5-`v334 zugIOTN+zpRB}=u8UWK^)(%tCeEHdk?OToe|r7!&dJTAGsTkduR@N< zR%uRH!lCV}uw(PS?|an>=l(ggydhO;<6kF1IJmgx?9uwq8s485T6h1tWaNx^sLl)}8$yI_vsPdj=i<+ZT*@SDK&RusfH*A+em_G={O^ zMUC*Ch0Ntav-+J@G~SaJN!5LO)L`;yCWdo)cH-|j&f0W;^ zEI|sBPb=+xwe-Nr*0s8gTe~DWM4f{fE$7 literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Consumable/Food/burger.rsi/burger-big-inhand-left.png b/Resources/Textures/Objects/Consumable/Food/burger.rsi/burger-big-inhand-left.png new file mode 100644 index 0000000000000000000000000000000000000000..21a9f8d60f6f3913bdc91e6d2a56494aff5280bc GIT binary patch literal 752 zcmVPx%s!2paRCt{2+A(MoQ5XmCe~V3uX|!Z0hAN@x5Nn~aMN!eAsFi3Ir(#ibQs^LL zaZ!qtxO55Vmc`Uc)WJGfEka`|4lP1!1qUN2Hl{62nkJV^hzY`TxLi1bNXdPNjeb7} zB!T;Q@6X-6;#>qf_Z~ti*M_C}h06bl_zyf@ z_~W6Qq7B#xy6@J{Z(I=H`Ad6=EA$yXQMXTZ}_ z8#vlML|fi#{j;CrIj5(;dLRyK5L6Xv83F$VDZ{)@CH9 zzk%wC)dq|yqM{nQ11LZARPNBRlnH=I_rO%zfOn8ptusE4OK6`o8Doqw#u#IaF~%5U ztXAZWhI(t0>wYa>?dI4J zi5URfYpzEgz~zfdQ`FJh15-;gq%RR*l%}>3dlAS37<;(8(k6Gd+tF(41MrBXwh?;~ z=r4h;0+wS<_G`h6{Fp@UhSV|dwVD^38 i&4V$<7-Nk6ZNC5)f>f^>dct}D0000Px%?MXyIRCt{2+FwXhQ5*;G??l~FS4&H@ERiBBg`85fC_*Y?We+_WtH=jgJ%r#x zL=+O@lP^NO?a8*#ddOaiARQVOMxfP0pkbosoKENN-R{^Qg44tPv_RV3c1CmlJ}?;L zoWpOw-{IcF{at_%LI@#*5V9F5WBk7MUNr@IHH{O6FhY!K} zbrq8~JG_A)3YAJMy1eiOMJ@sJ=5dKw85jXjAZvWw1f04!jBWdlA}Ez&ZhRv8yJNwR zXA}RN`d^sG6bTh5ZUQu?mlT#(Kby2U(9u(m&UObDT>^YT6@VokF>`g}+5(V3f#N0r z0K9jqFg)&tZ9WgyS|84wtHFoCX&?i4z>}vH2^C0I0&Z2C6mE;2NmC*`Y86(7W|9AX zD@;5h=FFU6fn*(MVh=&{&d?Oo*yoHq3{7>`uodYS%%cSv8)I4-b=s^sqYy#}A%qY@ z2qAI;{lC^2SE(TqARV@^}_-GSI-@UUKM zp6B|I+ZkGqQKw}Odyc{0*9!nBH?*J)F9Cq@+zFB(LJGI$(;?{u0Km+^2zC~Qmk1|< zr}bL%yd_#zL)mZ?rXk;Htp& z8j$o3xZNzEv_b_y0svGt)FZ!01@Xr)(9I{f(btU-)>aYQng;|vi-#qhfRlIq3c!#1 z`dZe}Q;N=ZM|cM`0_f)w+>5hoI9~a8YaVa7EFG27HK66~d1fA*hHX9%->(;9PeT=~ zb93Bw!2U*|J{3Dn-ORW1H*&*&YNs^uIl?5%zydyZ}91_ zQJobr^6`yP{lTx_>@P@=zMy+Hw8U7dPwbSXX6f(b%6}U}=Cv6;c+VPtcfU*0%7v@G zX+8V3Htk%V-`REP5HmsM3dAnlzP9&s)6bPBKd)3)<(G{$$^X9X>eh9~%}cqoE9=7i zH#@wX+`~4x^9ql8^=;jz+|+&B?Kk^w4L5YX9-97T&78?s7T8aFo_nw%;&j0SN%UHx3vIVCg!0BZ?{XaE2J literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Consumable/Food/burger.rsi/burger-inhand-right.png b/Resources/Textures/Objects/Consumable/Food/burger.rsi/burger-inhand-right.png new file mode 100644 index 0000000000000000000000000000000000000000..1c260fdb1b9326961b43e2d3126f773665914b79 GIT binary patch literal 333 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=jKx9jP7LeL$-D%z**#qxLn`LH zy=my}lqhlZqc8`buA-ij&_a(17alyyGcSC>yrrW#{^2%@?O!xm+N0*ksOVo5+4ACw zK%qGMYR5N19vTO4i#$~d-*w6L|Nftq@_aV$%T$22071?)U3=%Vvr^^S^=J7kzt!jV z_0O}H$=_D4{$#UweXQ=^7UL%Z>OEI?!N|FF7Z&kZtjA47#^ UaK(D-qW2)4r>mdKI;Vst057bH6951J literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Consumable/Food/burger.rsi/burger-super-inhand-left.png b/Resources/Textures/Objects/Consumable/Food/burger.rsi/burger-super-inhand-left.png new file mode 100644 index 0000000000000000000000000000000000000000..7b2863d8ced6301d49927befda90cfa3e03232ae GIT binary patch literal 896 zcmV-`1AqL9P)Px&I!Q!9RCt{2+EGYTQ5**FPe~`uO&cLC3(7igR zy;Kr1UwjFQUVJFc(1J=R(*(^VOc68#K@E~L-EcbH?zU_eogU`Kk_hqsFKGUMFc^b< zJNtI;-Pz6o7-Nhv#@O~0K^0^*8%6N`jkXc8+%3UsHVUc9B%~&j5YBp0nU^Kj@wER# z@XZTny|CRq61WXiZJ82wP=t70Zg`s;;8}750Op^+1+bGMT5+-q$V@Y!`{M$}XYKI$ zSD;p@U|aHGdBsgKK&#m(E|mnz+)#K)wd}RNS z9SwvER^wi~M3T3b>?6QnDn#Gp0>&jfd=Y-AB|B^{#;_dqi)4Uf9lbbPUI2p!sKqEr zW;ode6rAos+<{!IcoQ%+G#q-|G4madhyVH1bqOz639`?rm)FXLYcX&QsJ@+m8jAzA zB^MqH%#fU~uHHQ&P_PfG)HmeU0NF>tv*U|6oRo~7Aqlh7QRvQC#<3IWK=BO80N=eT zLZDy=N#0tr3pjXZ4i#mQsDKXM2{$~N7|eHlK?BYB{wNq7M4@417qB|*4NZEcozVcI zWe+SUykIR^>K0=)8%6kU4aOK_j4{R-V~jDzHjeyn=B>6&PO>-}RGF70t~XwWr@b}! zkWiw8O<8hfUY4*8RE3tvg|l8rO(ya`GpY9?kheEclP&;2vnvh&aKG~#*{5VR8^zT! zJv66EVQ*etdB{D4Tb4o8_kY;XYmlA-0PwIs0zSVVYL$f4L_IRol7O}mvV7{j2;>En zYV}xf*s)uyhb~2jr!Bo?*-Gq1pjpHZ(<<5VI>L`u$&S9sMHozlWZ6pWMIb){E}RQ2 ziYDb`BRVz)?$13y9Zj|pdlASBXneFUv`n6ws7Ji62tW%-wi0_0=r4j9%b1;x!l(0U z?9WL?_tX^G5fHvqUVS?oH5LbIJ4R)F!;lxyrHO%N!h_g&9WeM63s2_Avj4Uh;i9EP zG!%DkxCBLJQA*9!g7W~ZejR$2+?eEm%~gPs!pog@28O@UNf2XN W%8u-%tc~OV0000Px&Xh}ptRCt{2+FwXiSscLe??mcsYU|FHG}R_;k(ohi6j@2c7BQ{+5D1pLu|0&_ zLj*lUEJcLaOD{q_L<2!-WI=x*il7oRlOm`TiZt3tOQ*(BXT}+H-01Y+%ru2GcgCaH z^!vcTFx+$a&F`Fh&*A@cZ#d#|9egBna!|f76WpSSJ*4UJ{#->z{ zU6mK+D+A3EL+H<|9=qx~x^nn)@1KN8!ek>C`P?3SXHL@J=K-Mm;w@mxSjRRlq9$O; zq8#d4T(ovN@CSxSO-Z4v&(FY+XM7@zQCmf>>h`^(x^W8jyN{witD+|0>9qz*wiJ=m z4=$&JX;ZCOigGz$+sIjMVe3RIUu^nST#9jkq9!0?%^OqA_CeL!>Eu9F z0TsKQboIFz7%~HIbi}OH-+#S^7zW7DD&XHUm-+`@Iy;i6TRgyT>vL(k@f;@L3^;Xq zc1#0gC;>aN?Iv%HP5Ih9^rxHYzWI{mJ5#aih*-1g7zfDEmNs%5+|e`K#K;o!HN?6M zCYiIJsswDm`I3Lr&7`;W zla^tD`>$}Fd#f$D;C>=vr};$t4scW*hIV9ge*U;I`|gg>3L%6LLWpnF2l|fhQ~&?~ literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Consumable/Food/burger.rsi/cat-inhand-left.png b/Resources/Textures/Objects/Consumable/Food/burger.rsi/cat-inhand-left.png new file mode 100644 index 0000000000000000000000000000000000000000..e6eacf6bb93fc5f4a176db275a4fd051f0e557e3 GIT binary patch literal 253 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=jKx9jP7LeL$-D$|wtKobhE&XX zdut=-VFQ8IhsG>>95^y337YgR|0tkobd-0Zl5z!0s8(LXl3gKf4ot^lSd4z|4{~z4 zv$9&931|RAgu3|Wm^0VkZA}rktl4${iKXwP?w>z*ynpsJ<_!P!?k}3Ha^~V6{=R#* za+@%0J%GIX~p=b|z+!5nzzv|JtxpLoWW)>KQR&i#~bu#BF6zQmXa3 q#OrKvf4yz@22Rs-L9ogL|0@_p7Z%(^>2@zac}ah_xkBK%VMXhdiy-w^FH=S z@*gj&l{=5$$ob`Y_Wj`tU;65=Rylx-fPlEHtM6}C)%dNeid!{p-s)%5!@e+@zGHK` l-@Z)xp6NYah^meb8^%=~W!thj=4ydNJYD@<);T3K0RS+9VYC1M literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Consumable/Food/burger.rsi/clown-inhand-left.png b/Resources/Textures/Objects/Consumable/Food/burger.rsi/clown-inhand-left.png new file mode 100644 index 0000000000000000000000000000000000000000..3831dda7a4daa2022703237bcc0a9345d76b3b00 GIT binary patch literal 804 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 Br-%Rm literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Consumable/Food/burger.rsi/crazy-inhand-right.png b/Resources/Textures/Objects/Consumable/Food/burger.rsi/crazy-inhand-right.png new file mode 100644 index 0000000000000000000000000000000000000000..b1664e77d5378a60364b5b6724b8b81bb0b586e4 GIT binary patch literal 1784 zcmVPx*vPnciRCt{2ozIILMHI*1tb+%CkxS5Z4}-I~-edz4B*#`9Y1p$T527TeTyhk4 zLFhGqgy4X}fHyBf%XnDSLl8D3o{TvxOdwf2M1v4n1t||x)l=Qm^F!11zLm}QbJ?&- z=3Di;>ecI^zpq8+kmh|e@9%;!5PeP5TvsIKu@OQV1C;%u7zESYEc!9YVpxHZU}K?v z5#ZMVnTFt#w;*Ex&|X6c&#(d3w=qc9`{04-GFbp0NK3$zPuKgUETEo#Z46*!Vi56P z^9P`=?vWpkB<)QXL7tBEFGwuM5QIz&yc!<>#{iyxn)eN^1`rY1vndd@3(&g{U4wvF zTjAg6ura9v^23q7wmp9#$BrdG9L>~0`k+#n!=}i+@~xPf{+_h*Y-G}2U-E2Z+&EO{@8a*pKtsRn#M7R= z2lXa@Sy}%uRTwaBr)UhSdNa4q}%OEr_+(~cr2YxM?^#p4i17A zgVfj4Z`b|ut!ICii&r;AWK;fm_=kx6DL?)4f;=zx3#U!e@6GCDEngySr6dVij%@yqc zQltoeEOUmBBZdrs3PKEXuNecz8iou8$OBkdzhhVk9;yqV2!f&)zjOwIJoqJmeF*Bj zhx!>nIRzJnPiuaGm`@$>GZ+lge;0!R6z)H)F`w#XfEw=`1oSS9tPepv{Q&|~`0s%i zAWugvSPuZ#0|9je#*l)G6c||=)&L*>7Th=g38}eIU%CD$ z>HBvfO5-T$YxIDsyWqZ?rEmZT8pJYv37iTS>MLZPrSlJc7jWhBmYiJQEeZIZ_B3IY`2e(3tkuC@|Ml9W~?_2bfSvdAv9WvCyiKHSqzefAU}gb+dqA%qY@2qANfrdin+W z`bEO^Hdy_cKyV7q53QfTjsxyycYj0hmYmso)sSAG8PWl=cCbM|lCT55TGI12B(SUjX|6z+-@geE?2n zAAotxW&rj9c%q1}KLGmxunz$H0O-ZP))-RVf&Me-AuZ5_1Ge&VXDxkKfch42O??L{ z{u3%j(EXil^YEK@&B^s$bMLb^g8S~OJ5WgpOay` zEuD{^mSOvmyrj#qyD#naMFwKj^(`(A5Ph%y!OY+51CS(1(R85O?drS+-RlDY(YHYL zGrjpQtSI+)w#~)&&Weaw8?wmDAO5Izk4*jW`b$4d`xc1$ap@C62qAPx%fJsC_RCt{2+CfNDaU2Km@1&_=!0IENQ+d(Tl>tXrJ)acv6@UP z)pi05#;PvWb^eV~0Kr(*<=p(8&?x|bHa3na<1v6Wl7-6wPrq2LTM$PUF?3-?17g6_ zDJ;tp1D;NiPfUr)p?;F>Z-(8%xduhO{aPrB*rhV!*&ME&>qb1AL-tvmqAUQw*%~f{fDa)*u3q$DCgewcdk0Sv8M5tam&&l8&Qq29jdB2s*SB!F`z+qP zvv9$48jG(#VR*y~jD96qU@hQp-%0B2ryM}f>;@)6Eto(T>`WOItsR@opF#D!I@ zmHPsYdbY`NK&xD(jZPAP(07*qoM6N<$f>g&xPx%vPnciRCt{2+D}N6VH^kW?<<+2E&Q`XA~g)rY9rqnjJ87rBC(iOp4!5 zgZg$-6om%$?Ub5#lgnzZ%fCNmyyUW)Rd3G*HG>M-93t@~ZeBDX5>Fx?jA#y8D?eYq z!sBNagc2rI<13y46VpqQ;oLBNbJ}p@sveV08&Vsa*!q3UI&QD=B_E6;^V{>za|CN#OLy zv+!z7TLV7RR#gk6>J;}li% qi*4u&o%?6gZfM3BV~jDz>f9e^B1IfJQ4C%H0000z@qLn`LHy>*bc$v}ejf&DSX z4!?_zH=1MbG+XYlZeJJ3*Y;xOwh71H@BaMBsrq#{P!9vc4NcyO)#vmlwVn7ZQ8{y; zsyFxly8S-$|J<^F7-gKZ*=OSY^&Q7I+hofr-+%Yivi(M$*n0-wmmxv>yiV)wCM|*E=+IRlxUk;!yh6eGXu1~Ld-iMt3Uh(jT zyW}p7Xjvz}?KR2u=eMi8&U<&@g6mCryWa1y$?{K&`Yh&Y#hCe)o!)OBshjP0yZ+CT zrE5T@Ffd%0wEyPx%JV``BRCt{2+A(MoQ5?tdZ&c_Y2q#6*ARny3+4~xrGG)j4=T8`+eH& zHk}|yJg|cZ7~47E4ulUM-=(*^!`kLH-}d%6IWfVO>Css2TDN^O3b+~tTrQWL&jE?= z0DwivoSE4TZ(X>^+xAy-lUe3h)|oC|gHqROV2k?~XFuTPOV&2Gt=b#MDgb~}%`4<9 z6`p7BVT_?LWtc6^I=ND#0khoh^{~T@|UFC=(kzu*2QaAOMtj!Zycm|ruV&9uJUxls z$N%$Mgj%ik?;e3s=jSek)5Xht-sy4w#&uRVHh5iHw(e)#T7+jyAFSH8z5_-*oqB@z z-NVaz@C80L=YeJGcE_znc<|_UXcKTM-_`L-ZoOW2)@~ literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Consumable/Food/burger.rsi/mime-inhand-right.png b/Resources/Textures/Objects/Consumable/Food/burger.rsi/mime-inhand-right.png new file mode 100644 index 0000000000000000000000000000000000000000..fe545efd69e21458e8acdab0de5b5f1eb3f360d7 GIT binary patch literal 665 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 LNkvXXu0mjf35O!l literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Consumable/Food/burger.rsi/plain-inhand-right.png b/Resources/Textures/Objects/Consumable/Food/burger.rsi/plain-inhand-right.png new file mode 100644 index 0000000000000000000000000000000000000000..4236e9ec81fbc44a996c525f3694ad2e0a9a24ba GIT binary patch literal 678 zcmV;X0$KfuP)Px%U`a$lRCt{2+D}N+VHgMS?ncMQ>(EKqX@^*yymg2? zNbF<>p>8{k4Hg|*7f;U7pu!L=Jp>JwXp%#=vHkW3nFMbKH`_t*w|?&rr+z;$*x`L& zo;}aY`@)_VAR;0nA|j%T$Dnp#(CZM*@3V{Rs^^^xL9auUqaIO?dW0y1M8M?~DyE%^ z)pcuG@{ddkMam|K{D+9X^$ zX~68_y1{Yv~005{x9m0pTGDfU} zc$dgv(mjUHi45>nYq;`7Rt#+wNL2!!jD`&5s7F-O3M!^<c`JxSSn(LlF@X5fKp)5fKs5X*(1D zo9o${*SwhC?*@WihnShR0RT+*AHvWd=$xVjTuvbhp`*70vU~H#wdQ5654F9);{;qz zF}E;*Y%B}_u=)I$!FvD@GIv6?q@dbp&FkU669534@e~I78cQ@1A=B+!H<8@PqqQ|J zo90SA_l%2Ly^da^5jO^HFk7s6F#kr%4)8BciMw_?B5NBMv6_)gWU%w{r_?h*(+==2 zO^HY%gGu)=R`VrXyEBC3_BJptC%EBPd+<$n!3PVPt@%+oOCQmcfJe()cxLK`DP2LI z*#fNYApdqxT5yfCq~(_RF8v13v|zIheZBwR;e6qq&=C<45z!g-7v|jpB6LZJW&i*H M07*qoM6N<$g3CZN8UO$Q literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Consumable/Food/burger.rsi/plasma-inhand-left.png b/Resources/Textures/Objects/Consumable/Food/burger.rsi/plasma-inhand-left.png new file mode 100644 index 0000000000000000000000000000000000000000..199689aada59ad45b6b7ae222b0b52d240ea3804 GIT binary patch literal 924 zcmV;N17rM&P)Px&R!KxbRCt{2+D~YccO1v@_w%f2O}Dz3l3^cG6<0NS2-<>er-#}IN)??ahv`942Bc^)3f_X|P@A%qY@2q8W^S|t}JMw=Jdhcms0t^DlyZ+dhOPz7KF zquEL~=_cg>5~IzHfEUPL?6%^EwlzQz>biFF-Jb91{!v>FcmUG~M*mT~$14FJzdBse z4>lKF<)XxBa|j3ntvAkD@dJD7@ow#4DnCK;$_2Vlui}@p#W>Ikgzfd^-lGv%0yJFg zw(>{5YEaqg8&xS@w*vSAXjr^b!>pOa9O@(MGto52#2>J1jRznCB<-O8ns0GCu+IVi zjdRvd2lm$EZS4SlQ`~N8N>2b#2Y6$b1N&Rry2!;t)P54dKfW2C(TQPfp)M03b~&)$ zeogAitiJ--2t;NB9vkXY-0JJ822cQI@}^Fze++-93GH41I(LB)sp*vD-f<&vr~dg4K|XnH1|YOnq$Ojno_s{~vJHUSEz^0ME){@NI-a`|-~Ji8AZY8L%5F`3zPA z)pm#(V8#eWt;A@vZl9~QAOC417@aP&b|YZeHO&5#)<7W-M|z$A3_4!WDWw8_+xrqi z2qAIC=e7(BOw_N%ox4D{hnH;w*yW z0VK}17qK9)<4dOQ{Lb~kr))Z?e+{I7$3`$Z?=JC+nl8>Fs5VDS%K6e{eQCz-_F>jc zvUsJ2-6r2?cYVv^_AG+q0W1n^$3MOq@1k~c@enO-U6r)SDb*^^`qJb+P4i#;0n65a zYRHZUkh(Pvoj$Zbi}*uLr25AyX_MpjEP~?!uw;Nt>>Ae6`xK`CU|1U@yzj{|U__x! z&U|JOLc7L$R6|y6kC(JygJ)Im;oQT8pXK<-1G`S>?G?1inb#}=H8DHnvS$$-4*(cB yesx%LqD^jdbr#{BZI8dq%~=E?gb+fA57u)I?wnT2KtU1!0000>P)Px&qDe$SRCt{2+D~Ykbr`_$@B7-OP1ek`p|ZY29lEV?Lba*bRy>S$xLGGsFT&WE zw4n7kp$E~O=4BM!wOSPFVIEdib#6CpL9i%GSH`3sBr+Njx|TL{&A-0M`+9j>tMq-x zn=~%N=W`0b{CM;Hp63m3$n$^@LI@#*5JHImAI0g-L_AV&y)1k=Wayjg1EXp!Py?Wa zW^E0D|aM!+!n|#0Y#voXH`}vmuLzf zK)G3jo&c$6ik0a!9ZEZTRs|?n`>TT60@c{8CxJiOPA{H?MI+6POufE$EH|IU3}#s0 zV=#Tk!>a?zSs-WauL`MX3S+IFj)rz-vbVTjf$S3SCy)nxKz8!HF;mo2tlfpQr-qtZ zc<&RX+sbYRNL1`ZE}6los{%Pa20ehsN>T7v!AUtslz1sb0X;k%Q=e9i!FxxAb+ zS9ien;QX0pH0>CT%_nGDK8m-on|v%xM^|6Da|4d8`Q7F=0b9X^`Dhr~FEB<420m{6c2_8fGwB!sVQ~{R(WG8^Bm^`3Zl$N@m_i z{gYnUfH@^a*J-t!xq+?LeAioQ_t)oBGesTN?!v%mZEFeFbL2Jw|Ck$?xbC5#!=8;i zdmqd5NG literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Consumable/Food/burger.rsi/rat-inhand-right.png b/Resources/Textures/Objects/Consumable/Food/burger.rsi/rat-inhand-right.png new file mode 100644 index 0000000000000000000000000000000000000000..723e57cac4d053e0ee63975db67ccc7c8c116526 GIT binary patch literal 336 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=jKx9jP7LeL$-D%zxjbDQLn`LH zy|vNnaDvFukBcp$6jM%eO9)JNdbV5id5-LyZv77r-!P{XdcPF@!4*_+f_q0tz;T^O zr+~+Qc3R$&2=4g$fA;%U=5m{GCZORA3jd@!UaanG0E<0i+5KON cAa}o6?w_+Zysr4gGBJ?Zp00i_>zopr0AS3OeEPx%yh%hsRCt{2nm=e$Q543%HZ6&L6l;^k8Vo`S{-b6v8tWFMMTwhBg@Cw>?X z@Q}C^gi^@jpkjv%As{HN5vqe=id9sKU^CggS{qE$*cg+D$#tkNropNA-2S2GH(tn> zbH1FLJA4OV7=~dOhG7^IG=ErV{;=5WIyME(9~PFL!EM!iGnJ6$4~wcZKqa?fkQiV# zFN$f{9B!zX0#(Lr7WqQ%IT6eK=X%1#qNbDreRr{1_11G`q1nSZj1kdCYcX6 zj%6v61R5rwnjDkE z=U29#0gtZ_h+H;oAwPBw?ZI)}83BMeNr9%pFW#;I z6C{#rkbVVjK6&2+04c*jdvF{n!yqZlqh)8R&1PhP0S#!!+9UQF)>K3!2r6+Y_@==8{i9K9>{!V)7BR zym>@&1pwgEvwq=oxv&`Ns-1oAP2fRaeBJuw6Ob|t?5~T-shWqPT?F!HFdB;?Wf+LY zV$gM+bi!2cB9NgvCRe$Oux;4U%`*(cFbqS&AFNPx&21!IgRCt{2+RsZAVHgMS@3@t#(~6~m*^&mam5Dzf!7YN=eu%M$KsYmL%L)x{=#fs72UUkjjXmhGdu6BgFK(x z;OxuuKJWWFhwlpzLI@#*5Tc6c3NX8*W~pdCRFltA`=aOyu!P-hY&8c! zRRiS7vv?HNLI=#e3$z|j)jJ>=TU|)!XBm;OyEQdIu>qnhz%~nNz~WI@=7#|QIrds) zIXtG_1zHIE{c(3ESLedOt{spFx9>Yfrdb<5F#xd44STv<398nsurE5$mDZ0(R{rrX4+B(GSY)mi45MN*7Q7?BR zH(qL5AjJj%K*cO3BxqV7RbPRbj$-(IK6ndy;rIDa zI^;zCK%U-O4bfH}2YYrIgEvK0@2lDY05BDa;H;+`Q;`S&nDYDsK%dQu*}fk*HjsxP z&w(XLViV)zOp+v1fBwAAYUXuT8&jj%Cr=0=gb+dqA%qY@4ja=&^O-EjsAxW|a8wrS zZxUAL!kQCVt&EK3bu~byHIda~cQntNt_D~tnwhoG0Tz!M+5{u14n|Tj`ksIs%_AwA z=Pm7YC(GesIriG^=goo|Ktn98WUpv`^UHItiBwvHC0~vZtS15Bzw^nX38|v_3r{Dw zHXyAdkO;R6US~CXaD4@*j&BWNJF&GzU-hh@rE82!k(Fha@c#20lB0Rv(*7S142=rG z5b&hFoW<7GAZGu@#WSZ-Sylpcjd3Zi^VR}tOLj){c>9&h*fL!!^{}^&l@2+#pNsBK zVDpzAYOI^^7OZ(ydQ80TL^xfLfL zrKv~+wxnpDCtaUGq_{W0>-@_kNfH3C#)byG>Fne=G#{C|H(=^$-qghrLI@#*?BOqL Wvps~3fggkb0000 Date: Wed, 3 Sep 2025 15:21:00 -0400 Subject: [PATCH 312/340] Add inhand sprites to Cartons and Cups, give new inhands to Cans. (#39814) * Added inhand sprites to cans, cartons and cups. * small tweak --- .../Objects/Consumable/Drinks/drinks_fun.yml | 4 + .../Drinks/beer_can.rsi/inhand-left.png | Bin 0 -> 432 bytes .../Drinks/beer_can.rsi/inhand-right.png | Bin 0 -> 463 bytes .../Consumable/Drinks/beer_can.rsi/meta.json | 10 +- .../Drinks/cafe_latte.rsi/inhand-left.png | Bin 0 -> 350 bytes .../Drinks/cafe_latte.rsi/inhand-right.png | Bin 0 -> 381 bytes .../Drinks/cafe_latte.rsi/meta.json | 10 +- .../Drinks/changelingsting.rsi/icon.png | Bin 1592 -> 1857 bytes .../Drinks/changelingsting.rsi/icon_open.png | Bin 1645 -> 1879 bytes .../changelingsting.rsi/inhand-left.png | Bin 0 -> 1591 bytes .../changelingsting.rsi/inhand-right.png | Bin 0 -> 1610 bytes .../Drinks/changelingsting.rsi/meta.json | 130 +++++++++++++++++- .../Drinks/coconutwater.rsi/inhand-left.png | Bin 0 -> 520 bytes .../Drinks/coconutwater.rsi/inhand-right.png | Bin 0 -> 546 bytes .../Drinks/coconutwater.rsi/meta.json | 10 +- .../Drinks/cola.rsi/inhand-left.png | Bin 219 -> 408 bytes .../Drinks/cola.rsi/inhand-right.png | Bin 239 -> 420 bytes .../Consumable/Drinks/cola.rsi/meta.json | 72 +++------- .../Drinks/cream.rsi/inhand-left.png | Bin 0 -> 408 bytes .../Drinks/cream.rsi/inhand-right.png | Bin 0 -> 404 bytes .../Consumable/Drinks/cream.rsi/meta.json | 10 +- .../Drinks/dr_gibb.rsi/inhand-left.png | Bin 219 -> 384 bytes .../Drinks/dr_gibb.rsi/inhand-right.png | Bin 224 -> 404 bytes .../Consumable/Drinks/dr_gibb.rsi/meta.json | 72 +++------- .../Drinks/energy_drink.rsi/inhand-left.png | Bin 225 -> 382 bytes .../Drinks/energy_drink.rsi/inhand-right.png | Bin 238 -> 388 bytes .../Drinks/energy_drink.rsi/meta.json | 72 +++------- .../Drinks/fourteen_loko.rsi/inhand-left.png | Bin 247 -> 408 bytes .../Drinks/fourteen_loko.rsi/inhand-right.png | Bin 249 -> 425 bytes .../Drinks/fourteen_loko.rsi/meta.json | 72 +++------- .../glue-tube.rsi/inhand-left-fill-1.png | Bin 0 -> 135 bytes .../glue-tube.rsi/inhand-left-fill-2.png | Bin 0 -> 197 bytes .../glue-tube.rsi/inhand-left-fill-3.png | Bin 0 -> 203 bytes .../Drinks/glue-tube.rsi/inhand-left.png | Bin 0 -> 358 bytes .../glue-tube.rsi/inhand-right-fill-1.png | Bin 0 -> 135 bytes .../glue-tube.rsi/inhand-right-fill-2.png | Bin 0 -> 200 bytes .../glue-tube.rsi/inhand-right-fill-3.png | Bin 0 -> 209 bytes .../Drinks/glue-tube.rsi/inhand-right.png | Bin 0 -> 354 bytes .../Consumable/Drinks/glue-tube.rsi/meta.json | 34 ++++- .../Drinks/golden_cup.rsi/inhand-left.png | Bin 0 -> 692 bytes .../Drinks/golden_cup.rsi/inhand-right.png | Bin 0 -> 792 bytes .../Drinks/golden_cup.rsi/meta.json | 24 +++- .../Drinks/ice_tea_can.rsi/inhand-left.png | Bin 0 -> 443 bytes .../Drinks/ice_tea_can.rsi/inhand-right.png | Bin 0 -> 430 bytes .../Drinks/ice_tea_can.rsi/meta.json | 14 +- .../Drinks/lean.rsi/inhand-left.png | Bin 211 -> 356 bytes .../Drinks/lean.rsi/inhand-right.png | Bin 227 -> 348 bytes .../Consumable/Drinks/lean.rsi/meta.json | 66 +++------ .../lemon-lime-cranberry.rsi/inhand-left.png | Bin 268 -> 447 bytes .../lemon-lime-cranberry.rsi/inhand-right.png | Bin 278 -> 447 bytes .../Drinks/lemon-lime-cranberry.rsi/meta.json | 44 +++--- .../Drinks/lemon-lime.rsi/inhand-left.png | Bin 213 -> 423 bytes .../Drinks/lemon-lime.rsi/inhand-right.png | Bin 223 -> 430 bytes .../Drinks/lemon-lime.rsi/meta.json | 72 +++------- .../lube-tube.rsi/inhand-left-fill-1.png | Bin 0 -> 135 bytes .../lube-tube.rsi/inhand-left-fill-2.png | Bin 0 -> 197 bytes .../lube-tube.rsi/inhand-left-fill-3.png | Bin 0 -> 203 bytes .../Drinks/lube-tube.rsi/inhand-left.png | Bin 0 -> 354 bytes .../lube-tube.rsi/inhand-right-fill-1.png | Bin 0 -> 135 bytes .../lube-tube.rsi/inhand-right-fill-2.png | Bin 0 -> 200 bytes .../lube-tube.rsi/inhand-right-fill-3.png | Bin 0 -> 209 bytes .../Drinks/lube-tube.rsi/inhand-right.png | Bin 0 -> 359 bytes .../Consumable/Drinks/lube-tube.rsi/meta.json | 34 ++++- .../Drinks/milk.rsi/inhand-left.png | Bin 0 -> 559 bytes .../Drinks/milk.rsi/inhand-right.png | Bin 0 -> 569 bytes .../Consumable/Drinks/milk.rsi/meta.json | 10 +- .../Drinks/oatmilk.rsi/inhand-left.png | Bin 0 -> 546 bytes .../Drinks/oatmilk.rsi/inhand-right.png | Bin 0 -> 584 bytes .../Consumable/Drinks/oatmilk.rsi/meta.json | 10 +- .../Drinks/orangejuice.rsi/inhand-left.png | Bin 0 -> 586 bytes .../Drinks/orangejuice.rsi/inhand-right.png | Bin 0 -> 580 bytes .../Drinks/orangejuice.rsi/meta.json | 10 +- .../Drinks/pineapplejuice.rsi/inhand-left.png | Bin 0 -> 599 bytes .../pineapplejuice.rsi/inhand-right.png | Bin 0 -> 657 bytes .../Drinks/pineapplejuice.rsi/meta.json | 10 +- .../Drinks/purple_can.rsi/inhand-left.png | Bin 262 -> 371 bytes .../Drinks/purple_can.rsi/inhand-right.png | Bin 268 -> 409 bytes .../Drinks/purple_can.rsi/meta.json | 72 +++------- .../Drinks/pwrgame.rsi/inhand-left.png | Bin 287 -> 396 bytes .../Drinks/pwrgame.rsi/inhand-right.png | Bin 291 -> 438 bytes .../Consumable/Drinks/pwrgame.rsi/meta.json | 72 +++------- .../Drinks/robustnukie.rsi/inhand-left.png | Bin 277 -> 341 bytes .../Drinks/robustnukie.rsi/inhand-right.png | Bin 279 -> 334 bytes .../Drinks/robustnukie.rsi/meta.json | 44 +++--- .../Drinks/rootbeer.rsi/inhand-left.png | Bin 399 -> 391 bytes .../Drinks/rootbeer.rsi/inhand-right.png | Bin 420 -> 384 bytes .../Consumable/Drinks/rootbeer.rsi/meta.json | 44 +++--- .../Drinks/shamblersjuice.rsi/inhand-left.png | Bin 281 -> 392 bytes .../shamblersjuice.rsi/inhand-right.png | Bin 284 -> 396 bytes .../Drinks/shamblersjuice.rsi/meta.json | 72 +++------- .../Drinks/sodawater.rsi/inhand-left.png | Bin 229 -> 412 bytes .../Drinks/sodawater.rsi/inhand-right.png | Bin 232 -> 435 bytes .../Consumable/Drinks/sodawater.rsi/meta.json | 72 +++------- .../Drinks/sol_dry.rsi/inhand-left.png | Bin 4557 -> 392 bytes .../Drinks/sol_dry.rsi/inhand-right.png | Bin 4565 -> 416 bytes .../Consumable/Drinks/sol_dry.rsi/meta.json | 72 +++------- .../Drinks/soymilk.rsi/inhand-left.png | Bin 0 -> 443 bytes .../Drinks/soymilk.rsi/inhand-right.png | Bin 0 -> 477 bytes .../Consumable/Drinks/soymilk.rsi/meta.json | 10 +- .../Drinks/space-up.rsi/inhand-left.png | Bin 215 -> 331 bytes .../Drinks/space-up.rsi/inhand-right.png | Bin 219 -> 338 bytes .../Consumable/Drinks/space-up.rsi/meta.json | 72 +++------- .../space_mountain_wind.rsi/inhand-left.png | Bin 249 -> 410 bytes .../space_mountain_wind.rsi/inhand-right.png | Bin 251 -> 393 bytes .../Drinks/space_mountain_wind.rsi/meta.json | 72 +++------- .../Drinks/starkist.rsi/inhand-left.png | Bin 229 -> 434 bytes .../Drinks/starkist.rsi/inhand-right.png | Bin 236 -> 426 bytes .../Consumable/Drinks/starkist.rsi/meta.json | 72 +++------- .../Drinks/teacup.rsi/inhand-left.png | Bin 0 -> 276 bytes .../Drinks/teacup.rsi/inhand-right.png | Bin 0 -> 277 bytes .../Consumable/Drinks/teacup.rsi/meta.json | 12 +- .../Drinks/tomatojuice.rsi/inhand-left.png | Bin 0 -> 505 bytes .../Drinks/tomatojuice.rsi/inhand-right.png | Bin 0 -> 547 bytes .../Drinks/tomatojuice.rsi/meta.json | 10 +- .../Drinks/tonic.rsi/inhand-left.png | Bin 254 -> 379 bytes .../Drinks/tonic.rsi/inhand-right.png | Bin 264 -> 375 bytes .../Consumable/Drinks/tonic.rsi/meta.json | 72 +++------- .../Drinks/water_cup.rsi/inhand-left.png | Bin 0 -> 357 bytes .../Drinks/water_cup.rsi/inhand-right.png | Bin 0 -> 388 bytes .../Consumable/Drinks/water_cup.rsi/meta.json | 10 +- .../Drinks/wine_can.rsi/inhand-left.png | Bin 0 -> 429 bytes .../Drinks/wine_can.rsi/inhand-right.png | Bin 0 -> 432 bytes .../Consumable/Drinks/wine_can.rsi/meta.json | 10 +- .../Objects/Misc/6pack.rsi/inhand-left.png | Bin 0 -> 522 bytes .../Objects/Misc/6pack.rsi/inhand-right.png | Bin 0 -> 543 bytes .../Textures/Objects/Misc/6pack.rsi/meta.json | 66 +++++---- 126 files changed, 776 insertions(+), 868 deletions(-) create mode 100644 Resources/Textures/Objects/Consumable/Drinks/beer_can.rsi/inhand-left.png create mode 100644 Resources/Textures/Objects/Consumable/Drinks/beer_can.rsi/inhand-right.png create mode 100644 Resources/Textures/Objects/Consumable/Drinks/cafe_latte.rsi/inhand-left.png create mode 100644 Resources/Textures/Objects/Consumable/Drinks/cafe_latte.rsi/inhand-right.png create mode 100644 Resources/Textures/Objects/Consumable/Drinks/changelingsting.rsi/inhand-left.png create mode 100644 Resources/Textures/Objects/Consumable/Drinks/changelingsting.rsi/inhand-right.png create mode 100644 Resources/Textures/Objects/Consumable/Drinks/coconutwater.rsi/inhand-left.png create mode 100644 Resources/Textures/Objects/Consumable/Drinks/coconutwater.rsi/inhand-right.png create mode 100644 Resources/Textures/Objects/Consumable/Drinks/cream.rsi/inhand-left.png create mode 100644 Resources/Textures/Objects/Consumable/Drinks/cream.rsi/inhand-right.png create mode 100644 Resources/Textures/Objects/Consumable/Drinks/glue-tube.rsi/inhand-left-fill-1.png create mode 100644 Resources/Textures/Objects/Consumable/Drinks/glue-tube.rsi/inhand-left-fill-2.png create mode 100644 Resources/Textures/Objects/Consumable/Drinks/glue-tube.rsi/inhand-left-fill-3.png create mode 100644 Resources/Textures/Objects/Consumable/Drinks/glue-tube.rsi/inhand-left.png create mode 100644 Resources/Textures/Objects/Consumable/Drinks/glue-tube.rsi/inhand-right-fill-1.png create mode 100644 Resources/Textures/Objects/Consumable/Drinks/glue-tube.rsi/inhand-right-fill-2.png create mode 100644 Resources/Textures/Objects/Consumable/Drinks/glue-tube.rsi/inhand-right-fill-3.png create mode 100644 Resources/Textures/Objects/Consumable/Drinks/glue-tube.rsi/inhand-right.png create mode 100644 Resources/Textures/Objects/Consumable/Drinks/golden_cup.rsi/inhand-left.png create mode 100644 Resources/Textures/Objects/Consumable/Drinks/golden_cup.rsi/inhand-right.png create mode 100644 Resources/Textures/Objects/Consumable/Drinks/ice_tea_can.rsi/inhand-left.png create mode 100644 Resources/Textures/Objects/Consumable/Drinks/ice_tea_can.rsi/inhand-right.png create mode 100644 Resources/Textures/Objects/Consumable/Drinks/lube-tube.rsi/inhand-left-fill-1.png create mode 100644 Resources/Textures/Objects/Consumable/Drinks/lube-tube.rsi/inhand-left-fill-2.png create mode 100644 Resources/Textures/Objects/Consumable/Drinks/lube-tube.rsi/inhand-left-fill-3.png create mode 100644 Resources/Textures/Objects/Consumable/Drinks/lube-tube.rsi/inhand-left.png create mode 100644 Resources/Textures/Objects/Consumable/Drinks/lube-tube.rsi/inhand-right-fill-1.png create mode 100644 Resources/Textures/Objects/Consumable/Drinks/lube-tube.rsi/inhand-right-fill-2.png create mode 100644 Resources/Textures/Objects/Consumable/Drinks/lube-tube.rsi/inhand-right-fill-3.png create mode 100644 Resources/Textures/Objects/Consumable/Drinks/lube-tube.rsi/inhand-right.png create mode 100644 Resources/Textures/Objects/Consumable/Drinks/milk.rsi/inhand-left.png create mode 100644 Resources/Textures/Objects/Consumable/Drinks/milk.rsi/inhand-right.png create mode 100644 Resources/Textures/Objects/Consumable/Drinks/oatmilk.rsi/inhand-left.png create mode 100644 Resources/Textures/Objects/Consumable/Drinks/oatmilk.rsi/inhand-right.png create mode 100644 Resources/Textures/Objects/Consumable/Drinks/orangejuice.rsi/inhand-left.png create mode 100644 Resources/Textures/Objects/Consumable/Drinks/orangejuice.rsi/inhand-right.png create mode 100644 Resources/Textures/Objects/Consumable/Drinks/pineapplejuice.rsi/inhand-left.png create mode 100644 Resources/Textures/Objects/Consumable/Drinks/pineapplejuice.rsi/inhand-right.png create mode 100644 Resources/Textures/Objects/Consumable/Drinks/soymilk.rsi/inhand-left.png create mode 100644 Resources/Textures/Objects/Consumable/Drinks/soymilk.rsi/inhand-right.png create mode 100644 Resources/Textures/Objects/Consumable/Drinks/teacup.rsi/inhand-left.png create mode 100644 Resources/Textures/Objects/Consumable/Drinks/teacup.rsi/inhand-right.png create mode 100644 Resources/Textures/Objects/Consumable/Drinks/tomatojuice.rsi/inhand-left.png create mode 100644 Resources/Textures/Objects/Consumable/Drinks/tomatojuice.rsi/inhand-right.png create mode 100644 Resources/Textures/Objects/Consumable/Drinks/water_cup.rsi/inhand-left.png create mode 100644 Resources/Textures/Objects/Consumable/Drinks/water_cup.rsi/inhand-right.png create mode 100644 Resources/Textures/Objects/Consumable/Drinks/wine_can.rsi/inhand-left.png create mode 100644 Resources/Textures/Objects/Consumable/Drinks/wine_can.rsi/inhand-right.png create mode 100644 Resources/Textures/Objects/Misc/6pack.rsi/inhand-left.png create mode 100644 Resources/Textures/Objects/Misc/6pack.rsi/inhand-right.png diff --git a/Resources/Prototypes/Entities/Objects/Consumable/Drinks/drinks_fun.yml b/Resources/Prototypes/Entities/Objects/Consumable/Drinks/drinks_fun.yml index 0cd960bed12..1ab7c3180bb 100644 --- a/Resources/Prototypes/Entities/Objects/Consumable/Drinks/drinks_fun.yml +++ b/Resources/Prototypes/Entities/Objects/Consumable/Drinks/drinks_fun.yml @@ -29,6 +29,8 @@ - type: SolutionContainerVisuals maxFillLevels: 6 fillBaseName: fill + inHandsMaxFillLevels: 3 + inHandsFillBaseName: -fill- - type: GenericVisualizer visuals: enum.OpenableVisuals.Opened: @@ -71,6 +73,8 @@ - type: SolutionContainerVisuals maxFillLevels: 6 fillBaseName: fill + inHandsMaxFillLevels: 3 + inHandsFillBaseName: -fill- - type: GenericVisualizer visuals: enum.OpenableVisuals.Opened: diff --git a/Resources/Textures/Objects/Consumable/Drinks/beer_can.rsi/inhand-left.png b/Resources/Textures/Objects/Consumable/Drinks/beer_can.rsi/inhand-left.png new file mode 100644 index 0000000000000000000000000000000000000000..8bf6755c94a2d0263161edb5cbec7150f4b6f1ec GIT binary patch literal 432 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=jKx9jP7LeL$-D%zvpiiKLn`LH zy|vNHsZiwj$M}l^k5u%!{A`n?k~BPt=xA=$NVF@Rl>CcJAYs2OXDQ43RCl zU%PMj^)o_(2q1etb2rcloYxkf%rDAaW$(_Iu<>@%wfsa&Nu{3E&y}OTbEpZcU6w4_ zGtt#b=&tgY=!iGl*voyy9-I%?2+tOKDR1&l@QV0{h~2h3_w2iP?%%0Tat}3{U3`F! zFk9Mm)BVCPAb+Y`FwmV(id{D|u6-x?ucv06#@9UmE$;<8fZ)acA8av`r+*eMOHKqv O0fVQjpUXO@geCwhUb)=> literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Consumable/Drinks/beer_can.rsi/inhand-right.png b/Resources/Textures/Objects/Consumable/Drinks/beer_can.rsi/inhand-right.png new file mode 100644 index 0000000000000000000000000000000000000000..49af4002dc4cf8f22c791264b21aa51b737aa0e3 GIT binary patch literal 463 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=jKx9jP7LeL$-D%zJ3U<-Ln`LH zy>-xwDNuy%!DNvT4#ypVTYS6a4$R%MVeXa>k}YD6O8XAkI9%A_!4V^R=zxKcVvoQj z4kg8ubxacj1;o2%-`vr2c@+ouOv$~MS^jUgyYstv=bf|loj|)l;DLFOXKHcI#=I?& zdMp22ubgIheA?og*=22O5*pgpYV9?hpHU!DE_;sqaM;z0H3!}$M6M6k5GtK~GB|bb zyNr9^7*mQWjjEK*XWC3X`ShsnI+g5?V^AG+O~S5>))R}_q0uKS=lLS@7R1Vg!@$0+)3{2CITC_y_R-x5$SS~ z{r)kpW6iU0D~849Lbs3C7gv?}UH{q5>u*-P=;F&wOEM1KYw)x>Ie+T*6}DkXZOJyC z>aDHbM}l=UXW84QrEt4W6X_NHIOYE#u)B1=GV&alo9R%nq88*pPgg&ebxsLQ04_qu AOaK4? literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Consumable/Drinks/beer_can.rsi/meta.json b/Resources/Textures/Objects/Consumable/Drinks/beer_can.rsi/meta.json index b712e503a15..5a1b399e502 100644 --- a/Resources/Textures/Objects/Consumable/Drinks/beer_can.rsi/meta.json +++ b/Resources/Textures/Objects/Consumable/Drinks/beer_can.rsi/meta.json @@ -5,13 +5,21 @@ "y": 32 }, "license": "CC-BY-SA-3.0", - "copyright": "Github #DrMelon", + "copyright": "Github #DrMelon. Inhands by Tiniest Shark (Github)", "states": [ { "name": "icon" }, { "name": "icon_open" + }, + { + "name": "inhand-right", + "directions": 4 + }, + { + "name": "inhand-left", + "directions": 4 } ] } diff --git a/Resources/Textures/Objects/Consumable/Drinks/cafe_latte.rsi/inhand-left.png b/Resources/Textures/Objects/Consumable/Drinks/cafe_latte.rsi/inhand-left.png new file mode 100644 index 0000000000000000000000000000000000000000..50314fb33bbc6c30b87254d1ddfc62425dbc9e56 GIT binary patch literal 350 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=jKx9jP7LeL$-D%zB|KdmLn`LH zy>&3R)j*)-p`sTfoAOT9Rf}2p^bW>e;1IIC(4hMLL5zY|M^R{GJJ*Lf z-mAVEwf2$S%;!6+-p@{%?Q_7Q@7DL&+uJf@!#^APYL@=q7k%7IjQzr^ynj=c^Cv`3 zdsoF$+V}c$ed%XId9ZaLg5PNUmUU?vGVU*P`qu1EJh?`8-;+6}zLVz^TlF2biZi=7-yF|`3$8sjZTV2g8@1t@9Va==a!Y|{;z!Ycx}_BYhIIn?b~m2ValYu z?X#z)UbHzMo?pL4=I#**p#8De`-Qa@rs&pdG1Pwln0q_U_^ke#t+%p%+HNgh7tGl6 zIHFa+#P{-JshCWOwyj6DR+atYzwxCu-ZuQj`(4ldmtQJ9x7N_DG*&%3ccQxh&~lB( Y+$QhRu9bffbOX7?)78&qol`;+0Bu#Ns{jB1 literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Consumable/Drinks/cafe_latte.rsi/meta.json b/Resources/Textures/Objects/Consumable/Drinks/cafe_latte.rsi/meta.json index c92d6f1b0ef..c3942590a6f 100644 --- a/Resources/Textures/Objects/Consumable/Drinks/cafe_latte.rsi/meta.json +++ b/Resources/Textures/Objects/Consumable/Drinks/cafe_latte.rsi/meta.json @@ -6,7 +6,7 @@ "y": 32 }, "license": "CC-BY-SA-3.0", - "copyright": "https://github.com/discordia-space/CEV-Eris/raw/f7aa28fd4b4d0386c3393d829681ebca526f1d2d/icons/obj/drinks.dmi. Fill levels by Tayrtahn on GitHub.", + "copyright": "https://github.com/discordia-space/CEV-Eris/raw/f7aa28fd4b4d0386c3393d829681ebca526f1d2d/icons/obj/drinks.dmi. Fill levels by Tayrtahn on GitHub. Inhands by Tiniest Shark (Github)", "states": [ { @@ -17,6 +17,14 @@ }, { "name": "fill-1" + }, + { + "name": "inhand-right", + "directions": 4 + }, + { + "name": "inhand-left", + "directions": 4 } ] } diff --git a/Resources/Textures/Objects/Consumable/Drinks/changelingsting.rsi/icon.png b/Resources/Textures/Objects/Consumable/Drinks/changelingsting.rsi/icon.png index ea7735183ef279da890571ff26ea05496c597e50..9ef4af5e60ff32ef4e71a290dc530868739d4aad 100644 GIT binary patch literal 1857 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 diff --git a/Resources/Textures/Objects/Consumable/Drinks/changelingsting.rsi/icon_open.png b/Resources/Textures/Objects/Consumable/Drinks/changelingsting.rsi/icon_open.png index 04cfae2fc3cc1c4ed76fefb7e98a6c70411a89eb..a09984dbd3cf41b4b097088c88f146f61a2c11b0 100644 GIT binary patch literal 1879 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 diff --git a/Resources/Textures/Objects/Consumable/Drinks/changelingsting.rsi/inhand-left.png b/Resources/Textures/Objects/Consumable/Drinks/changelingsting.rsi/inhand-left.png new file mode 100644 index 0000000000000000000000000000000000000000..80d124e334e8e0be66e9fb8c6c77d06954386ccf GIT binary patch literal 1591 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 Jhvyad>%UCL2D1PF literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Consumable/Drinks/changelingsting.rsi/meta.json b/Resources/Textures/Objects/Consumable/Drinks/changelingsting.rsi/meta.json index 681df632623..ce1ecaa5abf 100644 --- a/Resources/Textures/Objects/Consumable/Drinks/changelingsting.rsi/meta.json +++ b/Resources/Textures/Objects/Consumable/Drinks/changelingsting.rsi/meta.json @@ -5,17 +5,22 @@ "y": 32 }, "license": "CC-BY-SA-3.0", - "copyright": "https://github.com/discordia-space/CEV-Eris/raw/f7aa28fd4b4d0386c3393d829681ebca526f1d2d/icons/obj/drinks.dmi", + "copyright": "https://github.com/discordia-space/CEV-Eris/raw/f7aa28fd4b4d0386c3393d829681ebca526f1d2d/icons/obj/drinks.dmi. Inhands by Tiniest Shark (Github)", "states": [ { "name": "icon", "delays": [ [ 10.0, + 0.1, 10.0, + 0.1, 10.0, + 0.1, 10.0, - 10.0 + 0.1, + 10.0, + 0.1 ] ] }, @@ -24,12 +29,125 @@ "delays": [ [ 10.0, + 0.1, 10.0, + 0.1, 10.0, + 0.1, 10.0, - 10.0 + 0.1, + 10.0, + 0.1 ] ] - } - ] -} \ No newline at end of file + }, + { + "name": "inhand-right", + "directions": 4, + "delays": [ + [ + 5.0, + 0.1, + 5.0, + 0.1, + 5.0, + 0.1, + 5.0, + 0.1, + 5.0, + 0.1 + ], + [ + 5.0, + 0.1, + 5.0, + 0.1, + 5.0, + 0.1, + 5.0, + 0.1, + 5.0, + 0.1 + ], + [ + 5.0, + 0.1, + 5.0, + 0.1, + 5.0, + 0.1, + 5.0, + 0.1, + 5.0, + 0.1 + ], + [ + 5.0, + 0.1, + 5.0, + 0.1, + 5.0, + 0.1, + 5.0, + 0.1, + 5.0, + 0.1 + ] + ] + }, + { + "name": "inhand-left", + "directions": 4, + "delays": [ + [ + 5.0, + 0.1, + 5.0, + 0.1, + 5.0, + 0.1, + 5.0, + 0.1, + 5.0, + 0.1 + ], + [ + 5.0, + 0.1, + 5.0, + 0.1, + 5.0, + 0.1, + 5.0, + 0.1, + 5.0, + 0.1 + ], + [ + 5.0, + 0.1, + 5.0, + 0.1, + 5.0, + 0.1, + 5.0, + 0.1, + 5.0, + 0.1 + ], + [ + 5.0, + 0.1, + 5.0, + 0.1, + 5.0, + 0.1, + 5.0, + 0.1, + 5.0, + 0.1 + ] + ] + } + ] +} diff --git a/Resources/Textures/Objects/Consumable/Drinks/coconutwater.rsi/inhand-left.png b/Resources/Textures/Objects/Consumable/Drinks/coconutwater.rsi/inhand-left.png new file mode 100644 index 0000000000000000000000000000000000000000..609b685ec117330d38107ae63aa070cbe9593df6 GIT binary patch literal 520 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=jKx9jP7LeL$-D%z4|%#chE&XX zduzA%;Q$e~5Bf(PF9u#%I9WjSi+n+GruNeA4vj}D9Fbd^EIiU*DzL8gc6hO5g2E#u zyH|_5A1HO?na47k?4*)cD7*1h=u zeN|gMT71suT>1AQ#7JB4ritRp1xH&AdA7tWN_l&@))m%PuTKf@6n&6UEID<#P*=6) z$`kTGwK_x-Qp|W6UP#AI?D}IGKP!TfA)!J|S@L^*jEr2R{&)Vkn}t*NEU(+wl`}E= zz@0(^NiJ^}Q``7Aq8r{Y>FjRssEIo{dDEMwt_X;OAg(%K=9?<3Bx>@~VZY&}t81^@ z-9B};bNyp&>viRIWnG+yGctH5Ub|6#F@h=ootazOlxw_-&#ESd2C1DKR@1w+pZmme8k#uPx$+(|@1RCt{2+P_NzVI0TtkI`VXG!!*7MN-fo&>Hrq^s`p=K%56r*F~=nC}*)Fw6fv6mqA=V-J2<6A^l3`AoIVL#NSz0*Q2Q0uR_D|eeW80V!P5Zl(;KM1RFKaT(8C!3gA768!Q)A-~M k50@~07*qoM6N<$f|&C5LjV8( literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Consumable/Drinks/coconutwater.rsi/meta.json b/Resources/Textures/Objects/Consumable/Drinks/coconutwater.rsi/meta.json index d7f3d6da42b..c336b26583f 100644 --- a/Resources/Textures/Objects/Consumable/Drinks/coconutwater.rsi/meta.json +++ b/Resources/Textures/Objects/Consumable/Drinks/coconutwater.rsi/meta.json @@ -5,13 +5,21 @@ "y": 32 }, "license": "CC0-1.0", - "copyright": "Original work by noctis on Discord", + "copyright": "Original work by noctis on Discord. Inhands by Tiniest Shark (Github)", "states": [ { "name": "icon" }, { "name": "icon_open" + }, + { + "name": "inhand-right", + "directions": 4 + }, + { + "name": "inhand-left", + "directions": 4 } ] } diff --git a/Resources/Textures/Objects/Consumable/Drinks/cola.rsi/inhand-left.png b/Resources/Textures/Objects/Consumable/Drinks/cola.rsi/inhand-left.png index 477a29c3e2fd5157771c56877e86363144238912..6fc55016b008e87c849392b4cedf942aa6ee1c8f 100644 GIT binary patch delta 381 zcmV-@0fPS90hj}jB!2;OQb$4nuFf3k0003}Nklsd^It)_=4@z3U6u_`=M#(S3W@ z%FfLW_tl#Ku%a2;IXy=)YHKFvOm)=+jw?;aF>bG7L_|bHL_|bHL_|bHl$Yt5T$|cFo-sX>XTnxTye%I|nxLP)qI`0& z&}^pu0+7w*XLe;gdfO)Q0D$iC5jHp0@iCd8m*X*1*I@u?j8f~ReuwA1UG4NQ#i(s$ zk+%z=iCcz+5xOt&2!ial8TPmRjx_A z&+}3(W*Pq^6;B{C-<)#nTB)sB1{K5^#RYUY3cGP}4LD$>~5%T+-}fY6fJKP>KV|Hi%S7GF<*@HdW^>kscY q$?7-gowdPz#xJG=cN>6;?7lK7XWPcDT-=tx00f?{elF{r5}E*^e^|%> diff --git a/Resources/Textures/Objects/Consumable/Drinks/cola.rsi/inhand-right.png b/Resources/Textures/Objects/Consumable/Drinks/cola.rsi/inhand-right.png index 23a82d03f8db9f82d915680ad4e2ddea33388e6e..b4a47272c51a144de6ad3fabff84cb62c79c5e9e 100644 GIT binary patch delta 394 zcmaFQxP*CvNGZx^prw85kJjJY5_^D(1YsrSE?@K!o*!@dM=r5gf6XwnYD8 z6mV@&sbM(NbU^>Igo|UsG+wbgDtVloS(Cb?ZlrMDOkmu&P(WBk*g=o!${~;cdrMWG zFOQG+zf^ry)4>G-zI0#v+WUoFIdkXspllP>w>I@J`Rm;le$r*NymIgU;a8`O?zK6W zG}%s?_3@qGiqG7R{88)LomR@IUiOJxxBT6wWy?GRFF&tht+~xNRsRDE!w+-e2jQz4 z?L!{4mK80VbLD(;>+Du#<^Fj!%Ve87kbqNg>{<7ByRv(i&G;q7bJyYh!tS?gzxr&t zxNl|sx@XGwZ&=znh{;Q&Z_e1iM{Rai)6=R0k-XttyG{nY{jkJo<(h5%{|mS8Z2bL8 zQ*WO9RG&zleYxF}ji>%Ke(=O+V!7b{pwLf!H@s7K%IWpi7-cRCh^#y=wQ|w2?un5s m3^I15&+~0ML9SW$i>WldWU8Es=r#r*@O1TaS;y>@&;$SlX16E+ delta 211 zcmZ3&{GM@wO8quZ7srr_Id5<67CfvV(DHEV@r}jX9a&#JyA>e4Oig!tInC5d(<^iGB~AIVO|?bG zy5?-3)GvNSmjt KpUXO@geCx3a9cS5 diff --git a/Resources/Textures/Objects/Consumable/Drinks/cola.rsi/meta.json b/Resources/Textures/Objects/Consumable/Drinks/cola.rsi/meta.json index 1bebea0aa9c..181ce00e880 100644 --- a/Resources/Textures/Objects/Consumable/Drinks/cola.rsi/meta.json +++ b/Resources/Textures/Objects/Consumable/Drinks/cola.rsi/meta.json @@ -1,53 +1,25 @@ { - "version": 1, - "size": { - "x": 32, - "y": 32 - }, - "license": "CC-BY-SA-3.0", - "copyright": "https://github.com/discordia-space/CEV-Eris/raw/9c980cb9bc84d07b1c210c5447798af525185f80/icons/obj/food.dmi", - "states": [ - { - "name": "icon" + "version": 1, + "size": { + "x": 32, + "y": 32 }, - { - "name": "icon_open" - }, - { - "name": "inhand-right", - "directions": 4, - "delays": [ - [ - 1 - ], - [ - 1 - ], - [ - 1 - ], - [ - 1 - ] - ] - }, - { - "name": "inhand-left", - "directions": 4, - "delays": [ - [ - 1 - ], - [ - 1 - ], - [ - 1 - ], - [ - 1 - ] - ] - } - ] + "license": "CC-BY-SA-3.0", + "copyright": "https://github.com/discordia-space/CEV-Eris/raw/9c980cb9bc84d07b1c210c5447798af525185f80/icons/obj/food.dmi, inhands by Tiniest Shark (Github)", + "states": [ + { + "name": "icon" + }, + { + "name": "icon_open" + }, + { + "name": "inhand-right", + "directions": 4 + }, + { + "name": "inhand-left", + "directions": 4 + } + ] } diff --git a/Resources/Textures/Objects/Consumable/Drinks/cream.rsi/inhand-left.png b/Resources/Textures/Objects/Consumable/Drinks/cream.rsi/inhand-left.png new file mode 100644 index 0000000000000000000000000000000000000000..81e381ec4ae1e4c30dab732de029fd1a4c372bdd GIT binary patch literal 408 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=jKx9jP7LeL$-D%zgFIavLn`LH zy|vMsDN*A1M|aL&{45U-u>Eg{3d$(RE9=-{W-h+*?6iy`u6E|_$J(Yf%jmfX%@LAe z30EvyInDVf+uV7}iZkBa+wS+H?pX8h!talFM$Zdp0oudBpwO0g>|*R`zu8<|HU9nQ zy)WgN_Sk1knH$mgeq~+nRa@(;FPAJ<^X}MWA76cPUPJe(sdvoueUJW~X&dZV{x*AM zNdA+54>eP@j5poP@o~?SoZav*K}G$jv-W=w<6rXq5*@HTAR=k@^_Z|4HY@^zpD z&>@d=^ujogU3+Y=J5BqhzIe{jeA(JFK|%Tde${ESewi2V;__rc$QD8Umqm_Zr>9QT wdE73U(`~nM`_13qqPE_%@(^)a`x`TqF(ox7jx1%Z|@Ff_z(G3v{+J{%u*c1GXs3*TdG zEwsHB$8FukqAXc^K6LK4Ej3k39QUs@oBrYBtvJo(H|h`mJo1yv-Y(s``J&$(*W>Ef zSN>dTcPD<9@0asQq6(j{Cw%y(_x5?;O&94;^WwJ2GJ>rE5!u+r*4|{ zC;!0rnBI4ZcSCjsuFop5+V@;d?%ekn-no0u9a_isciFd1mepJtS61IT{mkTrd8t^L zY00O~=^J7kCRMv9`L|Dxy?Z4{NvW~pVzB3QE+Z-bp11qU7`xpbcfOg%<(c!d vbF=dMkRDU}s6QHSpMP`N_s<99n20yR{c00(j@+5Z19Fw8tDnm{r-UW|RHv`g literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Consumable/Drinks/cream.rsi/meta.json b/Resources/Textures/Objects/Consumable/Drinks/cream.rsi/meta.json index 9e1d9a9075d..e65d47fd416 100644 --- a/Resources/Textures/Objects/Consumable/Drinks/cream.rsi/meta.json +++ b/Resources/Textures/Objects/Consumable/Drinks/cream.rsi/meta.json @@ -5,13 +5,21 @@ "y": 32 }, "license": "CC-BY-SA-3.0", - "copyright": "https://github.com/discordia-space/CEV-Eris/raw/f7aa28fd4b4d0386c3393d829681ebca526f1d2d/icons/obj/drinks.dmi", + "copyright": "https://github.com/discordia-space/CEV-Eris/raw/f7aa28fd4b4d0386c3393d829681ebca526f1d2d/icons/obj/drinks.dmi. Inhands by Tiniest Shark (Github)", "states": [ { "name": "icon" }, { "name": "icon_open" + }, + { + "name": "inhand-right", + "directions": 4 + }, + { + "name": "inhand-left", + "directions": 4 } ] } diff --git a/Resources/Textures/Objects/Consumable/Drinks/dr_gibb.rsi/inhand-left.png b/Resources/Textures/Objects/Consumable/Drinks/dr_gibb.rsi/inhand-left.png index b831c1087e1565596a4bf79831791e45780ef95e..d5ff9cf1248deadb79a9324b5e3dae0ae858e307 100644 GIT binary patch delta 357 zcmV-r0h<2X0e}OLB!2;OQb$4nuFf3k0003xNklo04>G6)M6fy?;D^s+JA(YL`9P-*?TM zl5}MmYZnuJ+&)?+PkeRFj2cZh?##TbsU*cg;H7Q80oF#1rh99(oUaWq9l(5dP%o&P zf2sNIpfnp=X8`~J00000002-*7{xAGrf$8>y`0Jay*l58)#AOTc>}qc#m+g8z4!GYF`h@U8PLJ%K*}B zsQjktBmINLdxTQcJE!kI*!O**>1K7YzXJdO0O#@rYNUG8yH^fc00000NkvXXu0mjf DEjFQ* delta 191 zcmZo*zRfs6rGAm8i(^Q|oVT|ec@G;1xLnNa{4!^?B}?~0m&OOl22We2nd}yk(|e9_+$~W&x=(hR z^Sj%Eic7b@zj^TZmot7*yI0Oi*{S;S@2*)ZdBH{i2@8gp1MmNBtxs6-w&AeBZpP_7 qwobq79^7ub!MnraI|oq3k8*uhZ?`kA&$O6=GxUV diff --git a/Resources/Textures/Objects/Consumable/Drinks/dr_gibb.rsi/inhand-right.png b/Resources/Textures/Objects/Consumable/Drinks/dr_gibb.rsi/inhand-right.png index 4767d514b169479fc5eaa7db1b3cfc10ea52374e..adac96faed8f8d5c674c0a2cd681e83e81ab39bb 100644 GIT binary patch delta 377 zcmV-<0fzqI0h9xfB!2;OQb$4nuFf3k0003_NklAs=7{>9((y_RgE*Yc{ zaPlL#`5Efk#i4rdP6eST2(`Fs7NHcbi<3x6G^ZB+zxi@J zT;7|WlK=n!0002C@SA~|%oe8G9~i$Gm}BSp%Vf4ll9io#jd&U#FiF00000000000Gm#>n)jQ5>GlU^GFw;;R?8Pmz0@|girJmZ z{^8TTuJohO^>P$_zNDLKLosTo=X#QbZZc6jylL)wcKi6XUbdpkQB|$!IFt6?J0C!6 zI?mj6Z!*1XCEY|@*nFI^*96G+i;T6-awS{U{9Yqfc5>$WA}dLHcz;WMJOKaz0DFD` XFK2uF>w?+M00000NkvXXu0mjfZE0ORe|o5q@65%>lAAPnxDE|&x=XO>u6W_k(^OhN&X8zrOpE#+nv)o>4 zKDn)qVRBCN_h`xa;q3A6&;NCi-SO1qqg&pFQR>ng?1j suTv^vi_-hfe9q-1&yLOuk{~7LWc9V(&YXR0xdFuUboFyt=akR{0Nbrm?EnA( diff --git a/Resources/Textures/Objects/Consumable/Drinks/dr_gibb.rsi/meta.json b/Resources/Textures/Objects/Consumable/Drinks/dr_gibb.rsi/meta.json index 1bebea0aa9c..087c100ebfa 100644 --- a/Resources/Textures/Objects/Consumable/Drinks/dr_gibb.rsi/meta.json +++ b/Resources/Textures/Objects/Consumable/Drinks/dr_gibb.rsi/meta.json @@ -1,53 +1,25 @@ { - "version": 1, - "size": { - "x": 32, - "y": 32 - }, - "license": "CC-BY-SA-3.0", - "copyright": "https://github.com/discordia-space/CEV-Eris/raw/9c980cb9bc84d07b1c210c5447798af525185f80/icons/obj/food.dmi", - "states": [ - { - "name": "icon" + "version": 1, + "size": { + "x": 32, + "y": 32 }, - { - "name": "icon_open" - }, - { - "name": "inhand-right", - "directions": 4, - "delays": [ - [ - 1 - ], - [ - 1 - ], - [ - 1 - ], - [ - 1 - ] - ] - }, - { - "name": "inhand-left", - "directions": 4, - "delays": [ - [ - 1 - ], - [ - 1 - ], - [ - 1 - ], - [ - 1 - ] - ] - } - ] + "license": "CC-BY-SA-3.0", + "copyright": "https://github.com/discordia-space/CEV-Eris/raw/9c980cb9bc84d07b1c210c5447798af525185f80/icons/obj/food.dmi. Inhands by Tiniest Shark (Github)", + "states": [ + { + "name": "icon" + }, + { + "name": "icon_open" + }, + { + "name": "inhand-right", + "directions": 4 + }, + { + "name": "inhand-left", + "directions": 4 + } + ] } diff --git a/Resources/Textures/Objects/Consumable/Drinks/energy_drink.rsi/inhand-left.png b/Resources/Textures/Objects/Consumable/Drinks/energy_drink.rsi/inhand-left.png index 365b3aa812b8451640faa233a5f5239488aa8b61..89cb06a092bcb5dcfad36815fde04cc7515a2984 100644 GIT binary patch delta 355 zcmaFJ_>XCVNGZx^prw85kHXJY5_^D(1YswbAQvfW*;{!XH&#ti|uNp804y zYisvp{Ri9}jO{`vVmR-5Dc)AS;QDBSrPFkkj8`EqF1@wta4lH)f%Ji?zN__uHENWjH4B{>?YGy9p=!{vWU~%9XWi$ul?-8(dj&bMM0^44JbQiT{{? y`P;W7dOY^ z-}(mqE#YoV3?Q&$=2_!u#q$(dJcHJTrj_m3zv$=7my*)SE57S_=JA_uUOUC;`#*o} zrDr4_$6V|)Joi^%p4`2Is|#%%vVApG&p(Ow@?5)BH5X`-9oRgE2W&C_Z=HX(QMTYN w`<&dPau0)SzHz)^-uJgbIqaPvP|b(;aV+Lb^rhX diff --git a/Resources/Textures/Objects/Consumable/Drinks/energy_drink.rsi/inhand-right.png b/Resources/Textures/Objects/Consumable/Drinks/energy_drink.rsi/inhand-right.png index c929a445b11d7300fa853dcc00f459ee53d3f0cd..d1794343ec44b735c4ffdd6780bc49457dab9ca0 100644 GIT binary patch delta 361 zcmV-v0ha#m0fYmPB!2;OQb$4nuFf3k0003#Nkl88;!QYY_7wKjF{QA7Rubb!SRUW`s_F*0qdv delta 210 zcmZo+e#baLrGBfYi(^Q|oVT|&@*Y+YXnpuxL%32{Y{A}{Gn#z&FkgD>(7C!~qQ@Hr z>8Jl+S-*U#Q7Oa#0teDuyhG{U=G{hN< z1CuP=FEFqe3?{2t1{!Q476pYH78C|%SuoD#qAV;~92*z$%3RSq1naSk%WSf}M-ZOh z2YABaoKxOc0ssI2005X$SZ}y~oVaGI?ZSG)S@)Z*ws}*M=6}pWH)lG!yVB>!mrBFP zDx11IshT$>DQg`(UoToGy>`uRfFxaPt*Eebow02CW_keow=b4CNm8v+b`SFlI_Sja zZCO8oV3g=^ZOQzz3Py>Se+2*l00000000292g?9CZ+uW$A+w1D7_pIvf_EbYz^8?U$lzkk%`$(s(_7TkY15O_Y8I4Ef ze___W0WUY;pc5+}Zi+zNDwaqc9Rw+A4iU+UhvjYGC b0DkWq)Z%Ay{3)uw00000NkvXXu0mjfEmy6Q delta 219 zcmV<103`pI1NQ-tB!9k1L_t(|obB4Zje}4W1>s@k(A5An0nLyvbmJUTjq~fktJTKq zVHaI4e??<8bj9!!?ys?SZCwGd zLbK+&0AI=2)bw0#b9D3YILym!W@`FmHm`=Res3$?-nyzG-&Bsi007o_@wHt^k|arz zBuSDa=`%!sagUam9eC>lNX#STe}@m0m`6Az7j(4m+TgrB)p+X{05~@wNs^?0x&t7p VJ?IED#?Al$002ovPDHLkV1gJ^YX$%S diff --git a/Resources/Textures/Objects/Consumable/Drinks/fourteen_loko.rsi/inhand-right.png b/Resources/Textures/Objects/Consumable/Drinks/fourteen_loko.rsi/inhand-right.png index 6c8548832a0f28043f73d5f00979dc18f3e6468a..b4d925a2ffd1ccca772174d0253288d4a6e68caf 100644 GIT binary patch delta 399 zcmV;A0dW5L0jUF!B!2;OQb$4nuFf3k0004FNklWs7m=8GokZ_)__%0~KALqSUy+ z$NMMNy_eA8;!w)(NYzit6jw63Y@Wa6`D9NN(}{^b0^ZfWR6eO4aQx&*2Z~#v*2UK5 zM&N}C)B^yZn#&5uo$T`u07lP;na<~kF*2u9Zof)=PSFK6S@Zg tKrx*Vy5jSH*nCvdT#1N?i0Hrj0z@ZqH;grW!vFvP00>D%PDHLkV1mG)zCr*1 delta 221 zcmZ3<{F8BlO8o&(7srr_Id5-m~>UXUJ7S3j3^P6z diff --git a/Resources/Textures/Objects/Consumable/Drinks/fourteen_loko.rsi/meta.json b/Resources/Textures/Objects/Consumable/Drinks/fourteen_loko.rsi/meta.json index 1bebea0aa9c..087c100ebfa 100644 --- a/Resources/Textures/Objects/Consumable/Drinks/fourteen_loko.rsi/meta.json +++ b/Resources/Textures/Objects/Consumable/Drinks/fourteen_loko.rsi/meta.json @@ -1,53 +1,25 @@ { - "version": 1, - "size": { - "x": 32, - "y": 32 - }, - "license": "CC-BY-SA-3.0", - "copyright": "https://github.com/discordia-space/CEV-Eris/raw/9c980cb9bc84d07b1c210c5447798af525185f80/icons/obj/food.dmi", - "states": [ - { - "name": "icon" + "version": 1, + "size": { + "x": 32, + "y": 32 }, - { - "name": "icon_open" - }, - { - "name": "inhand-right", - "directions": 4, - "delays": [ - [ - 1 - ], - [ - 1 - ], - [ - 1 - ], - [ - 1 - ] - ] - }, - { - "name": "inhand-left", - "directions": 4, - "delays": [ - [ - 1 - ], - [ - 1 - ], - [ - 1 - ], - [ - 1 - ] - ] - } - ] + "license": "CC-BY-SA-3.0", + "copyright": "https://github.com/discordia-space/CEV-Eris/raw/9c980cb9bc84d07b1c210c5447798af525185f80/icons/obj/food.dmi. Inhands by Tiniest Shark (Github)", + "states": [ + { + "name": "icon" + }, + { + "name": "icon_open" + }, + { + "name": "inhand-right", + "directions": 4 + }, + { + "name": "inhand-left", + "directions": 4 + } + ] } diff --git a/Resources/Textures/Objects/Consumable/Drinks/glue-tube.rsi/inhand-left-fill-1.png b/Resources/Textures/Objects/Consumable/Drinks/glue-tube.rsi/inhand-left-fill-1.png new file mode 100644 index 0000000000000000000000000000000000000000..fa5d91c412cbc846b32ad4a41ce9f49aba5ed243 GIT binary patch literal 135 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=jKx9jP7LeL$-D$|96eneLn`LH zy=5o}RK@K0=XMv{o`AaFrp6_^na()`u>#dFY`Ai__^NNwC6FON(6Cgc*mUaWkCH&< ZR`%P6L^Nk}2yO$(c)I$ztaD0e0sv}FC&>T+ literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Consumable/Drinks/glue-tube.rsi/inhand-left-fill-2.png b/Resources/Textures/Objects/Consumable/Drinks/glue-tube.rsi/inhand-left-fill-2.png new file mode 100644 index 0000000000000000000000000000000000000000..9cec22fdc8fc553c52cfa4bbe5886ff77f085876 GIT binary patch literal 197 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=jKx9jP7LeL$-D$|>OEZ?Ln`LH zy|s~-$&kk(kUP-e#M;8&`UM{)R<7sfJvx=+rc=jvwjV{8ZV3XFGkn;%^_t-^3+r34 zccW8vjJI2+ry4!_`lBx|q#h&<1P9_JljmfweSEuk&*D^To98`e?pWOl7yZs*zgKSk p4)-0?eTz4~|GjuIHv_|zN~Y@_25WMj6w85hdb;|#taD0e0suuaN#Fng literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Consumable/Drinks/glue-tube.rsi/inhand-left-fill-3.png b/Resources/Textures/Objects/Consumable/Drinks/glue-tube.rsi/inhand-left-fill-3.png new file mode 100644 index 0000000000000000000000000000000000000000..5abe7972d8e4aecef325661a099b222b113e7c43 GIT binary patch literal 203 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=jKx9jP7LeL$-D$|T0LDHLn`LH zy|s~-$&kn4B1fRXiM12|itk9_xqiL1tx2d+SLEeh#(is!#9opDs%N+#ojo_XXZ51k zt9wIT$|qGZ6rWR8GMc=0Z{Gezw{t)$fZ#*7;jyjPtp3{`SKn4AbM{AnKoNuB#bPx$AW1|)RCt{2+A&VUKoEuD2ST|5ks?lzGMvGUMHA%?&`p<`&b3SD9^0(M4c29@ z5Yf4I6`B~iC7vZR{NDkdS5G@`W+eas0000c`*?di-}($caqk&++^^2-<-#-a+vodJ zmSP_~!w&tfRWC`kXRORDRh?SzTvuk6VvJ3Uu`#pcogZUtyffuJ0(0a#0+Lh|#j9tY znWeHUTS+I++`+%U0j>pv5H>mHKZLLeA-s6!0ssI200000fa&J6BG0lJS}zwm?pN7M z@F+S<0adqc5B;vqkv-;7wEJ>&w9J&GRM+*h_csPrx4nGl`ga5F1^gDTqTNT}a*!;m z>>Or$0|ryyBV;LHPOI#@TOZ(B<97%-f3yGq0QjrE06wTy{ZsEeBLDyZ07*qoM6N<$ Eg6=t&F8}}l literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Consumable/Drinks/glue-tube.rsi/inhand-right-fill-1.png b/Resources/Textures/Objects/Consumable/Drinks/glue-tube.rsi/inhand-right-fill-1.png new file mode 100644 index 0000000000000000000000000000000000000000..c0f87542b23f560dcafc9b7fd950da1a3abb31d4 GIT binary patch literal 135 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=jKx9jP7LeL$-D$|96eneLn`LH zy=lnHpuof6_~-VjwyKvW{Fr*CJn=jD-X5fn;eeaVmDg>v&#aNRVg&IS7!od4Rc_~H bW?=AB3tc1pc}_s3ElAkY)z4*}Q$iB}tnVmA literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Consumable/Drinks/glue-tube.rsi/inhand-right-fill-2.png b/Resources/Textures/Objects/Consumable/Drinks/glue-tube.rsi/inhand-right-fill-2.png new file mode 100644 index 0000000000000000000000000000000000000000..c4640503fd11ba0b0d36c22af082299d4b71bf05 GIT binary patch literal 200 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=jKx9jP7LeL$-D$|nmk<`Ln`LH zy|t0|kbwZ}1&Kfd539}pnc@_`NvwN0hgCpA={VEg@c56V;s2t=fEpMoR&Cw(bdLPy z;yst6Zrjb=|Antj;N8}1>z(GVoU&=zlwJH+_kxsx0Go8=S^2E?^S>lDmabX6>ZddJ rkE!z;!`E$Q{?cK1FD;#cp}~GLbHAB(hm7lXHINQZS3j3^P6lUVn14r_n`SD3+`@c56VyWZV5VFc><5VN+_SJU>~ zxsP6JOKa2rUD7`#F-u&)X~*=SU(0?r%=s*noU`xB{{29uAn>62%bI8WQx`A(!}CUR zk?c9k^LtnQbmo?Lnx1g}>l+5$X{kHs&IOuVcZTikeeIqarK<-(+B{wTT-G@yGywqH CO;Q;E literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Consumable/Drinks/glue-tube.rsi/inhand-right.png b/Resources/Textures/Objects/Consumable/Drinks/glue-tube.rsi/inhand-right.png new file mode 100644 index 0000000000000000000000000000000000000000..db9b96c99bb4194e7593049ee6946fc447c8157c GIT binary patch literal 354 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=jKx9jP7LeL$-D%zWjtLRLn`LH zy``9U*g)ji$LpC|60$dz$SmAo>)es~euLrW3z_Z)Z*6^)-m)2<5v^)p(32D75Nf$` z{^~9N<-4D_&5x6vd|nA?ECWN#*UvxA?pZnK`ETU@y-ce7ee_)u$uGX9ul=j~Vk@Nj z9N7c~x2uF3E`KQTET!ib%%PSRK z>z}eN_xAc5bANrXR`?~b%{Eoz;F`$~n%a;pE)LP;V<{ tubCnD?(e+6*YoGcFJi}{&Vx+0SrtF&Tkz>;v-=)_xSpPx%Zb?KzRCt{2+C6X6P!tB>*98V>)CCD;L1aX67cU@`DQuo9b?Jyyg!mOihW-HN zsxne4=ByczoC#T(GKDDvr3{v($}~!VB#jS4u;nIpV{@<56rE>suAGzmajtE}2Vjgb z#u#Ia{VU7VXxTaS8kU}uHkM4cMFUu-M%BF?ShzgE)057n^K@NB9bJ0y4ocQo&tG;D zzjLiDQzIG}6drpz(ZC=Y7&PrwX!PX?xwc9N`y~PZ*H$Sh6Ov-(JqDo+I6dhAlcJQ4 z$c&YR&;-oVxk=>d)M_|kyYGAg0E~W*!#3Ae>F{WXHy`4+KwK=PV612A&#Tu!c4h~YHd+k_ zO2JTQV33SSkXeiokUjyiChdhzW)%!xDHw`nYE<1V0(YJQ0DR{jF2)m_pAT_(G{l2v zUB$IkN;3%?LcNL+)CL5|)9Ltq6KPX2$*h2)E!w>W`DDP~^snv~A!G26T#S*cX|EC% zIHau%%R*)`2J*;&jr&_@HJsckyJQw)+<07!v5w*jobn|4TT*X>(_V%Avp%-VZ7R>u@Ze<_Lp0000Px%(n&-?RCt{2+P`btKoke?uZ-g*h7?MRhy2hSWzmvSGP%$}Q^8BeKtjl0Q6rK+ zAhR(lIDddw4+Uj3nY=WfGUV4_T!M@L z#u#IaF$Ms(rBl#7l_CP~Nt#LRO8alhfBXO&-UeP@HatHv3=I{W(e?q9c*32Xzrmti z?{*vGW40}wsB4lub_}AfNz^sz;e3nw%}r|8H9Fi;2>{x4jgmeRsB02A28m=)*Cc;p z9CM`zIc&%=o(+HZG)SU$UGu~y+A(Rmru`>I8LH9Bnl8_Y-tXMqqg3wU z)8~ss_q<=Io*zeKFX_F`SWM)4z%l-rDR8)>%9z8fYEzRg*p^Nk>jOOAcJO%H!T#PN zlAeUa9hLU?7G=yE>x00h{j+}ow_5E?9$($45r!I{Qn`oKtx`l_J%DZLllR}JG^ti0s^<%#5>P3EL{WtMy#I@9U=cz{qVY=B zRBTJ9d?5!cycu2GZ3O*%DuD?Qjeq_2OcCGRmzEZh&MY96dq28qc#4y13rf~hsB6-! zNtkD?Lg*>9Hn&F~%5UvG@tV W3AK!G{i03)0000|1wj_O2IGx1?G} z?TY{6^~jf@!>d(q{V5Hbo(I2!7Y1s2r$+aklRG+_;exv4?i1${tu1wD<``ZTHJ-Ka zs{ZMRzB>&==4U7Y_dYC|)aI z-NfovnB^dPSK`e+y(-n%wdTD&Czp1fWpiGBT<=)gb3=natqwD#(<8Sn4i69dFtuMj z^zg%bX-g*e{op?EUZXm`Rl)LjkD(e-hSTE d1qkY&vTy(0kjt$TZU>AF22WQ%mvv4FO#pDJ#eV<* literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Consumable/Drinks/ice_tea_can.rsi/inhand-right.png b/Resources/Textures/Objects/Consumable/Drinks/ice_tea_can.rsi/inhand-right.png new file mode 100644 index 0000000000000000000000000000000000000000..8ce05ea8ea10cf9446f10658a3d8a7f5d82a4ff5 GIT binary patch literal 430 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=jKx9jP7LeL$-D%zGdx`!Ln`LH zy|v%_u!9Wihvgv!8=6De7fQ4UX>v5alKbc{AY*0Wy6e>q&2^8G3NDvj@^n&su|R@l zF3Uncze#+z#MtYnzN+K9DbN$&5cApDv_T9PriBCZZ0zM^9%?-@na^&XKwHr=t zlPH<@|BBSwfS*E+VzP3f5AQ7b@b%%tr~9NVW9%iOAAaIxkBu-geeyMDicf8*k!j^@ z`Eau%O9};FYX{`3J$)J-b5p!4s^crev>tCkwe$t%3=Bn8fk*!SV|KV*{PEi#yB88J zNI+!Pn=HEm({Hmww;hdfYn&BWSoJQcxVCh~_KS5V);&|^Pbfcr^vWNmW5?_-etS~Z zrW$;>)40i&lbPd>{Q>{D^QYcEX0%D2W;knxt5xj5$A=rI1Yet4Wvu!2yn~;9m)}#} zNWtYdjz+_&ATdpzj=`6<4wNqALaEfJ2}UE08gLO zv(@7kLw4DK*+LN1yJmfxRhtYLvbaVn$+l~3p*sJ?}Y`c z9~fZ8Bme*afTx)v_ghM7Ip=j=YfbY!|DE3>b1yWktz$Dqh4;$+cm-zdg%-9$-lkUp zE+e!6%WfWdWZ$f%=T(T(((%ELo(li~0002MQw;yr_De+Xz%Zo?5Yabqm+$e@2dO_` lfHj=fs~-UXfZIzcy#d;sAmWvBLl^)6002ovPDHLkV1lUXQ49b8 diff --git a/Resources/Textures/Objects/Consumable/Drinks/lean.rsi/inhand-right.png b/Resources/Textures/Objects/Consumable/Drinks/lean.rsi/inhand-right.png index b175cde91b534d8136d9f509d3d01b8b7ef75ee3..226a769bb9adecfe23511242765f1831241f91a1 100644 GIT binary patch delta 321 zcmV-H0lxm@0o($RB!2;OQb$4nuFf3k0003NNklfCR zKjZ`e000000002ME^nv#pFomSmaE2sH9gJO9?|YEQv1B@Tk-T@k7rkhO|_%RY5vbE z;xX?Anpmd2pE^;~d>RzXwN18R+fnu#$8qC7rYuVQJk1$&d&(mBV*~&I0KgyLd2V=_ T#uhC100000NkvXXu0mjf@jH}> delta 199 zcmV;&0672L0^y{+t927XSbN0RLuc?RQ<*t(5ZmuC>OpEX_G*$z<)?OpVy~bIPCv*yk*rd%N`v z>RoIg-FdqT@XHPr;4ye1GWqTY#!hqM2j4U&j_TnfFzN*ugFt5k00000061Oh)%Qw0 z11;&`SLqpONk5NYuxH>c{Q;jYFnZ4b006uZ5l=4Q9+pi-F{uCm002ovPDHLkV1i4l BSE&F1 diff --git a/Resources/Textures/Objects/Consumable/Drinks/lean.rsi/meta.json b/Resources/Textures/Objects/Consumable/Drinks/lean.rsi/meta.json index 666ec307329..e7c10c09ef1 100644 --- a/Resources/Textures/Objects/Consumable/Drinks/lean.rsi/meta.json +++ b/Resources/Textures/Objects/Consumable/Drinks/lean.rsi/meta.json @@ -1,50 +1,22 @@ { - "version": 1, - "size": { - "x": 32, - "y": 32 - }, - "license": "CC-BY-SA-3.0", - "copyright": "https://github.com/tgstation/tgstation/blob/master/icons/obj/drinks.dmi", - "states": [ - { - "name": "icon" + "version": 1, + "size": { + "x": 32, + "y": 32 }, - { - "name": "inhand-right", - "directions": 4, - "delays": [ - [ - 1 - ], - [ - 1 - ], - [ - 1 - ], - [ - 1 - ] - ] - }, - { - "name": "inhand-left", - "directions": 4, - "delays": [ - [ - 1 - ], - [ - 1 - ], - [ - 1 - ], - [ - 1 - ] - ] - } - ] + "license": "CC-BY-SA-3.0", + "copyright": "https://github.com/tgstation/tgstation/blob/master/icons/obj/drinks.dmi. Inhands by Tiniest Shark (Github)", + "states": [ + { + "name": "icon" + }, + { + "name": "inhand-right", + "directions": 4 + }, + { + "name": "inhand-left", + "directions": 4 + } + ] } diff --git a/Resources/Textures/Objects/Consumable/Drinks/lemon-lime-cranberry.rsi/inhand-left.png b/Resources/Textures/Objects/Consumable/Drinks/lemon-lime-cranberry.rsi/inhand-left.png index aa14f15e1a75ca41c8559d2f4c6379e713be20e2..17975bea034b6977df52baae34eedd5d8a4ca81f 100644 GIT binary patch delta 409 zcmV;K0cQS;0>1;0FnDu4XtIWamTYv87KaAIttE;gg21kz zQKG3W=n{m+ynx_di0nCcvC!>>;&fnSM%^C5S_STJ^=uwbevvz1@`Zzksqf7F*(J*)qkcNedB1iW7r`*LB;dZ@_D>g)+;x7+-+xIVBkxQ@J#ddWzYh$ VIe-`hE(K2pQJ$`TF6*2UngI3QS7!hK diff --git a/Resources/Textures/Objects/Consumable/Drinks/lemon-lime-cranberry.rsi/inhand-right.png b/Resources/Textures/Objects/Consumable/Drinks/lemon-lime-cranberry.rsi/inhand-right.png index 7e1507f80aea5da2b53ca39cc399d203844bac0b..dfc03d97867501d765d809e7b53c967a778d65f2 100644 GIT binary patch delta 409 zcmbQnw4Zr`K|N!or;B4q#hkY{_j@xX%CLQSzDSid;xu%+oo#+qj~pWbAMi>5E<`AMlVfZFashhhq4hx$k3H&!^W_R{q!*fA1+{ z2NcAFWbZP_bvIcTwJ7TH(fsE>J2S2KeL7oZdBwoQrvCiujP2GH22APQM=tt0{#z=& zTcB23@7?>PMN>TfzvO)pT^Ro}ZI6tVeZ!^=pO%%Z4SbLgDEZ~j-u~r`J+b-E|2*rA z3D#aT=}h&#kn_wdR6ZZ7sGqAAt%Qvk4d4So%?&^e7jH~^%@_PI3gb1Hvm2S@AvHtDJuMQx>Ay8-sY}$8XJU*DQ;&yf%vTTuf+V=iZs17U zlRkHT<;idM6I47Wsd)Y}_I>BzrMYVzb3$zRvBERwVp9FDEjqqLf+-5LQqLuu=Qhr{docSYPfaK;AJ^c~L4=Kufz diff --git a/Resources/Textures/Objects/Consumable/Drinks/lemon-lime-cranberry.rsi/meta.json b/Resources/Textures/Objects/Consumable/Drinks/lemon-lime-cranberry.rsi/meta.json index 2151beeb21c..c0d3bd982f8 100644 --- a/Resources/Textures/Objects/Consumable/Drinks/lemon-lime-cranberry.rsi/meta.json +++ b/Resources/Textures/Objects/Consumable/Drinks/lemon-lime-cranberry.rsi/meta.json @@ -1,25 +1,25 @@ { - "version": 1, - "size": { - "x": 32, - "y": 32 - }, - "license": "CC-BY-SA-3.0", - "copyright": "https://github.com/discordia-space/CEV-Eris/raw/9c980cb9bc84d07b1c210c5447798af525185f80/icons/obj/food.dmi; modified by AugustSun", - "states": [ - { - "name": "icon" + "version": 1, + "size": { + "x": 32, + "y": 32 }, - { - "name": "icon_open" - }, - { - "name": "inhand-right", - "directions": 4 - }, - { - "name": "inhand-left", - "directions": 4 - } - ] + "license": "CC-BY-SA-3.0", + "copyright": "https://github.com/discordia-space/CEV-Eris/raw/9c980cb9bc84d07b1c210c5447798af525185f80/icons/obj/food.dmi; modified by AugustSun. Inhands by Tiniest Shark (Github)", + "states": [ + { + "name": "icon" + }, + { + "name": "icon_open" + }, + { + "name": "inhand-right", + "directions": 4 + }, + { + "name": "inhand-left", + "directions": 4 + } + ] } diff --git a/Resources/Textures/Objects/Consumable/Drinks/lemon-lime.rsi/inhand-left.png b/Resources/Textures/Objects/Consumable/Drinks/lemon-lime.rsi/inhand-left.png index de164f3b8ce5f4ed18880bf05743511d9aa7fbb2..af00bf36e2027fa3db35c646609cd2ea542b14d8 100644 GIT binary patch delta 397 zcmcc0xSV-{NGZx^prw85kH7JzX3_D(1YsW$*1&D01xM`im)gYh6DdU8=Zf zk!=oV=7#VKI=*}P95YUe3s{)6Ci@8~@s&@k4pa%^lnU9v!Bo$y=D2uneEox;dm7qb z?|irOkYjC-eeAt= zH`=34Jt=(ruIsh=Eve69?#%twu~qhf>mEjzX%kaE z?RfjQAt__F_4X9WYb#uTMErLvbw7IlOS>JT0>E%3u2d~tQ-%?v5 zU(YNx@0X1oTWv{&!=1j)Ti@r*eI}-rdX}9b;EbB*+HV#se|pT{xXax@*PZd*I?p3_ zH776p|JMHg+rTqw`=>rkXFe2uDZjBY^xxE@woTI+d7LWbe*OI@aaXxw=d&N2GylBd oOZ;Q-`%T^NN>DgF*R delta 185 zcmZ3^e3fy6O8p#97srr_Id5+rN(=cUSdulB~jTc5G7`&drpD$hw(GdF%K*sNmeJ9ScR@fC}d=(vm9 zo)$j2-Cq)LzM?SGyslv;pWZtrurVOQ{Nw)kv+^EBIqci)4y>|0WF}PI^2hGMb-j0N h+w2*3GXj;=JZF78)jTz7ja)oPho`Hb%Q~loCICy;O>O`H diff --git a/Resources/Textures/Objects/Consumable/Drinks/lemon-lime.rsi/inhand-right.png b/Resources/Textures/Objects/Consumable/Drinks/lemon-lime.rsi/inhand-right.png index a2382a5b61659130fe826d9497c71047791855ab..7fd5dce65b5fd30e23c2a173aa54f6ca69dc05dc 100644 GIT binary patch delta 404 zcmcc5xQ=;(NGZx^prw85kHdJY5_^D(1YsW$1m_L5B5%c%fJ8J1@b7TXtCN zSaSbB;Hodu7Tv+&`<*ft1{a7Kl?bdndeqTt;-d*mRRWA8x*uE+%PM?jDKUM~Byau9 z_V2U%A3y!HUq_!o5CSgh`4_&UHgaj%*!#_`4z0q}9 zYIjmyy?AR4qj~xF9TuxIvKH5R@0!(L%W!?WXpTI??|j!UGU2(aSVNT$Y+3O5%1q7s z(W_+RLhP>vnlhDU{xgu}toSE$S8a-aE6Kfh}FURt!Mk>FVdQ&MBb@0A#PVVgLXD delta 195 zcmZ3-e4lZGO8qiV7srr_Id5;B7CfvV;v6_}lE$ekET)!uo|y{5c4~<;?reT$_$YTG z3j+vzNOyYcaPFp|o9Cs{STD`c^f1Yjx4z7Hb9hq83XPU+GevWDzL=o0G~n5@El+Ds z1?$h%nZN1o^p6*7KHZ#~-g|D&S#FKJj$$`e)xo9#2^)qF$nN literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Consumable/Drinks/lube-tube.rsi/inhand-left-fill-2.png b/Resources/Textures/Objects/Consumable/Drinks/lube-tube.rsi/inhand-left-fill-2.png new file mode 100644 index 0000000000000000000000000000000000000000..9cec22fdc8fc553c52cfa4bbe5886ff77f085876 GIT binary patch literal 197 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=jKx9jP7LeL$-D$|>OEZ?Ln`LH zy|s~-$&kk(kUP-e#M;8&`UM{)R<7sfJvx=+rc=jvwjV{8ZV3XFGkn;%^_t-^3+r34 zccW8vjJI2+ry4!_`lBx|q#h&<1P9_JljmfweSEuk&*D^To98`e?pWOl7yZs*zgKSk p4)-0?eTz4~|GjuIHv_|zN~Y@_25WMj6w85hdb;|#taD0e0suuaN#Fng literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Consumable/Drinks/lube-tube.rsi/inhand-left-fill-3.png b/Resources/Textures/Objects/Consumable/Drinks/lube-tube.rsi/inhand-left-fill-3.png new file mode 100644 index 0000000000000000000000000000000000000000..5abe7972d8e4aecef325661a099b222b113e7c43 GIT binary patch literal 203 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=jKx9jP7LeL$-D$|T0LDHLn`LH zy|s~-$&kn4B1fRXiM12|itk9_xqiL1tx2d+SLEeh#(is!#9opDs%N+#ojo_XXZ51k zt9wIT$|qGZ6rWR8GMc=0Z{Gezw{t)$fZ#*7;jyjPtp3{`SKn4AbM{AnKoNuB#b0&$TAY(7mAOBdMM zH2v3p@bcN&wUcZ)frc_P+E@WTrykwMPe>D$TARk7JaE}&xy2*t@pBvy^eZ!XzcP}+`aI0 z`>Ep2H!C|99iF~;a_TabufCV>xYs9dk>0h&t7`T{!MFqYomy5kEOz`sDN|z)CFLK; ycvsz`#Hy1ywYK;z^PekUWSvgR>jKUHw~GIGZ^&w;B@GE6>pWfkT-G@yGywnxv6=D! literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Consumable/Drinks/lube-tube.rsi/inhand-right-fill-1.png b/Resources/Textures/Objects/Consumable/Drinks/lube-tube.rsi/inhand-right-fill-1.png new file mode 100644 index 0000000000000000000000000000000000000000..c0f87542b23f560dcafc9b7fd950da1a3abb31d4 GIT binary patch literal 135 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=jKx9jP7LeL$-D$|96eneLn`LH zy=lnHpuof6_~-VjwyKvW{Fr*CJn=jD-X5fn;eeaVmDg>v&#aNRVg&IS7!od4Rc_~H bW?=AB3tc1pc}_s3ElAkY)z4*}Q$iB}tnVmA literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Consumable/Drinks/lube-tube.rsi/inhand-right-fill-2.png b/Resources/Textures/Objects/Consumable/Drinks/lube-tube.rsi/inhand-right-fill-2.png new file mode 100644 index 0000000000000000000000000000000000000000..c4640503fd11ba0b0d36c22af082299d4b71bf05 GIT binary patch literal 200 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=jKx9jP7LeL$-D$|nmk<`Ln`LH zy|t0|kbwZ}1&Kfd539}pnc@_`NvwN0hgCpA={VEg@c56V;s2t=fEpMoR&Cw(bdLPy z;yst6Zrjb=|Antj;N8}1>z(GVoU&=zlwJH+_kxsx0Go8=S^2E?^S>lDmabX6>ZddJ rkE!z;!`E$Q{?cK1FD;#cp}~GLbHAB(hm7lXHINQZS3j3^P6lUVn14r_n`SD3+`@c56VyWZV5VFc><5VN+_SJU>~ zxsP6JOKa2rUD7`#F-u&)X~*=SU(0?r%=s*noU`xB{{29uAn>62%bI8WQx`A(!}CUR zk?c9k^LtnQbmo?Lnx1g}>l+5$X{kHs&IOuVcZTikeeIqarK<-(+B{wTT-G@yGywqH CO;Q;E literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Consumable/Drinks/lube-tube.rsi/inhand-right.png b/Resources/Textures/Objects/Consumable/Drinks/lube-tube.rsi/inhand-right.png new file mode 100644 index 0000000000000000000000000000000000000000..8d8933316fb001c70d60ab8fd12a9125b4c3694a GIT binary patch literal 359 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=jKx9jP7LeL$-D%z6+K-XLn`LH zy=Cur*g)j?NB5%#Zp>V2og6JOA!73$>yp$}HBDTFEd4n#hrIa?h;&DPVc6@iOGJ}7 zr0;*|!u#jNPHwELD%`V2oe5|%!+}Wt+5P`6Nfym+)r-lCwU4)%>O1-1=Xcdt+;{QD z{xHhkE90_nQPS1V6+gZt8?nu0NcLI2DlT-d;j-@j@Oi6#8NP0=Z~U*dg5lb&(#t06 zl{V?iYsTK*mcLN_>nneU52_hGFXt4eUQT&1C%W^*t4o$3J3+uPx$=}AOERCt{2+C6USKokYwLzE?CL}k%C=`xF8%C`b{PMbcPNE>(PEx_flfppLz zUTwKTlRZp|;Kas?o`laRNI9Q`KrW7li~q#EfQX2Qh=_=s={`o_CI0j>&M{+zc<)DF z-Z@9fPHplcz4vjkSil$q05}{D0D$dwi=rrKMF=58V+_5hSBwy249xNd0B~2_qHSA7 z>~J5)d^Sn}I;j?!(lsk+|M%bL=cZw$4)gPzpGzx1cMSl5JkM$8s`oxxYgut4goVZ! z!W%*epIev(=;w2DNxb(FWgNX$s}<$BV341{K@X^*r(=@bs0ro5cwL1&|ZQJ6mxCM^g;(pI?s%{p+S_^9}vMfWE zWth^1q8Ff(s#VUOMW9~;aMCIVct=1VtHAUEIOk>|grrw~<}5;zBcR_ZH^#uZB{iQp zi;$+@e$vYJf7YbC0Dl%C(R08W-Bd>i0ng7hDSHj`v;@#Q|H~Lr&CV_Yy#RGx58gp+ xm47>nfHI!DkINf5`H!+Jlg%QCh=|DV@(yn`&oq`vMgaf-002ovPDHLkV1oSx0>1zN literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Consumable/Drinks/milk.rsi/inhand-right.png b/Resources/Textures/Objects/Consumable/Drinks/milk.rsi/inhand-right.png new file mode 100644 index 0000000000000000000000000000000000000000..6dc179cb7360542a9e2c1225b96dc355d88fada5 GIT binary patch literal 569 zcmV-90>=G`P)Px$^GQTORCt{2+CPq?Fc<~!m(?C&Tq1ggZhQz_<^oISI{jQ?+DV7z0F=%JwoAGw zQ%6(@dk0SwShOUH6WdvK^?njkgdFtvFn`1cKtx1DL_|avyjTmo+rJ$nhMCJCW6Wsh zl~PXsow}<#VT`e9nnDNx05}{D0D#SAgR(3qSA^|$Yx6vJ&h^b@kPrf*cme?A-GAy z{-<}=7|eVH+>q~T0hY_<48W+Gr}dLl*EKNVd_+VQ6+ugBv&wyb-Aq12vd^ZUIFlGhuS^$XqS&rY7(sp$8&3qN)UahsZi^XEpmY>XX zfY#d1PrZ04C2*PzZ*O&wV3*qRp?OtPYyHoBH$X&0MD(XGM_Px$+(|@1RCt{2+A(h1KoAAcuOLV8*6C$;(jl~EPLPgn)2DWCxHCJ!2Vl9pKsu#c z(6yj)bcabH$q+>w2*|&Qfcyst5?FjvLvlrE1`rVu5fKrQkrwX2v;XVE7-Pl=NhuA! ze2kHjeZCKNCPhlgyRLIHb5!m*XU{qNdcCGz5oT883j4$e2_Yb?ZeS04+_*DbA zr~KJ~nFXdVf-%Nfsd1JQ<}3oe0Js=t2q7TG6*ZqZi%@3uyl7>ouPte% z=FcJ&dJbrDn(8n!JU%w0>=xn23c%UGROOC(Ho6G(0yIt2dk3*q{^2YFDj&O#>v@3q kLseB3n?(>25t0APZ|5!{4~4nu?*IS*07*qoM6N<$f`F{=5&!@I literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Consumable/Drinks/oatmilk.rsi/inhand-right.png b/Resources/Textures/Objects/Consumable/Drinks/oatmilk.rsi/inhand-right.png new file mode 100644 index 0000000000000000000000000000000000000000..a2ffe45a210ffbadeddae2a90b2281ea1e398dfe GIT binary patch literal 584 zcmV-O0=NB%P)Px%0!c(cRCt{2+C7fqKoAAs$7+v2$K*f;hrl5hSZ5us$S0nB(jl|<01n$1*o?_~ zog-%ycc=;Yku?V4pSG8g-X~c|mT5i8-3Cz&5D^g(5fRZH3svA<|96Z&jOtwEoU45J zD2i&m_uF&MX`bgQA_}YOy;twOCQ0&?Gs1h{DA$iV7a3z@{|H3d#2St?4EV4BmxrB*T-Vlqzi*dr0LBh_dxN)B17?V#j)_WRPbQ~+gn1dm|Na+d;82nzx$YH!RTUA<^IUJ;wKkk{ zr#%S^y}pJTyR3F^@Rp(|Fpp=D*Hi2K(me{P@3wrWC4d0}_T856UVu`-K4w69%;|I* zyxrBh0GHl-dEY=tQM7`{vGIn7rh?3X3u6qTXw`K{0DyBD%*zVEILLVSbemFED|g?m zvmoEq)>_?cHkG#g)BFyw*6RA)i(f96zPx%1W80eRCt{2+CNBJQ5XgAV-pZMHM~uqlL+n5fFM|`1jIm~9fAd+REkJIEUsBI zITbQED2gC%p%7@vkU}9@q?8H)Asrk_$vn3a4H%nS^D2t__*(*x>yuLMCAur(W@%ZWO_(SGrQz zAT8-b1OQMyY0x6C%V&GQ3`>@y%($MQ6(CuTA{{PZ{dbHN*%P!WkPa7+EJv}qvp2xX zguA}XjXz{YUP7G$>2QG=cXt%?S#JmU_2WBrwf1K-b6aRr;M+k7A9J4p_dvv)3jS;n z5fKp)5fKp)5$QLp%S-02T$NLAaR6XDHfUz2E!d#|J{_Ln&F(RM4ETBx*f&uf^Iwy< z`UcozWD=HfHbyA@2)yfYS9R+->`;Im>&YZ6Gxxp(0I&fpz5}rE*sOf{*VdarFMu5n z0Q>CJD}22Io%SP8FGm5Onri?NG@l-@;{iN*`>5^T)8BxxRBgZsjWp+F1i&GC1eaUj zYOaB!ucvLt&#3-7zxm-Do7iutUWnw;=H*Z%y)=+kFy=l9nk;s%QOthev`dj|UMKqMj}BGT{9 Y0Yr?uHvZ0V8vpPx${z*hZRCt{2**{1EQ5*;GuNeqU$qkX|(9qB#1Z{;71x5`~5JV6mf&?}?1ueBU zG#E(`4bc$@K|_I%OGG3HK@9~F4oQ#g5sf!`Aaa_-E15y`5SP36t^)BjcA~#DWVy<5ZwRFf-MpHk5mGBV& zpnIm(V!Xd2J!Ab1aC>?BIej%@gBPc>cQ4Fwrtn>jv80Qcuxz;k1xodJYX(Yb>w?2$wYnPW;r0VbV#Ui zMfwPRJ(f3n^lgOk;;bH2KrWQ5|sB{Gy|@-pAhI*-bMv*t`U*<+FgtH(icF> z4VcSSJ;>cd^M~FRrU-y@nbClbfo8{Nn5{M7ljB<8O=%VJ>`w#3z3(^XJLMIxu{EV` zFV94vy-mM9Efg_0Iw@_M<`1&^Yp;GZFMGdXx!A{@*~Hk0eqUw-h=_=Y$U(2h)xQ0o S!G(4J0000Px%5lKWrRCt{2+OcaBaTvz&Z&ad_V<{rBP|&GkNs(d+!ObP$bb=6vbVzh?690hG zS>mA3x@8Hp6ilaPNRiUePIXE_5<{&eq!hA53+>OLIi>1i^8VD)=QCZFC&`n%cL(o* zh=_=Yh=>d(n@PKW{Tcq$1&fewyY7-f&3zf4XEIeeb0rKc8Pr_2U3cAf-FSbor*#PIS;hX6Z_Q)`0P?8@S2i9o^l{cI@~&7z*yZ1>3HE$)9OGRh#Jc8*Oi{GrV z?>#xBT)5?BUDj!B^LcZRcZ*Yf=bJ4?LJwaZa&_ormzR&nfECmHWKeT&Uqpch5QXU& zcd593OE52B<~YIi_(gKnCb?=8*tUKP*uB%shE8j+eDia_M&m22hQGca;g`?HW6T^U z2FfxoAeh^a>>M0O0Fz0r^zp z`|;YfEy@Mk{9LsOmw{mhzL1$0kj&vo|m2V2~ZM}NGYSa+ji6MeT}ejni5&v%#$ lOUnRQK93+GA|i4wd;^!m$JO%K&6xlI002ovPDHLkV1hTz7XknP literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Consumable/Drinks/pineapplejuice.rsi/inhand-right.png b/Resources/Textures/Objects/Consumable/Drinks/pineapplejuice.rsi/inhand-right.png new file mode 100644 index 0000000000000000000000000000000000000000..60d661984a2c4c0e7f47a1debc8ea97cf240a151 GIT binary patch literal 657 zcmV;C0&e|@P)Px%OG!jQRCt{2*|BRAQ5*;GZ&X^l6oeAeBBx#2f4~xuP?6iTASZT-AXKmpt&3A} z6{VAdoP(8Crz`Wxr7#}m%R6EDBsVNJ1#HZ z_v5`^4jw>6L_|bHM8}&L9}_2?LA5hM9;#M~!i>9OXJ`&FD}CyU@K0vk71c^nR4YZX zzPcpZxd_!tv8in5f<8Doe;EL!hM7{rd!F?wgMNx z_xRC6JxNYTpaM9F!BAIEe`sfD4pSd4=uahS^qCvDPc^*)PMg3@@SwYTDE-*Ni;Z{4 z>dna${N@_bTHsh{HlX-dn{d`RZYF)J;4uSC!t9)P#F1}8BnHQrHX+!Y^Rb{x9b z)zh!^Hv*pw9Tl_E;`1A$cI5$92S(ru)kQ#Q7?b&L0D$fCn$n>mQvd+C_j(WA;Q;`E z9W?-aQI)ICpS&G4u(`00q~h_VdcgDF*J~4R1l7Tg8bAgpc)QBSmMTEO+XXVH7eNPq z@|#=xh|m5~yS-$#Kz9CGC=1~0(@t?Qa~AfnfssW`Tc8s_1hPH*ucUea08B@|AAHCI zfZ8VY6NMC$zkudBe3gM@l{00000NkvXXu0mjfbnquM literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Consumable/Drinks/pineapplejuice.rsi/meta.json b/Resources/Textures/Objects/Consumable/Drinks/pineapplejuice.rsi/meta.json index 31a3eae2e69..998efd88d20 100644 --- a/Resources/Textures/Objects/Consumable/Drinks/pineapplejuice.rsi/meta.json +++ b/Resources/Textures/Objects/Consumable/Drinks/pineapplejuice.rsi/meta.json @@ -5,13 +5,21 @@ "y": 32 }, "license": "CC-BY-SA-3.0", - "copyright": "GrownSamoyedDog on Github. A variant of orangejuice carton from: https://github.com/discordia-space/CEV-Eris/raw/f7aa28fd4b4d0386c3393d829681ebca526f1d2d/icons/obj/drinks.dmi", + "copyright": "GrownSamoyedDog on Github. A variant of orangejuice carton from: https://github.com/discordia-space/CEV-Eris/raw/f7aa28fd4b4d0386c3393d829681ebca526f1d2d/icons/obj/drinks.dmi. Inhands by Tiniest Shark (Github)", "states": [ { "name": "icon" }, { "name": "icon_open" + }, + { + "name": "inhand-right", + "directions": 4 + }, + { + "name": "inhand-left", + "directions": 4 } ] } diff --git a/Resources/Textures/Objects/Consumable/Drinks/purple_can.rsi/inhand-left.png b/Resources/Textures/Objects/Consumable/Drinks/purple_can.rsi/inhand-left.png index 69b23480056d821f34ab4c73015336a6539b2823..079908d808767aeeda7f981d2a336570ef682307 100644 GIT binary patch delta 344 zcmV-e0jK_k0`mfpB!2;OQb$4nuFf3k0003kNklJDtS`}}uOL2! zZf^Ajqz_O~aP5*c;M%2l$3_?{yEHFcG)SbYh*9tOsy@eQcSNBn<~6_fmd1Uq8U? zrG|r%lcd-BO_o2vR~G;P0000000018MbpHkdEquy?PX1F&3rjJAJ5b*`|522ttOdu zzGZcfU_JnStx>Y$u=J5`S=}R;4`97p1in_;zr|tM`EJ155Ad-n|4Y|<1TO=4e7M!s q*`<&44;DlIxBGVP1^@s6(9I{a=YN8IVo?eJ0000G zs-m-HM|y+y>3?(gvoL_bhxAFtX1>AaExjj2Wp{O~|LtuOpF4M>mG>?CbK;wyFA$u# z?DA6YptXIEcJ~@j^SWHHNAp=y?a~?EQhnx2FU^Vce8%}=dh(j=`<9dauYdO2n^t|@ zig8lN^cj~~cY`ee5eMdP`1fet*^Sl-e`VulC(A!vuCFk4*+YX2ndANHKbPwt*w~+N ipFcvnni;70#~Imkg|=)ZFU41Y^m@AbxvXHoatN<000000DujePFJ~pp!(yfYC2uD?>yVMexQ}_Ab(8Jq&||=!je@lBkf8n za=0X<7M521Vc5b>VNIBN4u87&RQYuAUys0TX&nCutPSQv?LbK@+c~*D zb3#8<=n*JouhiS?^G@NCP%Bi$3zqwi0RR9100000003>KSMyrC!QYxrSM|qJ<@$lq zKLe&$^N}y0U3Y28s+W<}!jegS6mP0OI*pmJ#cb&1=q7{tP~N?h_|j}~ae6Lyqf5Qt z4)}^5ESk(hUFr c06;u`04F1L=#1DXy#N3J07*qoM6N<$f)D_=iU0rr delta 240 zcmbQq+`}|MrT(&~i(^Q|oVT|Q@-it3v_5SAm?3|!aP>{5IkToQt#R9N`}n<&3yvL` z(I64t`M+Fl68o84Hzo!U_+h**#K1TB+dc0|L0(3iAI;3qJh@9xbjHlt-;V2e8t$9> zadFawExYgBbh_)lHmggAC(rs^k#m;+b_R2m+~bjAZLjon%Q6p~eYqj9Z=dc>r%xAO zPche@yYdx-XV?CF|HJn_VFB9%BE+tlyndgVzF>*vkJ@wvts`~v3#zRCte8Hxanh^5 o4e3=kBsDVMF?2@S0M%BNu~pmdKI;Vst08-X%!vFvP diff --git a/Resources/Textures/Objects/Consumable/Drinks/purple_can.rsi/meta.json b/Resources/Textures/Objects/Consumable/Drinks/purple_can.rsi/meta.json index 1bebea0aa9c..087c100ebfa 100644 --- a/Resources/Textures/Objects/Consumable/Drinks/purple_can.rsi/meta.json +++ b/Resources/Textures/Objects/Consumable/Drinks/purple_can.rsi/meta.json @@ -1,53 +1,25 @@ { - "version": 1, - "size": { - "x": 32, - "y": 32 - }, - "license": "CC-BY-SA-3.0", - "copyright": "https://github.com/discordia-space/CEV-Eris/raw/9c980cb9bc84d07b1c210c5447798af525185f80/icons/obj/food.dmi", - "states": [ - { - "name": "icon" + "version": 1, + "size": { + "x": 32, + "y": 32 }, - { - "name": "icon_open" - }, - { - "name": "inhand-right", - "directions": 4, - "delays": [ - [ - 1 - ], - [ - 1 - ], - [ - 1 - ], - [ - 1 - ] - ] - }, - { - "name": "inhand-left", - "directions": 4, - "delays": [ - [ - 1 - ], - [ - 1 - ], - [ - 1 - ], - [ - 1 - ] - ] - } - ] + "license": "CC-BY-SA-3.0", + "copyright": "https://github.com/discordia-space/CEV-Eris/raw/9c980cb9bc84d07b1c210c5447798af525185f80/icons/obj/food.dmi. Inhands by Tiniest Shark (Github)", + "states": [ + { + "name": "icon" + }, + { + "name": "icon_open" + }, + { + "name": "inhand-right", + "directions": 4 + }, + { + "name": "inhand-left", + "directions": 4 + } + ] } diff --git a/Resources/Textures/Objects/Consumable/Drinks/pwrgame.rsi/inhand-left.png b/Resources/Textures/Objects/Consumable/Drinks/pwrgame.rsi/inhand-left.png index 2ed4941501dd7478a5585b42d40979dae1e195a7..eb1fade9ba0b2bd2ddd9a36b40efd3ecba917ac5 100644 GIT binary patch delta 380 zcmV-?0fYXZ0*nKY8Gi-<0063Kaozv`00DDSM?wIu&K&6g00BlxL_t(|obB2%OG057 zhT+Ew+}g#ZaA_zx7|qh2KOx*)T=X|Iv=j&}4mPw2XH`y+p&=2tG>A9}4&r=>2AB96 zL?PPp{lMV9e!xAP^KI`V0RR91008_^tr5D(EOt?E;A)M~S%3GV-oU&mNqbhI=j$gO zzaMGzF;=@DT4mQp_ha*>B<)zna#v~PD}iNl%~#j#1xQjd&g$%RmauHDq!vXVS=$%z zb{kpdBuRx#$#u#@*Q{5~+mdAVw+fk(lcdkDxw_NV)^`B_0000000026sahj+QE%WT zv)Id-eCwSbTy?mc%Lmsf58djl<%888!Sp)3lCK2H9Hym5AN3`xJ%Z_VSdzNaRwA`1 zDj8?3)4y2k5xl&BX1%IlKPTzVM}Ey>kKpA4wELl6c3*v@e^~AjPBv=%+j~2^0RR91 aY~~yN;d|9T7ECPw0000Aiv=M5WsM+d2b|8jI+QavY3H^ z?=T269?xHq0u-$Aba4!caDRL4bUoJr0}hvqD$hRtufM~kmo>*pb@ib;Q#~wO*6F-9 zU}7-=B9cqm4(S9IGT;W!}Z+T(r0-!?}I6PhbT-G@yGywob C2y4Os diff --git a/Resources/Textures/Objects/Consumable/Drinks/pwrgame.rsi/inhand-right.png b/Resources/Textures/Objects/Consumable/Drinks/pwrgame.rsi/inhand-right.png index cb290981140d101f18398d8f9398583a8291e7b4..52b666dad12eb536bb787fe94096573f75c75488 100644 GIT binary patch delta 423 zcmZ3?w2gU!WIY=L1H-D!!h1l9u{g-xiDBJ2nU_Fzfv1aONX4ADH}`upCCadUI9{jV zc;!-%c#6g~fwCBrE{pWV$V!h=)ITM zv?Zo+`S(?aKhNAR!~eeaet9K>5)_EL9u_&_h2*NI zxohsOd-U%qqj-4Q`G;%^r`CTmwSQI`a9Y#jWtRR-Hm}o~pX~1K40E-bB>7VN!?ztT zwC6wPWoWqkxb}V{+uFbtj|!H*`RQI+#mtaky-VHg??2`P6GIQZKK^+_vVb50Ow8X@ zzq<1L)rjqj61%3}5PG!HLTegtt+_Op*)8*%S8L9*7nB7Y3p46IIaBkBj`fX@*e!FK zZeDwyAVi2+;=N9x zQKt8=vprCk3E)yYE1wc}uXb&S)g-~okGUBdyc9mWoKp610Rold;^ogv0{owS5(CBs NgQu&X%Q~loCIH|Xxt9O{ delta 275 zcmdnSyqIZ%WIZzj1H;_yjcNS%G|s0G|-o znKNgeK7D#m_GMq?w0G~`rKhJqIcflu{CT-T4@hy81o;L3hX96q&3hw(Vw?pYk;M!Q ze1}1p@p%4<6rf;(r;B4qg!|iT*7ZUS1{|&zTmF38pPb4jvXR5E_vmg>*5XGI6OW}a zFcbih_=KXqr2ebbN?Jx|wOowm&J53>*?uyDcmPiyR=>CGFlJjijOB~sP_n`vCI0j2VQ`6M!b5zyXK;f*BIK0aq{@(n#5WDR7<<{vqN$!l2zdq^}?BTfKINUXLV6l8(&> XI6q6qDXR!p00000NkvXXu0mjfd!UaK delta 260 zcmcc0G?i(BWIZzj1H;_yjcNS%G|s0G|+7 zAtfi*%pN~R)(OnaE4jFe85mrFQVa|>7rqt&DUOmLzu^B6z;Lg5ZzNERv%n(~sE%70 zgc%uT&5-~K7J0fjhD5l(y=GaK~ zkA?;g#=|_Z(etujJheGDM@sR*uHqLh^%I=cInKyj`=HCTf`y|4g8s2jx!cHk>fHgR s)ba=Q6AnxB)@)}H)8G^k$YpxRAHtSj=WjGO8fZO(r>mdKI;Vst0L9Z;g#Z8m diff --git a/Resources/Textures/Objects/Consumable/Drinks/robustnukie.rsi/inhand-right.png b/Resources/Textures/Objects/Consumable/Drinks/robustnukie.rsi/inhand-right.png index 39481d24ee548685e4c6c1dbb5bed2b3fbaa65b4..6d651c750d1e0ee5663636b7ee4c985a58090dbb 100644 GIT binary patch delta 318 zcmV-E0m1&40?q=E8Gi-<0063Kaozv`00DDSM?wIu&K&6g009U|L_t(|obB2%YJ*@H z#__+Ukln3I57ZkJ9Fl8zfR4ojICLmv@BpD(y5Gkskwlp;kFKWpIsn;hiz z;q!HR1WA%4Ns^=NS%G|s0G|+7 zAtfi*%$}88Toag?{TNwY85oLzQVa~|1WzsmQXC~ge!>4CfZ<;A-bkPrXMsl~P!YE< z2s1Lwnj--eEb(-442f`mdu?MqSAzkM>qR%|-~a1%_?y~96cxJ<@9vg;mHFbz##w?2 z4IBav{01(UX50|pYcKnJOQ>e~s#UsPmJ4hT`Y_jB`Es<@wShs&fdQ!UA6tkVXV{JS xdX*#0UpKjKl`n?+x6(pFiNcySLw6c|Q>V00000fIn)s zJ35)Iv^N-Pv)xhaes3@|Z<>n2K)bb~mJ327j<;8B3ouq*SR}Cck-g z%|v0Km#3lIG4(nDX^*I-C=9f8xGztWg-hS`6X?fl@%aAx@mk{L#ySfC000000001h zM4Ii6_69?p%vLUI@|~B@Wwcz#YPVL@C=A>NV09nCWjR`^)Fpj%Eb?&Xkrxq>`>S&~ zc)6CF$Ja!ALs--0sEEjTI#2a)8!~EDtI)f3Y` zl(QyiULK$9_5NbIK@%10+FBM1R5uvC)%S*?YH$L`_B*qIg1;vqOduGhF%6nSY2&D> zJt_`BtuflK37`{I(=!2TjnRHh0G+6so(WKEjP`2+=tR}@On_Qrv|kfIC#t4r0@NC# z{h9zeQ8hgipkUS*?big*iK^+D0JX+wztRK{w*%4v5cdeu0TA~H(gAb?#M~pu2M~LY zARPelA~*mdMP&^Wpxhqe-2@ORDr=Yk<@N~g$rJDc8|O|z(d}&P00000NkvXXu0mjf F006brolyV) diff --git a/Resources/Textures/Objects/Consumable/Drinks/rootbeer.rsi/inhand-right.png b/Resources/Textures/Objects/Consumable/Drinks/rootbeer.rsi/inhand-right.png index 8f299e007dac5bba7cfc0408f7ab95c92b10b6a8..458185df300c9e27036230e0225976822b6fb8de 100644 GIT binary patch delta 344 zcmV-e0jK_?1AqgNF@HKqL_t(|obA~!Ps30YhVe5}42lrM3}OQeQw{iLuBHi!1Ut-< z1v52I2o;Dr1pNjTh>77gBnt_csiiC=6%)%+33dJ!-21vC0ssI2 z006Lr<9f;uLe(1#mE(G9-Fg1w2Vwg8485wl?YcTYJy5kuxqr|P&~4Xa<=cvSP_t|? z8=aLx*b?1pbb1MV*LY#Ojh;(U}Ab*Q0N)p-7sC|Dkz$KNswf7cxY0000000000 z0I?NzHSf5d>J5g<55i1?Wxbk@yc=BfczZ3!d)snl9LZDvE8SEJG|LwA@J+_|H|ft# za@lNjL_0YX=}}*%muQKPho-#xGZ{^$rL5fPD>_s`Vp2><{9WakfNDR4MusQ>%`0000)kQBYA+!WQ9_1tiQxk?c?F*pi-}k^&bY^Iws9{Q&@AK;{H60+|bdmmo#}Bak@( zj6miB;46R;zzAecfE|Iwdf%+7vc+_)ui<>yuzUJq8k4K2n15Y0X{e~v{T-gKk7!RH z5XPfHvz!jw(A)YU%2V_Z9eBCk8ZQRS%bBP7@$Gfats(?xjP!U!2k`)mSeyG%iYn)4F+gXwj2WnSniHS zZZJTDvgH^sz;$wWG;)Ih8k8-^fB}}fqmdg7(4cHNMw9_D|HE5_5CwpW@p5N?10M~5 z4)$r zB0OAEHPod4Lxb;Uzb`!Z+}&~~0RR91001nh)9tzOBz55+c7L62&sq1wL2TZXq#di! z^W%#yo)Yzoc@2}uD*LVf@MhkWq%G@Up_ExCy>`t6m8MH;Z7<7IlG3xQ&E5jO1eKD* W4Q@xQnlMHH0000@pPrt6;J^W(%nyS@Al>XGL4Lvi!GJ-^o7oL0#981GSgBT>0vmux z;6l~;>>W1FrxhPvww?Gen1iwSr$F@Oc7eJ^{*CYTB|e;^ diff --git a/Resources/Textures/Objects/Consumable/Drinks/shamblersjuice.rsi/inhand-right.png b/Resources/Textures/Objects/Consumable/Drinks/shamblersjuice.rsi/inhand-right.png index ace1850674ab1d548b98959a83fb2a5622fdb9b2..b144fcf5235f00c8c4e035be6e8327174c07cfb6 100644 GIT binary patch delta 380 zcmV-?0fYXW0*nKY8Gi-<0063Kaozv`00DDSM?wIu&K&6g00BlxL_t(|obB47O9NpX z#_?w&D~1WP4Vz$DkcFiMlQ6JZ9hm$BL@ZX51`iR_uqc)d1k1tF2Br&QSh=t^OdB4H z!gwvFG3DNQ@9o0(lV9$Axcj|Vo>u|@00000n8Rzf%wQN9zkeGTuh}xo&hwYSFtW)S(aT~hRUVtVc~rOIjo z&bBt)B}vfn!L_ND>#_a?u_i#0YL$k``uUfn{Yj{=(P-H*00000000000AMY%)x6hi z8NVBt!7y?ftaVmtm}vLH*z|oiVt0eHp1gbQZ13rE+);ZHCYx%GLTM^F*v6_Io|Wc( zf%D#ng1(pk7D-Z}00000 a_r3u-`fHFmrrucq0000H`^!v`kW3Cvy+AJ}C-=rXYgFfw&8Fn%#l zNc7y$_W7ggK`DJ6ea>qfIr|m%s6?!;|JKF8xP|je9fN^jd|s3Go;sjQ7(8A5SY6gR HB{Ts5Y4u=y diff --git a/Resources/Textures/Objects/Consumable/Drinks/shamblersjuice.rsi/meta.json b/Resources/Textures/Objects/Consumable/Drinks/shamblersjuice.rsi/meta.json index d269458e27a..db298f17e6e 100644 --- a/Resources/Textures/Objects/Consumable/Drinks/shamblersjuice.rsi/meta.json +++ b/Resources/Textures/Objects/Consumable/Drinks/shamblersjuice.rsi/meta.json @@ -1,53 +1,25 @@ { - "version": 1, - "size": { - "x": 32, - "y": 32 - }, - "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/70ccd0f2305286a1312425a85365881fac16fcac. Modified by potato1234x (github) for SS14", - "states": [ - { - "name": "icon" + "version": 1, + "size": { + "x": 32, + "y": 32 }, - { - "name": "icon_open" - }, - { - "name": "inhand-right", - "directions": 4, - "delays": [ - [ - 1 - ], - [ - 1 - ], - [ - 1 - ], - [ - 1 - ] - ] - }, - { - "name": "inhand-left", - "directions": 4, - "delays": [ - [ - 1 - ], - [ - 1 - ], - [ - 1 - ], - [ - 1 - ] - ] - } - ] + "license": "CC-BY-SA-3.0", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/70ccd0f2305286a1312425a85365881fac16fcac. Modified by potato1234x (github) for SS14. Inhands by Tiniest Shark (Github)", + "states": [ + { + "name": "icon" + }, + { + "name": "icon_open" + }, + { + "name": "inhand-right", + "directions": 4 + }, + { + "name": "inhand-left", + "directions": 4 + } + ] } diff --git a/Resources/Textures/Objects/Consumable/Drinks/sodawater.rsi/inhand-left.png b/Resources/Textures/Objects/Consumable/Drinks/sodawater.rsi/inhand-left.png index 2e1c5e06a093ca340256a08578c210e29c6e86c0..3ccb23f298e9b3083f557ba2cd39a61b7808142d 100644 GIT binary patch delta 385 zcmaFLIEQ(HNGZx^prw85kJDJY5_^D(1YsW$5ixDAM-vc$VNH-zMuDN{_@d zva+-L=QOiz5A$SEXID2DKYVuKYrRFWF~!9lYV5A96CSYfnf;x;D=>MkwB!5t%r=J~ z<~(ocfPfR`rcwK5>p5MQ?u}ji)cSQ@zKK~r)0@cFL-md`-(Hl}iJw{WE9@r!>1DOT zHw@RRdOr~Lojh^It~6-|gZ=xSY_ax z_G4>9xA6I`%~M~B0hu?el4pttBEUrX>@77wi|>{Q9xGDYo>nc(rZ!hQ!tAEqbPo2^ zs@F9~UdbQ)VkYsiYl00!Q^Y5Uf66oX7s##=dVajryuPL}_Vq9ElR_2#2jry~7=DV( z+-&lFYo*T5azmvv4FO#oj0s%8KH delta 201 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 literal 4565 zcmeHLeQ*jWhaS@%Gxz%004O=V~8#XSem+pT&flSLHvfFm{jpW6l2d-^jia z7F>765AJ;PTFuR^Rzquba{7_qTV>0)n_J^ce|)<6t=9&V&g>k%%Ael(YD;zf$eE{n z$K2`prhw(IR}W~DdOX>E*o&VI_VVmQweII0_&P8+=W1G1 zL2>u`vf2J!trT5+DR%L>XvN{jnm&nHH-sdw`IyUXxU@edaZCH{CDr-M79XEmQ|9qr zscue1ihg+ZReebbRQ-FUH=X;TToE@RICbCA|nT|4APDtI+ZU&3fGm zhV$BiBINc#;~|J4E#za^G9aRM;N(3<`Ec6_Im&ZJd4a})TYQN$B@YMdcNLjpGt88qZ}dHi(9C=c_}@Lpf zBEpdc{H(zHMBeK`B~Hfftq_fJIqXNr@^kwvmT`KIe^dpihcd+Yl!O9Ty4}jj5q{AW zfFz>{{c42Y2A8Qa5BR+m0t-w5;1QE2Q*i8fystuVh0EbsC2#>Zg!wv_QW0o*@E4LjD(|B4wjdP+-DS{9>NJAtVw%8uzdEdlMt=~=Cw;21qSmEG@k zh(SgG=}xF4)Cw9jtQGq3=v1Xl#Rp4)G!IZR3@0&yu#p5!k~FE8EAM`Jte#b|b`D?^ zp@9Yk4ieLo1i%QjonUZEjYG>%P4|B+Z`={%UN8wv!wEgj%EF=dhMK)~PER()<+~dnF@*~K+h0-|-X=+{!8)HPX z#T4`X>;zfTZ`FVUY&{(-LCvPsS%))9YW@wAZC;Q7 diff --git a/Resources/Textures/Objects/Consumable/Drinks/sol_dry.rsi/meta.json b/Resources/Textures/Objects/Consumable/Drinks/sol_dry.rsi/meta.json index 8bc80009c58..8c03f722571 100644 --- a/Resources/Textures/Objects/Consumable/Drinks/sol_dry.rsi/meta.json +++ b/Resources/Textures/Objects/Consumable/Drinks/sol_dry.rsi/meta.json @@ -1,53 +1,25 @@ { - "version": 1, - "size": { - "x": 32, - "y": 32 - }, - "license": "CC-BY-SA-3.0", - "copyright": "Modified from https://github.com/discordia-space/CEV-Eris/raw/9c980cb9bc84d07b1c210c5447798af525185f80/icons/obj/food.dmi, Sol Dry from /tg/.", - "states": [ - { - "name": "icon" + "version": 1, + "size": { + "x": 32, + "y": 32 }, - { - "name": "icon_open" - }, - { - "name": "inhand-right", - "directions": 4, - "delays": [ - [ - 1 - ], - [ - 1 - ], - [ - 1 - ], - [ - 1 - ] - ] - }, - { - "name": "inhand-left", - "directions": 4, - "delays": [ - [ - 1 - ], - [ - 1 - ], - [ - 1 - ], - [ - 1 - ] - ] - } - ] + "license": "CC-BY-SA-3.0", + "copyright": "Modified from https://github.com/discordia-space/CEV-Eris/raw/9c980cb9bc84d07b1c210c5447798af525185f80/icons/obj/food.dmi, Sol Dry from /tg/. Inhands by Tiniest Shark (Github)", + "states": [ + { + "name": "icon" + }, + { + "name": "icon_open" + }, + { + "name": "inhand-right", + "directions": 4 + }, + { + "name": "inhand-left", + "directions": 4 + } + ] } diff --git a/Resources/Textures/Objects/Consumable/Drinks/soymilk.rsi/inhand-left.png b/Resources/Textures/Objects/Consumable/Drinks/soymilk.rsi/inhand-left.png new file mode 100644 index 0000000000000000000000000000000000000000..16ddaabceaa12fa72a0039d27561f5467bae51e5 GIT binary patch literal 443 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=jKx9jP7LeL$-D%zOFdm2Ln`LH zy|vKqaDW8s1LLOIipi(%7#P1@=W>49KIVMG*455mbt~F`y*jl{^h!yv?{S%5i>~n$ z6x1D>^m*s3$+PYEW?uTwpacQ-)3)4G{(eu({s~*Yv-p0n&E8*;wo8vUnKoF&Gd>c3~s`ene={@kL^_Zze4>)K095&d;j{q18Sr`?kc zKd{cN?Dj04hMgS`*B(FrHfwY3KhD+t2}TWevu3{i%)Z2qsg~i~&cN%XZ*JsA)UssR zKR5!^B?OOzY+id literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Consumable/Drinks/soymilk.rsi/inhand-right.png b/Resources/Textures/Objects/Consumable/Drinks/soymilk.rsi/inhand-right.png new file mode 100644 index 0000000000000000000000000000000000000000..1e1c7d31b58ac382d2cf74af05b837cd12290c28 GIT binary patch literal 477 zcmV<30V4j1P)Px$mq|oHRCt{2+OclJFcbyQ8`O=ZqRmPcmO#eNtij)tiH#rNd%QCic`|tt4}ge>h=_=Y=%U5m7_5xBcMjJAn?+K}t;9+7ncFpPnZcdudY!MXrCuAtM?)MUYY&QAfZqh8k?pX7+Exems6gnx+u_Su>FI$>V6gQvm=p!G^Ju zFqilo&37(RjMm!xd|5d)-!>h}sN(x|}(I<6q6J9nv0tk-K4MRDvrE1p=5Jur&A(vQPV{?E6 z)TEd1<0Gh3qZ*hes=Fm|gOjEmSRQUz-^MDV@?JcO97W+VUr0001h2Q^)9 z$J1m(8m;Mi^X?C6bZ@!}b+8!C)XG%J|6|(>O-WClvHku<+kf}cGdauEefEqM=^(wS z@NBL|sDqhB_c5KjYj^_X=Bym=zucUqop%)g0000000000%QRhYLmKUPnzF3P|G!G6 zRu-dKs6)0Nkoz9tag}WQRhn7M`UAY~5nPv}lBAFC^>~pE?&+U$-Xkp2>Q5#>pUXGV z{u3ZcyW2`TGbwwGiyN!G=D1JSWxCAI4gdfE_`NGVDRXC{&@}P@0000_m&B442UrQxWE3biF!b;@6olb%lmnz)Ut@EC z6mHVPeK>+UH@<;GO%o~92#$c10^!y-m^4wUfN<Hig2n&<002ov JPDHLkV1me_kd6QV delta 191 zcmcb_benO4O8p{F7srr_Id5+r6l^x&ak;3fy6}sO?>o+n%;E>LByX$mWqi6H`E8Bq zK2ISA5I8V@W)|yGk@KH*Ja2uEJ-sR9d`xOg*y%Ehu%FiAeS)ti2Fp#nT-5UZZbQNM z$MS1i!#tjD+y6gcnR0sjGd7#;Ypu_VZhFE3HVQ;o)V;Z~#rX2M0~VfTY{$Gd7zbRo pk*ilfdd}gfJ8yy*KLbO`PR%z3J-k60JYD@<);T3K0RU9PQY!!e diff --git a/Resources/Textures/Objects/Consumable/Drinks/space-up.rsi/meta.json b/Resources/Textures/Objects/Consumable/Drinks/space-up.rsi/meta.json index 1bebea0aa9c..087c100ebfa 100644 --- a/Resources/Textures/Objects/Consumable/Drinks/space-up.rsi/meta.json +++ b/Resources/Textures/Objects/Consumable/Drinks/space-up.rsi/meta.json @@ -1,53 +1,25 @@ { - "version": 1, - "size": { - "x": 32, - "y": 32 - }, - "license": "CC-BY-SA-3.0", - "copyright": "https://github.com/discordia-space/CEV-Eris/raw/9c980cb9bc84d07b1c210c5447798af525185f80/icons/obj/food.dmi", - "states": [ - { - "name": "icon" + "version": 1, + "size": { + "x": 32, + "y": 32 }, - { - "name": "icon_open" - }, - { - "name": "inhand-right", - "directions": 4, - "delays": [ - [ - 1 - ], - [ - 1 - ], - [ - 1 - ], - [ - 1 - ] - ] - }, - { - "name": "inhand-left", - "directions": 4, - "delays": [ - [ - 1 - ], - [ - 1 - ], - [ - 1 - ], - [ - 1 - ] - ] - } - ] + "license": "CC-BY-SA-3.0", + "copyright": "https://github.com/discordia-space/CEV-Eris/raw/9c980cb9bc84d07b1c210c5447798af525185f80/icons/obj/food.dmi. Inhands by Tiniest Shark (Github)", + "states": [ + { + "name": "icon" + }, + { + "name": "icon_open" + }, + { + "name": "inhand-right", + "directions": 4 + }, + { + "name": "inhand-left", + "directions": 4 + } + ] } diff --git a/Resources/Textures/Objects/Consumable/Drinks/space_mountain_wind.rsi/inhand-left.png b/Resources/Textures/Objects/Consumable/Drinks/space_mountain_wind.rsi/inhand-left.png index d1cd7229ee3f67585cc1416398f5f40da62dc367..e42490a3dd6ab9575252e51d2c86719aae5da17c 100644 GIT binary patch delta 383 zcmV-_0f7Gb0h$AlB!2;OQb$4nuFf3k00040Nkl*qo=fyYYG74&7I|b0;VLKl?dK{)uU0u=HIbA|fIpA|fIpA|fJ+s^Znf4?-D^CPrrRrMG^# zC0DH*abFK)Hh629p!FX?bsnFo^?hXQs)_VmpY)G#uSyZ5KS*PV&R diff --git a/Resources/Textures/Objects/Consumable/Drinks/space_mountain_wind.rsi/inhand-right.png b/Resources/Textures/Objects/Consumable/Drinks/space_mountain_wind.rsi/inhand-right.png index 5843404b9d870746557a7f3f9d87ab72e400b27a..a777932f4c5ac83235331f9a39eb33a2723a818d 100644 GIT binary patch delta 366 zcmV-!0g?Xu0f_^UB!2;OQb$4nuFf3k0003)Nkl9(Y-kar)kcQ~ z*G6{-L1+q^T-^Ks4MhzNZLZgZu*Km{(r|~Ogs8x#z)5tx0000000000VA{e~^R*iQ7khe0 zKI!UxM~8Puvu8~;#bz}hc>$8t?0I(k_;1zjuI`VYt(2XsQ7=x~gT$mgP<8V)mVfEA zDpLM&=5r%2AWqlkZ@L_xSegB=CzUE?O>%urlH{ND=;8qY0I)>90K1NYKB{%A(EtDd M07*qoM6N<$f?t8Gv;Y7A delta 223 zcmeBV{>?Z+rT&noi(^Q|oVT|Q@-`a?xLmxc;l3(yB`4PcK5>VvO)J`dKa+Faav;fb!MdGDB-dA*`1%?#cDXKz`-yR?_f@5i5tm^gL!p4UEC`6sB@emnMa zQdkia!~!6B-D-<{{z~J5Sz%Vps$XwE6kl7y=C$fKToCs!c7e=2elOM*l{=sjfsjT9n$0=++hU9+oBS*gg!43 z{62rcm-n7~x90_jh=_=Yh=_=$WZ8~xcl%noRc+ahmhLOJDu3PtfCZ`0@a__^ryM>$ z-=OMIsqDnk&5n2z0OllP!Ig)HT2eAOVX7-8pGxRfZQsZ>1pxK9Zlo=G1LDQHWDXb& zHaJ<;KuNp}=>e4e5T_f<;(w~_hfvwHbe4#Sh=_=Yh=_=Yh=^ul*^X9jRkyo+BWrSL zV(am-m+K2`C4U3N<`*&aL+Sj4WjlIzdlSu86OGm@&W`pX({#iKfYB=Z;PxIkTr-ge z1m7cwE=K{N;B_J^xpxeD8R_&767La=+yJ12c=6aw`kO&7gY!yds;fU{WB@9g#&dM0 zbN!0Mdj#{RG$fx&XaMj7je^(tx8FfTL_|b?P>00009=^3t)O%7`X2j!N z4`WtWzdx7p{odQC;9H4zy7pQ>op>*IyU@LTF6^aq4^3Vf>jW_nNIsDH_kHzGUcuXq w&hiS`{RI*;t6Q8qZYUpl&s^7g7o^PY6N5yj$0l~3Jz!^ey85}Sb4q9e0MdU~_5c6? diff --git a/Resources/Textures/Objects/Consumable/Drinks/starkist.rsi/inhand-right.png b/Resources/Textures/Objects/Consumable/Drinks/starkist.rsi/inhand-right.png index be9651c15539063808b646882ba616c1ce398ad0..5aaa431daddb943af1fbc7e2fac2b466e4ea4453 100644 GIT binary patch delta 400 zcmV;B0dM~70jdL#B!2;OQb$4nuFf3k0004GNklGXaB6jEh~t6=<8Ucx6^B$1YjO}2BQTzZt09rNJMXy) z-mm$~!-wbB@(}?500000n4(awsAjjX%)19wC|A^P=lMyq+kbbJZ{Eq!`07}qk9m1} ze-X10@fpr$ zB$gzZNXqrit$*zAZHN4gX475Gd)|Q7<&mtX1`?fHka1_|Z>kA{oF&HArbzhN_qAQN z!`~V8l-@r6)2Nq`)%>dzt+wyC%<~2mt#;_JRtt@K8GjQ^5i2#cRr8*oz!y85UOFr9 unXXhe9aoDHdx-<1rR5U@0002=_yAr$cw9bZKiL2P00{s|MNUMnLSTXjzPpnE delta 208 zcmZ3*{DyIYO8sU}7srr_Id5+n3N{}7Y?6uZs_i_75DvU!=YuU~3hutLg;xqa0_z diff --git a/Resources/Textures/Objects/Consumable/Drinks/starkist.rsi/meta.json b/Resources/Textures/Objects/Consumable/Drinks/starkist.rsi/meta.json index 1bebea0aa9c..087c100ebfa 100644 --- a/Resources/Textures/Objects/Consumable/Drinks/starkist.rsi/meta.json +++ b/Resources/Textures/Objects/Consumable/Drinks/starkist.rsi/meta.json @@ -1,53 +1,25 @@ { - "version": 1, - "size": { - "x": 32, - "y": 32 - }, - "license": "CC-BY-SA-3.0", - "copyright": "https://github.com/discordia-space/CEV-Eris/raw/9c980cb9bc84d07b1c210c5447798af525185f80/icons/obj/food.dmi", - "states": [ - { - "name": "icon" + "version": 1, + "size": { + "x": 32, + "y": 32 }, - { - "name": "icon_open" - }, - { - "name": "inhand-right", - "directions": 4, - "delays": [ - [ - 1 - ], - [ - 1 - ], - [ - 1 - ], - [ - 1 - ] - ] - }, - { - "name": "inhand-left", - "directions": 4, - "delays": [ - [ - 1 - ], - [ - 1 - ], - [ - 1 - ], - [ - 1 - ] - ] - } - ] + "license": "CC-BY-SA-3.0", + "copyright": "https://github.com/discordia-space/CEV-Eris/raw/9c980cb9bc84d07b1c210c5447798af525185f80/icons/obj/food.dmi. Inhands by Tiniest Shark (Github)", + "states": [ + { + "name": "icon" + }, + { + "name": "icon_open" + }, + { + "name": "inhand-right", + "directions": 4 + }, + { + "name": "inhand-left", + "directions": 4 + } + ] } diff --git a/Resources/Textures/Objects/Consumable/Drinks/teacup.rsi/inhand-left.png b/Resources/Textures/Objects/Consumable/Drinks/teacup.rsi/inhand-left.png new file mode 100644 index 0000000000000000000000000000000000000000..61f2fc9590d918271de463d97d8f28cf59edd928 GIT binary patch literal 276 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=jKx9jP7LeL$-D$|&Uv~xhE&XX zd+Q+QVFRAlhu1Hu+B9!!TmDVz6dU7Rrg;Z!S&LpSo#^fTKfghIf=IjyCr}du!-Mm8 z*0F85)}}HwNX7H?rkHazU*|?;SADZpK5`}{?b1qxnRje$KTim1xVKx$X_Coe@6F4! ze6w?9Vt;Lg7yvfqgZ#3$pT0KEZsh5I<4`UysAwFl>H2!tvgh7j(Z`qHVV@&=*X}+~ zinV-7Ozhm{;s@@!ul>3$clNj1`9}W)7v9_b<>~(GChzR}%G(};Ox^RGQ(|gtF7utP Q#~|Z9UHx3vIVCg!0EKXH9RL6T literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Consumable/Drinks/teacup.rsi/inhand-right.png b/Resources/Textures/Objects/Consumable/Drinks/teacup.rsi/inhand-right.png new file mode 100644 index 0000000000000000000000000000000000000000..910124fefa98e3710a0743a2483837eddf8b6573 GIT binary patch literal 277 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=jKx9jP7LeL$-D$|&U?BzhE&XX zdutuLvj(H z(+SU4&nB!W=dBdl@$xs@(a$&YD&JMuzPGl~cW?oNE!!M-C#M@rMjOW~Usn~J^y%kx z{_9fT7#aATZrZ;uG=I~b#?%n4rSazGv9qN-`fedwMXK@5HyHfZ`59)01bT}vQ40TL z+QGXZX-Y$$@Xa^}ts>L-Mt7}@oUFir zk5`Unzkn=MC=)z^7QrWp4`{lnD20R)}lP$K$)2x%#Zem-JRv-E+hyC zo)>hCmUN2q79Ozs@^kuisi|gSznS`f%IFDq_I^4lpLf3F*7~)vAw5E;Hv3Oy^mwP- zVd~r$wX4B%@v5+N>m}a=kFZa8%i53^y!Kp~$6Mu&tB?DhoGAIZy~%7rbb5G?P+$43 z?pl`Ow=y3Y861}UVPTl@tk^+mVIlX%T9&DdB8Sr%8qAlveSh&!Y~tq|-;W;r=N4K2 sNn*+!_W;YqTmK%5k^{Q*;{NZff~q@@+0W3G0>&kSr>mdKI;Vst0B>{E4*&oF literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Consumable/Drinks/tomatojuice.rsi/inhand-right.png b/Resources/Textures/Objects/Consumable/Drinks/tomatojuice.rsi/inhand-right.png new file mode 100644 index 0000000000000000000000000000000000000000..cec7beb423ade270b818bab53323b8efbf107e08 GIT binary patch literal 547 zcmV+;0^I$HP)Px$-AP12RCt{2+ObOlQ5*;GujSz0CFgKkMMU@qs0o#GYXmJ0E$t0WSJ2)TZjR#O z|ByyO)X-2wIz$m3*li6(>93)T2!nTb@2SK0vnkJa-+SEi4c`NZh=_=Yh=~5xX||+V zD#@sG=oV8Moi+(Rd0;-X%IA@@+#GmjsSqy{XoNSkL@XNG?kJd`INSRYuR$udj|mA`Ci0`W;Oiw zs3Q;&5fKp)5fKp)5k+CLnvYy=R7)jUSuJ3CcE(6i^0%7TUC4x@hmxpz{ zU0)zm%;`%sfXQlJsT=%H^(lpQ+~V~7RbQe3UV2>|dk(h!N9|iI^a50XSjBI{o^%B0 z>P_{_!oePvRtsMrW@n6DC$vtpB_@w4*RrLSbfjO;>lSGX98IO9kzED=+7;A=0OOt~-r4PeWz)4o%UF~ZmN}8H(VDD=dUzmxi)Jp7p(3POqZjL zc(HV{DE;Z?VOb!romgH@bGg17?A$SbfM$U??s?YfKccK~b~n&UQ2RPr4V{iabCJ@v yV|pObm|jff_{2r|H;Xa*xBGVP1^@s6(9Q>;>wS=o!qL_M0000@fC2aBPd%*yMWLaSmaKc7l4k$i+vIpmvQs diff --git a/Resources/Textures/Objects/Consumable/Drinks/tonic.rsi/inhand-right.png b/Resources/Textures/Objects/Consumable/Drinks/tonic.rsi/inhand-right.png index cb145ca15145530a16dd5aa8091ae62373e83502..2f2ad705149fd53040f17e7c38e59c44533b28b2 100644 GIT binary patch delta 348 zcmV-i0i*ti0`~%tB!2;OQb$4nuFf3k0003oNkl=~2(k!2SKF1X`MSq~Zv8SD`wE6>>BB+&b zq3XscG4k~IJXNSBMTxO@`16b5-Z69_+ZHui0e%a##Ji zru~(i000000000004Qs1HSdS94u&I5v)pPh+tqyKdc5rLVoSVhPnH)SN zR`a#m;j*jK8&$h~{JY(aHIcTKou&xXaqayx;JBjuw>#P!dsf~t^%eNg#02#F=W=;s u=jYP9F}=Slhw?Q74MS9=Ck?(&;`+4A|>Gyc0?9yxQy`gtl_>YXEe^Iq>hwN7eY zmYeJM3#;Y6xxKz|a8vBJhxS1yIl)$dh%-4?#EZPV k#fyI%?EV~OW?)c=&0oIBOS|%q5IabZr>mdKI;Vst09f;FD*ylh diff --git a/Resources/Textures/Objects/Consumable/Drinks/tonic.rsi/meta.json b/Resources/Textures/Objects/Consumable/Drinks/tonic.rsi/meta.json index d2cf48f2862..087c100ebfa 100644 --- a/Resources/Textures/Objects/Consumable/Drinks/tonic.rsi/meta.json +++ b/Resources/Textures/Objects/Consumable/Drinks/tonic.rsi/meta.json @@ -1,53 +1,25 @@ { - "version": 1, - "size": { - "x": 32, - "y": 32 - }, - "license": "CC-BY-SA-3.0", - "copyright": "https://github.com/discordia-space/CEV-Eris/raw/9c980cb9bc84d07b1c210c5447798af525185f80/icons/obj/food.dmi", - "states": [ - { - "name": "icon" + "version": 1, + "size": { + "x": 32, + "y": 32 }, - { - "name": "icon_open" - }, - { - "name": "inhand-right", - "directions": 4, - "delays": [ - [ - 1 - ], - [ - 1 - ], - [ - 1 - ], - [ - 1 - ] - ] - }, - { - "name": "inhand-left", - "directions": 4, - "delays": [ - [ - 1 - ], - [ - 1 - ], - [ - 1 - ], - [ - 1 - ] - ] - } - ] + "license": "CC-BY-SA-3.0", + "copyright": "https://github.com/discordia-space/CEV-Eris/raw/9c980cb9bc84d07b1c210c5447798af525185f80/icons/obj/food.dmi. Inhands by Tiniest Shark (Github)", + "states": [ + { + "name": "icon" + }, + { + "name": "icon_open" + }, + { + "name": "inhand-right", + "directions": 4 + }, + { + "name": "inhand-left", + "directions": 4 + } + ] } diff --git a/Resources/Textures/Objects/Consumable/Drinks/water_cup.rsi/inhand-left.png b/Resources/Textures/Objects/Consumable/Drinks/water_cup.rsi/inhand-left.png new file mode 100644 index 0000000000000000000000000000000000000000..8b7b77afa2fad4337187a3bed7da7cfcb777f1cc GIT binary patch literal 357 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=jKx9jP7LeL$-D%z-Ln`LH zy`|{K94OHKv7XcM$^xweIsJ{RS{DSY$nvOSV408Fj)v?J zHEnL>zEC;a>~9_Wk8gXo7r8M3&1PV@VYs)WW9HA=k6NBt;@+{fb23b%TDQwrUspU^ zkoHVd)n9Yx%%49uSND~L7{|nhy}Mj_&G}i@dsmmf{Bu>^Ps?4hs%OspUGi@8O`Sjf zf445){jexzU$+_9Y#?#Kk3-(P|MjKc?(LJ7+&&-7+kW`0Oy>Vv{e1V<>X~M+Pg>&U zTN1~0&z+;b;bio}>D^&}mzT??%#pC)lI$6@Im_gy)~4F$@j+g3(?ho4RzC2}QV7T^`*-&cvjSKx86G8TSy85}Sb4q9e08dbu AtN;K2 literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Consumable/Drinks/water_cup.rsi/inhand-right.png b/Resources/Textures/Objects/Consumable/Drinks/water_cup.rsi/inhand-right.png new file mode 100644 index 0000000000000000000000000000000000000000..ba7c125b362b09030dbc3df4e71de901ab8a360b GIT binary patch literal 388 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=jKx9jP7LeL$-D%z?L1u^Ln`LH zy}90x*-?P)1HY3%`YOMM4F7}*W}b8bm0GqER{n+uj2tV~RND7R&0BE8*F)fWw*!x& z<&i{z;xYr)#syDyMQ?lf`{m!yZ+*ge9b6#b%lRCgCxXyF#J5pWI}>v=+!pi&5KuC{bFLVzF{f;_3_1p472w~swhpH zviaP?Fip*Lj!P>_U)WvKP!~jii>F+zpZ)t%YZL!&Ugg<4KMkJGx%)hdmA7{Qk{q3#tq%R@rP#DE^9dw1Cz*<1r9Aoz8Y ZUBhXmi$SNCF)&yeJYD@<);T3K0RRLaqaOeO literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Consumable/Drinks/water_cup.rsi/meta.json b/Resources/Textures/Objects/Consumable/Drinks/water_cup.rsi/meta.json index 7c719f160d5..6301d09d7db 100644 --- a/Resources/Textures/Objects/Consumable/Drinks/water_cup.rsi/meta.json +++ b/Resources/Textures/Objects/Consumable/Drinks/water_cup.rsi/meta.json @@ -5,13 +5,21 @@ "y": 32 }, "license": "CC-BY-SA-3.0", - "copyright": "https://github.com/discordia-space/CEV-Eris/raw/f7aa28fd4b4d0386c3393d829681ebca526f1d2d/icons/obj/drinks.dmi", + "copyright": "https://github.com/discordia-space/CEV-Eris/raw/f7aa28fd4b4d0386c3393d829681ebca526f1d2d/icons/obj/drinks.dmi. Inhands by Tiniest Shark (Github)", "states": [ { "name": "icon-0" }, { "name": "icon-1" + }, + { + "name": "inhand-right", + "directions": 4 + }, + { + "name": "inhand-left", + "directions": 4 } ] } diff --git a/Resources/Textures/Objects/Consumable/Drinks/wine_can.rsi/inhand-left.png b/Resources/Textures/Objects/Consumable/Drinks/wine_can.rsi/inhand-left.png new file mode 100644 index 0000000000000000000000000000000000000000..a66de5a6aa3a0f3f40af984bd353b4e4be6e3665 GIT binary patch literal 429 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=jKx9jP7LeL$-D%z(>+}rLn`LH zy|ppxP=Ls>kLNGlbSw}&;=54x_QEaeTJ0M6%u2WgMOyYXc2vK8Aa)`^!z1kALfM#2 z9@BY_>fCfX;3;U{e%qD#u2->M=&!$W56(Y5u=lhrgCGR_y>_51RATLw6sut7+oAQf z^X6Mk(<4O4qW-hajbD= z+jsMozoXVQm}(_${t{rUB>VHo;mIqv)?Zks|1LykhF6t*V+RoY>((zd?GL!K^yzkB P_%nFA`njxgN@xNAe7C_` literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Consumable/Drinks/wine_can.rsi/inhand-right.png b/Resources/Textures/Objects/Consumable/Drinks/wine_can.rsi/inhand-right.png new file mode 100644 index 0000000000000000000000000000000000000000..3b745d9c8b1f42f3d24446953e2a027164f4cc96 GIT binary patch literal 432 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=jKx9jP7LeL$-D%zvpiiKLn`LH zy|vMsDN%y$!}5O(Z3kRA%voi#y{<2?S75ij#mCFOaHH=L+v&IYWM&--6}WUzm7{Q{ z;-06|CNxi*lu=v}&9#W<-MMPthd;i&daM37txAwgpy}uVDZk2`q zv-Y1;)~pkiV)Y?PugXuhHN@HeD%U$bIj7nM4$KBZo)&JxHxqS>Hk20jq^qSp_g6vo{gWkF2(3X?icBVsh_KUYW=R3wr|+}yl=&mFR{UD&2wbr=jDB2 z*ruuuu^i$8{aaUS9u$39zU}VRe;GRWa@PGi-%w^MU&+uK!fd;oZ~fDxi7$`LekJ`j z%kC2cgM#&%gNCyVgiiht(p?yNcD+f%B-5*JAKTxJxy8`1c=B=CuZIt9I#u~GHux>? zhuGkKTKTt_1{NC8FxgQu&X%Q~loCIAP%xeWjS literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Consumable/Drinks/wine_can.rsi/meta.json b/Resources/Textures/Objects/Consumable/Drinks/wine_can.rsi/meta.json index b712e503a15..5a1b399e502 100644 --- a/Resources/Textures/Objects/Consumable/Drinks/wine_can.rsi/meta.json +++ b/Resources/Textures/Objects/Consumable/Drinks/wine_can.rsi/meta.json @@ -5,13 +5,21 @@ "y": 32 }, "license": "CC-BY-SA-3.0", - "copyright": "Github #DrMelon", + "copyright": "Github #DrMelon. Inhands by Tiniest Shark (Github)", "states": [ { "name": "icon" }, { "name": "icon_open" + }, + { + "name": "inhand-right", + "directions": 4 + }, + { + "name": "inhand-left", + "directions": 4 } ] } diff --git a/Resources/Textures/Objects/Misc/6pack.rsi/inhand-left.png b/Resources/Textures/Objects/Misc/6pack.rsi/inhand-left.png new file mode 100644 index 0000000000000000000000000000000000000000..5035ce2d8120d2ee43ccc254ccf25427b4c8de1a GIT binary patch literal 522 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=jKx9jP7LeL$-D%zk9fK`hE&XX zduyZLp#TxK2l5XE=agu6Y6{e_u-`jyWabfZfx?18X$!t<+C?%XO#wN$; zq@uR##S`I7W1qCgwOdRKHv9KHJe>dF(N9BGhSY5Lvi@^|@8-{ybBp`DJ(4|ow#2@Dj~FFm z_S|176e5kp*^k3HDBNLLg zw>vGhTF<`JmS=BRN__gXOt(CTJ8hG5oSr{h`^ewV;qJM^oU)N~g%_MN^8LLq==3ud z1~((d26_HfJN~V@uc`zGi~eU%RjJIi%v0!-KB05VY-{D@!arx`tLSgd@pCgeXlECA z?vfcV6FGklQ7-;8ett`byQnzpg!Z8#ZlKZuR>5yR}VotC?%>g~zX4 zd*(45{~X9KTMiWX+YS`CrdJoHTw*=-*rHj2)`EhrznMJyh1`Gk>+b_bE`z75pUXO@ GgeCx?{^dge literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Misc/6pack.rsi/inhand-right.png b/Resources/Textures/Objects/Misc/6pack.rsi/inhand-right.png new file mode 100644 index 0000000000000000000000000000000000000000..ac4b9e1fc58ecc20349ec929b5be03d7347f0caf GIT binary patch literal 543 zcmV+)0^t3LP)Px$*-1n}RCt{2**{LgU>L{oUll!plP)Ea0;xw};07knBpyH!2M1%K10L_|bHL_|bH|B_Rx z$}GM!3l~?na&dJ#@!r&XHq>R*Tm}FBJAZQw4R^QKm?XC59x_CE2nT=Z)_h{$!rex&MvO4 z1R7@rto9G&uH6~Cc251kuGNvu<_2>!okGhkPu+)6%PpgsP7UT{HV3;_pLp%q0qB0P zx(_4u2df7%O#1{BtOOj_o4OAp$MsOK5`+1@Ct&1-kdMX%0Pf`#0C4{F@Tq+mWz3iW zfMv`Bz~H4$L_|bHL_|bHL_|d45Sr@zo5|cMRmIQTPN^zCbtu|Oq9$`SFYESSm5;_{ zqhF$L`lb3Os*bjCt9dzN#>7uz`Dk2p`T0BSS{1jf;)r z6Oo?Cw0%(265ULvaA}%>{uMrS0BT;=%|TI1v_Jd7GYDUL0(5gw)HJWoLD2r6)V%Dc h@o6*jGZ7K}9dG2j1_k5h?Kc1b002ovPDHLkV1iFt^UnYP literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Misc/6pack.rsi/meta.json b/Resources/Textures/Objects/Misc/6pack.rsi/meta.json index 76280403d4a..4c7757a3839 100644 --- a/Resources/Textures/Objects/Misc/6pack.rsi/meta.json +++ b/Resources/Textures/Objects/Misc/6pack.rsi/meta.json @@ -1,32 +1,40 @@ { - "version": 1, - "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at https://github.com/tgstation/tgstation/commit/e1142f20f5e4661cb6845cfcf2dd69f864d67432 and modified by Swept", - "size": { - "x": 32, - "y": 32 - }, - "states": [ - { - "name": "6pack1" + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Taken from tgstation at https://github.com/tgstation/tgstation/commit/e1142f20f5e4661cb6845cfcf2dd69f864d67432 and modified by Swept. Inhands by Tiniest Shark (Github)", + "size": { + "x": 32, + "y": 32 }, - { - "name": "6pack2" - }, - { - "name": "6pack3" - }, - { - "name": "6pack4" - }, - { - "name": "6pack5" - }, - { - "name": "6pack6" - }, - { - "name": "plastic-thingy" - } - ] + "states": [ + { + "name": "6pack1" + }, + { + "name": "6pack2" + }, + { + "name": "6pack3" + }, + { + "name": "6pack4" + }, + { + "name": "6pack5" + }, + { + "name": "6pack6" + }, + { + "name": "plastic-thingy" + }, + { + "name": "inhand-right", + "directions": 4 + }, + { + "name": "inhand-left", + "directions": 4 + } + ] } From aee0e440a54caad022442fefbaeca81238986e3f Mon Sep 17 00:00:00 2001 From: Quasr <182430031+quasr-9@users.noreply.github.com> Date: Wed, 3 Sep 2025 07:07:35 -0500 Subject: [PATCH 313/340] Updated inspector description to reflect functionality (#40072) update inspector desc. Co-authored-by: Quasr <~182430031+quasr-9@users.noreply.github.com> --- .../Entities/Objects/Weapons/Guns/Revolvers/revolvers.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Revolvers/revolvers.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Revolvers/revolvers.yml index bc7b151fc87..67935b50c2f 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Revolvers/revolvers.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Revolvers/revolvers.yml @@ -84,7 +84,7 @@ name: Inspector parent: [BaseWeaponRevolver, BaseSecurityContraband] id: WeaponRevolverInspector - description: A single-action revolver manufactured by various companies. It is readily available on the civilian market, making it a popular choice among private investigators. You feel lucky just holding it. Loads 6 rounds of .45 magnum. + description: A double-action revolver manufactured by various companies. It is readily available on the civilian market, making it a popular choice among private investigators. You feel lucky just holding it. Loads 6 rounds of .45 magnum. components: - type: Sprite sprite: Objects/Weapons/Guns/Revolvers/inspector.rsi From 2bc7d10eecc77b4eebc18908761c8f9ee0d08ebe Mon Sep 17 00:00:00 2001 From: ArtisticRoomba <145879011+ArtisticRoomba@users.noreply.github.com> Date: Wed, 3 Sep 2025 16:58:48 -0700 Subject: [PATCH 314/340] Atmos Delta-Pressure Window Shattering (#39238) This PR adds delta-pressure damage. In short, airtight structures can now take damage proportional to the difference in pressures between the sides of the structure. --- Content.Benchmarks/DeltaPressureBenchmark.cs | 174 ++++++++ .../Tests/Atmos/DeltaPressureTest.cs | 417 ++++++++++++++++++ .../Components/DeltaPressureComponent.cs | 139 ++++++ .../Components/GridAtmosphereComponent.cs | 34 ++ .../EntitySystems/AtmosphereSystem.API.cs | 103 +++++ .../AtmosphereSystem.BenchmarkHelpers.cs | 49 ++ .../EntitySystems/AtmosphereSystem.CVars.cs | 6 + .../AtmosphereSystem.DeltaPressure.cs | 259 +++++++++++ .../AtmosphereSystem.Processing.cs | 75 ++++ .../Atmos/EntitySystems/AtmosphereSystem.cs | 5 +- .../EntitySystems/DeltaPressureSystem.cs | 82 ++++ Content.Shared/CCVar/CCVars.Atmos.cs | 27 ++ .../en-US/atmos/delta-pressure-component.ftl | 1 + .../DeltaPressure/deltapressuretest.yml | 234 ++++++++++ .../Doors/Windoors/base_structurewindoors.yml | 24 + .../Entities/Structures/Windows/plasma.yml | 9 + .../Structures/Windows/reinforced.yml | 7 + .../Entities/Structures/Windows/rplasma.yml | 9 + .../Entities/Structures/Windows/ruranium.yml | 9 + .../Entities/Structures/Windows/shuttle.yml | 5 + .../Entities/Structures/Windows/uranium.yml | 9 + .../Entities/Structures/Windows/window.yml | 9 + 22 files changed, 1685 insertions(+), 1 deletion(-) create mode 100644 Content.Benchmarks/DeltaPressureBenchmark.cs create mode 100644 Content.IntegrationTests/Tests/Atmos/DeltaPressureTest.cs create mode 100644 Content.Server/Atmos/Components/DeltaPressureComponent.cs create mode 100644 Content.Server/Atmos/EntitySystems/AtmosphereSystem.BenchmarkHelpers.cs create mode 100644 Content.Server/Atmos/EntitySystems/AtmosphereSystem.DeltaPressure.cs create mode 100644 Content.Server/Atmos/EntitySystems/DeltaPressureSystem.cs create mode 100644 Resources/Locale/en-US/atmos/delta-pressure-component.ftl create mode 100644 Resources/Maps/Test/Atmospherics/DeltaPressure/deltapressuretest.yml diff --git a/Content.Benchmarks/DeltaPressureBenchmark.cs b/Content.Benchmarks/DeltaPressureBenchmark.cs new file mode 100644 index 00000000000..b31b3ed1a24 --- /dev/null +++ b/Content.Benchmarks/DeltaPressureBenchmark.cs @@ -0,0 +1,174 @@ +using System.Threading.Tasks; +using BenchmarkDotNet.Attributes; +using BenchmarkDotNet.Diagnosers; +using Content.IntegrationTests; +using Content.IntegrationTests.Pair; +using Content.Server.Atmos.Components; +using Content.Server.Atmos.EntitySystems; +using Content.Shared.Atmos.Components; +using Content.Shared.CCVar; +using Robust.Shared; +using Robust.Shared.Analyzers; +using Robust.Shared.Configuration; +using Robust.Shared.GameObjects; +using Robust.Shared.Map; +using Robust.Shared.Map.Components; +using Robust.Shared.Maths; +using Robust.Shared.Prototypes; +using Robust.Shared.Random; + +namespace Content.Benchmarks; + +/// +/// Spawns N number of entities with a and +/// simulates them for a number of ticks M. +/// +[Virtual] +[GcServer(true)] +//[MemoryDiagnoser] +//[ThreadingDiagnoser] +public class DeltaPressureBenchmark +{ + /// + /// Number of entities (windows, really) to spawn with a . + /// + [Params(1, 10, 100, 1000, 5000, 10000, 50000, 100000)] + public int EntityCount; + + /// + /// Number of entities that each parallel processing job will handle. + /// + // [Params(1, 10, 100, 1000, 5000, 10000)] For testing how multithreading parameters affect performance (THESE TESTS TAKE 16+ HOURS TO RUN) + [Params(10)] + public int BatchSize; + + /// + /// Number of entities to process per iteration in the DeltaPressure + /// processing loop. + /// + // [Params(100, 1000, 5000, 10000, 50000)] + [Params(1000)] + public int EntitiesPerIteration; + + private readonly EntProtoId _windowProtoId = "Window"; + private readonly EntProtoId _wallProtoId = "WallPlastitaniumIndestructible"; + + private TestPair _pair = default!; + private IEntityManager _entMan = default!; + private SharedMapSystem _map = default!; + private IRobustRandom _random = default!; + private IConfigurationManager _cvar = default!; + private ITileDefinitionManager _tileDefMan = default!; + private AtmosphereSystem _atmospereSystem = default!; + + private Entity + _testEnt; + + [GlobalSetup] + public async Task SetupAsync() + { + ProgramShared.PathOffset = "../../../../"; + PoolManager.Startup(); + _pair = await PoolManager.GetServerClient(); + var server = _pair.Server; + + var mapdata = await _pair.CreateTestMap(); + + _entMan = server.ResolveDependency(); + _map = _entMan.System(); + _random = server.ResolveDependency(); + _cvar = server.ResolveDependency(); + _tileDefMan = server.ResolveDependency(); + _atmospereSystem = _entMan.System(); + + _random.SetSeed(69420); // Randomness needs to be deterministic for benchmarking. + + _cvar.SetCVar(CCVars.DeltaPressureParallelToProcessPerIteration, EntitiesPerIteration); + _cvar.SetCVar(CCVars.DeltaPressureParallelBatchSize, BatchSize); + + var plating = _tileDefMan["Plating"].TileId; + + /* + Basically, we want to have a 5-wide grid of tiles. + Edges are walled, and the length of the grid is determined by N + 2. + Windows should only touch the top and bottom walls, and each other. + */ + + var length = EntityCount + 2; // ensures we can spawn exactly N windows between side walls + const int height = 5; + + await server.WaitPost(() => + { + // Fill required tiles (extend grid) with plating + for (var x = 0; x < length; x++) + { + for (var y = 0; y < height; y++) + { + _map.SetTile(mapdata.Grid, mapdata.Grid, new Vector2i(x, y), new Tile(plating)); + } + } + + // Spawn perimeter walls and windows row in the middle (y = 2) + const int midY = height / 2; + for (var x = 0; x < length; x++) + { + for (var y = 0; y < height; y++) + { + var coords = new EntityCoordinates(mapdata.Grid, x + 0.5f, y + 0.5f); + + var isPerimeter = x == 0 || x == length - 1 || y == 0 || y == height - 1; + if (isPerimeter) + { + _entMan.SpawnEntity(_wallProtoId, coords); + continue; + } + + // Spawn windows only on the middle row, spanning interior (excluding side walls) + if (y == midY) + { + _entMan.SpawnEntity(_windowProtoId, coords); + } + } + } + }); + + // Next we run the fixgridatmos command to ensure that we have some air on our grid. + // Wait a little bit as well. + // TODO: Unhardcode command magic string when fixgridatmos is an actual command we can ref and not just + // a stamp-on in AtmosphereSystem. + await _pair.WaitCommand("fixgridatmos " + mapdata.Grid.Owner, 1); + + var uid = mapdata.Grid.Owner; + _testEnt = new Entity( + uid, + _entMan.GetComponent(uid), + _entMan.GetComponent(uid), + _entMan.GetComponent(uid), + _entMan.GetComponent(uid)); + } + + [Benchmark] + public async Task PerformFullProcess() + { + await _pair.Server.WaitPost(() => + { + while (!_atmospereSystem.RunProcessingStage(_testEnt, AtmosphereProcessingState.DeltaPressure)) { } + }); + } + + [Benchmark] + public async Task PerformSingleRunProcess() + { + await _pair.Server.WaitPost(() => + { + _atmospereSystem.RunProcessingStage(_testEnt, AtmosphereProcessingState.DeltaPressure); + }); + } + + [GlobalCleanup] + public async Task CleanupAsync() + { + await _pair.DisposeAsync(); + PoolManager.Shutdown(); + } +} diff --git a/Content.IntegrationTests/Tests/Atmos/DeltaPressureTest.cs b/Content.IntegrationTests/Tests/Atmos/DeltaPressureTest.cs new file mode 100644 index 00000000000..9dda130847d --- /dev/null +++ b/Content.IntegrationTests/Tests/Atmos/DeltaPressureTest.cs @@ -0,0 +1,417 @@ +using System.Linq; +using System.Numerics; +using Content.Server.Atmos; +using Content.Server.Atmos.Components; +using Content.Server.Atmos.EntitySystems; +using Content.Shared.Atmos; +using Robust.Shared.EntitySerialization; +using Robust.Shared.EntitySerialization.Systems; +using Robust.Shared.GameObjects; +using Robust.Shared.Map; +using Robust.Shared.Map.Components; +using Robust.Shared.Utility; + +namespace Content.IntegrationTests.Tests.Atmos; + +/// +/// Tests for AtmosphereSystem.DeltaPressure and surrounding systems +/// handling the DeltaPressureComponent. +/// +[TestFixture] +[TestOf(typeof(DeltaPressureSystem))] +public sealed class DeltaPressureTest +{ + #region Prototypes + + [TestPrototypes] + private const string Prototypes = @" +- type: entity + parent: BaseStructure + id: DeltaPressureSolidTest + placement: + mode: SnapgridCenter + snap: + - Wall + components: + - type: Physics + bodyType: Static + - type: Fixtures + fixtures: + fix1: + shape: + !type:PhysShapeAabb + bounds: ""-0.5,-0.5,0.5,0.5"" + mask: + - FullTileMask + layer: + - WallLayer + density: 1000 + - type: Airtight + - type: DeltaPressure + minPressure: 15000 + minPressureDelta: 10000 + scalingType: Threshold + baseDamage: + types: + Structural: 1000 + - type: Damageable + - type: Destructible + thresholds: + - trigger: + !type:DamageTrigger + damage: 300 + behaviors: + - !type:SpawnEntitiesBehavior + spawn: + Girder: + min: 1 + max: 1 + - !type:DoActsBehavior + acts: [ ""Destruction"" ] + +- type: entity + parent: DeltaPressureSolidTest + id: DeltaPressureSolidTestNoAutoJoin + components: + - type: DeltaPressure + autoJoinProcessingList: false + +- type: entity + parent: DeltaPressureSolidTest + id: DeltaPressureSolidTestAbsolute + components: + - type: DeltaPressure + minPressure: 10000 + minPressureDelta: 15000 + scalingType: Threshold + baseDamage: + types: + Structural: 1000 +"; + + #endregion + + private readonly ResPath _testMap = new("Maps/Test/Atmospherics/DeltaPressure/deltapressuretest.yml"); + + /// + /// Asserts that an entity with a DeltaPressureComponent with autoJoinProcessingList + /// set to true is automatically added to the DeltaPressure processing list + /// on the grid's GridAtmosphereComponent. + /// + /// Also asserts that an entity with a DeltaPressureComponent with autoJoinProcessingList + /// set to false is not automatically added to the DeltaPressure processing list. + /// + [Test] + public async Task ProcessingListAutoJoinTest() + { + await using var pair = await PoolManager.GetServerClient(); + var server = pair.Server; + + var entMan = server.EntMan; + var mapLoader = entMan.System(); + var atmosphereSystem = entMan.System(); + var deserializationOptions = DeserializationOptions.Default with { InitializeMaps = true }; + + Entity grid = default; + Entity dpEnt; + + // Load our test map in and assert that it exists. + await server.WaitPost(() => + { +#pragma warning disable NUnit2045 + Assert.That(mapLoader.TryLoadMap(_testMap, out _, out var gridSet, deserializationOptions), + $"Failed to load map {_testMap}."); + Assert.That(gridSet, Is.Not.Null, "There were no grids loaded from the map!"); +#pragma warning restore NUnit2045 + + grid = gridSet.First(); + }); + + await server.WaitAssertion(() => + { + var uid = entMan.SpawnAtPosition("DeltaPressureSolidTest", new EntityCoordinates(grid.Owner, Vector2.Zero)); + dpEnt = new Entity(uid, entMan.GetComponent(uid)); + + Assert.That(atmosphereSystem.IsDeltaPressureEntityInList(grid.Owner, dpEnt), "Entity was not in processing list when it should have automatically joined!"); + entMan.DeleteEntity(uid); + Assert.That(!atmosphereSystem.IsDeltaPressureEntityInList(grid.Owner, dpEnt), "Entity was still in processing list after deletion!"); + }); + + await pair.CleanReturnAsync(); + } + + /// + /// Asserts that an entity that doesn't need to be damaged by DeltaPressure + /// is not damaged by DeltaPressure. + /// + [Test] + public async Task ProcessingDeltaStandbyTest() + { + await using var pair = await PoolManager.GetServerClient(); + var server = pair.Server; + + var entMan = server.EntMan; + var mapLoader = entMan.System(); + var atmosphereSystem = entMan.System(); + var transformSystem = entMan.System(); + var deserializationOptions = DeserializationOptions.Default with { InitializeMaps = true }; + + Entity grid = default; + Entity dpEnt = default; + TileAtmosphere tile = null!; + AtmosDirection direction = default; + + // Load our test map in and assert that it exists. + await server.WaitPost(() => + { +#pragma warning disable NUnit2045 + Assert.That(mapLoader.TryLoadMap(_testMap, out _, out var gridSet, deserializationOptions), + $"Failed to load map {_testMap}."); + Assert.That(gridSet, Is.Not.Null, "There were no grids loaded from the map!"); +#pragma warning restore NUnit2045 + + grid = gridSet.First(); + var uid = entMan.SpawnAtPosition("DeltaPressureSolidTest", new EntityCoordinates(grid.Owner, Vector2.Zero)); + dpEnt = new Entity(uid, entMan.GetComponent(uid)); + Assert.That(atmosphereSystem.IsDeltaPressureEntityInList(grid.Owner, dpEnt), "Entity was not in processing list when it should have been added!"); + }); + + for (var i = 0; i < Atmospherics.Directions; i++) + { + await server.WaitPost(() => + { + var indices = transformSystem.GetGridOrMapTilePosition(dpEnt); + var gridAtmosComp = entMan.GetComponent(grid); + + direction = (AtmosDirection)(1 << i); + var offsetIndices = indices.Offset(direction); + tile = gridAtmosComp.Tiles[offsetIndices]; + + Assert.That(tile.Air, Is.Not.Null, $"Tile at {offsetIndices} should have air!"); + + var toPressurize = dpEnt.Comp!.MinPressureDelta - 10; + var moles = (toPressurize * tile.Air.Volume) / (Atmospherics.R * Atmospherics.T20C); + + tile.Air!.AdjustMoles(Gas.Nitrogen, moles); + }); + + await server.WaitRunTicks(30); + + // Entity should exist, if it took one tick of damage then it should be instantly destroyed. + await server.WaitAssertion(() => + { + Assert.That(!entMan.Deleted(dpEnt), $"{dpEnt} should still exist after experiencing non-threshold pressure from {direction} side!"); + tile.Air!.Clear(); + }); + + await server.WaitRunTicks(30); + } + + await pair.CleanReturnAsync(); + } + + /// + /// Asserts that an entity that needs to be damaged by DeltaPressure + /// is damaged by DeltaPressure when the pressure is above the threshold. + /// + [Test] + public async Task ProcessingDeltaDamageTest() + { + await using var pair = await PoolManager.GetServerClient(); + var server = pair.Server; + + var entMan = server.EntMan; + var mapLoader = entMan.System(); + var atmosphereSystem = entMan.System(); + var transformSystem = entMan.System(); + var deserializationOptions = DeserializationOptions.Default with { InitializeMaps = true }; + + Entity grid = default; + Entity dpEnt = default; + TileAtmosphere tile = null!; + AtmosDirection direction = default; + + // Load our test map in and assert that it exists. + await server.WaitPost(() => + { +#pragma warning disable NUnit2045 + Assert.That(mapLoader.TryLoadMap(_testMap, out _, out var gridSet, deserializationOptions), + $"Failed to load map {_testMap}."); + Assert.That(gridSet, Is.Not.Null, "There were no grids loaded from the map!"); +#pragma warning restore NUnit2045 + + grid = gridSet.First(); + }); + + for (var i = 0; i < Atmospherics.Directions; i++) + { + await server.WaitPost(() => + { + // Need to spawn an entity each run to ensure it works for all directions. + var uid = entMan.SpawnAtPosition("DeltaPressureSolidTest", new EntityCoordinates(grid.Owner, Vector2.Zero)); + dpEnt = new Entity(uid, entMan.GetComponent(uid)); + Assert.That(atmosphereSystem.IsDeltaPressureEntityInList(grid.Owner, dpEnt), "Entity was not in processing list when it should have been added!"); + + var indices = transformSystem.GetGridOrMapTilePosition(dpEnt); + var gridAtmosComp = entMan.GetComponent(grid); + + direction = (AtmosDirection)(1 << i); + var offsetIndices = indices.Offset(direction); + tile = gridAtmosComp.Tiles[offsetIndices]; + + Assert.That(tile.Air, Is.Not.Null, $"Tile at {offsetIndices} should have air!"); + + var toPressurize = dpEnt.Comp!.MinPressureDelta + 10; + var moles = (toPressurize * tile.Air.Volume) / (Atmospherics.R * Atmospherics.T20C); + + tile.Air!.AdjustMoles(Gas.Nitrogen, moles); + }); + + await server.WaitRunTicks(30); + + // Entity should exist, if it took one tick of damage then it should be instantly destroyed. + await server.WaitAssertion(() => + { + Assert.That(entMan.Deleted(dpEnt), $"{dpEnt} still exists after experiencing threshold pressure from {direction} side!"); + tile.Air!.Clear(); + }); + + await server.WaitRunTicks(30); + } + + await pair.CleanReturnAsync(); + } + + /// + /// Asserts that an entity that doesn't need to be damaged by DeltaPressure + /// is not damaged by DeltaPressure when using absolute pressure thresholds. + /// + [Test] + public async Task ProcessingAbsoluteStandbyTest() + { + await using var pair = await PoolManager.GetServerClient(); + var server = pair.Server; + + var entMan = server.EntMan; + var mapLoader = entMan.System(); + var atmosphereSystem = entMan.System(); + var transformSystem = entMan.System(); + var deserializationOptions = DeserializationOptions.Default with { InitializeMaps = true }; + + Entity grid = default; + Entity dpEnt = default; + TileAtmosphere tile = null!; + AtmosDirection direction = default; + + await server.WaitPost(() => + { +#pragma warning disable NUnit2045 + Assert.That(mapLoader.TryLoadMap(_testMap, out _, out var gridSet, deserializationOptions), + $"Failed to load map {_testMap}."); + Assert.That(gridSet, Is.Not.Null, "There were no grids loaded from the map!"); +#pragma warning restore NUnit2045 + grid = gridSet.First(); + var uid = entMan.SpawnAtPosition("DeltaPressureSolidTestAbsolute", new EntityCoordinates(grid.Owner, Vector2.Zero)); + dpEnt = new Entity(uid, entMan.GetComponent(uid)); + Assert.That(atmosphereSystem.IsDeltaPressureEntityInList(grid.Owner, dpEnt), "Entity was not in processing list when it should have been added!"); + }); + + for (var i = 0; i < Atmospherics.Directions; i++) + { + await server.WaitPost(() => + { + var indices = transformSystem.GetGridOrMapTilePosition(dpEnt); + var gridAtmosComp = entMan.GetComponent(grid); + + direction = (AtmosDirection)(1 << i); + var offsetIndices = indices.Offset(direction); + tile = gridAtmosComp.Tiles[offsetIndices]; + Assert.That(tile.Air, Is.Not.Null, $"Tile at {offsetIndices} should have air!"); + + var toPressurize = dpEnt.Comp!.MinPressure - 10; // just below absolute threshold + var moles = (toPressurize * tile.Air.Volume) / (Atmospherics.R * Atmospherics.T20C); + tile.Air!.AdjustMoles(Gas.Nitrogen, moles); + }); + + await server.WaitRunTicks(30); + + await server.WaitAssertion(() => + { + Assert.That(!entMan.Deleted(dpEnt), $"{dpEnt} should still exist after experiencing non-threshold absolute pressure from {direction} side!"); + tile.Air!.Clear(); + }); + + await server.WaitRunTicks(30); + } + + await pair.CleanReturnAsync(); + } + + /// + /// Asserts that an entity that needs to be damaged by DeltaPressure + /// is damaged by DeltaPressure when the pressure is above the absolute threshold. + /// + [Test] + public async Task ProcessingAbsoluteDamageTest() + { + await using var pair = await PoolManager.GetServerClient(); + var server = pair.Server; + + var entMan = server.EntMan; + var mapLoader = entMan.System(); + var atmosphereSystem = entMan.System(); + var transformSystem = entMan.System(); + var deserializationOptions = DeserializationOptions.Default with { InitializeMaps = true }; + + Entity grid = default; + Entity dpEnt = default; + TileAtmosphere tile = null!; + AtmosDirection direction = default; + + await server.WaitPost(() => + { +#pragma warning disable NUnit2045 + Assert.That(mapLoader.TryLoadMap(_testMap, out _, out var gridSet, deserializationOptions), + $"Failed to load map {_testMap}."); + Assert.That(gridSet, Is.Not.Null, "There were no grids loaded from the map!"); +#pragma warning restore NUnit2045 + grid = gridSet.First(); + }); + + for (var i = 0; i < Atmospherics.Directions; i++) + { + await server.WaitPost(() => + { + // Spawn fresh entity each iteration to verify all directions work + var uid = entMan.SpawnAtPosition("DeltaPressureSolidTestAbsolute", new EntityCoordinates(grid.Owner, Vector2.Zero)); + dpEnt = new Entity(uid, entMan.GetComponent(uid)); + Assert.That(atmosphereSystem.IsDeltaPressureEntityInList(grid.Owner, dpEnt), "Entity was not in processing list when it should have been added!"); + + var indices = transformSystem.GetGridOrMapTilePosition(dpEnt); + var gridAtmosComp = entMan.GetComponent(grid); + + direction = (AtmosDirection)(1 << i); + var offsetIndices = indices.Offset(direction); + tile = gridAtmosComp.Tiles[offsetIndices]; + Assert.That(tile.Air, Is.Not.Null, $"Tile at {offsetIndices} should have air!"); + + // Above absolute threshold but below delta threshold to ensure absolute alone causes damage + var toPressurize = dpEnt.Comp!.MinPressure + 10; + var moles = (toPressurize * tile.Air.Volume) / (Atmospherics.R * Atmospherics.T20C); + tile.Air!.AdjustMoles(Gas.Nitrogen, moles); + }); + + await server.WaitRunTicks(30); + + await server.WaitAssertion(() => + { + Assert.That(entMan.Deleted(dpEnt), $"{dpEnt} still exists after experiencing threshold absolute pressure from {direction} side!"); + tile.Air!.Clear(); + }); + + await server.WaitRunTicks(30); + } + + await pair.CleanReturnAsync(); + } +} diff --git a/Content.Server/Atmos/Components/DeltaPressureComponent.cs b/Content.Server/Atmos/Components/DeltaPressureComponent.cs new file mode 100644 index 00000000000..f90c133dea7 --- /dev/null +++ b/Content.Server/Atmos/Components/DeltaPressureComponent.cs @@ -0,0 +1,139 @@ +using Content.Server.Atmos.EntitySystems; +using Content.Shared.Damage; +using Content.Shared.FixedPoint; + +namespace Content.Server.Atmos.Components; + +/// +/// Entities that have this component will have damage done to them depending on the local pressure +/// environment that they reside in. +/// +/// Atmospherics.DeltaPressure batch-processes entities with this component in a list on +/// the grid's . +/// The entities are automatically added and removed from this list, and automatically +/// added on initialization. +/// +/// Note that the entity should have an and be a grid structure. +[RegisterComponent] +public sealed partial class DeltaPressureComponent : Component +{ + /// + /// Whether the entity is currently in the processing list of the grid's . + /// + [DataField(readOnly: true)] + [ViewVariables(VVAccess.ReadOnly)] + [Access(typeof(DeltaPressureSystem), typeof(AtmosphereSystem))] + public bool InProcessingList; + + /// + /// Whether this entity is currently taking damage from pressure. + /// + [DataField(readOnly: true)] + [ViewVariables(VVAccess.ReadOnly)] + [Access(typeof(DeltaPressureSystem), typeof(AtmosphereSystem))] + public bool IsTakingDamage; + + /// + /// The current cached position of this entity on the grid. + /// Updated via MoveEvent. + /// + [DataField(readOnly: true)] + public Vector2i CurrentPosition = Vector2i.Zero; + + /// + /// The grid this entity is currently joined to for processing. + /// Required for proper deletion, as we cannot reference the grid + /// for removal while the entity is being deleted. + /// + [DataField] + public EntityUid? GridUid; + + /// + /// The percent chance that the entity will take damage each atmos tick, + /// when the entity is above the damage threshold. + /// Makes it so that windows don't all break in one go. + /// Float is from 0 to 1, where 1 means 100% chance. + /// If this is set to 0, the entity will never take damage. + /// + [DataField] + public float RandomDamageChance = 1f; + + /// + /// The base damage applied to the entity per atmos tick when it is above the damage threshold. + /// This damage will be scaled as defined by the enum + /// depending on the current effective pressure this entity is experiencing. + /// Note that this damage will scale depending on the pressure above the minimum pressure, + /// not at the current pressure. + /// + [DataField] + public DamageSpecifier BaseDamage = new() + { + DamageDict = new Dictionary + { + { "Structural", 10 }, + }, + }; + + /// + /// The minimum pressure in kPa at which the entity will start taking damage. + /// This doesn't depend on the difference in pressure. + /// The entity will start to take damage if it is exposed to this pressure. + /// This is needed because we don't correctly handle 2-layer windows yet. + /// + [DataField] + public float MinPressure = 10000; + + /// + /// The minimum difference in pressure between any side required for the entity to start taking damage. + /// + [DataField] + public float MinPressureDelta = 7500; + + /// + /// The maximum pressure at which damage will no longer scale. + /// If the effective pressure goes beyond this, the damage will be considered at this pressure. + /// + [DataField] + public float MaxEffectivePressure = 10000; + + /// + /// Simple constant to affect the scaling behavior. + /// See comments in the types to see how this affects scaling. + /// + [DataField] + public float ScalingPower = 1; + + /// + /// Defines the scaling behavior for the damage. + /// + [DataField] + public DeltaPressureDamageScalingType ScalingType = DeltaPressureDamageScalingType.Threshold; +} + +/// +/// An enum that defines how the damage dealt by the scales +/// depending on the pressure experienced by the entity. +/// The scaling is done on the effective pressure, which is the pressure above the minimum pressure. +/// See https://www.desmos.com/calculator/9ctlq3zpnt for a visual representation of the scaling types. +/// +[Serializable] +public enum DeltaPressureDamageScalingType : byte +{ + /// + /// Damage dealt will be constant as long as the minimum values are met. + /// Scaling power is ignored. + /// + Threshold, + + /// + /// Damage dealt will be a linear function. + /// Scaling power determines the slope of the function. + /// + Linear, + + /// + /// Damage dealt will be a logarithmic function. + /// Scaling power determines the base of the log. + /// + Log, +} diff --git a/Content.Server/Atmos/Components/GridAtmosphereComponent.cs b/Content.Server/Atmos/Components/GridAtmosphereComponent.cs index e682fd09644..2d36d2bd148 100644 --- a/Content.Server/Atmos/Components/GridAtmosphereComponent.cs +++ b/Content.Server/Atmos/Components/GridAtmosphereComponent.cs @@ -1,3 +1,4 @@ +using System.Collections.Concurrent; using Content.Server.Atmos.EntitySystems; using Content.Server.Atmos.Piping.Components; using Content.Server.Atmos.Serialization; @@ -61,6 +62,39 @@ namespace Content.Server.Atmos.Components [ViewVariables] public int HighPressureDeltaCount => HighPressureDelta.Count; + /// + /// A list of entities that have a and are to + /// be processed by the , if enabled. + /// + /// To prevent massive bookkeeping overhead, this list is processed in-place, + /// with add/remove/find operations helped via a dict. + /// + /// If you want to add/remove/find entities in this list, + /// use the API methods in the Atmospherics API. + [ViewVariables] + public readonly List> DeltaPressureEntities = + new(AtmosphereSystem.DeltaPressurePreAllocateLength); + + /// + /// An index lookup for the list. + /// Used for add/remove/find operations to speed up processing. + /// + public readonly Dictionary DeltaPressureEntityLookup = + new(AtmosphereSystem.DeltaPressurePreAllocateLength); + + /// + /// Integer that indicates the current position in the + /// list that is being processed. + /// + [ViewVariables(VVAccess.ReadOnly)] + public int DeltaPressureCursor; + + /// + /// Queue of entities that need to have damage applied to them. + /// + [ViewVariables] + public readonly ConcurrentQueue DeltaPressureDamageResults = new(); + [ViewVariables] public readonly HashSet PipeNets = new(); diff --git a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.API.cs b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.API.cs index 67f3a207794..87cfce135d7 100644 --- a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.API.cs +++ b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.API.cs @@ -1,3 +1,4 @@ +using System.Diagnostics; using System.Linq; using Content.Server.Atmos.Components; using Content.Server.Atmos.Piping.Components; @@ -5,6 +6,7 @@ using Content.Server.NodeContainer.NodeGroups; using Content.Shared.Atmos; using Content.Shared.Atmos.Components; using Content.Shared.Atmos.Reactions; +using JetBrains.Annotations; using Robust.Shared.Map.Components; using Robust.Shared.Utility; @@ -319,6 +321,107 @@ public partial class AtmosphereSystem return true; } + /// + /// Adds an entity with a DeltaPressureComponent to the DeltaPressure processing list. + /// Also fills in important information on the component itself. + /// + /// The grid to add the entity to. + /// The entity to add. + /// True if the entity was added to the list, false if it could not be added or + /// if the entity was already present in the list. + [PublicAPI] + public bool TryAddDeltaPressureEntity(Entity grid, Entity ent) + { + // The entity needs to be part of a grid, and it should be the right one :) + var xform = Transform(ent); + + // The entity is not on a grid, so it cannot possibly have an atmosphere that affects it. + if (xform.GridUid == null) + { + return false; + } + + // Entity should be on the grid it's being added to. + Debug.Assert(xform.GridUid == grid.Owner); + + if (!_atmosQuery.Resolve(grid, ref grid.Comp, false)) + return false; + + if (grid.Comp.DeltaPressureEntityLookup.ContainsKey(ent.Owner)) + { + return false; + } + + grid.Comp.DeltaPressureEntityLookup[ent.Owner] = grid.Comp.DeltaPressureEntities.Count; + grid.Comp.DeltaPressureEntities.Add(ent); + + ent.Comp.CurrentPosition = _map.CoordinatesToTile(grid, + Comp(grid), + xform.Coordinates); + + ent.Comp.GridUid = grid.Owner; + ent.Comp.InProcessingList = true; + + return true; + } + + /// + /// Removes an entity with a DeltaPressureComponent from the DeltaPressure processing list. + /// + /// The grid to remove the entity from. + /// The entity to remove. + /// True if the entity was removed from the list, false if it could not be removed or + /// if the entity was not present in the list. + [PublicAPI] + public bool TryRemoveDeltaPressureEntity(Entity grid, Entity ent) + { + if (!_atmosQuery.Resolve(grid, ref grid.Comp, false)) + return false; + + if (!grid.Comp.DeltaPressureEntityLookup.TryGetValue(ent.Owner, out var index)) + return false; + + var lastIndex = grid.Comp.DeltaPressureEntities.Count - 1; + if (lastIndex < 0) + return false; + + if (index != lastIndex) + { + var lastEnt = grid.Comp.DeltaPressureEntities[lastIndex]; + grid.Comp.DeltaPressureEntities[index] = lastEnt; + grid.Comp.DeltaPressureEntityLookup[lastEnt.Owner] = index; + } + + grid.Comp.DeltaPressureEntities.RemoveAt(lastIndex); + grid.Comp.DeltaPressureEntityLookup.Remove(ent.Owner); + + if (grid.Comp.DeltaPressureCursor > grid.Comp.DeltaPressureEntities.Count) + grid.Comp.DeltaPressureCursor = grid.Comp.DeltaPressureEntities.Count; + + ent.Comp.InProcessingList = false; + ent.Comp.GridUid = null; + return true; + } + + /// + /// Checks if a DeltaPressureComponent is currently considered for processing on a grid. + /// + /// The grid that the entity may belong to. + /// The entity to check. + /// True if the entity is part of the processing list, false otherwise. + [PublicAPI] + public bool IsDeltaPressureEntityInList(Entity grid, Entity ent) + { + // Dict and list must be in sync - deep-fried if we aren't. + if (!_atmosQuery.Resolve(grid, ref grid.Comp, false)) + return false; + + var contains = grid.Comp.DeltaPressureEntityLookup.ContainsKey(ent.Owner); + Debug.Assert(contains == grid.Comp.DeltaPressureEntities.Contains(ent)); + + return contains; + } + [ByRefEvent] private record struct SetSimulatedGridMethodEvent (EntityUid Grid, bool Simulated, bool Handled = false); diff --git a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.BenchmarkHelpers.cs b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.BenchmarkHelpers.cs new file mode 100644 index 00000000000..f86ebcee734 --- /dev/null +++ b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.BenchmarkHelpers.cs @@ -0,0 +1,49 @@ +using Content.Server.Atmos.Components; +using Content.Shared.Atmos.Components; +using Robust.Shared.Map.Components; + +namespace Content.Server.Atmos.EntitySystems; + +public sealed partial class AtmosphereSystem +{ + /* + Helper methods to assist in getting very low overhead profiling of individual stages of the atmospherics simulation. + Ideal for benchmarking and performance testing. + These methods obviously aren't to be used in production code. Don't call them. They know my voice. + */ + + /// + /// Runs the grid entity through a single processing stage of the atmosphere simulation. + /// Ideal for benchmarking single stages of the simulation. + /// + /// The entity to profile Atmospherics with. + /// The state to profile on the entity. + /// The optional mapEntity to provide when benchmarking ProcessAtmosDevices. + /// True if the processing stage completed, false if the processing stage had to pause processing due to time constraints. + public bool RunProcessingStage( + Entity ent, + AtmosphereProcessingState state, + Entity? mapEnt = null) + { + var processingPaused = state switch + { + AtmosphereProcessingState.Revalidate => ProcessRevalidate(ent), + AtmosphereProcessingState.TileEqualize => ProcessTileEqualize(ent), + AtmosphereProcessingState.ActiveTiles => ProcessActiveTiles(ent), + AtmosphereProcessingState.ExcitedGroups => ProcessExcitedGroups(ent), + AtmosphereProcessingState.HighPressureDelta => ProcessHighPressureDelta(ent), + AtmosphereProcessingState.DeltaPressure => ProcessDeltaPressure(ent), + AtmosphereProcessingState.Hotspots => ProcessHotspots(ent), + AtmosphereProcessingState.Superconductivity => ProcessSuperconductivity(ent), + AtmosphereProcessingState.PipeNet => ProcessPipeNets(ent), + AtmosphereProcessingState.AtmosDevices => mapEnt is not null + ? ProcessAtmosDevices(ent, mapEnt.Value) + : throw new ArgumentException( + "An Entity must be provided when benchmarking ProcessAtmosDevices."), + _ => throw new ArgumentOutOfRangeException(), + }; + ent.Comp1.ProcessingPaused = !processingPaused; + + return processingPaused; + } +} diff --git a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.CVars.cs b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.CVars.cs index 3aaa5429fb0..f24f0ae171f 100644 --- a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.CVars.cs +++ b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.CVars.cs @@ -26,6 +26,9 @@ namespace Content.Server.Atmos.EntitySystems public float AtmosTickRate { get; private set; } public float Speedup { get; private set; } public float HeatScale { get; private set; } + public bool DeltaPressureDamage { get; private set; } + public int DeltaPressureParallelProcessPerIteration { get; private set; } + public int DeltaPressureParallelBatchSize { get; private set; } /// /// Time between each atmos sub-update. If you are writing an atmos device, use AtmosDeviceUpdateEvent.dt @@ -55,6 +58,9 @@ namespace Content.Server.Atmos.EntitySystems Subs.CVar(_cfg, CCVars.AtmosHeatScale, value => { HeatScale = value; InitializeGases(); }, true); Subs.CVar(_cfg, CCVars.ExcitedGroups, value => ExcitedGroups = value, true); Subs.CVar(_cfg, CCVars.ExcitedGroupsSpaceIsAllConsuming, value => ExcitedGroupsSpaceIsAllConsuming = value, true); + Subs.CVar(_cfg, CCVars.DeltaPressureDamage, value => DeltaPressureDamage = value, true); + Subs.CVar(_cfg, CCVars.DeltaPressureParallelToProcessPerIteration, value => DeltaPressureParallelProcessPerIteration = value, true); + Subs.CVar(_cfg, CCVars.DeltaPressureParallelBatchSize, value => DeltaPressureParallelBatchSize = value, true); } } } diff --git a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.DeltaPressure.cs b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.DeltaPressure.cs new file mode 100644 index 00000000000..207589e5545 --- /dev/null +++ b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.DeltaPressure.cs @@ -0,0 +1,259 @@ +using Content.Server.Atmos.Components; +using Content.Shared.Atmos; +using Content.Shared.Damage; +using Robust.Shared.Random; +using Robust.Shared.Threading; + +namespace Content.Server.Atmos.EntitySystems; + +public sealed partial class AtmosphereSystem +{ + /// + /// The number of pairs of opposing directions we can have. + /// This is Atmospherics.Directions / 2, since we always compare opposing directions + /// (e.g. North vs South, East vs West, etc.). + /// Used to determine the size of the opposing groups when processing delta pressure entities. + /// + private const int DeltaPressurePairCount = Atmospherics.Directions / 2; + + /// + /// The length to pre-allocate list/dicts of delta pressure entities on a . + /// + public const int DeltaPressurePreAllocateLength = 1000; + + /// + /// Processes a singular entity, determining the pressures it's experiencing and applying damage based on that. + /// + /// The entity to process. + /// The that belongs to the entity's GridUid. + private void ProcessDeltaPressureEntity(Entity ent, GridAtmosphereComponent gridAtmosComp) + { + if (!_random.Prob(ent.Comp.RandomDamageChance)) + return; + + /* + To make our comparisons a little bit faster, we take advantage of SIMD-accelerated methods + in the NumericsHelpers class. + + This involves loading our values into a span in the form of opposing pairs, + so simple vector operations like min/max/abs can be performed on them. + */ + + var tiles = new TileAtmosphere?[Atmospherics.Directions]; + for (var i = 0; i < Atmospherics.Directions; i++) + { + var direction = (AtmosDirection)(1 << i); + var offset = ent.Comp.CurrentPosition.Offset(direction); + tiles[i] = gridAtmosComp.Tiles.GetValueOrDefault(offset); + } + + Span pressures = stackalloc float[Atmospherics.Directions]; + + GetBulkTileAtmospherePressures(tiles, pressures); + + Span opposingGroupA = stackalloc float[DeltaPressurePairCount]; + Span opposingGroupB = stackalloc float[DeltaPressurePairCount]; + Span opposingGroupMax = stackalloc float[DeltaPressurePairCount]; + + // Directions are always in pairs: the number of directions is always even + // (we must consider the future where Multi-Z is real) + // Load values into opposing pairs. + for (var i = 0; i < DeltaPressurePairCount; i++) + { + opposingGroupA[i] = pressures[i]; + opposingGroupB[i] = pressures[i + DeltaPressurePairCount]; + } + + // TODO ATMOS: Needs to be changed to batch operations so that more operations can actually be done in parallel. + + // Need to determine max pressure in opposing directions for absolute pressure calcs. + NumericsHelpers.Max(opposingGroupA, opposingGroupB, opposingGroupMax); + + // Calculate pressure differences between opposing directions. + NumericsHelpers.Sub(opposingGroupA, opposingGroupB); + NumericsHelpers.Abs(opposingGroupA); + + var maxPressure = 0f; + var maxDelta = 0f; + for (var i = 0; i < DeltaPressurePairCount; i++) + { + maxPressure = MathF.Max(maxPressure, opposingGroupMax[i]); + maxDelta = MathF.Max(maxDelta, opposingGroupA[i]); + } + + EnqueueDeltaPressureDamage(ent, + gridAtmosComp, + maxPressure, + maxDelta); + } + + /// + /// A DeltaPressure helper method that retrieves the pressures of all gas mixtures + /// in the given array of s, and stores the results in the + /// provided span. + /// The tiles array length is limited to Atmosphereics.Directions. + /// + /// The tiles array to find the pressures of. + /// The span to store the pressures to - this should be the same length + /// as the tile array. + /// This is for internal use of the DeltaPressure system - + /// it may not be a good idea to use this generically. + private static void GetBulkTileAtmospherePressures(TileAtmosphere?[] tiles, Span pressures) + { + #if DEBUG + // Just in case someone tries to use this method incorrectly. + if (tiles.Length != pressures.Length || tiles.Length != Atmospherics.Directions) + throw new ArgumentException("Length of arrays must be the same and of Atmospherics.Directions length."); + #endif + + // This hardcoded direction limit is stopping goobers from + // overflowing the stack with massive arrays. + // If this method is pulled into a more generic place, + // it should be replaced with method params. + Span mixtVol = stackalloc float[Atmospherics.Directions]; + Span mixtTemp = stackalloc float[Atmospherics.Directions]; + Span mixtMoles = stackalloc float[Atmospherics.Directions]; + Span atmosR = stackalloc float[Atmospherics.Directions]; + + for (var i = 0; i < tiles.Length; i++) + { + if (tiles[i] is not { Air: { } mixture }) + { + pressures[i] = 0f; + + // To prevent any NaN/Div/0 errors, we just bite the bullet + // and set everything to the lowest possible value. + mixtVol[i] = 1; + mixtTemp[i] = 1; + mixtMoles[i] = float.Epsilon; + atmosR[i] = 1; + continue; + } + + mixtVol[i] = mixture.Volume; + mixtTemp[i] = mixture.Temperature; + mixtMoles[i] = mixture.TotalMoles; + atmosR[i] = Atmospherics.R; + } + + /* + Retrieval of single tile pressures requires calling a get method for each tile, + which does a bunch of scalar operations. + + So we go ahead and batch-retrieve the pressures of all tiles + and process them in bulk. + */ + NumericsHelpers.Multiply(mixtMoles, atmosR); + NumericsHelpers.Multiply(mixtMoles, mixtTemp); + NumericsHelpers.Divide(mixtMoles, mixtVol, pressures); + } + + /// + /// Packs data into a data struct and enqueues it + /// into the queue for + /// later processing. + /// + /// The entity to enqueue if necessary. + /// The + /// containing the queue. + /// The current absolute pressure being experienced by the entity. + /// The current delta pressure being experienced by the entity. + private static void EnqueueDeltaPressureDamage(Entity ent, + GridAtmosphereComponent gridAtmosComp, + float pressure, + float delta) + { + var aboveMinPressure = pressure > ent.Comp.MinPressure; + var aboveMinDeltaPressure = delta > ent.Comp.MinPressureDelta; + if (!aboveMinPressure && !aboveMinDeltaPressure) + { + ent.Comp.IsTakingDamage = false; + return; + } + + gridAtmosComp.DeltaPressureDamageResults.Enqueue(new DeltaPressureDamageResult(ent, + pressure, + delta)); + } + + /// + /// Job for solving DeltaPressure entities in parallel. + /// Batches are given some index to start from, so each thread can simply just start at that index + /// and process the next n entities in the list. + /// + /// The AtmosphereSystem instance. + /// The GridAtmosphereComponent to work with. + /// The index in the DeltaPressureEntities list to start from. + /// The batch size to use for this job. + private sealed class DeltaPressureParallelJob( + AtmosphereSystem system, + GridAtmosphereComponent atmosphere, + int startIndex, + int cvarBatchSize) + : IParallelRobustJob + { + public int BatchSize => cvarBatchSize; + + public void Execute(int index) + { + // The index is relative to the startIndex (because we can pause and resume computation), + // so we need to add it to the startIndex. + var actualIndex = startIndex + index; + + if (actualIndex >= atmosphere.DeltaPressureEntities.Count) + return; + + var ent = atmosphere.DeltaPressureEntities[actualIndex]; + system.ProcessDeltaPressureEntity(ent, atmosphere); + } + } + + /// + /// Struct that holds the result of delta pressure damage processing for an entity. + /// This is only created and enqueued when the entity needs to take damage. + /// + /// The entity to deal damage to. + /// The current absolute pressure the entity is experiencing. + /// The current delta pressure the entity is experiencing. + public readonly record struct DeltaPressureDamageResult( + Entity Ent, + float Pressure, + float DeltaPressure); + + /// + /// Does damage to an entity depending on the pressure experienced by it, based on the + /// entity's . + /// + /// The entity to apply damage to. + /// The absolute pressure being exerted on the entity. + /// The delta pressure being exerted on the entity. + private void PerformDamage(Entity ent, float pressure, float deltaPressure) + { + var maxPressure = Math.Max(pressure - ent.Comp.MinPressure, deltaPressure - ent.Comp.MinPressureDelta); + var appliedDamage = ScaleDamage(ent, ent.Comp.BaseDamage, maxPressure); + + _damage.TryChangeDamage(ent, appliedDamage, ignoreResistances: true, interruptsDoAfters: false); + ent.Comp.IsTakingDamage = true; + } + + /// + /// Returns a new DamageSpecifier scaled based on values on an entity with a DeltaPressureComponent. + /// + /// The entity to base the manipulations off of (pull scaling type) + /// The base damage specifier to scale. + /// The pressure being exerted on the entity. + /// A scaled DamageSpecifier. + private static DamageSpecifier ScaleDamage(Entity ent, DamageSpecifier damage, float pressure) + { + var factor = ent.Comp.ScalingType switch + { + DeltaPressureDamageScalingType.Threshold => 1f, + DeltaPressureDamageScalingType.Linear => pressure * ent.Comp.ScalingPower, + DeltaPressureDamageScalingType.Log => + (float) Math.Log(pressure, ent.Comp.ScalingPower), + _ => throw new ArgumentOutOfRangeException(nameof(ent), "Invalid damage scaling type!"), + }; + + return damage * factor; + } +} diff --git a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Processing.cs b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Processing.cs index 02d389b2153..9b8654af6dc 100644 --- a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Processing.cs +++ b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Processing.cs @@ -467,6 +467,66 @@ namespace Content.Server.Atmos.EntitySystems return true; } + /// + /// Processes all entities with a , doing damage to them + /// depending on certain pressure differential conditions. + /// + /// True if we've finished processing all entities that required processing this run, + /// otherwise, false. + private bool ProcessDeltaPressure(Entity ent) + { + var atmosphere = ent.Comp1; + var count = atmosphere.DeltaPressureEntities.Count; + if (!atmosphere.ProcessingPaused) + { + atmosphere.DeltaPressureCursor = 0; + atmosphere.DeltaPressureDamageResults.Clear(); + } + + var remaining = count - atmosphere.DeltaPressureCursor; + var batchSize = Math.Max(50, DeltaPressureParallelProcessPerIteration); + var toProcess = Math.Min(batchSize, remaining); + + var timeCheck1 = 0; + while (atmosphere.DeltaPressureCursor < count) + { + var job = new DeltaPressureParallelJob(this, + atmosphere, + atmosphere.DeltaPressureCursor, + DeltaPressureParallelBatchSize); + _parallel.ProcessNow(job, toProcess); + + atmosphere.DeltaPressureCursor += toProcess; + + if (timeCheck1++ < LagCheckIterations) + continue; + + timeCheck1 = 0; + if (_simulationStopwatch.Elapsed.TotalMilliseconds >= AtmosMaxProcessTime) + return false; + } + + var timeCheck2 = 0; + while (atmosphere.DeltaPressureDamageResults.TryDequeue(out var result)) + { + PerformDamage(result.Ent, + result.Pressure, + result.DeltaPressure); + + if (timeCheck2++ < LagCheckIterations) + continue; + + timeCheck2 = 0; + // Process the rest next time. + if (_simulationStopwatch.Elapsed.TotalMilliseconds >= AtmosMaxProcessTime) + { + return false; + } + } + + return true; + } + private bool ProcessPipeNets(GridAtmosphereComponent atmosphere) { if (!atmosphere.ProcessingPaused) @@ -510,6 +570,8 @@ namespace Content.Server.Atmos.EntitySystems num--; if (!ExcitedGroups) num--; + if (!DeltaPressureDamage) + num--; if (!Superconduction) num--; return num * AtmosTime; @@ -653,6 +715,18 @@ namespace Content.Server.Atmos.EntitySystems return; } + atmosphere.ProcessingPaused = false; + atmosphere.State = DeltaPressureDamage + ? AtmosphereProcessingState.DeltaPressure + : AtmosphereProcessingState.Hotspots; + continue; + case AtmosphereProcessingState.DeltaPressure: + if (!ProcessDeltaPressure(ent)) + { + atmosphere.ProcessingPaused = true; + return; + } + atmosphere.ProcessingPaused = false; atmosphere.State = AtmosphereProcessingState.Hotspots; continue; @@ -721,6 +795,7 @@ namespace Content.Server.Atmos.EntitySystems ActiveTiles, ExcitedGroups, HighPressureDelta, + DeltaPressure, Hotspots, Superconductivity, PipeNet, diff --git a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.cs b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.cs index e9383f3a23a..00b7e169134 100644 --- a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.cs +++ b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.cs @@ -1,6 +1,5 @@ using Content.Server.Administration.Logs; using Content.Server.Atmos.Components; -using Content.Server.Body.Systems; using Content.Server.Fluids.EntitySystems; using Content.Server.NodeContainer.EntitySystems; using Content.Shared.Atmos.EntitySystems; @@ -15,6 +14,8 @@ using Robust.Shared.Map; using Robust.Shared.Physics.Systems; using Robust.Shared.Prototypes; using System.Linq; +using Content.Shared.Damage; +using Robust.Shared.Threading; namespace Content.Server.Atmos.EntitySystems; @@ -27,6 +28,7 @@ public sealed partial class AtmosphereSystem : SharedAtmosphereSystem [Dependency] private readonly IMapManager _mapManager = default!; [Dependency] private readonly ITileDefinitionManager _tileDefinitionManager = default!; [Dependency] private readonly IAdminLogManager _adminLog = default!; + [Dependency] private readonly IParallelManager _parallel = default!; [Dependency] private readonly EntityLookupSystem _lookup = default!; [Dependency] private readonly SharedContainerSystem _containers = default!; [Dependency] private readonly SharedPhysicsSystem _physics = default!; @@ -37,6 +39,7 @@ public sealed partial class AtmosphereSystem : SharedAtmosphereSystem [Dependency] private readonly TileSystem _tile = default!; [Dependency] private readonly MapSystem _map = default!; [Dependency] public readonly PuddleSystem Puddle = default!; + [Dependency] private readonly DamageableSystem _damage = default!; private const float ExposedUpdateDelay = 1f; private float _exposedTimer = 0f; diff --git a/Content.Server/Atmos/EntitySystems/DeltaPressureSystem.cs b/Content.Server/Atmos/EntitySystems/DeltaPressureSystem.cs new file mode 100644 index 00000000000..a6cbec0d0c8 --- /dev/null +++ b/Content.Server/Atmos/EntitySystems/DeltaPressureSystem.cs @@ -0,0 +1,82 @@ +using Content.Server.Atmos.Components; +using Content.Shared.Examine; +using Robust.Shared.Map.Components; + +namespace Content.Server.Atmos.EntitySystems; + +/// +/// System that handles . +/// +/// Entities with a will take damage per atmostick +/// depending on the pressure they experience. +/// +/// DeltaPressure logic is mostly handled in a partial class in Atmospherics. +/// This system handles the adding and removing of entities to a processing list, +/// as well as any field changes via the API. +/// +public sealed class DeltaPressureSystem : EntitySystem +{ + [Dependency] private readonly AtmosphereSystem _atmosphereSystem = default!; + [Dependency] private readonly SharedMapSystem _map = default!; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnComponentInit); + SubscribeLocalEvent(OnComponentShutdown); + SubscribeLocalEvent(OnExamined); + SubscribeLocalEvent(OnMoveEvent); + + SubscribeLocalEvent(OnGridChanged); + } + + private void OnMoveEvent(Entity ent, ref MoveEvent args) + { + var xform = Transform(ent); + // May move off-grid, so, might as well protect against that. + if (!TryComp(xform.GridUid, out var mapGridComponent)) + { + return; + } + + ent.Comp.CurrentPosition = _map.CoordinatesToTile(xform.GridUid.Value, mapGridComponent, args.NewPosition); + } + + private void OnComponentInit(Entity ent, ref ComponentInit args) + { + var xform = Transform(ent); + if (xform.GridUid == null) + return; + + _atmosphereSystem.TryAddDeltaPressureEntity(xform.GridUid.Value, ent); + } + + private void OnComponentShutdown(Entity ent, ref ComponentShutdown args) + { + // Wasn't part of a list, so nothing to clean up. + if (ent.Comp.GridUid == null) + return; + + _atmosphereSystem.TryRemoveDeltaPressureEntity(ent.Comp.GridUid.Value, ent); + } + + private void OnExamined(Entity ent, ref ExaminedEvent args) + { + if (ent.Comp.IsTakingDamage) + args.PushMarkup(Loc.GetString("window-taking-damage")); + } + + private void OnGridChanged(Entity ent, ref GridUidChangedEvent args) + { + if (args.OldGrid != null) + { + _atmosphereSystem.TryRemoveDeltaPressureEntity(args.OldGrid.Value, ent); + } + + if (args.NewGrid != null) + { + _atmosphereSystem.TryAddDeltaPressureEntity(args.NewGrid.Value, ent); + } + } +} diff --git a/Content.Shared/CCVar/CCVars.Atmos.cs b/Content.Shared/CCVar/CCVars.Atmos.cs index cc1069b4fc8..7ef40b7911b 100644 --- a/Content.Shared/CCVar/CCVars.Atmos.cs +++ b/Content.Shared/CCVar/CCVars.Atmos.cs @@ -150,4 +150,31 @@ public sealed partial class CCVars /// public static readonly CVarDef AtmosTankFragment = CVarDef.Create("atmos.max_explosion_range", 26f, CVar.SERVERONLY); + + /// + /// Whether atmospherics will process delta-pressure damage on entities with a DeltaPressureComponent. + /// Entities with this component will take damage if they are exposed to a pressure difference + /// above the minimum pressure threshold defined in the component. + /// + // TODO: Needs CVARs for global configuration, like min pressure, max damage, etc. + public static readonly CVarDef DeltaPressureDamage = + CVarDef.Create("atmos.delta_pressure_damage", true, CVar.SERVERONLY); + + /// + /// Number of entities to submit for parallel processing per processing run. + /// Low numbers may suffer from thinning out the work per job and leading to threads waiting, + /// or seeing a lot of threading overhead. + /// High numbers may cause Atmospherics to exceed its time budget per tick, as it will not + /// check its time often enough to know if it's exceeding it. + /// + public static readonly CVarDef DeltaPressureParallelToProcessPerIteration = + CVarDef.Create("atmos.delta_pressure_parallel_process_per_iteration", 1000, CVar.SERVERONLY); + + /// + /// Number of entities to process per processing job. + /// Low numbers may cause Atmospherics to see high threading overhead, + /// high numbers may cause Atmospherics to distribute the work unevenly. + /// + public static readonly CVarDef DeltaPressureParallelBatchSize = + CVarDef.Create("atmos.delta_pressure_parallel_batch_size", 10, CVar.SERVERONLY); } diff --git a/Resources/Locale/en-US/atmos/delta-pressure-component.ftl b/Resources/Locale/en-US/atmos/delta-pressure-component.ftl new file mode 100644 index 00000000000..f8ffd6d6abf --- /dev/null +++ b/Resources/Locale/en-US/atmos/delta-pressure-component.ftl @@ -0,0 +1 @@ +window-taking-damage = [color=orange]It's straining under pressure![/color] diff --git a/Resources/Maps/Test/Atmospherics/DeltaPressure/deltapressuretest.yml b/Resources/Maps/Test/Atmospherics/DeltaPressure/deltapressuretest.yml new file mode 100644 index 00000000000..cedbfb1cff4 --- /dev/null +++ b/Resources/Maps/Test/Atmospherics/DeltaPressure/deltapressuretest.yml @@ -0,0 +1,234 @@ +meta: + format: 7 + category: Map + engineVersion: 265.0.0 + forkId: "" + forkVersion: "" + time: 08/16/2025 22:09:01 + entityCount: 27 +maps: +- 1 +grids: +- 2 +orphans: [] +nullspace: [] +tilemap: + 1: Space + 0: Plating +entities: +- proto: "" + entities: + - uid: 1 + components: + - type: MetaData + name: Map Entity + - type: Transform + - type: Map + mapPaused: True + - type: GridTree + - type: Broadphase + - type: OccluderTree + - uid: 2 + components: + - type: MetaData + name: grid + - type: Transform + pos: -0.33581543,-0.640625 + parent: 1 + - type: MapGrid + chunks: + 0,0: + ind: 0,0 + tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAA== + version: 7 + 0,-1: + ind: 0,-1 + tiles: AQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAA== + version: 7 + -1,-1: + ind: -1,-1 + tiles: AQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAA== + version: 7 + -1,0: + ind: -1,0 + tiles: AQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAAEAAAAAAAABAAAAAAAAAQAAAAAAAA== + version: 7 + - type: Broadphase + - type: Physics + bodyStatus: InAir + fixedRotation: False + bodyType: Dynamic + - type: Fixtures + fixtures: {} + - type: OccluderTree + - type: SpreaderGrid + - type: Shuttle + dampingModifier: 0.25 + - type: ImplicitRoof + - type: GridPathfinding + - type: Gravity + gravityShakeSound: !type:SoundPathSpecifier + path: /Audio/Effects/alert.ogg + - type: DecalGrid + chunkCollection: + version: 2 + nodes: [] + - type: GridAtmosphere + version: 2 + data: + tiles: + 0,0: + 0: 19 + 0,-1: + 0: 4096 + -1,0: + 0: 8 + uniqueMixes: + - volume: 2500 + temperature: 293.15 + moles: + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + chunkSize: 4 + - type: GasTileOverlay + - type: RadiationGridResistance +- proto: AtmosFixBlockerMarker + entities: + - uid: 23 + components: + - type: Transform + pos: 0.5,1.5 + parent: 2 + - uid: 24 + components: + - type: Transform + pos: 0.5,0.5 + parent: 2 + - uid: 25 + components: + - type: Transform + pos: 0.5,-0.5 + parent: 2 + - uid: 26 + components: + - type: Transform + pos: -0.5,0.5 + parent: 2 + - uid: 27 + components: + - type: Transform + pos: 1.5,0.5 + parent: 2 +- proto: WallPlastitaniumIndestructible + entities: + - uid: 3 + components: + - type: Transform + pos: -1.5,2.5 + parent: 2 + - uid: 4 + components: + - type: Transform + pos: -0.5,2.5 + parent: 2 + - uid: 5 + components: + - type: Transform + pos: 0.5,2.5 + parent: 2 + - uid: 6 + components: + - type: Transform + pos: 1.5,2.5 + parent: 2 + - uid: 7 + components: + - type: Transform + pos: 2.5,2.5 + parent: 2 + - uid: 8 + components: + - type: Transform + pos: 2.5,1.5 + parent: 2 + - uid: 9 + components: + - type: Transform + pos: 2.5,0.5 + parent: 2 + - uid: 10 + components: + - type: Transform + pos: 2.5,-0.5 + parent: 2 + - uid: 11 + components: + - type: Transform + pos: 2.5,-1.5 + parent: 2 + - uid: 12 + components: + - type: Transform + pos: 1.5,-1.5 + parent: 2 + - uid: 13 + components: + - type: Transform + pos: 0.5,-1.5 + parent: 2 + - uid: 14 + components: + - type: Transform + pos: -0.5,-1.5 + parent: 2 + - uid: 15 + components: + - type: Transform + pos: -1.5,-1.5 + parent: 2 + - uid: 16 + components: + - type: Transform + pos: -1.5,-0.5 + parent: 2 + - uid: 17 + components: + - type: Transform + pos: -1.5,0.5 + parent: 2 + - uid: 18 + components: + - type: Transform + pos: -1.5,1.5 + parent: 2 + - uid: 19 + components: + - type: Transform + pos: -0.5,1.5 + parent: 2 + - uid: 20 + components: + - type: Transform + pos: 1.5,1.5 + parent: 2 + - uid: 21 + components: + - type: Transform + pos: 1.5,-0.5 + parent: 2 + - uid: 22 + components: + - type: Transform + pos: -0.5,-0.5 + parent: 2 +... diff --git a/Resources/Prototypes/Entities/Structures/Doors/Windoors/base_structurewindoors.yml b/Resources/Prototypes/Entities/Structures/Doors/Windoors/base_structurewindoors.yml index 991b999273f..03af7ea13fe 100644 --- a/Resources/Prototypes/Entities/Structures/Doors/Windoors/base_structurewindoors.yml +++ b/Resources/Prototypes/Entities/Structures/Doors/Windoors/base_structurewindoors.yml @@ -163,6 +163,10 @@ noAirWhenFullyAirBlocked: false airBlockedDirection: - South + - type: DeltaPressure + minPressure: 250 + minPressureDelta: 187.5 + scalingType: Threshold - type: Construction graph: Windoor node: windoor @@ -235,6 +239,10 @@ - type: Construction graph: Windoor node: windoorSecure + - type: DeltaPressure + minPressure: 3750 + minPressureDelta: 2500 + scalingType: Threshold - type: StaticPrice price: 350 - type: Tag @@ -304,6 +312,10 @@ - type: Construction graph: Windoor node: pwindoor + - type: DeltaPressure + minPressure: 18750 + minPressureDelta: 12500 + scalingType: Threshold - type: StaticPrice price: 500 - type: RadiationBlocker @@ -370,6 +382,10 @@ - type: Construction graph: Windoor node: pwindoorSecure + - type: DeltaPressure + minPressure: 37500 + minPressureDelta: 25000 + scalingType: Threshold - type: StaticPrice price: 500 - type: RadiationBlocker @@ -438,6 +454,10 @@ max: 2 - !type:DoActsBehavior acts: [ "Destruction" ] + - type: DeltaPressure + minPressure: 18750 + minPressureDelta: 12500 + scalingType: Threshold - type: Construction graph: Windoor node: uwindoor @@ -504,6 +524,10 @@ max: 2 - !type:DoActsBehavior acts: [ "Destruction" ] + - type: DeltaPressure + minPressure: 37500 + minPressureDelta: 25000 + scalingType: Threshold - type: Construction graph: Windoor node: uwindoorSecure diff --git a/Resources/Prototypes/Entities/Structures/Windows/plasma.yml b/Resources/Prototypes/Entities/Structures/Windows/plasma.yml index 25361d7ce0a..ccbdee804e1 100644 --- a/Resources/Prototypes/Entities/Structures/Windows/plasma.yml +++ b/Resources/Prototypes/Entities/Structures/Windows/plasma.yml @@ -48,6 +48,11 @@ trackAllDamage: true damageOverlay: sprite: Structures/Windows/cracks.rsi + - type: DeltaPressure + minPressure: 75000 + minPressureDelta: 50000 + scalingType: Linear + scalingPower: 0.0005 - type: StaticPrice price: 100 - type: RadiationBlocker @@ -106,6 +111,10 @@ max: 1 - !type:DoActsBehavior acts: [ "Destruction" ] + - type: DeltaPressure + minPressure: 18750 + minPressureDelta: 12500 + scalingType: Threshold - type: StaticPrice price: 50 - type: RadiationBlocker diff --git a/Resources/Prototypes/Entities/Structures/Windows/reinforced.yml b/Resources/Prototypes/Entities/Structures/Windows/reinforced.yml index ec2e7933ad2..38adfaf8a93 100644 --- a/Resources/Prototypes/Entities/Structures/Windows/reinforced.yml +++ b/Resources/Prototypes/Entities/Structures/Windows/reinforced.yml @@ -57,6 +57,10 @@ sprite: Structures/Windows/cracks.rsi - type: CosmicCorruptible # DeltaV - Cosmic Cult convertTo: WindowCosmicCult + - type: DeltaPressure + minPressure: 15000 + minPressureDelta: 10000 + scalingType: Threshold - type: entity id: WindowReinforcedDirectional @@ -115,6 +119,9 @@ max: 1 - !type:DoActsBehavior acts: [ "Destruction" ] + - type: DeltaPressure + minPressure: 3750 + minPressureDelta: 2500 - type: StaticPrice price: 22.5 diff --git a/Resources/Prototypes/Entities/Structures/Windows/rplasma.yml b/Resources/Prototypes/Entities/Structures/Windows/rplasma.yml index eb541305d0e..8f51e0c0bc4 100644 --- a/Resources/Prototypes/Entities/Structures/Windows/rplasma.yml +++ b/Resources/Prototypes/Entities/Structures/Windows/rplasma.yml @@ -53,6 +53,11 @@ trackAllDamage: true damageOverlay: sprite: Structures/Windows/cracks.rsi + - type: DeltaPressure + minPressure: 150000 + minPressureDelta: 100000 + scalingType: Linear + scalingPower: 0.0001 - type: StaticPrice price: 132 @@ -109,6 +114,10 @@ max: 1 - !type:DoActsBehavior acts: [ "Destruction" ] + - type: DeltaPressure + minPressure: 37500 + minPressureDelta: 25000 + scalingType: Threshold - type: StaticPrice price: 66 - type: CosmicCorruptible # DeltaV - Cosmic Cult diff --git a/Resources/Prototypes/Entities/Structures/Windows/ruranium.yml b/Resources/Prototypes/Entities/Structures/Windows/ruranium.yml index 404ae6fd4d2..7cf5e03caa6 100644 --- a/Resources/Prototypes/Entities/Structures/Windows/ruranium.yml +++ b/Resources/Prototypes/Entities/Structures/Windows/ruranium.yml @@ -48,6 +48,11 @@ trackAllDamage: true damageOverlay: sprite: Structures/Windows/cracks.rsi + - type: DeltaPressure + minPressure: 150000 + minPressureDelta: 100000 + scalingType: Linear + scalingPower: 0.0001 - type: StaticPrice price: 215 - type: RadiationBlocker @@ -106,6 +111,10 @@ max: 2 - !type:DoActsBehavior acts: [ "Destruction" ] + - type: DeltaPressure + minPressure: 37500 + minPressureDelta: 25000 + scalingType: Threshold - type: StaticPrice price: 110 - type: RadiationBlocker diff --git a/Resources/Prototypes/Entities/Structures/Windows/shuttle.yml b/Resources/Prototypes/Entities/Structures/Windows/shuttle.yml index 45eef726397..d635ff04864 100644 --- a/Resources/Prototypes/Entities/Structures/Windows/shuttle.yml +++ b/Resources/Prototypes/Entities/Structures/Windows/shuttle.yml @@ -51,6 +51,11 @@ trackAllDamage: true damageOverlay: sprite: Structures/Windows/cracks.rsi + - type: DeltaPressure + minPressure: 15000 + minPressureDelta: 10000 + scalingType: Linear + scalingPower: 0.0005 - type: StaticPrice price: 150 - type: CosmicCorruptible # DeltaV - Cosmic Cult diff --git a/Resources/Prototypes/Entities/Structures/Windows/uranium.yml b/Resources/Prototypes/Entities/Structures/Windows/uranium.yml index d1621f9572c..3f81d9dc0a6 100644 --- a/Resources/Prototypes/Entities/Structures/Windows/uranium.yml +++ b/Resources/Prototypes/Entities/Structures/Windows/uranium.yml @@ -46,6 +46,11 @@ trackAllDamage: true damageOverlay: sprite: Structures/Windows/cracks.rsi + - type: DeltaPressure + minPressure: 75000 + minPressureDelta: 50000 + scalingType: Linear + scalingPower: 0.0005 - type: StaticPrice price: 200 - type: RadiationBlocker @@ -101,6 +106,10 @@ max: 1 - !type:DoActsBehavior acts: [ "Destruction" ] + - type: DeltaPressure + minPressure: 18750 + minPressureDelta: 12500 + scalingType: Threshold - type: StaticPrice price: 100 - type: RadiationBlocker diff --git a/Resources/Prototypes/Entities/Structures/Windows/window.yml b/Resources/Prototypes/Entities/Structures/Windows/window.yml index 59facb454e0..6c729076dd8 100644 --- a/Resources/Prototypes/Entities/Structures/Windows/window.yml +++ b/Resources/Prototypes/Entities/Structures/Windows/window.yml @@ -75,6 +75,11 @@ - !type:DoActsBehavior acts: [ "Destruction" ] - type: Airtight + - type: DeltaPressure + minPressure: 1000 + minPressureDelta: 750 + scalingType: Linear + scalingPower: 0.0005 - type: IconSmooth key: walls # Delta V - Make windows iconsmooth with walls base: window @@ -209,6 +214,10 @@ noAirWhenFullyAirBlocked: false airBlockedDirection: - South + - type: DeltaPressure + minPressure: 250 + minPressureDelta: 187.5 + scalingType: Threshold - type: Construction graph: WindowDirectional node: windowDirectional From f5e1f62d4d5dcfd491564fe60fdc726f75136fa7 Mon Sep 17 00:00:00 2001 From: Kyle Tyo <36606155+VerinSenpai@users.noreply.github.com> Date: Wed, 3 Sep 2025 16:16:43 -0400 Subject: [PATCH 315/340] Cleanup AddPolymorphActionCommand and LEC conversion. (#38853) commit --- .../Commands/AddPolymorphActionCommand.cs | 22 +++++++------------ .../commands/polymorph-command.ftl | 8 ------- .../commands/addpolymorphaction-command.ftl | 2 ++ 3 files changed, 10 insertions(+), 22 deletions(-) delete mode 100644 Resources/Locale/en-US/administration/commands/polymorph-command.ftl create mode 100644 Resources/Locale/en-US/commands/addpolymorphaction-command.ftl diff --git a/Content.Server/Administration/Commands/AddPolymorphActionCommand.cs b/Content.Server/Administration/Commands/AddPolymorphActionCommand.cs index b92cbfc0de9..f089268beae 100644 --- a/Content.Server/Administration/Commands/AddPolymorphActionCommand.cs +++ b/Content.Server/Administration/Commands/AddPolymorphActionCommand.cs @@ -6,17 +6,13 @@ using Robust.Shared.Console; namespace Content.Server.Administration.Commands; [AdminCommand(AdminFlags.Fun)] -public sealed class AddPolymorphActionCommand : IConsoleCommand +public sealed class AddPolymorphActionCommand : LocalizedEntityCommands { - [Dependency] private readonly IEntityManager _entityManager = default!; + [Dependency] private readonly PolymorphSystem _polySystem = default!; - public string Command => "addpolymorphaction"; + public override string Command => "addpolymorphaction"; - public string Description => Loc.GetString("add-polymorph-action-command-description"); - - public string Help => Loc.GetString("add-polymorph-action-command-help-text"); - - public void Execute(IConsoleShell shell, string argStr, string[] args) + public override void Execute(IConsoleShell shell, string argStr, string[] args) { if (args.Length != 2) { @@ -24,15 +20,13 @@ public sealed class AddPolymorphActionCommand : IConsoleCommand return; } - if (!NetEntity.TryParse(args[0], out var entityUidNet) || !_entityManager.TryGetEntity(entityUidNet, out var entityUid)) + if (!NetEntity.TryParse(args[0], out var entityUidNet) || !EntityManager.TryGetEntity(entityUidNet, out var entityUid)) { - shell.WriteError(Loc.GetString("shell-entity-uid-must-be-number")); + shell.WriteError(Loc.GetString("shell-could-not-find-entity-with-uid", ("uid", args[0]))); return; } - var polySystem = _entityManager.EntitySysManager.GetEntitySystem(); - - var polymorphable = _entityManager.EnsureComponent(entityUid.Value); - polySystem.CreatePolymorphAction(args[1], (entityUid.Value, polymorphable)); + var polymorphable = EntityManager.EnsureComponent(entityUid.Value); + _polySystem.CreatePolymorphAction(args[1], (entityUid.Value, polymorphable)); } } diff --git a/Resources/Locale/en-US/administration/commands/polymorph-command.ftl b/Resources/Locale/en-US/administration/commands/polymorph-command.ftl deleted file mode 100644 index ef7d1b744da..00000000000 --- a/Resources/Locale/en-US/administration/commands/polymorph-command.ftl +++ /dev/null @@ -1,8 +0,0 @@ -polymorph-command-description = For when you need someone to stop being a person. Takes an entity and a polymorph prototype. -polymorph-command-help-text = polymorph - -add-polymorph-action-command-description = Takes an entity and gives them a voluntary polymorph. -add-polymorph-action-command-help-text = addpolymorphaction - - -polymorph-not-valid-prototype-error = Polymorph prototype is not valid. \ No newline at end of file diff --git a/Resources/Locale/en-US/commands/addpolymorphaction-command.ftl b/Resources/Locale/en-US/commands/addpolymorphaction-command.ftl new file mode 100644 index 00000000000..72f2158273d --- /dev/null +++ b/Resources/Locale/en-US/commands/addpolymorphaction-command.ftl @@ -0,0 +1,2 @@ +cmd-addpolymorphaction-desc = Takes an entity and gives them a voluntary polymorph. +cmd-addpolymorphaction-help = Usage: addpolymorphaction From 5828a77370127efe49f6510169d023011deab664 Mon Sep 17 00:00:00 2001 From: Tiniest Shark Date: Wed, 3 Sep 2025 12:45:18 -0400 Subject: [PATCH 316/340] Helm + Mask Displacements for Reptilians (and some unique helmets) (#39351) * Liz displacements + unique helms * small fix * Couple of small fixes --- .../Clothing/Head/hardsuit-helmets.yml | 46 ++++++++++++++++++ .../Entities/Mobs/Species/reptilian.yml | 44 ++++++++++++++++- .../ERThelmets/ertengineer.rsi/meta.json | 10 +++- .../off-equipped-HELMET-reptilian.png | Bin 0 -> 1081 bytes .../on-equipped-HELMET-reptilian.png | Bin 0 -> 1719 bytes .../ERThelmets/ertjanitor.rsi/meta.json | 10 +++- .../off-equipped-HELMET-reptilian.png | Bin 0 -> 1098 bytes .../on-equipped-HELMET-reptilian.png | Bin 0 -> 1813 bytes .../ERThelmets/ertleader.rsi/meta.json | 10 +++- .../off-equipped-HELMET-reptilian.png | Bin 0 -> 1262 bytes .../on-equipped-HELMET-reptilian.png | Bin 0 -> 1802 bytes .../ERThelmets/ertmedical.rsi/meta.json | 10 +++- .../off-equipped-HELMET-reptilian.png | Bin 0 -> 1038 bytes .../on-equipped-HELMET-reptilian.png | Bin 0 -> 1710 bytes .../ERThelmets/ertsecurity.rsi/meta.json | 10 +++- .../off-equipped-HELMET-reptilian.png | Bin 0 -> 1035 bytes .../on-equipped-HELMET-reptilian.png | Bin 0 -> 1702 bytes .../equipped-head-light-reptilian.png | Bin 0 -> 1381 bytes .../equipped-head-reptilian.png | Bin 0 -> 942 bytes .../equipped-head-unshaded-reptilian.png | Bin 0 -> 195 bytes .../Head/Hardsuits/atmospherics.rsi/meta.json | 14 +++++- .../Head/Hardsuits/capspace.rsi/meta.json | 10 +++- .../off-equipped-HELMET-reptilian.png | Bin 0 -> 1127 bytes .../on-equipped-HELMET-reptilian.png | Bin 0 -> 1270 bytes .../cburn.rsi/equipped-head-reptilian.png | Bin 0 -> 657 bytes .../equipped-head-unshaded-reptilian.png | Bin 0 -> 173 bytes .../Head/Hardsuits/cburn.rsi/meta.json | 10 +++- .../Head/Hardsuits/clown.rsi/meta.json | 10 +++- .../off-equipped-HELMET-reptilian.png | Bin 0 -> 950 bytes .../on-equipped-HELMET-reptilian.png | Bin 0 -> 1135 bytes .../equipped-HELMET-reptilian.png | Bin 0 -> 532 bytes .../Head/Hardsuits/cybersun.rsi/meta.json | 6 ++- .../equipped-head-light-reptilian.png | Bin 0 -> 1356 bytes .../equipped-head-reptilian.png | Bin 0 -> 1180 bytes .../equipped-head-unshaded-reptilian.png | Bin 0 -> 189 bytes .../Hardsuits/engineering-white.rsi/meta.json | 14 +++++- .../equipped-head-light-reptilian.png | Bin 0 -> 1343 bytes .../equipped-head-reptilian.png | Bin 0 -> 1223 bytes .../equipped-head-unshaded-reptilian.png | Bin 0 -> 188 bytes .../Head/Hardsuits/engineering.rsi/meta.json | 14 +++++- .../equipped-head-light-reptilian.png | Bin 0 -> 753 bytes .../equipped-head-reptilian.png | Bin 0 -> 986 bytes .../equipped-head-unshaded-reptilian.png | Bin 0 -> 130 bytes .../Head/Hardsuits/goliathhelm.rsi/meta.json | 15 +++++- .../Head/Hardsuits/luxury.rsi/meta.json | 10 +++- .../off-equipped-HELMET-reptilian.png | Bin 0 -> 1060 bytes .../on-equipped-HELMET-reptilian.png | Bin 0 -> 1376 bytes .../maxim.rsi/equipped-HELMET-reptilian.png | Bin 0 -> 1111 bytes .../Head/Hardsuits/maxim.rsi/meta.json | 8 ++- .../equipped-HELMET-light-reptilian.png | Bin 0 -> 698 bytes .../equipped-HELMET-reptilian.png | Bin 0 -> 1262 bytes .../equipped-HELMET-unshaded-reptilian.png | Bin 0 -> 294 bytes .../Hardsuits/piratecaptainhelm.rsi/meta.json | 14 +++++- .../Clothing/Head/Hardsuits/rd.rsi/meta.json | 10 +++- .../rd.rsi/off-equipped-HELMET-reptilian.png | Bin 0 -> 870 bytes .../rd.rsi/on-equipped-HELMET-reptilian.png | Bin 0 -> 1218 bytes .../Head/Hardsuits/salvage.rsi/meta.json | 10 +++- .../off-equipped-HELMET-reptilian.png | Bin 0 -> 1139 bytes .../on-equipped-HELMET-reptilian.png | Bin 0 -> 1479 bytes .../Head/Hardsuits/security-red.rsi/meta.json | 10 +++- .../off-equipped-HELMET-reptilian.png | Bin 0 -> 1027 bytes .../on-equipped-HELMET-reptilian.png | Bin 0 -> 1476 bytes .../Hardsuits/security-warden.rsi/meta.json | 10 +++- .../off-equipped-HELMET-reptilian.png | Bin 0 -> 760 bytes .../on-equipped-HELMET-reptilian.png | Bin 0 -> 827 bytes .../Head/Hardsuits/security.rsi/meta.json | 10 +++- .../off-equipped-HELMET-reptilian.png | Bin 0 -> 817 bytes .../on-equipped-HELMET-reptilian.png | Bin 0 -> 887 bytes .../equipped-head-light-reptilian.png | Bin 0 -> 1414 bytes .../equipped-head-reptilian.png | Bin 0 -> 767 bytes .../equipped-head-unshaded-reptilian.png | Bin 0 -> 129 bytes .../Head/Hardsuits/spatiohelm.rsi/meta.json | 14 +++++- .../Head/Hardsuits/syndicate.rsi/meta.json | 10 +++- .../off-equipped-HELMET-reptilian.png | Bin 0 -> 1137 bytes .../on-equipped-HELMET-reptilian.png | Bin 0 -> 1737 bytes .../Hardsuits/syndiecommander.rsi/meta.json | 11 ++++- .../off-equipped-HELMET-reptilian.png | Bin 0 -> 928 bytes .../on-equipped-HELMET-reptilian.png | Bin 0 -> 1148 bytes .../Head/Hardsuits/syndieelite.rsi/meta.json | 11 ++++- .../off-equipped-HELMET-reptilian.png | Bin 0 -> 829 bytes .../on-equipped-HELMET-reptilian.png | Bin 0 -> 1660 bytes .../Head/Hardsuits/syndiemedic.rsi/meta.json | 10 +++- .../off-equipped-HELMET-reptilian.png | Bin 0 -> 1152 bytes .../on-equipped-HELMET-reptilian.png | Bin 0 -> 1765 bytes .../eva.rsi/equipped-HELMET-reptilian.png | Bin 0 -> 1022 bytes .../Clothing/Head/Helmets/eva.rsi/meta.json | 6 ++- .../equipped-HELMET-reptilian.png | Bin 0 -> 1020 bytes .../Head/Helmets/eva_large.rsi/meta.json | 6 ++- .../equipped-HELMET-reptilian.png | Bin 0 -> 1108 bytes .../Head/Helmets/eva_syndicate.rsi/meta.json | 6 ++- .../equipped-HELMET-reptilian.png | Bin 0 -> 722 bytes .../Head/Helmets/spaceninja.rsi/meta.json | 6 ++- .../equipped-MASK-reptilian.png | Bin 0 -> 387 bytes .../Clothing/Mask/goldenmask.rsi/meta.json | 6 ++- .../equipped-MASK-reptilian.png | Bin 0 -> 184 bytes .../Mask/italian_moustache.rsi/meta.json | 4 ++ .../Reptilian/displacement.rsi/head.png | Bin 0 -> 259 bytes .../displacement.rsi/jumpsuit-female.png | Bin 0 -> 275 bytes .../Reptilian/displacement.rsi/mask.png | Bin 0 -> 245 bytes .../Reptilian/displacement.rsi/meta.json | 26 ++++++++++ 100 files changed, 396 insertions(+), 35 deletions(-) create mode 100644 Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertengineer.rsi/off-equipped-HELMET-reptilian.png create mode 100644 Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertengineer.rsi/on-equipped-HELMET-reptilian.png create mode 100644 Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertjanitor.rsi/off-equipped-HELMET-reptilian.png create mode 100644 Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertjanitor.rsi/on-equipped-HELMET-reptilian.png create mode 100644 Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertleader.rsi/off-equipped-HELMET-reptilian.png create mode 100644 Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertleader.rsi/on-equipped-HELMET-reptilian.png create mode 100644 Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertmedical.rsi/off-equipped-HELMET-reptilian.png create mode 100644 Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertmedical.rsi/on-equipped-HELMET-reptilian.png create mode 100644 Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertsecurity.rsi/off-equipped-HELMET-reptilian.png create mode 100644 Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertsecurity.rsi/on-equipped-HELMET-reptilian.png create mode 100644 Resources/Textures/Clothing/Head/Hardsuits/atmospherics.rsi/equipped-head-light-reptilian.png create mode 100644 Resources/Textures/Clothing/Head/Hardsuits/atmospherics.rsi/equipped-head-reptilian.png create mode 100644 Resources/Textures/Clothing/Head/Hardsuits/atmospherics.rsi/equipped-head-unshaded-reptilian.png create mode 100644 Resources/Textures/Clothing/Head/Hardsuits/capspace.rsi/off-equipped-HELMET-reptilian.png create mode 100644 Resources/Textures/Clothing/Head/Hardsuits/capspace.rsi/on-equipped-HELMET-reptilian.png create mode 100644 Resources/Textures/Clothing/Head/Hardsuits/cburn.rsi/equipped-head-reptilian.png create mode 100644 Resources/Textures/Clothing/Head/Hardsuits/cburn.rsi/equipped-head-unshaded-reptilian.png create mode 100644 Resources/Textures/Clothing/Head/Hardsuits/clown.rsi/off-equipped-HELMET-reptilian.png create mode 100644 Resources/Textures/Clothing/Head/Hardsuits/clown.rsi/on-equipped-HELMET-reptilian.png create mode 100644 Resources/Textures/Clothing/Head/Hardsuits/cybersun.rsi/equipped-HELMET-reptilian.png create mode 100644 Resources/Textures/Clothing/Head/Hardsuits/engineering-white.rsi/equipped-head-light-reptilian.png create mode 100644 Resources/Textures/Clothing/Head/Hardsuits/engineering-white.rsi/equipped-head-reptilian.png create mode 100644 Resources/Textures/Clothing/Head/Hardsuits/engineering-white.rsi/equipped-head-unshaded-reptilian.png create mode 100644 Resources/Textures/Clothing/Head/Hardsuits/engineering.rsi/equipped-head-light-reptilian.png create mode 100644 Resources/Textures/Clothing/Head/Hardsuits/engineering.rsi/equipped-head-reptilian.png create mode 100644 Resources/Textures/Clothing/Head/Hardsuits/engineering.rsi/equipped-head-unshaded-reptilian.png create mode 100644 Resources/Textures/Clothing/Head/Hardsuits/goliathhelm.rsi/equipped-head-light-reptilian.png create mode 100644 Resources/Textures/Clothing/Head/Hardsuits/goliathhelm.rsi/equipped-head-reptilian.png create mode 100644 Resources/Textures/Clothing/Head/Hardsuits/goliathhelm.rsi/equipped-head-unshaded-reptilian.png create mode 100644 Resources/Textures/Clothing/Head/Hardsuits/luxury.rsi/off-equipped-HELMET-reptilian.png create mode 100644 Resources/Textures/Clothing/Head/Hardsuits/luxury.rsi/on-equipped-HELMET-reptilian.png create mode 100644 Resources/Textures/Clothing/Head/Hardsuits/maxim.rsi/equipped-HELMET-reptilian.png create mode 100644 Resources/Textures/Clothing/Head/Hardsuits/piratecaptainhelm.rsi/equipped-HELMET-light-reptilian.png create mode 100644 Resources/Textures/Clothing/Head/Hardsuits/piratecaptainhelm.rsi/equipped-HELMET-reptilian.png create mode 100644 Resources/Textures/Clothing/Head/Hardsuits/piratecaptainhelm.rsi/equipped-HELMET-unshaded-reptilian.png create mode 100644 Resources/Textures/Clothing/Head/Hardsuits/rd.rsi/off-equipped-HELMET-reptilian.png create mode 100644 Resources/Textures/Clothing/Head/Hardsuits/rd.rsi/on-equipped-HELMET-reptilian.png create mode 100644 Resources/Textures/Clothing/Head/Hardsuits/salvage.rsi/off-equipped-HELMET-reptilian.png create mode 100644 Resources/Textures/Clothing/Head/Hardsuits/salvage.rsi/on-equipped-HELMET-reptilian.png create mode 100644 Resources/Textures/Clothing/Head/Hardsuits/security-red.rsi/off-equipped-HELMET-reptilian.png create mode 100644 Resources/Textures/Clothing/Head/Hardsuits/security-red.rsi/on-equipped-HELMET-reptilian.png create mode 100644 Resources/Textures/Clothing/Head/Hardsuits/security-warden.rsi/off-equipped-HELMET-reptilian.png create mode 100644 Resources/Textures/Clothing/Head/Hardsuits/security-warden.rsi/on-equipped-HELMET-reptilian.png create mode 100644 Resources/Textures/Clothing/Head/Hardsuits/security.rsi/off-equipped-HELMET-reptilian.png create mode 100644 Resources/Textures/Clothing/Head/Hardsuits/security.rsi/on-equipped-HELMET-reptilian.png create mode 100644 Resources/Textures/Clothing/Head/Hardsuits/spatiohelm.rsi/equipped-head-light-reptilian.png create mode 100644 Resources/Textures/Clothing/Head/Hardsuits/spatiohelm.rsi/equipped-head-reptilian.png create mode 100644 Resources/Textures/Clothing/Head/Hardsuits/spatiohelm.rsi/equipped-head-unshaded-reptilian.png create mode 100644 Resources/Textures/Clothing/Head/Hardsuits/syndicate.rsi/off-equipped-HELMET-reptilian.png create mode 100644 Resources/Textures/Clothing/Head/Hardsuits/syndicate.rsi/on-equipped-HELMET-reptilian.png create mode 100644 Resources/Textures/Clothing/Head/Hardsuits/syndiecommander.rsi/off-equipped-HELMET-reptilian.png create mode 100644 Resources/Textures/Clothing/Head/Hardsuits/syndiecommander.rsi/on-equipped-HELMET-reptilian.png create mode 100644 Resources/Textures/Clothing/Head/Hardsuits/syndieelite.rsi/off-equipped-HELMET-reptilian.png create mode 100644 Resources/Textures/Clothing/Head/Hardsuits/syndieelite.rsi/on-equipped-HELMET-reptilian.png create mode 100644 Resources/Textures/Clothing/Head/Hardsuits/syndiemedic.rsi/off-equipped-HELMET-reptilian.png create mode 100644 Resources/Textures/Clothing/Head/Hardsuits/syndiemedic.rsi/on-equipped-HELMET-reptilian.png create mode 100644 Resources/Textures/Clothing/Head/Helmets/eva.rsi/equipped-HELMET-reptilian.png create mode 100644 Resources/Textures/Clothing/Head/Helmets/eva_large.rsi/equipped-HELMET-reptilian.png create mode 100644 Resources/Textures/Clothing/Head/Helmets/eva_syndicate.rsi/equipped-HELMET-reptilian.png create mode 100644 Resources/Textures/Clothing/Head/Helmets/spaceninja.rsi/equipped-HELMET-reptilian.png create mode 100644 Resources/Textures/Clothing/Mask/goldenmask.rsi/equipped-MASK-reptilian.png create mode 100644 Resources/Textures/Clothing/Mask/italian_moustache.rsi/equipped-MASK-reptilian.png create mode 100644 Resources/Textures/Mobs/Species/Reptilian/displacement.rsi/head.png create mode 100644 Resources/Textures/Mobs/Species/Reptilian/displacement.rsi/jumpsuit-female.png create mode 100644 Resources/Textures/Mobs/Species/Reptilian/displacement.rsi/mask.png create mode 100644 Resources/Textures/Mobs/Species/Reptilian/displacement.rsi/meta.json diff --git a/Resources/Prototypes/Entities/Clothing/Head/hardsuit-helmets.yml b/Resources/Prototypes/Entities/Clothing/Head/hardsuit-helmets.yml index 8384fe8863e..53d9dec7903 100644 --- a/Resources/Prototypes/Entities/Clothing/Head/hardsuit-helmets.yml +++ b/Resources/Prototypes/Entities/Clothing/Head/hardsuit-helmets.yml @@ -33,6 +33,9 @@ head-vox: - state: equipped-head-light-vox shader: unshaded + head-reptilian: + - state: equipped-head-light-reptilian + shader: unshaded head-dog: - state: equipped-head-light-dog shader: unshaded @@ -46,6 +49,10 @@ - state: equipped-head-vox - state: equipped-head-unshaded-vox shader: unshaded + head-reptilian: + - state: equipped-head-reptilian + - state: equipped-head-unshaded-reptilian + shader: unshaded # Begin DeltaV species helmets head-vulpkanin: - state: equipped-head-vulpkanin @@ -107,6 +114,9 @@ head-vox: - state: equipped-head-light-vox shader: unshaded + head-reptilian: + - state: equipped-head-light-reptilian + shader: unshaded head-dog: - state: equipped-head-light-dog shader: unshaded @@ -128,6 +138,10 @@ - state: equipped-head-vox - state: equipped-head-unshaded-vox shader: unshaded + head-reptilian: + - state: equipped-head-reptilian + - state: equipped-head-unshaded-reptilian + shader: unshaded # Begin DeltaV species helmets head-vulpkanin: - state: equipped-head-vulpkanin @@ -179,6 +193,9 @@ head-vox: - state: equipped-head-light-vox shader: unshaded + head-reptilian: + - state: equipped-head-light-reptilian + shader: unshaded head-dog: - state: equipped-head-light-dog shader: unshaded @@ -192,6 +209,10 @@ - state: equipped-head-vox - state: equipped-head-unshaded-vox shader: unshaded + head-reptilian: + - state: equipped-head-reptilian + - state: equipped-head-unshaded-reptilian + shader: unshaded # Begin DeltaV species helmets head-vulpkanin: - state: equipped-head-vulpkanin @@ -265,6 +286,9 @@ head-vox: - state: equipped-head-light-vox shader: unshaded + head-reptilian: + - state: equipped-head-reptilian + shader: unshaded head-dog: - state: equipped-head-light-dog shader: unshaded @@ -278,6 +302,10 @@ - state: equipped-head-vox - state: equipped-head-unshaded-vox shader: unshaded + head-reptilian: + - state: equipped-head-reptilian + - state: equipped-head-unshaded-reptilian + shader: unshaded head-dog: - state: equipped-head-dog - state: equipped-head-unshaded-dog @@ -440,6 +468,9 @@ head-vox: - state: equipped-head-light-vox shader: unshaded + head-reptilian: + - state: equipped-head-light-reptilian + shader: unshaded # Begin DeltaV species helmets head-vulpkanin: - state: equipped-head-light-vulpkanin @@ -464,6 +495,10 @@ - state: equipped-head-vox - state: equipped-head-unshaded-vox shader: unshaded + head-reptilian: + - state: equipped-head-reptilian + - state: equipped-head-unshaded-reptilian + shader: unshaded head-dog: - state: equipped-head-dog - state: equipped-head-unshaded-dog @@ -798,6 +833,9 @@ head-vox: - state: equipped-HELMET-light-vox shader: unshaded + head-reptilian: + - state: equipped-HELMET-light-reptilian + shader: unshaded - type: Clothing sprite: Clothing/Head/Hardsuits/piratecaptainhelm.rsi clothingVisuals: @@ -809,6 +847,10 @@ - state: equipped-HELMET-vox - state: equipped-HELMET-unshaded-vox shader: unshaded + head-reptilian: + - state: equipped-HELMET-reptilian + - state: equipped-HELMET-unshaded-reptilian + shader: unshaded - type: PointLight # Color matches visor colors, radius/energy same as mining hardsuit for the big captain. color: "#f3ea9c" radius: 7 @@ -970,6 +1012,10 @@ - state: equipped-head-vox - state: equipped-head-unshaded-vox shader: unshaded + head-reptilian: + - state: equipped-head-reptilian + - state: equipped-head-unshaded-reptilian + shader: unshaded - type: PointLight color: orange - type: PressureProtection diff --git a/Resources/Prototypes/Entities/Mobs/Species/reptilian.yml b/Resources/Prototypes/Entities/Mobs/Species/reptilian.yml index a50c0345155..612484f96b3 100644 --- a/Resources/Prototypes/Entities/Mobs/Species/reptilian.yml +++ b/Resources/Prototypes/Entities/Mobs/Species/reptilian.yml @@ -79,6 +79,27 @@ 32: sprite: Mobs/Species/Human/displacement.rsi state: jumpsuit-female + head: + sizeMaps: + 32: + sprite: Mobs/Species/Reptilian/displacement.rsi + state: head + mask: + sizeMaps: + 32: + sprite: Mobs/Species/Reptilian/displacement.rsi + state: mask + displacements: + head: + sizeMaps: + 32: + sprite: Mobs/Species/Reptilian/displacement.rsi + state: head + mask: + sizeMaps: + 32: + sprite: Mobs/Species/Reptilian/displacement.rsi + state: mask - type: FootPrints # DeltaV port from EE, blood splatter leftBarePrint: "footprint-left-bare-lizard" rightBarePrint: "footprint-right-bare-lizard" @@ -103,7 +124,28 @@ jumpsuit: sizeMaps: 32: - sprite: Mobs/Species/Human/displacement.rsi + sprite: Mobs/Species/Reptilian/displacement.rsi state: jumpsuit-female + head: + sizeMaps: + 32: + sprite: Mobs/Species/Reptilian/displacement.rsi + state: head + mask: + sizeMaps: + 32: + sprite: Mobs/Species/Reptilian/displacement.rsi + state: mask + displacements: + head: + sizeMaps: + 32: + sprite: Mobs/Species/Reptilian/displacement.rsi + state: head + mask: + sizeMaps: + 32: + sprite: Mobs/Species/Reptilian/displacement.rsi + state: mask #Weh diff --git a/Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertengineer.rsi/meta.json b/Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertengineer.rsi/meta.json index bcd0d726dcf..b0d552fc028 100644 --- a/Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertengineer.rsi/meta.json +++ b/Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertengineer.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from paradisestation at commit https://github.com/ParadiseSS13/Paradise/commit/f09526480788c2e18fff8c16c4318fd6b4272c10. Vox states by Flareguy for Space Station 14", + "copyright": "Taken from paradisestation at commit https://github.com/ParadiseSS13/Paradise/commit/f09526480788c2e18fff8c16c4318fd6b4272c10. Vox states by Flareguy for Space Station 14. Reptilian states by TiniestShark (Github)", "size": { "x": 32, "y": 32 @@ -21,6 +21,10 @@ "name": "off-equipped-HELMET-vox", "directions": 4 }, + { + "name": "off-equipped-HELMET-reptilian", + "directions": 4 + }, { "name": "on-equipped-HELMET", "directions": 4 @@ -36,6 +40,10 @@ { "name": "on-equipped-HELMET-vulpkanin", "directions": 4 + }, + { + "name": "on-equipped-HELMET-reptilian", + "directions": 4 } ] } diff --git a/Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertengineer.rsi/off-equipped-HELMET-reptilian.png b/Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertengineer.rsi/off-equipped-HELMET-reptilian.png new file mode 100644 index 0000000000000000000000000000000000000000..4f7708dbb099547bbd5744031a3ff5e80a084f4d GIT binary patch literal 1081 zcmV-91jhS`P)Px&^GQTORCt{2nmueAHx$SJXLT*K)OUqC6)4>x2p3O|<3UsHrEp*Ym(5+up&x*e z#*2q!NC$WFl%~UV=~xyD5Oi@m1Rhj0lNS|*ECvYRK>(>NLg$(tPCVT?GH_IMW}EQ0 zP)8p4-uv_T0X+h5IYHSMkB*MA-;6Q6zag-9NMOn&NlN$ix|FfsY&J{vwJ?kE_4ReM zHi3M}7}K_W&BDCxTM57z)09#S1_Qk4p-@svD;J>(`=tdiolB`8rNZ$E3Z;~)@ZP-1 z+n>g)_TRC2SqPE+-a8}!WLBDXLWoV5)+m+QIz9oq-7bzlNP{=^wpa-O0F+X^+x`pJ z@o84~2Y$uht*Zrrs)ACAZnulQLxTPf0!v?{17PZHu@bh*f1+o7=!01s~|EPtF%g)e^& z0ia;N>^5k94v6DeKfI;T+MKktAE!=m&MQ9)jFAgWlH|JRLwvg(ynX zQjJCfPj((uCc@{81;IFYV;=yNlnA2;jYb2%?L1hp6~Rh?{SATLr&|C9Q&ZBrgDvcD zJOZmgga9}@Zyx}ZQqbcB*Y02o-)%gyng*qvB!uXE7FH>VD2mYObS}&a&r5`C&B?Dk zL3$ryZEX!wN}Tge3n5AgVWrmX&6U$Pxf#bKgvb#oqHz6K*g{@%cQt)sbo1uxsp zEck=F!0-miY=&V3A^Hdad_TT3uyQ|yQmT~g(u?5vj4%KQ(TDjWD5dD$0G7vFRQqw+ zp3BkNOt;$M8UdvgQmQO?Ae|9kjRyu6Q`>46n3fTabD~g60aSZWh+a#BH-U4`gE)=@ zU~)S8g>zl$1&L|Iajfh0I)HS$oY&`Xc-e01^hO#m8jZ5RIph>ZyMX% z+Y6_sr)On-@pwEQkH_Qjcsw4D$K&yMJg@LCtL6eRa+a(Q00000NkvXXu0mjf!{+f2 literal 0 HcmV?d00001 diff --git a/Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertengineer.rsi/on-equipped-HELMET-reptilian.png b/Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertengineer.rsi/on-equipped-HELMET-reptilian.png new file mode 100644 index 0000000000000000000000000000000000000000..073817340badcf20d1aec46d1bf9b8221d126a69 GIT binary patch literal 1719 zcmb7FX*3&%7S2K}9bKM`mNKceX$3vCl+q%kp*4|^(l^ndN~RhkLDHZmQCdqpyPDY3 z7DXjRE7TA(9n{toCE5~1$s=KQ*o>8ySRS(&sZYv6?=pUxz~_t0kAYcqFfCxZye(Q|d;ND7#l| zHEysow1sf#?VB{Sfr39iAb(%_VqTTgL~jWpq#u@hpE)vX&W>qcU7x$1Q8K?J|Ji@L zWPWA>TuM=@)q6QbS#5x)E-kv?Vj$z!`CP2qx*zPYnQUccrC{#;GoK`it;aF!3vCLJ za6p$4`lz8H=V8*r#NigPcV!#D#Bs0pTszGv-8CDw;8}ZWOZJ_ouX7v@I$TxNV7E)L z-HF%IMCf#UU>U~6fepJd9Pjlvau(H+JFaNTy|5(>HSs(mwTyIPtWYFxP@Yy+HBC08GP3?Le|zML7~z6TwL;F z;w$=^{@1Q-742}f6;S^K`d4n4NILX{-@&S7wO04UiwS5HN*h4xEW|-Mmec(JJU(}7 zV+4137VwnR8Ky+ATnCoHPuD*=byh7XC@2k6k>d-sW2S}dT8ml3xw*M(Z`|X28zi&D&U^V{cP3bpi`7aZATs7NrzD!M6VYk_&-PgltMS=S>t%qB^2W7K_H z>R+Q(7@r0jFYALKT$A0esNG>XZF6VY$wBzrViXr1VX`INJ!!SfZ>Ci(P1Lio-u@F# ze1yn*E1~e&j!BQ7^z{Bs^9!C$947CZ{F>~X;~8{tIOwp=wd1b{N`($3JV|-EF@VVM zwAH|j; zCV2TYKrYC6jqZ(Y-?Od&UQh|J`hT&M0Up_?d<;(w<$f8qmN}K-0m-h}%G-Pt_tOKo zdi%xr)lfKeaQE(#jT02Lk+%w`efStwTEfEM@C_zPpz;nUWs0WT!f-bhlB*0VKVy(J zv(0JD+bgrsg?41TPDGXt8kY64$e)G3e6?Y}q>>vALPO7AGN7^ zgR9)U_%qUl865hBK~&u4>i6Oux#mTm2_7`?`T19UeX$6{SYWS~z00_WAT20cJ{~E< z=2nXI^tIT54c`uoHfacj_wGSd=&^^+@gdPuYHN%ab1a{L15f>Zdp7GGEzva-Ok}q> z{71^5vRsC z2!TN0h;5t?;W8Hv<`=H({9}A@^y)CDC%Gsx2{QarmP$s2_1<)7uMy zCCryKHr`245xN;rle)WaC0_`7YbUNzshr4pImSw6zRw>$2JY4e;k%}90ApEM?pfDM0(r)JDJz@Au~kuBQ&U=pSK`nj5;fZ`H@=*W z)T-^k^<(UcF|@DR#=aSXA7C>BX#0bS!T1dzM8$vF@-XS^R;jRaJ0&``Ht(5(WZiHw z!YEt!?M;BwF>H+LsP%iMtn!_maJ$?wb79PxK)8h2p3UDw8c8k z_N7#cVoBt3$3N+@tiFLfpQp3~Sb?70Y7lS=l(yU>BTAHfe)16hmcRLHzf{RDEOL5% z#PY0;@-dy_9@@_*Be5Vob_>tC42!b;g_J6q2M@*@=e;9?B4ez4^ueZ_=0P1Itp3T& zfAWpoRUrwWu{e8Ku~F4gx#|oo6Yi>*VQ+75yp;amXscfpSG^Taw{8Jgn3>Hg5~?O; y5fd7(QbQL7#B@FT5KeLN)d3xL%D=2z_{kzApF^vns4pu%5x^aVapfTc?)(iLG(XM& literal 0 HcmV?d00001 diff --git a/Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertjanitor.rsi/meta.json b/Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertjanitor.rsi/meta.json index bcd0d726dcf..77d0fcbffb8 100644 --- a/Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertjanitor.rsi/meta.json +++ b/Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertjanitor.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from paradisestation at commit https://github.com/ParadiseSS13/Paradise/commit/f09526480788c2e18fff8c16c4318fd6b4272c10. Vox states by Flareguy for Space Station 14", + "copyright": "Taken from paradisestation at commit https://github.com/ParadiseSS13/Paradise/commit/f09526480788c2e18fff8c16c4318fd6b4272c10. Vox states by Flareguy for Space Station 14. Reptilian states by TiniestShark (Github)", "size": { "x": 32, "y": 32 @@ -21,6 +21,10 @@ "name": "off-equipped-HELMET-vox", "directions": 4 }, + { + "name": "off-equipped-HELMET-reptilian", + "directions": 4 + }, { "name": "on-equipped-HELMET", "directions": 4 @@ -36,6 +40,10 @@ { "name": "on-equipped-HELMET-vulpkanin", "directions": 4 + }, + { + "name": "on-equipped-HELMET-reptilian", + "directions": 4 } ] } diff --git a/Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertjanitor.rsi/off-equipped-HELMET-reptilian.png b/Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertjanitor.rsi/off-equipped-HELMET-reptilian.png new file mode 100644 index 0000000000000000000000000000000000000000..2e8269ebfa4453d713ffc5dd2e7702e8e28679f5 GIT binary patch literal 1098 zcmV-Q1hxB#P)Px(1W80eRCt{2nm=e8R~*Mb7qycp3Msy8T{<3$yC!5FTT3@IsOGQ_3WLx-poN#_iuMCG1Hu_&5MeI4XGOO6cp6v@}t z@3TDJyW{h-Y@d=??9Aq1}LMyd{EZ9laDapPeq2}8;5 z^Lk$yhO+OwQPXRG5X0J6ngT%(B)=sU=p2>td)u~Enp8&05P61~Yo9>ps9qH%0pi{bS~ZwB zst;N<-r>sFdq2iBEu;*)!5=;ki_$jex^C2Nx4HO>^`rv-CPFfv!8YwR6YkdjuRCpA8@-|Ox``**k-%AjPLuWvJJ)}^m1JM zu?YZO5f*PePM+7FE}Tm6Dva$Q1mOF=;W!IX@AEM2{2Lfb0QheQ-HXym@c)PwAZrJ* zMhlR&16iX5$l8Id(E?=cK-OphvUVVAv;bKtR2W2EkM=|WQ`UeYX`FC%nLBo zpQ0xvAWtbhZU6@ZUPYegDR<~l_XBQDZy;vQ_tjT-_HfeEh2^=~brkm9g9wG2r01eE=yXQPPjAe3-8&O@q`<+O{3_ zW?`iau`G+Nt*sNY!lM!)S#x?<9;167VQy}YFbp~7TNDIADj}5Ay3o0Ulp#`vucV}B z8#z`Qx0r3@m~G@nIt@I}Gvanv8n?Js&-IBBr^{P1n?1`!5`)`bz(VI|x9ZIDVpGQ+k$U&<{Yu3iJtUf;?B6foy@_ql@$g{(yX-11T z9{1(rZTnI(8e$Q8?+vVc_1;KE!Tq~0lHgxHS)_H{PHdW{MG!PFfSJQP1M5#0kW!|y zoq7>Go)HEJf(G%35JFJB4#nxqh?(;|+}KXrbSiF_i&S^^sLk03AqYd61P|RAvC~{; zr@J|%p4v*gz@Ut<<2Z>ZLI{=ShC*EJ1|J9B?HI>^qtns1z8{VCg2W&k$B7Ds0?^$q zM>YIo?%#b8)jAab+U<4{xbOP|Po-%E&}cLojYgx}KOj{pDw literal 0 HcmV?d00001 diff --git a/Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertjanitor.rsi/on-equipped-HELMET-reptilian.png b/Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertjanitor.rsi/on-equipped-HELMET-reptilian.png new file mode 100644 index 0000000000000000000000000000000000000000..67942c5e460beee9acd74c26a6ed58e036d05c36 GIT binary patch literal 1813 zcmV+w2kQ8VP)Px*&q+i;wYk?vGr%NoL9SrrA7=`}||ySLeLvoZt2Pp`5@SjzO(qdwYBQyC4Yi>Wo(UqOHU} zJsywhxxOrFFW-YnYo1R+n;3r{?zkW4IB%uh%jXeZ|5&*ZN7wL=ka4X{?S2Kd~afMvP zZ!p>9Y6QpwOtA-($;3U+8F=QodPbg5qBsITBr;9EH4;H^lMa3#EU%trS1G@+W{A6Wi;rF*a51d#0 zl9Kf7mgTP4DX{6_!FTuU-TQlf^xa=_eWEgMvn=xx`+ofccJKZsPe1+W&w%#<-(nqw z^N+!BIQ(xmO7U}!K{fY)qyo&p2RNPI=oH0Kw$&Yt+q`+Yk>cWfy1W1IAGrrCltmFB z#_XFQfZOesW8b}A?||XS}y7gdnuY zF%euY^D-dM%)7ZV@F`>C(`2v6eRtDsk5Ji!k zoOIT%U4heCMrCCICX)d%Z66yg2iUpul@VYQ@Bpw;Q^|ALsLZkHg%@5AZnPXgOxuUa zWT3LL0H?EzHEWB>$w@~PMF!-TSe?ka`+fvsBi0%iUG5x9By@ad;++_*_76k%v^gu63LI2@%k zHa^6O6X!U5_#|h~4#a(fK}ik-0;+`2v;=aa-{a$GD*&09>*C`zHTB%r7{tIW!i)m2 znlT-V;mg?fN29z-UMWmgM4ZYloH%igK;RR`zuwD=<@bwvte28ly3t!a@r&G9LtX$zHG5xahq>x7#gmt2;W=j~90# zNrQ}!H()SKBg=R3Ui|>e{`x1j{pJYcqn~pjfB2c5KPmbta8_&avp5Ar-}uGw&&Nk? z?-vF|F7srmBH|`L3(IEmFHg`>XK%$QD>^8Z>;fRk94NS)h7|{}A9ujbSXkZ#=wGzYb zK$3#-!e?HL+W=qOjt+Ufvf3rE;QtSpkK65*v$C>)nd9<@zbaYO_W3K{AChAma5x-} z7w+|X6Yei+1<=va(b3V-(b3V-(b3V-(b3V-xwH5eYE_Y9xeSz700000NkvXXu0mjf DQXF_w literal 0 HcmV?d00001 diff --git a/Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertleader.rsi/meta.json b/Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertleader.rsi/meta.json index bcd0d726dcf..940afc73a9f 100644 --- a/Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertleader.rsi/meta.json +++ b/Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertleader.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from paradisestation at commit https://github.com/ParadiseSS13/Paradise/commit/f09526480788c2e18fff8c16c4318fd6b4272c10. Vox states by Flareguy for Space Station 14", + "copyright": "Taken from paradisestation at commit https://github.com/ParadiseSS13/Paradise/commit/f09526480788c2e18fff8c16c4318fd6b4272c10. Vox states by Flareguy for Space Station 14. Reptilian state by TiniestShark (Github)", "size": { "x": 32, "y": 32 @@ -21,6 +21,10 @@ "name": "off-equipped-HELMET-vox", "directions": 4 }, + { + "name": "off-equipped-HELMET-reptilian", + "directions": 4 + }, { "name": "on-equipped-HELMET", "directions": 4 @@ -36,6 +40,10 @@ { "name": "on-equipped-HELMET-vulpkanin", "directions": 4 + }, + { + "name": "on-equipped-HELMET-reptilian", + "directions": 4 } ] } diff --git a/Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertleader.rsi/off-equipped-HELMET-reptilian.png b/Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertleader.rsi/off-equipped-HELMET-reptilian.png new file mode 100644 index 0000000000000000000000000000000000000000..3f00fa7c74e167d87eaf2d2c8a1f150f0a9e5e99 GIT binary patch literal 1262 zcmVPx(s7XXYRCt{2nonpPRUF4ZGpWi#$_h4b(jI!S*&sF3g11yHIi$_0rB3?Y`RYjOoFQRl~dWjb?htO^tPa>IG!@fO9JKZX5PH~zQ6g-`^U_KU5=5q;{5!4a_qXU28hO|G3O=$@I21|c<=C-{^;6#>bPlX zjr(u@=V`EQto-4Q6CXd$r^QQ;<#JsXN_xSsqDJ0 zE|h(OARq_=RvN3xaiQ!dPo`V6>I1AaRspu9pV|P|b+wd|yJ`ugLX-;cJKhOmogfIf ztCkWo;_|E}WbOjy+$7;Y9Pb3?+$2g^Se97Vv~83MG5z-RQybuUp5eN#wr!ieGuIg9 zRB~;BS?-)ZjPLtxC6Sip<>lmW7%HOiY5Wc2ZQI88{rd*Pt;pO00AzCs2JSr{+k*_A_1n@NB21AQwq7&bBe4~Wxo-thabsddQGqm_JK@gynqJH#S^s5&E&CMIv z6a6ftZvmx}j=#b-j(mza=OBc|<;#~iboLj_A05ydFu`0OB04oDB!+4O&|nxu;}y)g zNrbSFQnL5-4-7881wa@oq?D<&GZ-+eV^J^=LSR_}r9#4HlhNM{j&X_wW&wEZ(ia`= z246k@hQ@$VPH{!gvhY-tHp!N%Ps#x@M@7T_YFd>dgZ+QeGQ3GyBmPWoj~u~2W*|29?{s>*jJ>fJD12`7SO{y=0Ig|!c5wZX8b<1t zow{P>{P{I>)CW-?ko=^qA!QAvLhKQHizwU29RxB2i@=mV`Tf0HL8^v)Pvr?%%a8=r^x5zm;IXO8wIXO8wIXO8wIXO8wIS)5~ Y1MDCxCxJc*i~s-t07*qoM6N<$f>lRX4*&oF literal 0 HcmV?d00001 diff --git a/Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertleader.rsi/on-equipped-HELMET-reptilian.png b/Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertleader.rsi/on-equipped-HELMET-reptilian.png new file mode 100644 index 0000000000000000000000000000000000000000..a997702e630d6401c682ee0ed3690b957304442b GIT binary patch literal 1802 zcmV+l2le=gP)Px*#7RU!RCt{2nr&zs_Z`PSC&zQ`$WxNWlH)>$iBGhSl~6Nc;w+IH(wZ?wOT7qO zB`j>c7khXy$k>a)7-MW>tgtufN>MUaD0o$7FwJ0enBjAtXjv0tC7pWb;Igh4-N|uc zTXyVt((T3F$=a4!Iwh{MHdF#H5eNk10WjpHvt=gEx?Q{=d#W< zeSLjvnfOdF&AhIck4F71fC#h#p9kh%fBjd(AAg)-y89%eC<2g3 zBm{sTcJ`S+|8PvGI-7e?YFCmZ6QFSL6u!|zgu{a<%FuulACQSg{c34L-HSB^uv=aP zp0U3JZ@&4bqXPq9=95om_+uc#j=FxFpc09MFxeG^bZHKiSmJo`18n(D~sZ)4uPjiza6nnq(h zRcx8{LXsr2F`h!xGyrm$Wq_jpaCq=2(9LR(-B`|MIRUm{b*sSCl(w(Ey^T!`iwJ_r z%E~hJ3o5#9pz8(;db;||T;TZ8G>rv4T@=GP9}W-h0|Iv3TgurhC%}IpEPl$;(rxDE z<`B+*55v$g3?1L-A-ATg!Z&&dT{nuy0J?5e?Z4b4ID<8*%(l0;otc`__AM>tdFQ1B zdtUk~?d%5N0;icD=p>a&RTV^~%+AghzYRmDaPSl#3G{A*H9 zfCV6fJ*ix}r0#2IXhPkZhL+Wf)NGnoI^AdFl0YCpBog85*|WfE4+sWBrI%f_T(XLREpWz*>y|46iJdyXDE~s2n0}+p{HM*AmCq#kYFHNmz!JeZ{$EWV?n8iwol1YBxUK{K-|z&ebpW--6QI@s z)S9v{L>?B_>&??6-vb_b0oJ{Odr$?GHw4xRPk>qnP-{E^Y8^nW@dT)K0JX*wpwoaQ)lH{rdp3P-u)_#lNkA?l#!;7~EQdi&vMC zUfE$LPMj2?QU6w;4Qq*72QItzW6=(Tur@qsvYeX+@{RE;_**|`$73=XX{GgBsiJ>3 z4k{Kv`sOzT1Ye=?@KyFtf1fR81078*Y~TI`GV`|(o8~xq_$tyXU8bV`{zYILRu8yA z^#bfEv2k6Jq>;vWiv82a&?c?}rnORR!u}gSVBGefIB}w45h|Vp6DNOb7M?pr$3z@W z(^%~K1y4M&mEK;FO`A3l2-NePZLf0dwIt#2;0Ul6*ah@EW7!S%J^i+gz2Wf7BZY&f z=$LpJP1DeIoylE8m`BC|lk1=UgN}(fh3Ed@%1_0CiK1vatFW1!$N5VAtGw{Svm7|E ziyQN8%w$r`%;>gBYtHKF=^V3fKj3yEvjzAIz~yR=Sx7XZW1QB}2~+*~{c1u{F27dJzgW<9rVE%U}3BP=yv;Y`N}cXlr_y?c`B z-Ph>p>3j>w0vD>8#qE180NI|N&bNBgb@VDejwvs)C+)*G8Y37C5efwX6W?eI!!XF~ zJdV=ANxc2LJ2tWQbCMM4mx|W9GY3RjWBM1Vm-~K!PP(71B3Snfk73JpUF}Pv!$J_o{+PhR$!C5Ac zbnPV7D-^rsM<1mDCa{JtsV!1p;ZA)lgw*RT1_el6%Xx-FHFAu zb{?}(2ZcJI_)%2_RaMY+gGkrvrinXuR*>afMwWB=d)X|9Ea&pFoXeD+i*#AZJAUn@ zc{`p$9fd+&GMTJ+61eYDI2MaJBIW~uK=FKORrnw%-Gk`tMv28@zGO0a*Q)ek*uv}K s;o;%o;o;%o;o;%o;o;%o;qmbCFHD-$$!)bk`2YX_07*qoM6N<$g8VCRNdN!< literal 0 HcmV?d00001 diff --git a/Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertmedical.rsi/meta.json b/Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertmedical.rsi/meta.json index bcd0d726dcf..77d0fcbffb8 100644 --- a/Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertmedical.rsi/meta.json +++ b/Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertmedical.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from paradisestation at commit https://github.com/ParadiseSS13/Paradise/commit/f09526480788c2e18fff8c16c4318fd6b4272c10. Vox states by Flareguy for Space Station 14", + "copyright": "Taken from paradisestation at commit https://github.com/ParadiseSS13/Paradise/commit/f09526480788c2e18fff8c16c4318fd6b4272c10. Vox states by Flareguy for Space Station 14. Reptilian states by TiniestShark (Github)", "size": { "x": 32, "y": 32 @@ -21,6 +21,10 @@ "name": "off-equipped-HELMET-vox", "directions": 4 }, + { + "name": "off-equipped-HELMET-reptilian", + "directions": 4 + }, { "name": "on-equipped-HELMET", "directions": 4 @@ -36,6 +40,10 @@ { "name": "on-equipped-HELMET-vulpkanin", "directions": 4 + }, + { + "name": "on-equipped-HELMET-reptilian", + "directions": 4 } ] } diff --git a/Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertmedical.rsi/off-equipped-HELMET-reptilian.png b/Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertmedical.rsi/off-equipped-HELMET-reptilian.png new file mode 100644 index 0000000000000000000000000000000000000000..d401dc1a1a681aa55fe0bba9e04ace5199e26bc1 GIT binary patch literal 1038 zcmV+p1o8WcP)Px&$Vo&&RCt{2nmupZMi|Hcw7M3W%qz4R=ovwf`v9>uXey@y0Ssu+k|o?@L<>Iw zJNXMROI8-0I;oQey4|>_C{&&SZ3ON#37KPdu-t3!ye zZ~sT8&KYAU%Mz>AN`K0-1Y-)cq^+ zJlEfM^=~uJtgX0yS!ze}voKPP*9&2jU>N59|ibURf30f5p|5aL4!3C;@uX!vit4H};V z#^Z6-@AttN)AtsO1vZ-v(lkBDHmF3Xb6@<<1i)4VN>BAQ=fy#iH=(nG5CEiU>W#MC1a2Sk?|l~ppWY`)&%~IK04n*bt1Fac2_Ym1@c{sX!9W!&I}zbc7<%3| zdF3Afq!924!C)}JFSFT^sR%{_#Bq%2bP8 zC8}+KYdW3chd4Hx2CajnlvedBtds(T5M){QXjOP$BIq@zzVdi?{RqS15JCvti>>0E zw-Ulgt;@@|kWxTO@wbxnS<%D0;uX${9?pv1UKhk9NjzouUGWMp|LiryQ04Nq6u7*6 z3zHXXR2;1rMb+F_Q{niUgC0NA&wuciUcI3DC5%QRysn<d1M z(lkBVdvR1HPl%5!%fNX7N>BB#L7oG+Uh2L9N@-;x@IOH*t$scI1Z;Z|*5`N0t2K!8 z0v>?#;Se4?Rk&^CyY&=E)70a5TrZO|#u{B*UBF(jMpwwTRPUj7I{Gn9t4%z0Ta~ zpA`}~)5g$P>X`xKyd10nE$@^!004myC)=Ce=<==7NLT+E#j)h#bSe3au9U^}$j35$ zVRRQ4eDf#AaBZJ}ucERaAktfxJ_U!WH+F{Q!(75Gy+5sI=*S?#>l3+pZn#bDXL_Mq z+1_Eu;IiKly}x$mS1jMm87C&{lC91KY+I~yCW3Rji)*NnJ(j{7m7_P-5-U&556jgp z1-DWB&EliWZ5+nl(JGIJAucG`yz&qH6Slo<+TjCL^;iaCJuS3KJ#^6$!mmSj9OqndvEI84Dhndcq=`do(rB&FnQo$t~w>aU5-(xn$j9u zL3*D>bU>ES-SatJ=gia6*6i~xBq1W3)>Xn>GHV3i>?Pu)esNR7(KwL7x?h>hTTe)7 z8YXPb3O|t>fxYNR2#SrB24sxl7NczNdKxmZfX1dK+}KnD3$*;co@FGv#ENWd-U_cJ zk?5H<4V}0*2ya-C{*SCOkGo2cOwVkYV*##T=ZKEV)t>`Ab&NVCf1lPgl)4tc-;KJX*U#9fV^1v4U1 z*1#|+oj{O?3P#YLuq05`vaSd__wc#N$O`jjeprh-h%M? z_#EmP9s&16!^vc_E?A^+L-r>8UPydA%p!?n0LaOqnC<>`VyrBA-Q1i+4EO!~dGImC z@7>WJ61_!aCi#~DZfm03W_mSM#ajpmPRyt`%DuzUyh+ya-_$&*@mRvj4`$Jrg4KhjbS#)gmtt29hM11C}@l zb9K^)_HC3P`&sgWy_L2`l;I@bBp+DscPvTB#pP;0kHftDHZzIqmq~2Z?lPKoBzytX z4zppkaHz?GvQkz@9P*&KT{3Mw?BaR16nyEmn9$(5orWW`>Tq%GLTRXbepXEbb=p}I zDFO^WnC%u9?k;hCx3iQ+>5Az7L%hqnKwjPRza}P1ViWU&qTs-%+SnO-VN+8RWjCIt utYeV`g+d!s1=B|G^ehZ+qPH-J^C9*0!hmN literal 0 HcmV?d00001 diff --git a/Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertsecurity.rsi/meta.json b/Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertsecurity.rsi/meta.json index bcd0d726dcf..46f7db17a2b 100644 --- a/Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertsecurity.rsi/meta.json +++ b/Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertsecurity.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from paradisestation at commit https://github.com/ParadiseSS13/Paradise/commit/f09526480788c2e18fff8c16c4318fd6b4272c10. Vox states by Flareguy for Space Station 14", + "copyright": "Taken from paradisestation at commit https://github.com/ParadiseSS13/Paradise/commit/f09526480788c2e18fff8c16c4318fd6b4272c10. Vox states by Flareguy for Space Station 14. Reptilian states by TiniestShark (Github). Reptilian states by TiniestShark (Github)", "size": { "x": 32, "y": 32 @@ -21,6 +21,10 @@ "name": "off-equipped-HELMET-vox", "directions": 4 }, + { + "name": "off-equipped-HELMET-reptilian", + "directions": 4 + }, { "name": "on-equipped-HELMET", "directions": 4 @@ -36,6 +40,10 @@ { "name": "on-equipped-HELMET-vulpkanin", "directions": 4 + }, + { + "name": "on-equipped-HELMET-reptilian", + "directions": 4 } ] } diff --git a/Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertsecurity.rsi/off-equipped-HELMET-reptilian.png b/Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertsecurity.rsi/off-equipped-HELMET-reptilian.png new file mode 100644 index 0000000000000000000000000000000000000000..d718baa2685b28f22307646eb4fa741eef224620 GIT binary patch literal 1035 zcmV+m1oZofP)Px&#Ysd#RCt{2nz3&qMHGj>&Cw!PStA#41$#)Rn;L>G;f70<#z>nk5)u2dW^Ej4$9S{A&DTtJW)>+hO2QYrR@XT+uM{|DW!Ft zYZcaQ-$?)|r4>SO1&qhzxmE~Ky9jmIuPi`5xz>iOJKFMn>!xh~U@!pSYBqK-7_4mH z=?zdyVT@)!ik7xYDVOP1!WdlyyB|eBCW>9cUUaK+_I1jTfM42b#tU(6j?h;{|Bifu`{SH0?mscmbMrplQ4S zO*_yuUVx?@Xqq=(fR+9!dRGFn&ZJ1mb^uJ54A~?}oFAyO08&bOq7)Ao`mcbeQrdeE zVfsQT-dpJW9fGG)zWy#r9=J^ABtRbgH_x6i9*@!5&~9gGsZOWE$>CvbB77lb5Ww_A zDZZZB2QXR_w%c?%9bOzBZhYz}g3~K=q!b5(K@ohOs@B>t9*;Q~3^-D%mKuQorq37b zYi-bG-hQH#llYZyj-tqxv#`c!+U+){r>A#jh1c~a6oQsz4YGQLUayDNng!piQmWF! zby@;not@s9lK%Me0bA^F&M^R=zx;M>%OFXT;QLR$v{=|;ho9{+=O4T-#`AP}06fnM zrz+d7EI^VZK^(_6ngyP({cg9HRfjCp4Aer96=S^m;{u52c6)@g)Hr~}vOAgBG)Xqr zo*fRu(Eeh~Ts}UE9$}0wp1|grnyVXF`x1b{Ms70<+bDHOKvpyGF7QzpVvMO|yYeQO zrfKkD7#6`pmKM*Kf)Ju`tXw;=E`$(-VVj#?RLq|T583vx8-{FU{#B04X%ASI5iY06 zg%CvnQ(cHBnTH`002ovPDHLk FV1nj1>stT- literal 0 HcmV?d00001 diff --git a/Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertsecurity.rsi/on-equipped-HELMET-reptilian.png b/Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertsecurity.rsi/on-equipped-HELMET-reptilian.png new file mode 100644 index 0000000000000000000000000000000000000000..7d98a90e36c36b0a7cc14f9cd7257edd2908a7c0 GIT binary patch literal 1702 zcmV;X23h%uP)Px*U`a$lRCt{2npQX_OgZD#iEqj?h;_PP{5!R*%l+WmzpIGsSgBW z788V+NQgYB4}=F3qe)YF(A5_cH7vn|2Pr85yGXrI0ii^bj?z+a>C7%mFG~vrJ3j2i zr8MbGZ5S`}dzsynbI$*K|Cu@GWWEFcbA*X1w6?ZBP^Q+_s@q*IK9VHTSE03a!oH>o zt@^dKwG;L=O^cwJB{`0*HbG=$!m8PYul8ZtXTy#SC$it#n|pj8qr*tEcbZIDJ``Fl%(2C1#?pU0iY;y zCfMyR7mzeXQRM74n)Nl!0ohnA79QUv@XD_B++vt~ELgdR!qWk14WUO zli-+gy=XC@7l=n9Q2-K&5xSk1xnk|%CUI<(P?ng-oakbPhlhzoqIf*z@l?C1pcjZ| z7dRYF6h+QF0S?ClPrGLQ370Na{V_cWRW&soZj|L1v-b{icw-l`9LMP_VRLgiv3Ck^ zI%l(M*XGxNi$L2{tOQw;V3ph5(AeMK55Pf1VLr)uV2i^6Kv7W#Lw(E~6V(*UCfU^J!yMi0PfOaqJ_fYJQ#4VctN z(Lf-ej#nNG2Jib&>hoCzfN(f5ZvBZEuYDj85P;Efs;j|ZQ1=bhZ9pIpP+KI4`D4nv zfpvj^nl{1bv(5l!0fWGRUY!&LK!ML^y%7#4Zl}sdk4q9|V=8umur3hzE zAEmmwjLJ$o7K^~%Eh3*=V8@R4qQENPN#JQ+A>Yr_sXkWi*>gbo%mRD2h*&HFm6dj? ztIJrlxD=Z$k4PlKZoi+PBIrCIx|e3~&P#m4z&71?+nI zABSRq`ub;Df8pm^0f9oELRF_RBkln1rN&}IQO+O$A0`h@X}+XF834k^^K5|lZV6ML`7vwf4>?E26MFL1~oh7a5&T-6eW|7FD#tN#*K9d z!U(E5owl}f%s6&|XpM_!pIwgKZe!oRm)``=hQoZ`K%j&8zWr1)(OxKT+$Qt7%l>%=g)UCeR@%{@73V-RB-N`1SC`QY0?KJ&@s8| znghnm2xq6sy}j^>hGHJsM+>fzht6>nvDMl+^GfHPV5HLLosEMFIZW9UTgV z)G2=j#ycpHjVOw0QBhIm|JYsO-z9tZ+27xv2|N@EjXS?QbOX|&TIx-fty{O|^z`(M wY8{J-iHV7ciHV7ciHV7ciHV7ciOB=}2@Uy+RXgEG{Qv*}07*qoM6N<$f?KOI2><{9 literal 0 HcmV?d00001 diff --git a/Resources/Textures/Clothing/Head/Hardsuits/atmospherics.rsi/equipped-head-light-reptilian.png b/Resources/Textures/Clothing/Head/Hardsuits/atmospherics.rsi/equipped-head-light-reptilian.png new file mode 100644 index 0000000000000000000000000000000000000000..b12cc92d2fda2dd5927dcc469df488f2b9cf99af GIT binary patch literal 1381 zcmV-r1)BPaP)Px)A4x<(RCt{2nq6!ZRTRg6cXms$anThXShjR&gWH!{p;QYENr|*Z6QMO|iv(?q zU%_o+grvb25;b5$C~9o=$p>P9R*5MVpDdx8NI=RG3n8%>!kTVZOlon9&8F?{_%I*c zEw!ClEEDAZlF5ADIsbd^xidHST#($`h*|Hd#;&h4{c=;orhb6-&KRKvAI9;WBHgBO z+}7Ehp;1uYuOG~cGM6#E@x$l?KNg~Kw9gs z1**m;k{4fiEwp9DvOEArBZB~}Se8fFUuU++d||xbupjoU~M=XNQ0Yy0Wg04xQ52k!(d?hTqDIiDEa zu4;{!fG?L7%kucFXX^UtgRdL{`mMfi&fj3#cOU@xK6?M%=3g)Mr2v{63)p|?Hvn#q zB{|gnhy5DaB-G&J=2()Ak3VQ$JNeTM?$2}4)_LLps4*Y{3<%2m=ZXV64gk#wG&O8$ zO>G!}8sIxndV`LP1JY^h?0!zy7tt^MHxAHteYXrU(nZ|K%FjesYqhA|)l!P7*!n=o zk^}B)Zg(X3e@8mNX#q|n9pJP8r?EN`yt}Y82-djgBS1R9X#q|n9pJP8r;!eDT7c6? z2RJRjX`}<37T`3}0Zt2W8tDM11vriE`G7r*#bP)Szh%C7bt)!a{c36+IejYKoT9eD zY~@?GE#zv_drO&Yrsr)(z;Gh28Y!@f5|6oEP<$$A!qdbDjcayn%v3%--+wjf&9Dtx zrZ}553bq^&YVZ;E*HISjqP}JcpylQRzFa;&{52`{-1EuF31cyZkxjCkshvi8`5;g{ zHhOY30_tm)n07%sFN=0%<%F!J#KQhM!k4wj5?+AndQh6UaB$0yJ)WQoQ-hW9Jo@yHIht z3jsw{RR!?rn<3tA6r|@OeL|GC3Q^u_+-wQ<&@uj_sl(WN0{ONx)V99?qme;#Ex;mm zLIDs$s6vR85F#mrNZEa-UAFdCGV;x%#ADa-1oDZVIgclhZ>GrYV9Nnz(Jnfw!=|B6 zj-E<>dg5H!x91igNKQ^f&_Z4SF?};LwKjDb&qwt4WYDqUG~UfWGa4B*wTwmv>8K8y zt46G1D>=IF#ij1(xR^BZ^Jg!O0#H!2QYV=EHw2Wbp$DQdPg8 zzNApN_i3g1gAYse+d=f!%)$Yg<;7I_9qn3 z3R$)M&(v@t4nV;Dx6*t#o|=z=Q0umZ%GIPd1zKe{Ke0|!Exn-X^-y;mNm!|sL?V$$ nBoc{4B9TZW5{X12xrg}&6D7eMsZXGB00000NkvXXu0mjf9{ZUG literal 0 HcmV?d00001 diff --git a/Resources/Textures/Clothing/Head/Hardsuits/atmospherics.rsi/equipped-head-reptilian.png b/Resources/Textures/Clothing/Head/Hardsuits/atmospherics.rsi/equipped-head-reptilian.png new file mode 100644 index 0000000000000000000000000000000000000000..c22d201e930987f61997ce18a20d198752d91685 GIT binary patch literal 942 zcmV;f15x~mP)Px&Xh}ptRCt{2nm=e8cNE7z${(kQUhI(2=6piZV0#FnH5OQMDw=>2NFakIkxfe$ zp)6j6yB0!KEm_)n3dNhzWJ-rXENDYo{~^{8j0QOnU9hAiB-o9LNK)eKaK4M}hE%_+ zEhxMX9O(DckN3X6ckk{e^d1O;GP$&F<*8!NA%v!C=1B`f-f;rFDjT)n07umW|qhQWs#G{@?sIYeSI`w7;c$We7 zW{0)2*D>Nz<(qIsRlv*EQyONT!qIz#2mREW9j4Y2Xm0|lraUuMO^}V0Sz2uqi)c($ z6KEl5EUqZq>N)@mH>Z6QlUZx{_wU#`Ut{(>a2j|5qkqAnUq;-NJV>0!?p*W)A^jNP zK|j;;@8%b7PWx2sDJ=%bT=~RGjt{ub>&*^k>ow)&O=f<6rfg4@Tw1sO?7Ss8KH$!k zmpA#?f0*w}EoJ|n1UpC3x#$UgUD;r1we88dSKfEzdG+sE^iC1I+`J$Nf*=TjAP9mW z2!bF8f*^Rub6sHXT(AEc-!BcG`U9L2SS+HsS1+3+oWhKAfn6!~qCqKQ&gRD&bEGex z!fd_X)f-T{^ZdXwA(z&z^u<%|*wIkB^BhN;iU#HCFxb(qRJR8kP&jiBfP5whU>#Ht za%tVlXM%2de5#soHDGwNsT6>UkwOavIIe$6V{ru|9_9WIKQcS?o4sJfhjq(Gj$sS- z@4eup_S;))6rNa6w=>;{ms}l<#TB$rfC?#Kx@+6Y8Q_$m!R{3R*!byl%rloL^w~WF zWP%iD9;=%EAo)xX?k4Sigog=2)!V$hd<`uWa5ukGTem0$V5~7mJ`?2XyghE4>*!;j zLAA-~(6`LK!OnuyJ`T?eD~tIM-+Wodw|)0VhhU?6d)J2B<~p+%DimiPv!GyCDFE9k zZH;suksKdjX|-*C(GTgqF8~PF{7{3Uis3H!>TVK%dY}FLm-=6Ea=S$)7SSj#Z&GZi z_Xzyw-vKZF_=uDJul})Szh8v!JL2~GmNLB{2!bF8f*=TjAP9mW2*SVcH*yzZ3%LF6 Q@c;k-07*qoM6N<$f-Wn(&;S4c literal 0 HcmV?d00001 diff --git a/Resources/Textures/Clothing/Head/Hardsuits/atmospherics.rsi/equipped-head-unshaded-reptilian.png b/Resources/Textures/Clothing/Head/Hardsuits/atmospherics.rsi/equipped-head-unshaded-reptilian.png new file mode 100644 index 0000000000000000000000000000000000000000..b82f0400c0c0123fbc1cc084223659e5c13d7ae1 GIT binary patch literal 195 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=jKx9jP7LeL$-D$|YCT;XLn`LH zy}4WPkOL3vfpSZ=GUov9wyFc`Sfz@3PWCtO{gGsP|7=p4N~%6%!v0fp7QHjPI%m?Y zX;U_;tzWX=Y;)DebUUCyAdtWx=2^1)_ii=MbE;c)C1)L0^Zc0l>x$8}CqJdH-|rK8 lxiswdgKO~*et}hQxFH^PREzbcoZBZ5-_zC4Wt~$(6964gN;?1m literal 0 HcmV?d00001 diff --git a/Resources/Textures/Clothing/Head/Hardsuits/atmospherics.rsi/meta.json b/Resources/Textures/Clothing/Head/Hardsuits/atmospherics.rsi/meta.json index bece208bced..3254216e017 100644 --- a/Resources/Textures/Clothing/Head/Hardsuits/atmospherics.rsi/meta.json +++ b/Resources/Textures/Clothing/Head/Hardsuits/atmospherics.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e. Vox states made by Flareguy for SS14 | Vulpkanin version taken from Paradise station at https://github.com/ParadiseSS13/Paradise/commit/f0fa4e1fd809482fbc104a310aa34cebf7df157d, unshaded version of vulp's visor by Radezolid, Feroxi sprites edited by juniwoofs (Delta-V), equipped-head-light-dog modified from equipped-head-light by Sparlight (GitHub). equipped-head-unshaded-dog modified from equipped-head-unshaded by Sparlight (GitHub).", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e. Vox states made by Flareguy for SS14 | Vulpkanin version taken from Paradise station at https://github.com/ParadiseSS13/Paradise/commit/f0fa4e1fd809482fbc104a310aa34cebf7df157d, unshaded version of vulp's visor by Radezolid, Feroxi sprites edited by juniwoofs (Delta-V), equipped-head-light-dog modified from equipped-head-light by Sparlight (GitHub). equipped-head-unshaded-dog modified from equipped-head-unshaded by Sparlight (GitHub). Reptilian states by TiniestShark (Github).", "size": { "x": 32, "y": 32 @@ -67,6 +67,18 @@ "name": "equipped-head-dog", "directions": 4 }, + { + "name": "equipped-head-reptilian", + "directions": 4 + }, + { + "name": "equipped-head-light-reptilian", + "directions": 4 + }, + { + "name": "equipped-head-unshaded-reptilian", + "directions": 4 + }, { "name": "equipped-head-light-dog", "directions": 4 diff --git a/Resources/Textures/Clothing/Head/Hardsuits/capspace.rsi/meta.json b/Resources/Textures/Clothing/Head/Hardsuits/capspace.rsi/meta.json index 54da577fe64..e5fb282869b 100644 --- a/Resources/Textures/Clothing/Head/Hardsuits/capspace.rsi/meta.json +++ b/Resources/Textures/Clothing/Head/Hardsuits/capspace.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e, modified by Emisse for SS14. Vox states by Flareguy for SS14 | Vulpkanin states sprited by TJohnson (Delta-V), Feroxi sprites edited by juniwoofs (Delta-V), Dog states modified from base states in a collaborative shared effort by casiliuscestus (GitHub), Sparlight (GitHub), and Raccoononi (GitHub) for SS14.", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e, modified by Emisse for SS14. Vox states by Flareguy for SS14 | Vulpkanin states sprited by TJohnson (Delta-V), Feroxi sprites edited by juniwoofs (Delta-V), Dog states modified from base states in a collaborative shared effort by casiliuscestus (GitHub), Sparlight (GitHub), and Raccoononi (GitHub) for SS14. Reptilian states by TiniestShark (Github)", "size": { "x": 32, "y": 32 @@ -60,6 +60,14 @@ { "name": "on-equipped-HELMET-feroxi", "directions": 4 + }, + { + "name": "off-equipped-HELMET-reptilian", + "directions": 4 + }, + { + "name": "on-equipped-HELMET-reptilian", + "directions": 4 } ] } diff --git a/Resources/Textures/Clothing/Head/Hardsuits/capspace.rsi/off-equipped-HELMET-reptilian.png b/Resources/Textures/Clothing/Head/Hardsuits/capspace.rsi/off-equipped-HELMET-reptilian.png new file mode 100644 index 0000000000000000000000000000000000000000..9e8ff7906551b958976522b0bb8e93fde0ed65d9 GIT binary patch literal 1127 zcmV-t1ep7YP)Px(AxT6*RCt{2nqO#BR~*N`M}&6$lhQ5;rj)92G6bQ`Y8z;w_wFGg$e@Bxb|4kP zIuLzmo)jh)gg#W*hOkK?Lum0u*kBZ-eQ8GbV&mdypxCS(j?k=0Y@qhu*%!|qvU9xG zCVEdyc7{722;`po%Q?T_H@|ysxZePZ|2M>GApK>Sl8h+cwVPyt|{C4-NO;S{-c>m+xjfd3HzJ|CKD+DKP;A!?1QHf-Lmb7Rz6JOFeLM`+i%v5MArEC2wwdqUJS45U{QxK+4-p#p&;~3NTz|NWHnn--Dy-o^=sX|)bN&vtTaRF8D~rF@9}xhkg$QTIZty+E zDgrAW0PfwqN_1U!Jg1NVlv2Fs@1_9I)aK>mJ6l-*;KehlC4#1D{JrPI$+8=5E;z<^1dyG8Y?J`96OfG(Kz0JMQ3A+LKsHJM*$K!-3E(u4 zJrLDgQ#JShDuv}H^6*y39%r_<=9;1iOqcv@EesJW``42wN;QbHzvH$)jzAJZQ z6oR(fo49f}RPx(ut`KgRCt{2nr&!XRT#&A*QrSQGHl7-94jjAkk)2#L5CZ?^}|FO7zj>UHYgOQ z6Gk_&70UePWU?1rhac2Iq0q8Hk@=+{>zCf5AC$CNns$T4Q6gQpH0WGyQWfO*A-$J- z)3iB>fh&4`5ZZI@bI$XB{=K>P(&vKW|BWUSBt)p0@TU>{LmEsr1MELO8ZnQ5_j&Lz z5QDwbgpUgR@A(X4dAeL8b-i*;{yj&oTKR7dcdW^;X#uJHj}{6LBGe2t%!K1K`6ruS z>-sYC+v87h;>iIz-aNoeIL`j#j8y%3mv08%_GRN}(Dh1T7|YR8i#E~qN=JTs;U;^I zTpa*~#k$4(?Jzr^^E<|+ zB6|kVarUc=0BvnOm_N;recp^KH|D;XbQ;JOZGPe?uD?W{n7})(x$CeO!Z$$04A=T zI&51SE61%c_d@6m^o^_+n+lzE7CZwqEif%a$Qpn2?pqqb8}ENC%(?!Hr%fY$ zfB-1pbHLtdn6yTz&Olx#e0*Fs^j|@1YpYb8^hNN$iZZ}$ z0dAuVa9e=eC#f&yJ#X%xCcf4n`-j3mq-mO5X~h`;%nZCFf`dC8 z&B<8kTP`1r@qGPOet!0xW)p9AbYk`*3bD?5VHnHN+B+YJXgo>xSOX1#1J;`P+hImK z7ijAGUb=WF(g4%>(ar^OP59!)QJVbqc#kcbEh>A9I)S7KImJ8n@CN!uQdhPx6OQxF z4?*jIS$uGCM>f#7E^R{5?eR=HO*Ee5lb4fpkELm>-v+>mvE49+Ij#e?uP(V~DGuL0}R6;6}q80y0V^~FgI_BN(m31 z%{6PpW4i`O5+i$k+GXFzv$=-UL#%vrbN90vY@|Xrv|?_>@|VjEc;acFWlCku7E+F67GJLQ3WY+UP$(1%g+ifF gC=?2XLZQgR-@N1Nz}{koH2?qr07*qoM6N<$f*4(9=l}o! literal 0 HcmV?d00001 diff --git a/Resources/Textures/Clothing/Head/Hardsuits/cburn.rsi/equipped-head-reptilian.png b/Resources/Textures/Clothing/Head/Hardsuits/cburn.rsi/equipped-head-reptilian.png new file mode 100644 index 0000000000000000000000000000000000000000..8c64dd1f7066ea8a8eb278024448e7df061c3287 GIT binary patch literal 657 zcmV;C0&e|@P)Px%OG!jQRCt{2+CNAeQ5*;GZ%T_4S{yQ%|Aj0qRHQgGEe`e!iT8-_Mq3?!NE+^6nzJ zA3%3oN^;O@z3Ruu8g5f`uG`KxK4`UG_4D~63Z?RJ?C@Y8p4UmF2)6U@NhT2v*S#J$ zoB2isP}SGT=Zo5{Y126J@0+~2-|wUH+QFA^-!J`baefZ%_LgbB5tR=F+g>S@$|#h| zqI{zQgoA6Ze&g}8Nu2GTV*SU%$b`m8mvfVB;{pJ{aj%Pap8;TSF){$2X2p{*<$0Y; zW1}vOs~8u+^Ey~?X0> zYDgG&kHG)>0}7?GC|~q+`0!vqQUuj6aNO%kPIqnFdnef5JHb>Yi=V%`Se&1W%t^wy zK>`Rq>39)>et{AZZN!_3T! z$k=e&nxN=P*!S7ez*|QE)7%hg|E5q#kkF`rzRV*}!Q My85}Sb4q9e0E4VNq5uE@ literal 0 HcmV?d00001 diff --git a/Resources/Textures/Clothing/Head/Hardsuits/cburn.rsi/meta.json b/Resources/Textures/Clothing/Head/Hardsuits/cburn.rsi/meta.json index 1df9c2ddbf6..549fb3e0197 100644 --- a/Resources/Textures/Clothing/Head/Hardsuits/cburn.rsi/meta.json +++ b/Resources/Textures/Clothing/Head/Hardsuits/cburn.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Made by EmoGarbage404. Vox states by Flareguy for SS14", + "copyright": "Made by EmoGarbage404. Vox states by Flareguy for SS14. Reptilian states by TiniestShark (Github)", "size": { "x": 32, "y": 32 @@ -34,6 +34,14 @@ { "name": "equipped-head-unshaded-vox", "directions": 4 + }, + { + "name": "equipped-head-reptilian", + "directions": 4 + }, + { + "name": "equipped-head-unshaded-reptilian", + "directions": 4 } ] } diff --git a/Resources/Textures/Clothing/Head/Hardsuits/clown.rsi/meta.json b/Resources/Textures/Clothing/Head/Hardsuits/clown.rsi/meta.json index 5956a9b0f4f..91cbad243bc 100644 --- a/Resources/Textures/Clothing/Head/Hardsuits/clown.rsi/meta.json +++ b/Resources/Textures/Clothing/Head/Hardsuits/clown.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e, modified by brainfood1183 (github). Vox state by Flareguy for SS14", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e, modified by brainfood1183 (github). Vox state by Flareguy for SS14. Reptilian states by TiniestShark (Github)", "size": { "x": 32, "y": 32 @@ -28,6 +28,14 @@ { "name": "on-equipped-HELMET-vox", "directions": 4 + }, + { + "name": "off-equipped-HELMET-reptilian", + "directions": 4 + }, + { + "name": "on-equipped-HELMET-reptilian", + "directions": 4 } ] } diff --git a/Resources/Textures/Clothing/Head/Hardsuits/clown.rsi/off-equipped-HELMET-reptilian.png b/Resources/Textures/Clothing/Head/Hardsuits/clown.rsi/off-equipped-HELMET-reptilian.png new file mode 100644 index 0000000000000000000000000000000000000000..f8356f09250357c7922fc53889bb874c7e7a4cbd GIT binary patch literal 950 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=jKx9jP7LeL$-HD>U@q`eE44NTv4!N zYn<&mr7gBM&5p(T{E+_1Y||w5)!5`!`r0L5^!J|E|8wGe3HOD@t2cvd?Deg0?X5E4 ze0!csj+gD9`li^;)oiw#)!d`)-`N-x3dPzZ%_q+CuKdQfWA1(3y6u1S3T&Bk zl2(;|auB`%zPWqm ze^J@7C8}u8{P&MfGRN{LEO}dgVy{!6Rs8gMa!vn*E-_qWa#7|L&~-2&h3R;$?aPZ* z@vQ=TA1rGvb(vimamQ@I-8r=xr&>PkIsIev@d-?dXV30P-ksaDcJJ*C7SkE?Sh)|B zUTnJW29%l0rNnTWC5+jolFdXoY_G%D9b7>l^39IgRa!ld-8q@DB=p$HBSvM1)y&SF zuF{LYVjJi_@wE8Y-p`x%Nt+cKZG3a$zV;cmDPi6!CaK#d-RgYX)hk-d*nH8nr`Ki6 z#jj4cyoHN?F0$Jd=g|)oIQT*;>`SZk&P?Bhnw#I=St=c4yI@c7vBady8*B4Vv@Cnc z@N6ybE$ew3a<(L$bG}^ihSzen6QA&GjrSk!N}XBn_~04OhS-UYnnzNXHtkdQ-^uc! zC~~F3geweJ7$WvQ*rlg<_0ln^{?!hTzU_)NFsu`CUmWHfZ^Zc```RPZ@WS7dJWaAp zd*maZZPz~aVCJgl|M+(F-WC4V<|Du~=U*G2)0FG_^E1~dMVxrrZ6(smW7D!sW7^BP zT0u2G`3jo%$^Q8xwjjRw?y15E-U%KmLY*#36XDc<@p=Yf!9x$dEtM028Ii%$)z4*} HQ$iB}1}L&3 literal 0 HcmV?d00001 diff --git a/Resources/Textures/Clothing/Head/Hardsuits/clown.rsi/on-equipped-HELMET-reptilian.png b/Resources/Textures/Clothing/Head/Hardsuits/clown.rsi/on-equipped-HELMET-reptilian.png new file mode 100644 index 0000000000000000000000000000000000000000..c06f25ec6a37a1951b046d3bf389ce38cea53171 GIT binary patch literal 1135 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=jKx9jP7LeL$-HD>VA1q+aSW-L z^LEz3?Au{7$M`ME9PGOz3c0n+rK9z&#s&CVA_4T z+uqXVemM_BECj?8mAXANl439W@G9Op)V_6ZaOZ-P{0#YzfA;-ZoPAv;x#aZw#e!e{ zow77ps&LLN-pSZh`{&IU-haL>?ED^n?qbX0WnpU7}fIC^n) z)$xZhYep;dR@8+PJ9NOx-osDzM&`V~($@SXh7A)M*QC!Eb+q_dzA%pEe|7bU%1+0ob1xvvC2yqx#<;9i4^U7P3s{kt=4j;dc&#^V6V z2Vn+=%bqR}P3JtxTc_OkgafD`#pkr5fVgd@P3OF84Gu9b!CXoj=Nvw@F7Ur|RKZul z(&zn`Xp@Rs}shkW>~L zSv5WUUe2-w@-q*7(EC#*d+bx1f1$1Pf^(}=O1!pv1>OpkR@-!;-^Zq6hFeAr=gILsf^nDy28ANmzU%Qh9@TedC|1d0K0p?{|FggKvY?dZCw1 zDd8Py3mN`j4`0c0;gXKX1Md?IJPd1REv$bfG-;aI`j0EPRP6rV)0;74g~tj>wm+RL z3v{;h)qOTxXFt*5tbsvb=FImYQye#kzOSsllRJB-tFbmUGKz0^9msoX5y$(W lz(R(v{qRFL^@kkBIp1B literal 0 HcmV?d00001 diff --git a/Resources/Textures/Clothing/Head/Hardsuits/cybersun.rsi/equipped-HELMET-reptilian.png b/Resources/Textures/Clothing/Head/Hardsuits/cybersun.rsi/equipped-HELMET-reptilian.png new file mode 100644 index 0000000000000000000000000000000000000000..d10ee22c7aeb253623ead6c79a952f6978439304 GIT binary patch literal 532 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 literal 0 HcmV?d00001 diff --git a/Resources/Textures/Clothing/Head/Hardsuits/engineering-white.rsi/meta.json b/Resources/Textures/Clothing/Head/Hardsuits/engineering-white.rsi/meta.json index cfa6dd53b62..8a770611310 100644 --- a/Resources/Textures/Clothing/Head/Hardsuits/engineering-white.rsi/meta.json +++ b/Resources/Textures/Clothing/Head/Hardsuits/engineering-white.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e. Vox states by Flareguy for Space Station 14 | vulpkanin versions taken from Paradise station at https://github.com/ParadiseSS13/Paradise/commit/f0fa4e1fd809482fbc104a310aa34cebf7df157d, Feroxi sprites edited by juniwoofs (Delta-V), Dog states modified from base states by Sparlight (GitHub).", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e. Vox states by Flareguy for Space Station 14 | vulpkanin versions taken from Paradise station at https://github.com/ParadiseSS13/Paradise/commit/f0fa4e1fd809482fbc104a310aa34cebf7df157d, Feroxi sprites edited by juniwoofs (Delta-V), Dog states modified from base states by Sparlight (GitHub). Reptilian states by TiniestShark (Github)", "size": { "x": 32, "y": 32 @@ -43,6 +43,18 @@ "name": "equipped-head-unshaded-vox", "directions": 4 }, + { + "name": "equipped-head-reptilian", + "directions": 4 + }, + { + "name": "equipped-head-light-reptilian", + "directions": 4 + }, + { + "name": "equipped-head-unshaded-reptilian", + "directions": 4 + }, { "name": "equipped-head-dog", "directions": 4 diff --git a/Resources/Textures/Clothing/Head/Hardsuits/engineering.rsi/equipped-head-light-reptilian.png b/Resources/Textures/Clothing/Head/Hardsuits/engineering.rsi/equipped-head-light-reptilian.png new file mode 100644 index 0000000000000000000000000000000000000000..ebf8f2c19f94e754858b2db9fc86d57d302cb80b GIT binary patch literal 1343 zcmV-F1;F}=P)Px(`AI}URCt{2nqO=bMI6UJvv;M?aA<`Gjw>u}@cL3Kl+%JSX(Po*qELetC1_)U z8Z3z-vC#)HYQTojs4?g>F-TQn3hG;l_@EIvj(89fPeVA zInhQzByOi1W!8do&WH75emT>v!J1xz8_LWoElM2lgoBzljXe6tE* zK?Q=#YgVBK%K-?eRk;NHdd_gz`WAw~3MZw^D1fE)*8xqVW7!K&Ki{!+<+2I@hLimO ztXx(>EYxa7gj)!)_BEghXaw$_+;ykJZUls-Il6`3V6RdvcAlm)}UCBN| z>(&764BYbk=2I);Z z^S65Lxo%fVy8^@)l$Y%W4)}cvm0RNUGy_Y4KcR9A7M~6i3$+$z_8cH(^av2Q`~0k* zLCbqU1%e;E`*!E=7o!?LXZs2c9{B@+8zWhceEnBp))yH5Ql2{mG6f`ogdh?x_%moB z38Y?m^Q}DqT62P~a35N80-$i`3q;E36Bg%fGiw(RMBC~_2(o&ZIrGzBPP6qMF~f$6x#L*&vIARiovR+?R)hVDVtjbAGj^CRzjeL;a<+0p-2kyrYhHU4 z90|~|El4cXO2a@eZ5x+>zBfP(mh<7!uh8V#C$r;YVatXJoUGJN!kRw})Q$|FT7!VL zjZ4gWA$Q#{(3_VCc}PNG#Y>OgcTVy7s}-NW8c?K^ zioR1LXffVt6d2E|Kv0NCw-AwTBe5&oN6+XFrX9v_K&^7TLhbk+Fr4fsow^3VA~~i2 z2qB~pLK8w{g%Fz4GM)0&=?54(c`xbIH3DiC13#T3pjMeXR-E8SfQErydRk&;MIRme zF8lE}XB)mfyZBIcd@QMlyZ}=AVRV7Sj0I1{cs{9@Gl8DwAF15@3&Y8N)0W|6KRqom z8U}hDRpe+s;J`CW{R5+7{KiO@4fo&4nTx{!tf*Nfme;IO+MaviaiREpilSsEJLKe3 zXxWpHGg3s319Y?nIs8S6j<$&}y2iQyr+&W9!U`WXz9HYGYd}D`M%by+rS(LIG7O0 zYeuMR$6Y>vEc4`VC!^6YF!^6YF!^6YF!^6YF!^7h?=0D)*nm}jgLEiuX002ovPDHLkV1fal Bg9iWr literal 0 HcmV?d00001 diff --git a/Resources/Textures/Clothing/Head/Hardsuits/engineering.rsi/equipped-head-reptilian.png b/Resources/Textures/Clothing/Head/Hardsuits/engineering.rsi/equipped-head-reptilian.png new file mode 100644 index 0000000000000000000000000000000000000000..8d81dcf711082e4f3831aaed26ecd6a94da1b38c GIT binary patch literal 1223 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 Qz*isvPgg&ebxsLQ0P7qfApigX literal 0 HcmV?d00001 diff --git a/Resources/Textures/Clothing/Head/Hardsuits/goliathhelm.rsi/meta.json b/Resources/Textures/Clothing/Head/Hardsuits/goliathhelm.rsi/meta.json index a591ed0c5be..5d63229cb71 100644 --- a/Resources/Textures/Clothing/Head/Hardsuits/goliathhelm.rsi/meta.json +++ b/Resources/Textures/Clothing/Head/Hardsuits/goliathhelm.rsi/meta.json @@ -1,8 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Normal and vox sprites created by https://github.com/Pronana / princesscheeseballs (Discord). Dog states modified from base states by Sparlight (GitHub).", - + "copyright": "Normal and vox sprites created by https://github.com/Pronana / princesscheeseballs (Discord). Dog states modified from base states by Sparlight (GitHub). Reptilian states by TiniestShark (Github)", "size": { "x": 32, "y": 32 @@ -44,6 +43,18 @@ "name": "equipped-head-unshaded-vox", "directions": 4 }, + { + "name": "equipped-head-reptilian", + "directions": 4 + }, + { + "name": "equipped-head-light-reptilian", + "directions": 4 + }, + { + "name": "equipped-head-unshaded-reptilian", + "directions": 4 + }, { "name": "equipped-head-dog", "directions": 4 diff --git a/Resources/Textures/Clothing/Head/Hardsuits/luxury.rsi/meta.json b/Resources/Textures/Clothing/Head/Hardsuits/luxury.rsi/meta.json index e4270e72c63..31ba6056864 100644 --- a/Resources/Textures/Clothing/Head/Hardsuits/luxury.rsi/meta.json +++ b/Resources/Textures/Clothing/Head/Hardsuits/luxury.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Texture edit from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e. Vox states by Flareguy for Space Station 14 | Vulpkanin states sprited by TJohnson (Delta-V)", + "copyright": "Texture edit from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e. Vox states by Flareguy for Space Station 14 | Vulpkanin states sprited by TJohnson (Delta-V). Reptilian states by TiniestShark (Github)", "size": { "x": 32, "y": 32 @@ -36,6 +36,14 @@ { "name": "on-equipped-HELMET-vulpkanin", "directions": 4 + }, + { + "name": "off-equipped-HELMET-reptilian", + "directions": 4 + }, + { + "name": "on-equipped-HELMET-reptilian", + "directions": 4 } ] } diff --git a/Resources/Textures/Clothing/Head/Hardsuits/luxury.rsi/off-equipped-HELMET-reptilian.png b/Resources/Textures/Clothing/Head/Hardsuits/luxury.rsi/off-equipped-HELMET-reptilian.png new file mode 100644 index 0000000000000000000000000000000000000000..5ef62bcbd194048252c87df674cc65054f4223bc GIT binary patch literal 1060 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 literal 0 HcmV?d00001 diff --git a/Resources/Textures/Clothing/Head/Hardsuits/maxim.rsi/meta.json b/Resources/Textures/Clothing/Head/Hardsuits/maxim.rsi/meta.json index 2a085063a47..8b6da663c09 100644 --- a/Resources/Textures/Clothing/Head/Hardsuits/maxim.rsi/meta.json +++ b/Resources/Textures/Clothing/Head/Hardsuits/maxim.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/6b3f58d7de4d4e374282819a7001eaa9bde1676d. Vox state by Flareguy for Space Station 14", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/6b3f58d7de4d4e374282819a7001eaa9bde1676d. Vox state by Flareguy for Space Station 14. Reptilian state by TiniestShark (Github)", "size": { "x": 32, "y": 32 @@ -17,6 +17,10 @@ { "name": "equipped-HELMET-vox", "directions": 4 + }, + { + "name": "equipped-HELMET-reptilian", + "directions": 4 } ] -} \ No newline at end of file +} diff --git a/Resources/Textures/Clothing/Head/Hardsuits/piratecaptainhelm.rsi/equipped-HELMET-light-reptilian.png b/Resources/Textures/Clothing/Head/Hardsuits/piratecaptainhelm.rsi/equipped-HELMET-light-reptilian.png new file mode 100644 index 0000000000000000000000000000000000000000..d9f2a8fb630a2bb4a6e5131a57f00f3d11ae816e GIT binary patch literal 698 zcmV;r0!96aP)Px%bV)=(RCt{2nmumYFcg44wi%2dK$<0}yEw>TWYS>h0@-qaPQ60UlPh$}9dZF8 zL#Dz@;weF=0&Rj0EnWvd+LU6+6eR;i^FF|^Ouauol23w3FpPf>seVL!k)#tY#TP66 zzCnoiLd4HHsfwRv2a(hHh8R+OziE%f7r+!aOHG2xodHwT&qnq4dg`~*n1HDB0At`n z#D8jaxV(R%^3XL2n@8+4X9fbNDYC6IK$!pq@Buh!N`khZs9d3XLvh}52A-!HPDud3 z5%3wfcdq=hNkH50RqiM?fJCmHD{oQ+Rqi^~aB2ePz$L6k`UO$@rOFRU@-pZ${UI#@ z3*Z5`)8AhkcM$EQFymZ@1X{L$%{c zLDU>qieZSuxduD2tS%D~PpV(nct^rlrHb#htwkMy-*NC;yfm}+KWkn8@slI+BjRU{ z@+Ql-VHk#C7=~dOhG7_nVHk#C{GaUPUvu5le-|}9I?8#nHvz#(=BY(WX z);{p;TzNG_+=I*j?L5FC%YetM4@peW5$s6Z`CxCNK4PD}=$!x&A9m-)zya%yQ@hTk zZg1ry@|{iZ1UOfQW%LtxV!1UQczCJNnYz6v^%eWhCi?(VjC19cPRSn|ZpSsC3qfbX zIti<-_n~UQ;E%zmQirOaTmT~*^+E`GP-5su;V$0;Vt!@52aMw8UAzYvhG7_nVHk#C g7=~dOhVi=i3kA>nX298)ivR!s07*qoM6N<$f&&#nQUCw| literal 0 HcmV?d00001 diff --git a/Resources/Textures/Clothing/Head/Hardsuits/piratecaptainhelm.rsi/equipped-HELMET-reptilian.png b/Resources/Textures/Clothing/Head/Hardsuits/piratecaptainhelm.rsi/equipped-HELMET-reptilian.png new file mode 100644 index 0000000000000000000000000000000000000000..ba8c7472078fc3f3ebbd75bf0eb595bcb18f9606 GIT binary patch literal 1262 zcmVPx(s7XXYRCt{2nm=sYMij=sE7~bA(7_;)Ktt#*g+X>GP{1xA6v%1mB4o6OZt|im z1w18-$kBt*AcGeR=+Ge<3jsxdK@&s+$13cR79c(G zVV0F z^V*PzP)2}H%NRa6IVt625Cr0s9LGVg*DLnm2KI%}>B$S*K@cE{A`!NQ_6s|hrkVG7 zgXekj?OT?W`>f}AOAEjlBhxhHwXW-P`$kbD&wbwqO3bg2#5iS-G)156Cl7!21?cJ=0Pxa3MQ8s4r@#M*HLU{x zEH8!L1Y!UF?o$|skzQ*gqW#yWyI9jYAR<<277%YBiXuFJX5w?LCHwpt5ApquFC$MN=CrJ!2|sE(*P$?NTz8**Y$MH7pZ4z z<^AyC9Jg+5ly+nuZ{D2Z&Yf?kT;iP1^h?%;g~cxw0pEQ6CAPIc@Ld!#-}h(YIy-sy z#S>g!MwJL~`}TJFV+a7ub=};5g~dsx|8fu!jJq57dGo8O=IoJvE5_XoxG$bmk_MMK z%COLPfqxriBH)vc;Kx52B|zN{)Qu9LZU^c{2~f8Kb)y8R+kv`K0@Uq5-6#R-cA##Q z0ChW1H%frI9jKfCy#S?t6#Y9gwfdFs5pWy_nEVb2081BOmx_R#jS7@FxDv9HpX0+q z+~`M9VKlulAzP950MIz@69CdQjb8aXbUAuR% zm$}AqpDsra>6O1jnx;+J=A4sl+oWmQl-)AiC=G^Th-R}1&NrKO?37z093O{3b@Wb{lj&%e|U*@yDjgD6nJ!W1OSMlNZPDC3jmXq*s?6j?*Hj_ zy9mP&XJ=>F+S?8FXEzcDpUdZZsNl!UD^(;CUWPFO(}2U|!dBRIEaP%-hZ# zd*uQEK&#c7w*zeIdqGucG7)`h>}(&)vM?MDr`jsX0t$sfp-?Ck3WY+UP$(1%#ea*x Y04#Z7{qb!lR{#J207*qoM6N<$g3-BG+5i9m literal 0 HcmV?d00001 diff --git a/Resources/Textures/Clothing/Head/Hardsuits/piratecaptainhelm.rsi/equipped-HELMET-unshaded-reptilian.png b/Resources/Textures/Clothing/Head/Hardsuits/piratecaptainhelm.rsi/equipped-HELMET-unshaded-reptilian.png new file mode 100644 index 0000000000000000000000000000000000000000..6205a0ec9171f98a14ba90d7597b39f7fdaea91b GIT binary patch literal 294 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=jKx9jP7LeL$-D$|9(cMqhE&XX zd&`#Vkb^+mL;XcdSM<(pz0t{j;hfV4F3X1LAN1r7Xmf~7lT*muz`>pLIDTeQj>!Z6 zBU3-y~l5hwsd)jsAJJT1&xBki~7!mG1^+w9&<%li7PH9PK9A#>iUv!2%qgj)UmnSc(0f)CDn`nF8g*b=pP z?Se}?XUqLAxOeu=K)ehL5p literal 0 HcmV?d00001 diff --git a/Resources/Textures/Clothing/Head/Hardsuits/piratecaptainhelm.rsi/meta.json b/Resources/Textures/Clothing/Head/Hardsuits/piratecaptainhelm.rsi/meta.json index 5aa77bb0d51..6fb124f6d76 100644 --- a/Resources/Textures/Clothing/Head/Hardsuits/piratecaptainhelm.rsi/meta.json +++ b/Resources/Textures/Clothing/Head/Hardsuits/piratecaptainhelm.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Made by brainfood1183 (github) for ss14. Vox states by Flareguy for Space Station 14. Flashlight state sprites by TiniestShark (github).", + "copyright": "Made by brainfood1183 (github) for ss14. Vox states by Flareguy for Space Station 14. Flashlight and Reptilian state sprites by TiniestShark (github).", "size": { "x": 32, "y": 32 @@ -36,6 +36,18 @@ { "name": "equipped-HELMET-unshaded-vox", "directions": 4 + }, + { + "name": "equipped-HELMET-reptilian", + "directions": 4 + }, + { + "name": "equipped-HELMET-light-reptilian", + "directions": 4 + }, + { + "name": "equipped-HELMET-unshaded-reptilian", + "directions": 4 } ] } diff --git a/Resources/Textures/Clothing/Head/Hardsuits/rd.rsi/meta.json b/Resources/Textures/Clothing/Head/Hardsuits/rd.rsi/meta.json index 9c520d47c74..2a2712e0d67 100644 --- a/Resources/Textures/Clothing/Head/Hardsuits/rd.rsi/meta.json +++ b/Resources/Textures/Clothing/Head/Hardsuits/rd.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e. Vox states made by Flareguy for SS14 | vulpkanin versions taken from Paradise station at https://github.com/ParadiseSS13/Paradise/commit/f0fa4e1fd809482fbc104a310aa34cebf7df157d, Dog states modified from base states by Sparlight (GitHub).", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e. Vox states made by Flareguy for SS14 | vulpkanin versions taken from Paradise station at https://github.com/ParadiseSS13/Paradise/commit/f0fa4e1fd809482fbc104a310aa34cebf7df157d, Dog states modified from base states by Sparlight (GitHub). Reptilian states by TiniestShark (Github)", "size": { "x": 32, "y": 32 @@ -37,6 +37,14 @@ "name": "off-equipped-HELMET-vulpkanin", "directions": 4 }, + { + "name": "off-equipped-HELMET-reptilian", + "directions": 4 + }, + { + "name": "on-equipped-HELMET-reptilian", + "directions": 4 + }, { "name": "off-equipped-HELMET-dog", "directions": 4 diff --git a/Resources/Textures/Clothing/Head/Hardsuits/rd.rsi/off-equipped-HELMET-reptilian.png b/Resources/Textures/Clothing/Head/Hardsuits/rd.rsi/off-equipped-HELMET-reptilian.png new file mode 100644 index 0000000000000000000000000000000000000000..d86769ce5f856ed074498fbe9be31ba86dbbff79 GIT binary patch literal 870 zcmV-s1DX7ZP)Px&AW1|)RCt{2nomd+aTLct6D}Ttc0EjW@L(Hk{7gZl@;0|1I&{&CSb1E84533r zga^HJ3nfEuVqPQ>yC`&#xg`<8!VGy>_t2r{7qlyMh>fPhIHQJwzi}(1_klgk?>FM%9YpGw~-0aFwG;mq^9D5ds|E2WruemAufCi)$hFH*d> zNH&w>bG1x1lcRWVk&eq3Q|TKeVDiNVK~Q0MsEb;?%BFr#tzKn#sEZ(|F!^G`RNsh5 z{|f-MdNuh01i_b7`bR!DN~y53&_-#qf;Hz6-f7=8vhy6z`@Y}s`(UrW@B7yMOAo_Z zy-GHdW8%Y8>-YJi+BLod0KC;G=)RJNHRs{2rmvIG7UO(rjEtq+}xgFk5)uar_M z1n4ZZC1a({3c!h4c|i~aK@bE%5ClOG1VIo4LHG|z^*{b#zIb32cD6kISLy>&-5Ymaoz?vQ5G6PNi>@ zfH?S;fi=$BS%RR#(!v9jQfRGHJ7KD?wMHq$(!v9Rpu$-@OUuAoDt)6ZGng-i*-VZ% zr(P#x!$Vy_RJ*_S-ATq9eH``%w%+XS(~Y_Q^A@#w)kyouFUHw_x&4f|N(?0Z0=-@E zs<zpwV^0xF!kESMpfgAn8ef-Qw)+Gb3#3_eV~GQFZw7+oA>F`~JS3ptwJvujD1~ zjx{y*KHO`2abu?}PZT(iG)X=lq0iyl^Yc5(T?@D76(Ect;KzJt#Jk~qzQ8PLM2eIQovgJC)ZUW#P_CZQw wyCrrTHKZRw5ClOG1VIo4K@bE%5Cl_x0dFI4E?lqykN^Mx07*qoM6N<$f}NwBng9R* literal 0 HcmV?d00001 diff --git a/Resources/Textures/Clothing/Head/Hardsuits/rd.rsi/on-equipped-HELMET-reptilian.png b/Resources/Textures/Clothing/Head/Hardsuits/rd.rsi/on-equipped-HELMET-reptilian.png new file mode 100644 index 0000000000000000000000000000000000000000..c24c0e621a809e0197578b5694385a7bf4bbe82d GIT binary patch literal 1218 zcmV;z1U>tSP)Px(d`Uz>RCt{2nq6oVR}{y86E-wKFzd%g6HJ<9>)P3TV53D^+iffsqy?cUBoH-k z4F%iUhtdaW74@a`p-mUb2Vw{sP-zH?i-Ahfw6&HdHYPHou~8dElijV(CIlN2oj%OY zxJfs3XLs`uygwL*xpViPbN=_teb{s0IY&xpmTugha(sF0a0WZV@y1fHG^cIb_7k+1 zumDj*h0)7oIL`BMToFBO2O19T^8w&-RRVBmpN}SgASwH{1n3I%bZ+v=w68P#r)lj)>>cL!yqZkqf7+x8O@Aezp@M~+@4 z93CYv*TKEJ8rQBX+`Frhm+K%L9_7fs zgbzX4E908>ou<-*uBc1ER>Xte1O=7#O^R zs;bh*Yd+T_QyMv$PQJVGl{DkMqDqO{OY9SfE;c?siKac~(%CE`{$92ZC`A0dTsoVD zrafkSeDc}+*;g7kb^4s7s)o2LoF%l~YL-?wO8`(+RXTP0oD}P?jnMudS(bH|%f-qi ziwu=(6}($O=>oakOSz|rkw+7RLLp2i7Xl7DlS840)apv5C{YUfj}S-2n5e1_Ws4y;}0j?BakBV(Tk9>08yvjh&~R--qR&S zOyGsH?mws6i;$E6b?$l{jJo{l)yvtu`6Z?Y7g77A`+d?ZLcHMH4-9oWJQJKh|0g$Z zhB12u+J>5Km&R=O2h_Rib&so(4SU9DIlPOk>?c&$RN(MT(0*X3lbIbG>Bb7ax~77x z>?gDw-o=JJV|ZMZ*2dVuRtD6S7{M>8y+E!jhuqxd6ciTo<4=F^;K3Lk&BwLt3j5Dg zu45iDVE@)Dy=5%Q|vMoSPrjs8s z&RAogeflaZ^Oq9ny3Mk`+yMN2e-eMsYp!&j0UxdZHMA`M1!Mgehj?#GF(daM^7S{r zTl3y|x|PV3Ha`NGyMKJ_Tg)mk7f2)@OR8__2^H~llUC$gdIp|1loiujsj=pGF9wTso?(S|0U@!I5 zl_Y)^q~xX9GY|@etbT!QYmIjY9a35q_+nbuAtv~CFP7~TvMpsNO%cH8ACQh2JEg2o zuK?a2LjZlJ5x8kD)lbdVClHUQ16InF9efu6Wv(A2iMj3o&l)vEKY~CY5C{YUfj}S- g2m}IwKp?QozoPH%cz1pJEC2ui07*qoM6N<$f_HUAMF0Q* literal 0 HcmV?d00001 diff --git a/Resources/Textures/Clothing/Head/Hardsuits/salvage.rsi/meta.json b/Resources/Textures/Clothing/Head/Hardsuits/salvage.rsi/meta.json index 337a2a380a9..8998f15cb9b 100644 --- a/Resources/Textures/Clothing/Head/Hardsuits/salvage.rsi/meta.json +++ b/Resources/Textures/Clothing/Head/Hardsuits/salvage.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e. Vox states by Flareguy for Space Station 14 | vulpkanin version taken from Paradise station at https://github.com/ParadiseSS13/Paradise/commit/f0fa4e1fd809482fbc104a310aa34cebf7df157d, Dog states modified from base states by Sparlight (GitHub).", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e. Vox states by Flareguy for Space Station 14 | vulpkanin version taken from Paradise station at https://github.com/ParadiseSS13/Paradise/commit/f0fa4e1fd809482fbc104a310aa34cebf7df157d, Dog states modified from base states by Sparlight (GitHub). Reptilian states by TiniestShark (Github)", "size": { "x": 32, "y": 32 @@ -37,6 +37,14 @@ "name": "off-equipped-HELMET-vulpkanin", "directions": 4 }, + { + "name": "off-equipped-HELMET-reptilian", + "directions": 4 + }, + { + "name": "on-equipped-HELMET-reptilian", + "directions": 4 + }, { "name": "off-equipped-HELMET-dog", "directions": 4 diff --git a/Resources/Textures/Clothing/Head/Hardsuits/salvage.rsi/off-equipped-HELMET-reptilian.png b/Resources/Textures/Clothing/Head/Hardsuits/salvage.rsi/off-equipped-HELMET-reptilian.png new file mode 100644 index 0000000000000000000000000000000000000000..f16751549a4e9c135fe610a496b632ea5eab8899 GIT binary patch literal 1139 zcmV-(1dRKMP)Px(ElET{RCt{2nqNp;R~*Mb$K_>ztcJ=~ERmtIF!E5z+(><@f&)=UDXV>1SJysR zXggfz>wMV5UYb^EDU>mpV|%il45tK)SV0i6ZQ8o#;if9Z;O*2D|CG*$t=>IcZ<^RY zyXVe$$9g^xNY2Uq{l4eRA@`E+ftMU%`y&Z#`{I z8U1@S0U7$h_R8`cH9zP#g5`xYRFx1cFU&GyJ7{a#)W6Aje`y0+_gqRh(-&5sIi5?N z*T-ppDFgfunrZa405IwsV)W<`qrM>k8htG}H=%XUCBy2!8Et2`qnaMs3$)d1yjydK zxAMCw(|0qSKgWFN5ZW)-90_pJpVzX-;wdkUf1M|>5+lO6R6QvJIwy})R~_Q*SECRD zb^*me6z+LyiA>5hmqpvz4G+Mx%lzCwHcLF^B~Y|PLW?=t1yTl_`1AlXNuA2IGgRpn zpqt}kYqz+!F@KR>X%RB~Suu!~^a4u+%L{=e;wdks6@!qJuP5~zaPfy;0T8==hw0h5 z^ecAzPS$*`hzyU5nWRpsuQ+SG)K|<*QYU>2ltB6}V2PMtSOj2xVbO7OCs_RfVpGci z|Ej;#gHR@QHKFv#b}e2Cn~EG8@Si7_PlEp^lmTuFa2sWS+XCE18Q``6w^0VTEx>J* z0d5O$8)bmo0^CL!;I;s_Q3kjzz-^QPZVPZ5Wq{iP+{Sh?l$pIhFOIfy`drf1vJ_(phWh<*Qj^#c%E~-!x%tg9+;mRV6@nJP(MG&f3TOTBEPX z6tgY1t~z7{ip)H2V&Jo<=0B+a9x&6IT$x}Vj3@xahK7udC`=8pyDRJQls7MOH3vH& zp7Ih;L1RG>|Bm+oGp z74g1@wrffma5!X`&KE%VkG%l+SDNwoJJ|QpNyyi>OFFVotlYrk@8HH=M4$*GVzaK)4hWVP z^5eKjXYn&hovyR(0MzGqQ&zGYbQtTq1*c^y|1*`}o}sF;!rTF~bIh;7cj2%2dBAkU zIyZ1QWDuKLw!H-$JqKiF^w!w`FoorsCp`>qPR4;J=L4J|l@43?|9Hy#)bz&uh_v>XrUMAbatFq9toOFML_ErC>|qaqFx=uFnZ{oog4fbN9u>&EFnd z{Z1S?AT}Ei?$Hd1l_?Yog+ifFC=?2XLZMJ76bi-5!{4Kip>-Y&Xm$Vq002ovPDHLk FV1n^R7d-#~ literal 0 HcmV?d00001 diff --git a/Resources/Textures/Clothing/Head/Hardsuits/salvage.rsi/on-equipped-HELMET-reptilian.png b/Resources/Textures/Clothing/Head/Hardsuits/salvage.rsi/on-equipped-HELMET-reptilian.png new file mode 100644 index 0000000000000000000000000000000000000000..0c273b2649d6040f112e63b73888abf056c914f5 GIT binary patch literal 1479 zcmV;&1vvVNP)Px)fk{L`RCt{2nqN#)R~*Mbm$5O70+k8~t2ksdQU|0mVP?q~M6)_Di_!XEbembS z2lt?+Jellu$z*DbS+)lqFM9z)7Na&nK@&C=Rw^iUwu)K^<&PCchyQ|j_t4(%78LGf zkQ?UxBuy^och33#e!qL@IqC1fD~>R&RgC@9R$eMPo3986;Miu4T5IaP!sNd5jl(X} zuk#8q{=rOvW2O$4R6}67;dLTQ}-zzJm-I1Mx}Ah9 z4=bN829QMk3g=d=58w^`0gGado}huMXGigkx>f5dO#pzQY*#uBbxpVutDzLg05XAd zkRtrRmR%J9OI6IN27@=X79K!+M!4bhr5-#%0~X^5KCe5n3W`2U`m!xJ<)TdA;>c-1(dMjv3js1a|k0T{uWn*xmB2^z>LYJ^?@RO!$7 zB^bdE^jFwQ99La8ad&pn-P0HSxI4SJ+J2J?TZsecXKt5&RR3)AF~^9qbERX2ed{{fYuIZjh+Cl z9ncy*0a`ntHF^THc0g-h`2;BbNladQm)GXyNG0m|#9=oJ!1EWF#F{#997KHOiXvZB z|0a0x$ObWx8;WVmOiKzs*qKtNmrz?Lm}dO*%JnON*z!CeTs*R2qHOQE*VO1Jeq*+e zN=1t?T#suz^TibVx=(%vzMHak#yjX4Dam|{W3O4S0f3m2AbF^d1l{S0}E!%eXO*rXz599OhgH(7sJCib7 zIwuZ2W5QAny-@POC_}HmK|aIM(B*`aFdLRj56=qM@Zc%5{+0~DDngX+N@v2Eg@}l6 zw4HeKVcKsYSd55Hg#xO!L2GUbo}hv8qDBDj`U7;eceCz83)aMDHkmqjqx}X+ms{k+ zW*dCW*eAcYlIp+9CQ}F2#AX1lyKZyOAHJk8Uet&uXo%byP`(6aRT+|M^bK`QbX@)u zYvCFSi_HuKhsiK5CD1(><2>Pdz0&1Rq^|(1kmeZ+J%VKd1HlIj^b9jNG(^M6b5URJ z^af@Vin`jMwEug8hAHN)l^dhayZ3LNk6nNhhfYOrsGU3=UWM}DWp@VRYU;g;s+n_A z9F^`0L@y~aKj(nshrSVd`uc^otJfzay*;085hf>~rp_zA3YBdg9UUDV9UUDV9UUDV h9UUDV9UUFj`~y7zDUfM5ugCxZ002ovPDHLkV1ihnv|a!J literal 0 HcmV?d00001 diff --git a/Resources/Textures/Clothing/Head/Hardsuits/security-red.rsi/meta.json b/Resources/Textures/Clothing/Head/Hardsuits/security-red.rsi/meta.json index 66cc0161ea3..08c2f2d3803 100644 --- a/Resources/Textures/Clothing/Head/Hardsuits/security-red.rsi/meta.json +++ b/Resources/Textures/Clothing/Head/Hardsuits/security-red.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e. Vox states by Flareguy for Space Station 14 | vulpkanin versions taken from https://github.com/SPLURT-Station/S.P.L.U.R.T-Station-13/commit/091d9ec00f186052b87bd65125e896f78faefe38 and edited by Floofers", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e. Vox states by Flareguy for Space Station 14 | vulpkanin versions taken from https://github.com/SPLURT-Station/S.P.L.U.R.T-Station-13/commit/091d9ec00f186052b87bd65125e896f78faefe38 and edited by Floofers. Reptilian states by TiniestShark (Github)", "size": { "x": 32, "y": 32 @@ -36,6 +36,14 @@ { "name": "off-equipped-HELMET-vulpkanin", "directions": 4 + }, + { + "name": "off-equipped-HELMET-reptilian", + "directions": 4 + }, + { + "name": "on-equipped-HELMET-reptilian", + "directions": 4 } ] } diff --git a/Resources/Textures/Clothing/Head/Hardsuits/security-red.rsi/off-equipped-HELMET-reptilian.png b/Resources/Textures/Clothing/Head/Hardsuits/security-red.rsi/off-equipped-HELMET-reptilian.png new file mode 100644 index 0000000000000000000000000000000000000000..73c0c1a240825c5e8fe9799039341228c1a50d66 GIT binary patch literal 1027 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=jKx9jP7LeL$-HD>VBYKL;uumf z=j|-toZBf9$Lqb9vn4l8nkcKb^rW7m_clMLSs?@vyi7Np;_~iipm06#px5>9&PyIyvgRgcT%yzIrf-O%ZhDp{N8<}GX8b# zzkk0s{`ES~Jn8vtWvBGp=lu1iZe)BmP3*_IFRBdETXi>X>?Q!t{r5p#K%GYh@ZiP&_Y=0;D^V#AxIomz7UM-waU|M@@-HTiMk8RFck>AwN z)v%&r*TP^P_lTQ$AH)8rXy4ZDddN}gEFPPsbEi9gc308vj}2Q_zPPYM!-;Lj%KF1K zPKGiM%N{cxEohN`HhE#?`hsBl)onK}?qYb85&JB@sxl*vIYgPrdDX-tQR3JMsQ~<<)H&QDSHH^B4uVS*jkFvs@QB*U+_YVn_(kocW@5 zi|)Le5OQVX{DXxnUPzrj=y@%Bwhp^GzeuzO^E;D&1^3o}Y>^Fi-urRa!tc**Qa%Jv z?@t!Cw_M`=<=x>KzZn|JCoQk~zi;jTvW)76i64sOKg>UHy7s_--pq#kOn=;@9&BgW zKauT+?t%OzjCI@}qzMaGzT*|p>e;cw^+NBhYZDJPy-57Z@yGbt0=bJ@TZ|Q^pStmS ztM4W8XD62$eYAAk{rnuW*_E_0S{QtAm6&S%MmKv4)I`rqp$5xrsdtb5WFIm3w zg;aKMpx16S-_wu0LSD*NPvzVha;%S)Nk^8uXm9ERx%D~QPpnc5d;k9s`^w8Xf9$Gi z7V>nkGKpNeY@*w}WKqy9Q^w_HFXHxG2XZg1ySdtBdYSK}F0ad*G?pyyWIZw|>V@os zu(tIsqGen3e*U#Rpc%dT{pzbCA3i)>{3FLE(f)1HOCTk`+v4N%kB{}u7&gr}ejL`? z{g7jQi`tHRMlIf7oY+)EMGJNroqFr1Ur|@z|LE*u<8zV1A+0Js=c=D}3Mb5CIPw3k z4lp_w-+A|8-L>l)L8@X#2Wq!TpA6oXDb;XU!tjRLW|=u6kwFsXeugqH@3wTU`tlU4=z!f<%D1n!(f6&t;ucLK6VbKKEY$ literal 0 HcmV?d00001 diff --git a/Resources/Textures/Clothing/Head/Hardsuits/security-red.rsi/on-equipped-HELMET-reptilian.png b/Resources/Textures/Clothing/Head/Hardsuits/security-red.rsi/on-equipped-HELMET-reptilian.png new file mode 100644 index 0000000000000000000000000000000000000000..4b35c278d3f856f28be36637c4a5a056eba6f8cf GIT binary patch literal 1476 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 FV1jXGgj@gs literal 0 HcmV?d00001 diff --git a/Resources/Textures/Clothing/Head/Hardsuits/security.rsi/meta.json b/Resources/Textures/Clothing/Head/Hardsuits/security.rsi/meta.json index d038866cd74..61b7227c6af 100644 --- a/Resources/Textures/Clothing/Head/Hardsuits/security.rsi/meta.json +++ b/Resources/Textures/Clothing/Head/Hardsuits/security.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Sprite made by Gtheglorious based on the sprite taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e. Vox states by Flareguy for Space Station 14 | vulpkanin versions taken from https://github.com/SPLURT-Station/S.P.L.U.R.T-Station-13/commit/091d9ec00f186052b87bd65125e896f78faefe38 and edited by Floofers, Dog states modified from base states by Sparlight (GitHub).", + "copyright": "Sprite made by Gtheglorious based on the sprite taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e. Vox states by Flareguy for Space Station 14 | vulpkanin versions taken from https://github.com/SPLURT-Station/S.P.L.U.R.T-Station-13/commit/091d9ec00f186052b87bd65125e896f78faefe38 and edited by Floofers, Dog states modified from base states by Sparlight (GitHub). Reptilian states by TiniestShark (Github)", "size": { "x": 32, "y": 32 @@ -37,6 +37,14 @@ "name": "off-equipped-HELMET-vulpkanin", "directions": 4 }, + { + "name": "off-equipped-HELMET-reptilian", + "directions": 4 + }, + { + "name": "on-equipped-HELMET-reptilian", + "directions": 4 + }, { "name": "on-equipped-HELMET-dog", "directions": 4 diff --git a/Resources/Textures/Clothing/Head/Hardsuits/security.rsi/off-equipped-HELMET-reptilian.png b/Resources/Textures/Clothing/Head/Hardsuits/security.rsi/off-equipped-HELMET-reptilian.png new file mode 100644 index 0000000000000000000000000000000000000000..3dd36e2f9f7baa137de2c3dfe18ab756025d8004 GIT binary patch literal 817 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 U!cQfPmjD0&07*qoM6N<$g6l(@PXGV_ literal 0 HcmV?d00001 diff --git a/Resources/Textures/Clothing/Head/Hardsuits/spatiohelm.rsi/equipped-head-reptilian.png b/Resources/Textures/Clothing/Head/Hardsuits/spatiohelm.rsi/equipped-head-reptilian.png new file mode 100644 index 0000000000000000000000000000000000000000..c458ba5d56a5c987fbb953caa7edc6eb887d6fc2 GIT binary patch literal 767 zcmVPx%xk*GpRCt{2+QEwwQ5*;G?^+aF%TkbT3Q33Q&=3>3(MsV#x(LCZgbsm+ZhPq7 zpU|QIpqtSl>R(v)5P1k$=rRxyh~elCF3FINGnB7``=;lpyZheGjs?FDcyQGB`@Nsz zjPUyb?-RSi}trh{PBo%WLII*X34RDen`&7N-F5)ZLBix6de=>j~u zx5oDSBUrW*94qCsCrUyF-@F+Apct&aC%;}o_5;6ukC3Z%@MgP#X4eZIrF{0(uMxVg zvr;|_%XTJWTeic$1Zh$QFijHxuzUaN)N9SIhjnjDDT(7+_qKvfhhsOpUXY&*sRHP_ z4gkp2IskyYo}t)^~FukdM-oyqE#uTSthlDOREySu z-oUKBglc^0_Bd}(*I%_JI*gw_ zL(?>ra|{F5L!;G`z7s^!9?zs!rrs0fya1mGm=!}5+k8M+9PVA1w;aSW-L z^LAFghjhBk@%`bgLVD>ng;z69s?5=DoOsys|JT-pbV04jr@Gd&?YrO<|6@~Y*#@I9 z?%NCUe&ahUzOsObqLPalzCn|j7S=fK;4b<7N#DrKYm+|AZc?+u^b zF0S^^bib(|*F;8NZo?jaK4-t>3KbO{adJ)V?Q{GRYYHTQ;^tBv9cJ7N0n_f=`FZKS zv_E4P`r+WaP?^1ZTCX0pxK({v<4={;=7pKzOdc6g9S`pm${9;r8I?Y3+FU7HWYt={ z`}T~R7dn%L>RGR}Fe#h#0yVkl_XEkE3no`uoaWr&4fJPlmc5(Nx8Cu~Cm@-)VzG3f z|AA1OBxa_yiUp@QfOcFcvI3G1rU{c@$lZ`)RaR;TjuonL>$|D{PenH!QAGC zpUKnTT5+CyuYXq6++5LRx`CB>_*UHukIL%zKm7SfXWRc9Z7-fKd|F~sbEDypfBET8 z;knXVCcSyGY3cOZJ-2$!oh^Kw#ddQ~-<8d|DW9#bUF~`O=ZI)R;pfxqy>6d7vi&-L z>PHoewG5A94?NnxBg1^hF5y4+2YD9gHkh4ZxW$xlm;|Qtmz3*OCi~*8Z@s!4K6!qA z+yf=;>h*l5-hY{B;Sj)>?)O!qVdoD&&!z}%&^%%zP$NrOVgo0%p43Cgj6^^djw*g7XG+*Z-T6a;GrvjttT-4 zxvFH<_xy)f@6{_3kDCuOoH1q!v#tR~j(^;n83(5b+Wh*Vw`F?T{tZD>6Q*v9P+#zT z`(}f#birG%YL}iXSYX=HD7;KD`1|_@*Y3qV)jqJV;Pl^3*Gk^1w5*%VA(!o-GgF20 zub-7FXO!RZ`CBJ1HN3ja*;iwRm&TFYDkWy1Aup`XDZk=;6U`XS?0uo=iMr{%)@hd& zt13<2#ogV`wCj`BzjfaoRXbkaXxKVUA;8D%%0uQZKl{p!pMRBjyj3wuoT;$4cvIzP zhmeC|j2XOB*HuLC}LNssIXHq n$v}dKt@&UAoa*`BR?m=RxH_yMXGsRI3}Nte^>bP0l+XkKTyh#` literal 0 HcmV?d00001 diff --git a/Resources/Textures/Clothing/Head/Hardsuits/syndicate.rsi/on-equipped-HELMET-reptilian.png b/Resources/Textures/Clothing/Head/Hardsuits/syndicate.rsi/on-equipped-HELMET-reptilian.png new file mode 100644 index 0000000000000000000000000000000000000000..365d41db24588d3320c204cdad8c45f7a56def6e GIT binary patch literal 1737 zcmb7_c`)0F8^*t`h`3Xsu9ezYXR$45S_E|@w2q>RR2%FnDh;Ko+lHu{BBpDRx~fuf zpQWf{UD3MIpj|iB7D1^XLh-YI|Nh!{=6#--=Z|;ho%zf>iH`Odafkv00040ttfkYj zoBg|B(6N^K2hSWEUx*XtB2YP`vcfq&+kAP$uE6}Zw*KLhAU>-PG?Lo(9F24-y8RtPBo8NT7`4f zxJ1F`3hdSEY(Xdy3XPBHmNx=TjtCFGmarVW7vS%5FM?$p{^)C7$YF@@x1|{Y(-4H$ zCD_jTG%d_?wGu#a`y+k(O7Q8Z-L)DB`R~^J-_UL0RuIXUe&}_-`(Qxcoqsj@p{Y&l zCVLh^&b(<{$qplKZQBBok!yMZAA9boQ~pZ7n!c)YF`dqXBc2I$jLq^QemUt^$T^1t zgQ!dEk4yz#ALsJ!ECD^?KQ_%$BEEf*ODn6`77qnQ*MB%yE@e?ycl%>SA_bVhr`qPH zlnmXMy>70O?JIi8P%GP7w6Y+xB(+gai-ZK?=^T|ptfdHDkjYhPVIlfeO4ZCB zH3@W%EbJ)AfSJpUdOuB}8x`qZxw`_XNWG9GfFr z$S;DoH4WaGfIpp_%=UE3nwl9Jza8DP<4h&F3pqyhG)tzgQWby1S*{aU0>P!dYOKs# zHgAl2r{u1%(Z-tyip;%33mH4w`8jk@vEDQB?n3DthD1fUFe*)1RW^m0IS3*fQAzgQ z4w|qam8?<{cVp=Lypc}C*=wl7NT0ZgnZ>-(oMNloWcbfz9cQG3Kas`*@dij6Ra%fX z+Cr74ukdX2Y1(Z@ZP+w5!K94Mbw0(@?2X`X^9PqAiM+W+#aHmmsG=u1r@0Jfvs9nG z8=#SZ=L3t!K#2cre58_gO$_co!)Gsp77W-X-vPAqPiEgZ=kjA2LzXQ}6 zcp;##@E?_$-wLP^yp}~@ND?q|DAZ;=WV5V`-L-dJchkh?yfY4XPJcC8v{=LnxNd=8cjn&; z=|Ly^Fo{ooDg$@Isw0PW4bjL;xAd`lpJHK0?gD6~=~J?`{@yi4tB3Sr`7Dd|QKnSI zWABe0*bD_^u%#kdxy+K#V-_q9v-lTLgbGkr*)h_~+< zHXz()6np*eGv}(l?u|A&=DGLsSJP;Tv6e|RZroe7r&Gz+39ugNWNQ>GrJN3twuRy` z8ENWNPqFhjS68zPMWq`>FK`bww#8+i_T$qFj7j`jvWY#P&)kSt=Dx3>6K6Z>ng~`x z$3HG4x;)vxiuP6$)79zNHq-VS`s2c*0?mUjtwJxWdg<8Rn$*ksxuG09+76lhR`{ms zeAGr)S`^jJ*DdQcrglQ2>N;HU8rJ&f>ZXby#(ftaN;##Y8;}0*o=!3K;+t7o$$)T< z-ld9_r#(m{5`BU%pL&+FaQNfQ{vqd$ikp^wV6M&@Z;Nu&>8vs|A*(z!?HKiOks%zb zC7AGh8Ue2#31~uUA;aCn;HVEukG|5t(|g(4h$A0k856UfR*_mn)%d~h-v2+f3bT9( XV80?O2O{jan*bXtd&|m;_{aYPg|I-| literal 0 HcmV?d00001 diff --git a/Resources/Textures/Clothing/Head/Hardsuits/syndiecommander.rsi/meta.json b/Resources/Textures/Clothing/Head/Hardsuits/syndiecommander.rsi/meta.json index 4eb88244b4a..bff96521599 100644 --- a/Resources/Textures/Clothing/Head/Hardsuits/syndiecommander.rsi/meta.json +++ b/Resources/Textures/Clothing/Head/Hardsuits/syndiecommander.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from vg at commit https://github.com/vgstation-coders/vgstation13/commit/a16e41020a93479e9a7e2af343b1b74f7f2a61bd. Vox states by Flareguy for Space Station 14 | Feroxi sprites edited by juniwoofs (Delta-V), Dog states modified from base states by Scrubdelub (GitHub) for Space Station 14.", + "copyright": "Taken from vg at commit https://github.com/vgstation-coders/vgstation13/commit/a16e41020a93479e9a7e2af343b1b74f7f2a61bd. Vox states by Flareguy for Space Station 14 | Feroxi sprites edited by juniwoofs (Delta-V), Dog states modified from base states by Scrubdelub (GitHub) for Space Station 14. Reptilian state by TiniestShark (Github).", "size": { "x": 32, "y": 32 @@ -41,10 +41,19 @@ "name": "off-equipped-HELMET-feroxi", "directions": 4 }, + { "name": "on-equipped-HELMET-feroxi", "directions": 4 }, + { + "name": "off-equipped-HELMET-reptilian", + "directions": 4 + }, + { + "name": "on-equipped-HELMET-reptilian", + "directions": 4 + }, { "name": "off-equipped-HELMET-dog", "directions": 4 diff --git a/Resources/Textures/Clothing/Head/Hardsuits/syndiecommander.rsi/off-equipped-HELMET-reptilian.png b/Resources/Textures/Clothing/Head/Hardsuits/syndiecommander.rsi/off-equipped-HELMET-reptilian.png new file mode 100644 index 0000000000000000000000000000000000000000..f9d88a7b9b10bb4e96937d7230dad921b2724213 GIT binary patch literal 928 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 Hu0mjfcx89> literal 0 HcmV?d00001 diff --git a/Resources/Textures/Clothing/Head/Hardsuits/syndieelite.rsi/on-equipped-HELMET-reptilian.png b/Resources/Textures/Clothing/Head/Hardsuits/syndieelite.rsi/on-equipped-HELMET-reptilian.png new file mode 100644 index 0000000000000000000000000000000000000000..808d0ee8cb858e11c27999ce48f34f5d405f0cfa GIT binary patch literal 1660 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 literal 0 HcmV?d00001 diff --git a/Resources/Textures/Clothing/Head/Helmets/eva.rsi/meta.json b/Resources/Textures/Clothing/Head/Helmets/eva.rsi/meta.json index c925a9e786d..b6db4eaf17a 100644 --- a/Resources/Textures/Clothing/Head/Helmets/eva.rsi/meta.json +++ b/Resources/Textures/Clothing/Head/Helmets/eva.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Sprite edited by Flareguy for SS14, original unedited sprite can be found in https://github.com/tgstation/tgstation/commit/40d89d11ea4a5cb81d61dc1018b46f4e7d32c62a | vulpkanin version taken from Paradise station at https://github.com/ParadiseSS13/Paradise/commit/f0fa4e1fd809482fbc104a310aa34cebf7df157d modified by Floofers, equipped-HELMET-dog modified from equipped-HELMET in parts and collaboration by Sparlight (GitHub) and Raccoononi (GitHub).", + "copyright": "Sprite edited by Flareguy for SS14, original unedited sprite can be found in https://github.com/tgstation/tgstation/commit/40d89d11ea4a5cb81d61dc1018b46f4e7d32c62a | vulpkanin version taken from Paradise station at https://github.com/ParadiseSS13/Paradise/commit/f0fa4e1fd809482fbc104a310aa34cebf7df157d modified by Floofers, equipped-HELMET-dog modified from equipped-HELMET in parts and collaboration by Sparlight (GitHub) and Raccoononi (GitHub). Reptilian state by TiniestShark (Github)", "size": { "x": 32, "y": 32 @@ -18,6 +18,10 @@ "name": "equipped-HELMET-vox", "directions": 4 }, + { + "name": "equipped-HELMET-reptilian", + "directions": 4 + }, { "name": "inhand-left", "directions": 4 diff --git a/Resources/Textures/Clothing/Head/Helmets/eva_large.rsi/equipped-HELMET-reptilian.png b/Resources/Textures/Clothing/Head/Helmets/eva_large.rsi/equipped-HELMET-reptilian.png new file mode 100644 index 0000000000000000000000000000000000000000..86cf6f8c13619005aa40141a9ed83bcdd070ad1f GIT binary patch literal 1020 zcmVPx&wn;=mRCt{2n$JrcK@`WoX$wU(iVRlMqlYeP7rYhr;?^8WPKl>d#A90qytD_s zSxQglP%pw#dK4+uLs}_{htT*pELN5X-i$vo2&R`F%Jg7oyNL?|)9i_mo)?DQBsar>VU z{u^Xq5Vmbc76j8YF)}j3bzKJ`1e&G+0362wV+`!{7>7qENT<_SUS1AA0|e~!7(Fja zUmDx1AJaKmTR{<-2V7(T0FZ$}93GuW+wvVL5&d6NpD#^baJTR@7gZKeO1ZA<002UW zJ8>@}3-o`UzC4RUDP~y8vLK^8Sfv-$}jR27sYzH8f$(V5i3* z1A{I5g5Wz&#-|FhBJ0{AVfKtlu58b;I1Tp!;qZ3$`l@J>JAiW6M zwvCyY8EkHDqQAc%XJ=;^A0Nlc%8IP1z%+Z>kuQRx2%(g6Lda!NjCHIaNc2 zCeS;&*!De=yprlt9F4#O@93a{x{g^`vF&J2#Rz7D5X4^Ou~Cm*~$9>LIZH| zl)dMKlu|CML23=~p3vI14Z|?tI1W;&6jG^FC{M(X2I0?f92kZH!!R&BJPgw`r8P)r z03ignZ6lk_Vq;?i$>&A)xI779se;0*)XtQwT|X>UCJGN0e$*Y$Z+uMWG)+TaUtb`b z()R=s4 qC=?2XLZMJ76bgkxp-?FPYyJQOWsI-$a{Y$@0000Px(4oO5oRCt{2nlVfpR~X0tKt`~Fo=IaOB(P8}SL=o@9awn53!d1jsE8rnPGZTz zP!&b7t4gr2Al*`t0adERP7{;O}<%i!Yx0 zrMK^d_1qD?P|p}mi3jiByC9|$M(|veQUCyBtSP^qF;IH@PB@;h;Mv((zf>w=@cunK zeDpaqO$+*5*Tv5E77h-NBQt?g3SHNI!!SSy3G%zH3&t2&^#})t$H->0SYBSf{tDob zfzPnBy@j3atqbi3hsUzvLZN9IT-OCquYmuOU)U+`zT-G}HdL8!?O)o{i@ZOIDlkpc zH;npiNC*iA-UzRPN~IEA1w0+7th8(Y6-Hh*o-FkrU>^_qdV;on?=LLvJ!qPjM3FLp zRgdtps^^~$R91E~W-!>1O>5<4RnHIh97zk1!Eqb_z|VIln>+3T*mFYN0^On)T9(yy zaCi(#Dcv^=X#*OCwCn2>t*gVvc2Pnb@F^o>fbb;ve?=J(w}800 z^#(|<13ndGCc2Mt>nlJR5VwH1Q3k{ZWt8yiD9orYl;Fbv~bei2a(hG8I`P6rwYA)z!#KLrRO z@H`JwQ&VtV7v*vpwOS3eS`DdG3WY);G7}1gf}cvIf_&w2IXEZ4waFrVKAPN^zwEGtD50MMgb@5xn$=c14asB@uWJ**L5W;02LM=GTMI4dWAON|ULnYt zOeO&!(8Qkvk*x#zH&*c^(Tyeh4~&kEqEIMcb8{1CXJ^>m-30)6o+lgjN<7aC;^%TX zBoYZ^G8rr^Ec`nc?c@DM8IU|95NaK8)wNNr2V`?y literal 0 HcmV?d00001 diff --git a/Resources/Textures/Clothing/Head/Helmets/eva_syndicate.rsi/meta.json b/Resources/Textures/Clothing/Head/Helmets/eva_syndicate.rsi/meta.json index bef6d8e4597..9ad58ec14d4 100644 --- a/Resources/Textures/Clothing/Head/Helmets/eva_syndicate.rsi/meta.json +++ b/Resources/Textures/Clothing/Head/Helmets/eva_syndicate.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Sprite edited by Flareguy for SS14, modified from space suit sprites taken from tgstation at commit https://github.com/tgstation/tgstation/commit/40d89d11ea4a5cb81d61dc1018b46f4e7d32c62a. Vox state based off of biosuit, taken from vgstation at commit https://github.com/vgstation-coders/vgstation13/commit/31d6576ba8102135d058ef49c3cb6ecbe8db8a79 | vulpkanin version taken from Paradise station at https://github.com/ParadiseSS13/Paradise/commit/f0fa4e1fd809482fbc104a310aa34cebf7df157d modified by Floofers", + "copyright": "Sprite edited by Flareguy for SS14, modified from space suit sprites taken from tgstation at commit https://github.com/tgstation/tgstation/commit/40d89d11ea4a5cb81d61dc1018b46f4e7d32c62a. Vox state based off of biosuit, taken from vgstation at commit https://github.com/vgstation-coders/vgstation13/commit/31d6576ba8102135d058ef49c3cb6ecbe8db8a79 | vulpkanin version taken from Paradise station at https://github.com/ParadiseSS13/Paradise/commit/f0fa4e1fd809482fbc104a310aa34cebf7df157d modified by Floofers. Reptilian states by TiniestShark (Github)", "size": { "x": 32, "y": 32 @@ -18,6 +18,10 @@ "name": "equipped-HELMET-vox", "directions": 4 }, + { + "name": "equipped-HELMET-reptilian", + "directions": 4 + }, { "name": "inhand-left", "directions": 4 diff --git a/Resources/Textures/Clothing/Head/Helmets/spaceninja.rsi/equipped-HELMET-reptilian.png b/Resources/Textures/Clothing/Head/Helmets/spaceninja.rsi/equipped-HELMET-reptilian.png new file mode 100644 index 0000000000000000000000000000000000000000..ee05fdc9a0bfaf06406f455311e211d5767aa295 GIT binary patch literal 722 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=jKx9jP7LeL$-HD>VCwO7aSW-L z^LEzxu3G^j$Lzhc4T8BO4<3Dx5V%>g?IQaNr5(PX7+P=o%{;g5uE_OEzPr~R&AaoJ z@ygo=%0AswnidQ2=&|s6h%V{A9ePOR6wmjpJxguv3ntDk*jH@-e*RHQ2FE|wRVwV> zmF;F|IK7%%toHlQ%i`-IZWqkomnadlQSNhB^tO{ezmFdKShiYtH|Mn6O_w4iyB4t| zufFOPG5C~301!<(zQkl=F$jq=HYAxIC1!1e-=6>QA{B8Q;v$=1T^bY=m^}I$7WlWnCnN!piq)BE9 zuH$xDZT$NUKf@tgrrROQTEZGqXP+@R7pM~wp!Iy>HKUE;ZHs?p>NW>i_9rc5I&2|+ z?YUlWY+USyn0*cEoiYp$-p-!x*i&ob>0)YE^XC-91M}hsJnTPyE!Zjmnk8I=L=!;&Fen0c|A0f`8z424eJ)4)bv4)Rfhir`U+SC>vfp`2GbEi7LUv^K$Lt$O< z0s9x5j=N{Cet7%4^p@zkN8(OBzUX{n_SbKhR30Axp3nI9gGmX8FpHxAGUETh9>C4` VanXj||A2{gh3M^!KG(ZvYu|1*E?pHs)QOn>6S z{qv=NnZ!GPuiW$6{;c@ZySc|*-yOH`&iQHeq{{wx`-Ww*{l&Yk8LnA6{hNQ~^s<=w zZGTH&Z+&{AD!(tUY>rgTL`I<7LBOF@_ZN%T(=&E*`a3(OWgCbpv}|b*&3$<)z?|tWfk@?Y>YhmGbzX|W>v1G?Ly_MeZ zm4#>TiAUS-H>*B+Z}RO?{_gy@-WGQi79R85b^KJjY3-bOsq)eJHY~RQ>NS5>qmNvPaVqAI7#=ds#+?KibCC*=y6&>VNC^OFvXr z+NS+brtZc%7N8+O(D3$dsph}Zsq-Eh7vJEB3pL!_a^_9w*RRKl)=AIWx%Ty)RBy1l ZghKWLWi6p=Kabmk_@1tQF6*2UngCwoLKOf2 literal 0 HcmV?d00001 diff --git a/Resources/Textures/Clothing/Mask/italian_moustache.rsi/meta.json b/Resources/Textures/Clothing/Mask/italian_moustache.rsi/meta.json index 667a14698a4..71ce7feeecd 100644 --- a/Resources/Textures/Clothing/Mask/italian_moustache.rsi/meta.json +++ b/Resources/Textures/Clothing/Mask/italian_moustache.rsi/meta.json @@ -18,6 +18,10 @@ "name": "equipped-MASK-vox", "directions": 4 }, + { + "name": "equipped-MASK-reptilian", + "directions": 4 + }, { "name": "inhand-left", "directions": 4 diff --git a/Resources/Textures/Mobs/Species/Reptilian/displacement.rsi/head.png b/Resources/Textures/Mobs/Species/Reptilian/displacement.rsi/head.png new file mode 100644 index 0000000000000000000000000000000000000000..72384eedcd5bdd985c41089d82ae509eefa9ded7 GIT binary patch literal 259 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=jKx9jP7LeL$-D$|_IkQFhE&XX zd)1NaumKOl!6o|V&tLXts%OtY9W7=0PHG%RBvPWr%;4Zkg;=bWFJVsb!xyI^8=nLo%d1KWZs&%c{CMu+7c iaBEq6f2lfg#_O9+=R3KRL)CoD5_rT2d{(m37S^fXL>1b54wbbU#!8h7E5cVP&`0N|wyo6}6#xou2-awBrc)I$z JtaD0e0su*-VqX9N literal 0 HcmV?d00001 diff --git a/Resources/Textures/Mobs/Species/Reptilian/displacement.rsi/mask.png b/Resources/Textures/Mobs/Species/Reptilian/displacement.rsi/mask.png new file mode 100644 index 0000000000000000000000000000000000000000..e90745dcc4563acd17884f3f64d89f35b3562a5d GIT binary patch literal 245 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=jKx9jP7LeL$-D$|)_b}*hE&XX zd*vYK0Rx@`2ey=a$hlW%$K&jCAN!hjZf#h`5akfepu0e`LF|Hv19t}3 z0#*~&3rw?^G8lasw-76RQ|>|R=Gob2^L9avve_;E@8gPN{{5vTjI0_C_)R+dk Date: Fri, 21 Nov 2025 17:22:54 -0600 Subject: [PATCH 317/340] Forgot to save and commit the development.toml file. --- Resources/ConfigPresets/Build/development.toml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Resources/ConfigPresets/Build/development.toml b/Resources/ConfigPresets/Build/development.toml index 0a4be494e3b..d5cbfb225e3 100644 --- a/Resources/ConfigPresets/Build/development.toml +++ b/Resources/ConfigPresets/Build/development.toml @@ -4,14 +4,12 @@ lobbyenabled = false # Dev map for faster loading & convenience map = "Dev" role_timers = false -<<<<<<< HEAD + contraband_examine = false # DeltaV secret_weight_prototype = "SecretDeltaV" # DeltaV role_timer_override = "DeltaV" # DeltaV showgreentext = false # DeltaV -======= role_loadout_timers = false ->>>>>>> c709d4d55c (Add CVar for disabling loadout item role timers (#36775)) [events] enabled = false From d970bc4c7109fd922b6c098e9bfcade7182da6dd Mon Sep 17 00:00:00 2001 From: Tayrtahn Date: Thu, 12 Jun 2025 01:09:05 -0400 Subject: [PATCH 318/340] Cleanup chat highlighting code (#38235) * Cache regexes * Convert static LocManager to resolved * Use Any instead of Count > 0 * Use var instead of explicit types * Make _highlights readonly --- .../Chat/ChatUIController.Highlighting.cs | 29 +++++++++++-------- 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/Content.Client/UserInterface/Systems/Chat/ChatUIController.Highlighting.cs b/Content.Client/UserInterface/Systems/Chat/ChatUIController.Highlighting.cs index 6e16b3a328d..8a60e6d7dfe 100644 --- a/Content.Client/UserInterface/Systems/Chat/ChatUIController.Highlighting.cs +++ b/Content.Client/UserInterface/Systems/Chat/ChatUIController.Highlighting.cs @@ -17,12 +17,17 @@ namespace Content.Client.UserInterface.Systems.Chat; /// public sealed partial class ChatUIController : IOnSystemChanged { + [Dependency] private readonly ILocalizationManager _loc = default!; [UISystemDependency] private readonly CharacterInfoSystem _characterInfo = default!; + private static readonly Regex StartDoubleQuote = new("\"$"); + private static readonly Regex EndDoubleQuote = new("^\"|(?<=^@)\""); + private static readonly Regex StartAtSign = new("^@"); + /// /// The list of words to be highlighted in the chatbox. /// - private List _highlights = new(); + private readonly List _highlights = new(); /// /// The string holding the hex color used to highlight words. @@ -47,7 +52,7 @@ public sealed partial class ChatUIController : IOnSystemChanged { _highlightsColor = value; }, true); // Load highlights if any were saved. - string highlights = _config.GetCVar(DCCVars.ChatHighlights); // DeltaV - Switched to use our CVar + var highlights = _config.GetCVar(DCCVars.ChatHighlights); // DeltaV - Switched to use our CVar if (!string.IsNullOrEmpty(highlights) || AutoHighlightsEnabled) // DeltaV - Message auto-highlighting { @@ -89,13 +94,13 @@ public sealed partial class ChatUIController : IOnSystemChanged (c == '"')) > 0) + if (keyword.Any(c => c == '"')) { // Matches the last double quote character. - keyword = Regex.Replace(keyword, "\"$", "(?!\\w)"); + keyword = StartDoubleQuote.Replace(keyword, "(?!\\w)"); // When matching for the first double quote character we also consider the possibility // of the double quote being preceded by a @ character. - keyword = Regex.Replace(keyword, "^\"|(?<=^@)\"", "(? (c == ' ' || c == '-')) == 1) @@ -152,9 +157,9 @@ public sealed partial class ChatUIController : IOnSystemChanged Date: Wed, 3 Sep 2025 21:42:15 +0200 Subject: [PATCH 319/340] Fix small issues with Text Highlighting (#38144) --- .../Systems/Chat/ChatUIController.Highlighting.cs | 5 +++-- Resources/Locale/en-US/chat/ui/chat-box.ftl | 2 +- Resources/Locale/en-US/escape-menu/ui/options-menu.ftl | 4 ++-- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/Content.Client/UserInterface/Systems/Chat/ChatUIController.Highlighting.cs b/Content.Client/UserInterface/Systems/Chat/ChatUIController.Highlighting.cs index 8a60e6d7dfe..be95d73de33 100644 --- a/Content.Client/UserInterface/Systems/Chat/ChatUIController.Highlighting.cs +++ b/Content.Client/UserInterface/Systems/Chat/ChatUIController.Highlighting.cs @@ -122,8 +122,9 @@ public sealed partial class ChatUIController : IOnSystemChanged Date: Wed, 3 Sep 2025 16:16:07 -0400 Subject: [PATCH 320/340] Adjust bureaucratic error to prevent only passenger being available (#40001) Fire all the interns --- Resources/Prototypes/GameRules/events.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Resources/Prototypes/GameRules/events.yml b/Resources/Prototypes/GameRules/events.yml index 3c998433840..44d9a5f4e10 100644 --- a/Resources/Prototypes/GameRules/events.yml +++ b/Resources/Prototypes/GameRules/events.yml @@ -175,6 +175,11 @@ - type: BureaucraticErrorRule ignoredJobs: - StationAi + - ResearchAssistant + - MedicalIntern + - SecurityCadet + - TechnicalAssistant + # Clerical Error - type: entity id: ClericalError From 49cb073873ee0186e5587e89f217220478a47c2d Mon Sep 17 00:00:00 2001 From: Vanessa Date: Fri, 21 Nov 2025 17:48:00 -0600 Subject: [PATCH 321/340] Fixed Devil errors after rebasing. --- Content.Server/_Goobstation/Bible/GoobBibleSystem.cs | 2 +- .../_Goobstation/Devil/Contract/DevilContractSystem.cs | 4 ++-- Content.Server/_Goobstation/Devil/DevilSystem.cs | 10 +++++----- .../_Goobstation/Devil/Grip/DevilGripSystem.cs | 2 +- .../_Goobstation/Devil/Roles/DevilRoleComponent.cs | 2 +- .../_Goobstation/Possession/PossessionSystem.cs | 2 +- 6 files changed, 11 insertions(+), 11 deletions(-) diff --git a/Content.Server/_Goobstation/Bible/GoobBibleSystem.cs b/Content.Server/_Goobstation/Bible/GoobBibleSystem.cs index 29428fab686..6b1dcb4161c 100644 --- a/Content.Server/_Goobstation/Bible/GoobBibleSystem.cs +++ b/Content.Server/_Goobstation/Bible/GoobBibleSystem.cs @@ -69,7 +69,7 @@ public sealed partial class GoobBibleSystem : EntitySystem _popupSystem.PopupPredicted(popup, target, performer, PopupType.LargeCaution); _audio.PlayPvs(bibleComp.SizzleSoundPath, target); _damageableSystem.TryChangeDamage(target, bibleComp.SmiteDamage * multiplier, true, origin: bible, targetPart: TargetBodyPart.All); - _stun.TryParalyze(target, bibleComp.SmiteStunDuration * multiplier, false); + _stun.TryAddParalyzeDuration(target, bibleComp.SmiteStunDuration * multiplier); _delay.TryResetDelay((bible, useDelay)); } else if (isDevil && HasComp(performer)) diff --git a/Content.Server/_Goobstation/Devil/Contract/DevilContractSystem.cs b/Content.Server/_Goobstation/Devil/Contract/DevilContractSystem.cs index 0af7be647a9..cbc3e0fffe4 100644 --- a/Content.Server/_Goobstation/Devil/Contract/DevilContractSystem.cs +++ b/Content.Server/_Goobstation/Devil/Contract/DevilContractSystem.cs @@ -62,7 +62,7 @@ public sealed partial class DevilContractSystem : EntitySystem SubscribeLocalEvent(OnExamined); SubscribeLocalEvent>(OnGetVerbs); SubscribeLocalEvent(OnSignStep); - SubscribeLocalEvent(OnEaten); + SubscribeLocalEvent(OnEaten); } private readonly Dictionary> _targetResolvers = new() @@ -125,7 +125,7 @@ public sealed partial class DevilContractSystem : EntitySystem args.PushMarkup(Loc.GetString("devil-contract-examined", ("weight", contract.Comp.ContractWeight))); } - private void OnEaten(Entity contract, ref AfterFullyEatenEvent args) + private void OnEaten(Entity contract, ref FullyEatenEvent args) { _explosion.QueueExplosion( args.User, diff --git a/Content.Server/_Goobstation/Devil/DevilSystem.cs b/Content.Server/_Goobstation/Devil/DevilSystem.cs index 4e9c98df64f..8db19487564 100644 --- a/Content.Server/_Goobstation/Devil/DevilSystem.cs +++ b/Content.Server/_Goobstation/Devil/DevilSystem.cs @@ -26,11 +26,11 @@ using Content.Server.Jittering; using Content.Server.Mind; using Content.Server.Polymorph.Systems; using Content.Server.Popups; -using Content.Server.Speech; -using Content.Server.Speech.Components; +using Content.Shared.Speech; +using Content.Shared.Speech.Components; using Content.Server.Stunnable; using Content.Server.Temperature.Components; -using Content.Server.Zombies; +using Content.Shared.Zombies; using Content.Shared._Lavaland.Chasm; using Content.Shared._Shitmed.Body.Components; using Content.Shared.Actions; @@ -236,14 +236,14 @@ public sealed partial class DevilSystem : EntitySystem if (HasComp(args.Source)) { _damageable.TryChangeDamage(devil, devil.Comp.DamageOnTrueName * devil.Comp.BibleUserDamageMultiplier, true); - _stun.TryParalyze(devil, devil.Comp.ParalyzeDurationOnTrueName * devil.Comp.BibleUserDamageMultiplier, false); + _stun.TryAddParalyzeDuration(devil, devil.Comp.ParalyzeDurationOnTrueName * devil.Comp.BibleUserDamageMultiplier); var popup = Loc.GetString("devil-true-name-heard-chaplain", ("speaker", args.Source), ("target", devil)); _popup.PopupEntity(popup, devil, PopupType.LargeCaution); } else { - _stun.TryParalyze(devil, devil.Comp.ParalyzeDurationOnTrueName, false); + _stun.TryAddParalyzeDuration(devil, devil.Comp.ParalyzeDurationOnTrueName); _damageable.TryChangeDamage(devil, devil.Comp.DamageOnTrueName, true); var popup = Loc.GetString("devil-true-name-heard", ("speaker", args.Source), ("target", devil)); diff --git a/Content.Server/_Goobstation/Devil/Grip/DevilGripSystem.cs b/Content.Server/_Goobstation/Devil/Grip/DevilGripSystem.cs index cfd99ee90b7..b5f3940195d 100644 --- a/Content.Server/_Goobstation/Devil/Grip/DevilGripSystem.cs +++ b/Content.Server/_Goobstation/Devil/Grip/DevilGripSystem.cs @@ -61,7 +61,7 @@ public sealed class DevilGripSystem : EntitySystem if (TryComp(target, out StatusEffectsComponent? status)) { - _ = _stun.TryKnockdown(target, ent.Comp.KnockdownTime, true, status) || _stun.TryStun(target, ent.Comp.KnockdownTime, true, status); + _ = _stun.TryKnockdown(target, ent.Comp.KnockdownTime, true) || _stun.TryAddStunDuration(target, ent.Comp.KnockdownTime); _stamina.TakeStaminaDamage(target, ent.Comp.StaminaDamage); _language.DoRatvarian(target, ent.Comp.SpeechTime, true, status); } diff --git a/Content.Server/_Goobstation/Devil/Roles/DevilRoleComponent.cs b/Content.Server/_Goobstation/Devil/Roles/DevilRoleComponent.cs index 76c6f4c8d69..22de461a9b6 100644 --- a/Content.Server/_Goobstation/Devil/Roles/DevilRoleComponent.cs +++ b/Content.Server/_Goobstation/Devil/Roles/DevilRoleComponent.cs @@ -5,7 +5,7 @@ // // SPDX-License-Identifier: AGPL-3.0-or-later -using Content.Shared.Roles; +using Content.Shared.Roles.Components; namespace Content.Server._Goobstation.Devil.Roles; diff --git a/Content.Server/_Goobstation/Possession/PossessionSystem.cs b/Content.Server/_Goobstation/Possession/PossessionSystem.cs index 965ea31377d..b8e8273b2e8 100644 --- a/Content.Server/_Goobstation/Possession/PossessionSystem.cs +++ b/Content.Server/_Goobstation/Possession/PossessionSystem.cs @@ -136,7 +136,7 @@ public sealed partial class PossessionSystem : EntitySystem coordinates = _transform.ToMapCoordinates(possessed.Comp.OriginalEntity.ToCoordinates()); // Paralyze, so you can't just magdump them. - _stun.TryParalyze(possessed, TimeSpan.FromSeconds(10), false); + _stun.TryAddParalyzeDuration(possessed, TimeSpan.FromSeconds(10)); _popup.PopupEntity(Loc.GetString("possession-end-popup", ("target", possessed)), possessed, PopupType.LargeCaution); // Teleport to the entity, kinda like you're popping out of their head! From a0b1730113f9f6826859221599f30e1ce5f7c6cd Mon Sep 17 00:00:00 2001 From: Vanessa Date: Fri, 21 Nov 2025 17:58:51 -0600 Subject: [PATCH 322/340] Removed some Chem Bottles that were added in the upstream merge. --- .../Objects/Specific/chemistry-bottles.yml | 105 ------------------ 1 file changed, 105 deletions(-) diff --git a/Resources/Prototypes/_DV/Entities/Objects/Specific/chemistry-bottles.yml b/Resources/Prototypes/_DV/Entities/Objects/Specific/chemistry-bottles.yml index d1a7ae9710c..889a5cc8292 100644 --- a/Resources/Prototypes/_DV/Entities/Objects/Specific/chemistry-bottles.yml +++ b/Resources/Prototypes/_DV/Entities/Objects/Specific/chemistry-bottles.yml @@ -13,21 +13,6 @@ - ReagentId: Napalm Quantity: 30 -- type: entity - parent: BaseChemistryBottleFilled - id: ChemistryBottleUltravasculine - suffix: ultravasculine - components: - - type: Label - currentLabel: reagent-name-ultravasculine - - type: SolutionContainerManager - solutions: - drink: - maxVol: 30 - reagents: - - ReagentId: Ultravasculine - Quantity: 30 - - type: entity parent: BaseChemistryBottleFilled id: ChemistryBottleChloralHydrate @@ -43,96 +28,6 @@ - ReagentId: ChloralHydrate Quantity: 30 -- type: entity - parent: BaseChemistryBottleFilled - id: ChemistryBottleBruizine - suffix: bruizine - components: - - type: Label - currentLabel: reagent-name-bruizine - - type: SolutionContainerManager - solutions: - drink: - maxVol: 30 - reagents: - - ReagentId: Bruizine - Quantity: 30 - -- type: entity - parent: BaseChemistryBottleFilled - id: ChemistryBottleLacerinol - suffix: lacerinol - components: - - type: Label - currentLabel: reagent-name-lacerinol - - type: SolutionContainerManager - solutions: - drink: - maxVol: 30 - reagents: - - ReagentId: Lacerinol - Quantity: 30 - -- type: entity - parent: BaseChemistryBottleFilled - id: ChemistryBottlePuncturase - suffix: puncturase - components: - - type: Label - currentLabel: reagent-name-puncturase - - type: SolutionContainerManager - solutions: - drink: - maxVol: 30 - reagents: - - ReagentId: Puncturase - Quantity: 30 - -- type: entity - parent: BaseChemistryBottleFilled - id: ChemistryBottleDermaline - suffix: dermaline - components: - - type: Label - currentLabel: reagent-name-dermaline - - type: SolutionContainerManager - solutions: - drink: - maxVol: 30 - reagents: - - ReagentId: Dermaline - Quantity: 30 - -- type: entity - parent: BaseChemistryBottleFilled - id: ChemistryBottlePyrazine - suffix: pyrazine - components: - - type: Label - currentLabel: reagent-name-pyrazine - - type: SolutionContainerManager - solutions: - drink: - maxVol: 30 - reagents: - - ReagentId: Pyrazine - Quantity: 30 - -- type: entity - parent: BaseChemistryBottleFilled - id: ChemistryBottleDiphenhydramine - suffix: diphenhydramine - components: - - type: Label - currentLabel: reagent-name-diphenhydramine - - type: SolutionContainerManager - solutions: - drink: - maxVol: 30 - reagents: - - ReagentId: Diphenhydramine - Quantity: 30 - - type: entity parent: BaseChemistryBottleFilled id: ChemistryBottleFirebugsFriend From 370f309a48a208723dc4e93fa855f8cc6ecacc28 Mon Sep 17 00:00:00 2001 From: Vanessa Date: Fri, 21 Nov 2025 18:07:38 -0600 Subject: [PATCH 323/340] Revert "Remove NamesGolem" (#39478) --- .../Locale/en-US/datasets/names/golem.ftl | 1336 +++++++++++++++++ Resources/Prototypes/Datasets/Names/golem.yml | 5 + 2 files changed, 1341 insertions(+) create mode 100644 Resources/Locale/en-US/datasets/names/golem.ftl create mode 100644 Resources/Prototypes/Datasets/Names/golem.yml diff --git a/Resources/Locale/en-US/datasets/names/golem.ftl b/Resources/Locale/en-US/datasets/names/golem.ftl new file mode 100644 index 00000000000..6a91ac773a4 --- /dev/null +++ b/Resources/Locale/en-US/datasets/names/golem.ftl @@ -0,0 +1,1336 @@ +names-golem-dataset-1 = Abelsonite +names-golem-dataset-2 = Abenakiite +names-golem-dataset-3 = Abernathyite +names-golem-dataset-4 = Abhurite +names-golem-dataset-5 = Abramovite +names-golem-dataset-6 = Abswurmbachite +names-golem-dataset-7 = Acanthite +names-golem-dataset-8 = Achavalite +names-golem-dataset-9 = Actinolite +names-golem-dataset-10 = Acuminite +names-golem-dataset-11 = Adamite +names-golem-dataset-12 = Adelite +names-golem-dataset-13 = Admontite +names-golem-dataset-14 = Aegirine +names-golem-dataset-15 = Aenigmatite +names-golem-dataset-16 = Aerinite +names-golem-dataset-17 = Aerugite +names-golem-dataset-18 = Aeschynite +names-golem-dataset-19 = Afghanite +names-golem-dataset-20 = Afwillite +names-golem-dataset-21 = Agardite +names-golem-dataset-22 = Agrellite +names-golem-dataset-23 = Agrinierite +names-golem-dataset-24 = Aguilarite +names-golem-dataset-25 = Aheylite +names-golem-dataset-26 = Ahlfeldite +names-golem-dataset-27 = Aikinite +names-golem-dataset-28 = Ajoite +names-golem-dataset-29 = Akaganeite +names-golem-dataset-30 = Akatoreite +names-golem-dataset-31 = Akdalaite +names-golem-dataset-32 = Åkermanite +names-golem-dataset-33 = Akhtenskite +names-golem-dataset-34 = Akimotoite +names-golem-dataset-35 = Akrochordite +names-golem-dataset-36 = Aksaite +names-golem-dataset-37 = Aktashite +names-golem-dataset-38 = Alabandite +names-golem-dataset-39 = Alacranite +names-golem-dataset-40 = Alamosite +names-golem-dataset-41 = Alarsite +names-golem-dataset-42 = Albite +names-golem-dataset-43 = Albrechtschraufite +names-golem-dataset-44 = Aldermanite +names-golem-dataset-45 = Aleksite +names-golem-dataset-46 = Alforsite +names-golem-dataset-47 = Algodonite +names-golem-dataset-48 = Aliettite +names-golem-dataset-49 = Allabogdanite +names-golem-dataset-50 = Allactite +names-golem-dataset-51 = Allanite +names-golem-dataset-52 = Allanpringite +names-golem-dataset-53 = Allargentum +names-golem-dataset-54 = Alleghanyite +names-golem-dataset-55 = Alloclasite +names-golem-dataset-56 = Allophane +names-golem-dataset-57 = Alluaivite +names-golem-dataset-58 = Alluaudite +names-golem-dataset-59 = Almandine +names-golem-dataset-60 = Almarudite +names-golem-dataset-61 = Alsakharovite +names-golem-dataset-62 = Alstonite +names-golem-dataset-63 = Altaite +names-golem-dataset-64 = Althausite +names-golem-dataset-65 = Althupite +names-golem-dataset-66 = Altisite +names-golem-dataset-67 = Alum +names-golem-dataset-68 = Aluminite +names-golem-dataset-69 = Aluminium +names-golem-dataset-70 = Alunite +names-golem-dataset-71 = Alunogen +names-golem-dataset-72 = Amakinite +names-golem-dataset-73 = Amarantite +names-golem-dataset-74 = Amblygonite +names-golem-dataset-75 = Ameghinite +names-golem-dataset-76 = Amesite +names-golem-dataset-77 = Amicite +names-golem-dataset-78 = Amphibole +names-golem-dataset-79 = Analcime +names-golem-dataset-80 = Anandite +names-golem-dataset-81 = Anapaite +names-golem-dataset-82 = Anatase +names-golem-dataset-83 = Ancylite +names-golem-dataset-84 = Andalusite +names-golem-dataset-85 = Andersonite +names-golem-dataset-86 = Andesine +names-golem-dataset-87 = Andorite +names-golem-dataset-88 = Andradite +names-golem-dataset-89 = Andyrobertsite +names-golem-dataset-90 = Anglesite +names-golem-dataset-91 = Anhydrite +names-golem-dataset-92 = Ankerite +names-golem-dataset-93 = Annabergite +names-golem-dataset-94 = Annite +names-golem-dataset-95 = Anorthite +names-golem-dataset-96 = Anorthoclase +names-golem-dataset-97 = Antarcticite +names-golem-dataset-98 = Anthonyite +names-golem-dataset-99 = Anthophyllite +names-golem-dataset-100 = Antigorite +names-golem-dataset-101 = Antimony +names-golem-dataset-102 = Antitaenite +names-golem-dataset-103 = Antlerite +names-golem-dataset-104 = Apachite +names-golem-dataset-105 = Apatite +names-golem-dataset-106 = Aphthitalite +names-golem-dataset-107 = Apophyllite +names-golem-dataset-108 = Aragonite +names-golem-dataset-109 = Arcanite +names-golem-dataset-110 = Archerite +names-golem-dataset-111 = Arctite +names-golem-dataset-112 = Arcubisite +names-golem-dataset-113 = Ardaite +names-golem-dataset-114 = Arfvedsonite +names-golem-dataset-115 = Argentite +names-golem-dataset-116 = Argutite +names-golem-dataset-117 = Argyrodite +names-golem-dataset-118 = Armalcolite +names-golem-dataset-119 = Arsenic +names-golem-dataset-120 = Arseniosiderite +names-golem-dataset-121 = Arsenoclasite +names-golem-dataset-122 = Arsenolite +names-golem-dataset-123 = Arsenopyrite +names-golem-dataset-124 = Arthurite +names-golem-dataset-125 = Artinite +names-golem-dataset-126 = Artroeite +names-golem-dataset-127 = Ashburtonite +names-golem-dataset-128 = Ashoverite +names-golem-dataset-129 = Asisite +names-golem-dataset-130 = Astrophyllite +names-golem-dataset-131 = Atacamite +names-golem-dataset-132 = Athabascaite +names-golem-dataset-133 = Atheneite +names-golem-dataset-134 = Aubertite +names-golem-dataset-135 = Augelite +names-golem-dataset-136 = Augite +names-golem-dataset-137 = Aurichalcite +names-golem-dataset-138 = Auricupride +names-golem-dataset-139 = Aurostibite +names-golem-dataset-140 = Austinite +names-golem-dataset-141 = Autunite +names-golem-dataset-142 = Avicennite +names-golem-dataset-143 = Avogadrite +names-golem-dataset-144 = Awaruite +names-golem-dataset-145 = Axinite +names-golem-dataset-146 = Azurite +names-golem-dataset-147 = Babefphite +names-golem-dataset-148 = Babingtonite +names-golem-dataset-149 = Baddeleyite +names-golem-dataset-150 = Bakerite +names-golem-dataset-151 = Balangeroite +names-golem-dataset-152 = Banalsite +names-golem-dataset-153 = Baotite +names-golem-dataset-154 = Bararite +names-golem-dataset-155 = Barrerite +names-golem-dataset-156 = Barstowite +names-golem-dataset-157 = Baryte +names-golem-dataset-158 = Barytocalcite +names-golem-dataset-159 = Bassanite +names-golem-dataset-160 = Bastnasite +names-golem-dataset-161 = Baumhauerite +names-golem-dataset-162 = Bayldonite +names-golem-dataset-163 = Bayleyite +names-golem-dataset-164 = Bazzite +names-golem-dataset-165 = Becquerelite +names-golem-dataset-166 = Benitoite +names-golem-dataset-167 = Benstonite +names-golem-dataset-168 = Bentorite +names-golem-dataset-169 = Beraunite +names-golem-dataset-170 = Berborite +names-golem-dataset-171 = Bergenite +names-golem-dataset-172 = Berlinite +names-golem-dataset-173 = Berryite +names-golem-dataset-174 = Berthierite +names-golem-dataset-175 = Bertrandite +names-golem-dataset-176 = Beryl +names-golem-dataset-177 = Beryllonite +names-golem-dataset-178 = Beudantite +names-golem-dataset-179 = Bicchulite +names-golem-dataset-180 = Biehlite +names-golem-dataset-181 = Bilinite +names-golem-dataset-182 = Billietite +names-golem-dataset-183 = Billwiseite +names-golem-dataset-184 = Biotite +names-golem-dataset-185 = Birnessite +names-golem-dataset-186 = Bischofite +names-golem-dataset-187 = Bismite +names-golem-dataset-188 = Bismuth +names-golem-dataset-189 = Bismuthinite +names-golem-dataset-190 = Bismutite +names-golem-dataset-191 = Bityite +names-golem-dataset-192 = Bixbyite +names-golem-dataset-193 = Blodite +names-golem-dataset-194 = Blossite +names-golem-dataset-195 = Bobfergusonite +names-golem-dataset-196 = Boehmite +names-golem-dataset-197 = Boleite +names-golem-dataset-198 = Boltwoodite +names-golem-dataset-199 = Bonaccordite +names-golem-dataset-200 = Boracite +names-golem-dataset-201 = Borax +names-golem-dataset-202 = Bornite +names-golem-dataset-203 = Botallackite +names-golem-dataset-204 = Botryogen +names-golem-dataset-205 = Boulangerite +names-golem-dataset-206 = Bournonite +names-golem-dataset-207 = Boussingaultite +names-golem-dataset-208 = Bowieite +names-golem-dataset-209 = Braggite +names-golem-dataset-210 = Brassite +names-golem-dataset-211 = Braunite +names-golem-dataset-212 = Brazilianite +names-golem-dataset-213 = Breithauptite +names-golem-dataset-214 = Brewsterite +names-golem-dataset-215 = Brezinaite +names-golem-dataset-216 = Brianite +names-golem-dataset-217 = Brianyoungite +names-golem-dataset-218 = Briartite +names-golem-dataset-219 = Bridgmanite +names-golem-dataset-220 = Brochantite +names-golem-dataset-221 = Brockite +names-golem-dataset-222 = Bromargyrite +names-golem-dataset-223 = Bromellite +names-golem-dataset-224 = Bronzite +names-golem-dataset-225 = Brookite +names-golem-dataset-226 = Brownleeite +names-golem-dataset-227 = Brownmillerite +names-golem-dataset-228 = Brucite +names-golem-dataset-229 = Brushite +names-golem-dataset-230 = Buddingtonite +names-golem-dataset-231 = Bukovite +names-golem-dataset-232 = Bukovskyite +names-golem-dataset-233 = Bultfonteinite +names-golem-dataset-234 = Bunsenite +names-golem-dataset-235 = Bustamite +names-golem-dataset-236 = Bystrite +names-golem-dataset-237 = Cabalzarite +names-golem-dataset-238 = Cabriite +names-golem-dataset-239 = Cacoxenite +names-golem-dataset-240 = Cadmium +names-golem-dataset-241 = Cadmoindite +names-golem-dataset-242 = Cadmoselite +names-golem-dataset-243 = Cadwaladerite +names-golem-dataset-244 = Cafarsite +names-golem-dataset-245 = Cafetite +names-golem-dataset-246 = Cahnite +names-golem-dataset-247 = Calaverite +names-golem-dataset-248 = Calciborite +names-golem-dataset-249 = Calcite +names-golem-dataset-250 = Calderite +names-golem-dataset-251 = Caledonite +names-golem-dataset-252 = Calumetite +names-golem-dataset-253 = Campigliaite +names-golem-dataset-254 = Canavesite +names-golem-dataset-255 = Cancrinite +names-golem-dataset-256 = Canfieldite +names-golem-dataset-257 = Carletonite +names-golem-dataset-258 = Carlosruizite +names-golem-dataset-259 = Carlsbergite +names-golem-dataset-260 = Carminite +names-golem-dataset-261 = Carnallite +names-golem-dataset-262 = Carnotite +names-golem-dataset-263 = Carobbiite +names-golem-dataset-264 = Carpathite +names-golem-dataset-265 = Carpholite +names-golem-dataset-266 = Carrollite +names-golem-dataset-267 = Caryopilite +names-golem-dataset-268 = Cassiterite +names-golem-dataset-269 = Cattierite +names-golem-dataset-270 = Cavansite +names-golem-dataset-271 = Celadonite +names-golem-dataset-272 = Celestine +names-golem-dataset-273 = Celsian +names-golem-dataset-274 = Cerite +names-golem-dataset-275 = Cerium +names-golem-dataset-276 = Cerussite +names-golem-dataset-277 = Cervandonite +names-golem-dataset-278 = Cervantite +names-golem-dataset-279 = Cesanite +names-golem-dataset-280 = Cesbronite +names-golem-dataset-281 = Chabazite +names-golem-dataset-282 = Chaidamuite +names-golem-dataset-283 = Chalcanthite +names-golem-dataset-284 = Chalcocite +names-golem-dataset-285 = Chalcophyllite +names-golem-dataset-286 = Chalcopyrite +names-golem-dataset-287 = Challacolloite +names-golem-dataset-288 = Chambersite +names-golem-dataset-289 = Chamosite +names-golem-dataset-290 = Changbaiite +names-golem-dataset-291 = Chaoite +names-golem-dataset-292 = Chapmanite +names-golem-dataset-293 = Charoite +names-golem-dataset-294 = Chatkalite +names-golem-dataset-295 = Chesterite +names-golem-dataset-296 = Chibaite +names-golem-dataset-297 = Childrenite +names-golem-dataset-298 = Chlorargyrite +names-golem-dataset-299 = Chlorite +names-golem-dataset-300 = Chloritoid +names-golem-dataset-301 = Chlormayenite +names-golem-dataset-302 = Chlorocalcite +names-golem-dataset-303 = Chloroxiphite +names-golem-dataset-304 = Chondrodite +names-golem-dataset-305 = Chrisstanleyite +names-golem-dataset-306 = Christite +names-golem-dataset-307 = Chromite +names-golem-dataset-308 = Chromium +names-golem-dataset-309 = Chrysoberyl +names-golem-dataset-310 = Chrysocolla +names-golem-dataset-311 = Chrysotile +names-golem-dataset-312 = Chvaleticeite +names-golem-dataset-313 = Cinnabar +names-golem-dataset-314 = Clarkeite +names-golem-dataset-315 = Claudetite +names-golem-dataset-316 = Clausthalite +names-golem-dataset-317 = Clearcreekite +names-golem-dataset-318 = Cleusonite +names-golem-dataset-319 = Clinoclase +names-golem-dataset-320 = Clinohedrite +names-golem-dataset-321 = Clinohumite +names-golem-dataset-322 = Clinoptilolite +names-golem-dataset-323 = Clinozoisite +names-golem-dataset-324 = Clintonite +names-golem-dataset-325 = Cobaltite +names-golem-dataset-326 = Coccinite +names-golem-dataset-327 = Coconinoite +names-golem-dataset-328 = Coesite +names-golem-dataset-329 = Coffinite +names-golem-dataset-330 = Cohenite +names-golem-dataset-331 = Colemanite +names-golem-dataset-332 = Colimaite +names-golem-dataset-333 = Collinsite +names-golem-dataset-334 = Coloradoite +names-golem-dataset-335 = Columbite +names-golem-dataset-336 = Combeite +names-golem-dataset-337 = Conichalcite +names-golem-dataset-338 = Connellite +names-golem-dataset-339 = Cooperite +names-golem-dataset-340 = Copiapite +names-golem-dataset-341 = Copper +names-golem-dataset-342 = Corderoite +names-golem-dataset-343 = Cordierite +names-golem-dataset-344 = Corkite +names-golem-dataset-345 = Cornubite +names-golem-dataset-346 = Cornwallite +names-golem-dataset-347 = Corundum +names-golem-dataset-348 = Cotunnite +names-golem-dataset-349 = Covellite +names-golem-dataset-350 = Coyoteite +names-golem-dataset-351 = Creedite +names-golem-dataset-352 = Cristobalite +names-golem-dataset-353 = Crocoite +names-golem-dataset-354 = Cronstedtite +names-golem-dataset-355 = Crookesite +names-golem-dataset-356 = Crossite +names-golem-dataset-357 = Cryolite +names-golem-dataset-358 = Cryptomelane +names-golem-dataset-359 = Cubanite +names-golem-dataset-360 = Cummingtonite +names-golem-dataset-361 = Cupalite +names-golem-dataset-362 = Cuprite +names-golem-dataset-363 = Cuprosklodowskite +names-golem-dataset-364 = Cuprospinel +names-golem-dataset-365 = Curite +names-golem-dataset-366 = Cuspidine +names-golem-dataset-367 = Cyanotrichite +names-golem-dataset-368 = Cylindrite +names-golem-dataset-369 = Cymrite +names-golem-dataset-370 = Cyrilovite +names-golem-dataset-371 = Danalite +names-golem-dataset-372 = Danburite +names-golem-dataset-373 = Datolite +names-golem-dataset-374 = Daubreeite +names-golem-dataset-375 = Daubreelite +names-golem-dataset-376 = Davidite +names-golem-dataset-377 = Dawsonite +names-golem-dataset-378 = Delafossite +names-golem-dataset-379 = Delvauxite +names-golem-dataset-380 = Demesmaekerite +names-golem-dataset-381 = Derriksite +names-golem-dataset-382 = Descloizite +names-golem-dataset-383 = Devilline +names-golem-dataset-384 = Diaboleite +names-golem-dataset-385 = Diadochite +names-golem-dataset-386 = Diamond +names-golem-dataset-387 = Diaspore +names-golem-dataset-388 = Dickite +names-golem-dataset-389 = Digenite +names-golem-dataset-390 = Dimorphite +names-golem-dataset-391 = Diopside +names-golem-dataset-392 = Dioptase +names-golem-dataset-393 = Djerfisherite +names-golem-dataset-394 = Djurleite +names-golem-dataset-395 = Dmitryivanovite +names-golem-dataset-396 = Dollaseite +names-golem-dataset-397 = Dolomite +names-golem-dataset-398 = Domeykite +names-golem-dataset-399 = Donnayite +names-golem-dataset-400 = Drysdallite +names-golem-dataset-401 = Duftite +names-golem-dataset-402 = Dumortierite +names-golem-dataset-403 = Dundasite +names-golem-dataset-404 = Dypingite +names-golem-dataset-405 = Dyscrasite +names-golem-dataset-406 = Dzhalindite +names-golem-dataset-407 = Edenite +names-golem-dataset-408 = Edingtonite +names-golem-dataset-409 = Efremovite +names-golem-dataset-410 = Ekanite +names-golem-dataset-411 = Elbaite +names-golem-dataset-412 = Emmonsite +names-golem-dataset-413 = Empressite +names-golem-dataset-414 = Enargite +names-golem-dataset-415 = Enstatite +names-golem-dataset-416 = Eosphorite +names-golem-dataset-417 = Ephesite +names-golem-dataset-418 = Epidote +names-golem-dataset-419 = Epsomite +names-golem-dataset-420 = Ericssonite +names-golem-dataset-421 = Erionite +names-golem-dataset-422 = Erythrite +names-golem-dataset-423 = Eskolaite +names-golem-dataset-424 = Esperite +names-golem-dataset-425 = Ettringite +names-golem-dataset-426 = Euchroite +names-golem-dataset-427 = Euclase +names-golem-dataset-428 = Eucryptite +names-golem-dataset-429 = Eudialyte +names-golem-dataset-430 = Euxenite +names-golem-dataset-431 = Eveite +names-golem-dataset-432 = Evenkite +names-golem-dataset-433 = Eveslogite +names-golem-dataset-434 = Fabianite +names-golem-dataset-435 = Farneseite +names-golem-dataset-436 = Faujasite +names-golem-dataset-437 = Faustite +names-golem-dataset-438 = Fayalite +names-golem-dataset-439 = Feldspar +names-golem-dataset-440 = Feldspathoid +names-golem-dataset-441 = Felsobanyaite +names-golem-dataset-442 = Ferberite +names-golem-dataset-443 = Fergusonite +names-golem-dataset-444 = Feroxyhyte +names-golem-dataset-445 = Ferrierite +names-golem-dataset-446 = Ferrihydrite +names-golem-dataset-447 = Ferrimolybdite +names-golem-dataset-448 = Ferro-actinolite +names-golem-dataset-449 = Ferrogedrite +names-golem-dataset-450 = Ferrohortonolite +names-golem-dataset-451 = Ferronigerite +names-golem-dataset-452 = Ferropericlase +names-golem-dataset-453 = Ferroselite +names-golem-dataset-454 = Fettelite +names-golem-dataset-455 = Fichtelite +names-golem-dataset-456 = Fletcherite +names-golem-dataset-457 = Fluckite +names-golem-dataset-458 = Fluellite +names-golem-dataset-459 = Fluoborite +names-golem-dataset-460 = Fluocerite +names-golem-dataset-461 = Fluorapatite +names-golem-dataset-462 = Fluorapophyllite +names-golem-dataset-463 = Fluorcaphite +names-golem-dataset-464 = Fluorellestadite +names-golem-dataset-465 = Fluorite +names-golem-dataset-466 = Fluororichterite +names-golem-dataset-467 = Fornacite +names-golem-dataset-468 = Forsterite +names-golem-dataset-469 = Fougerite +names-golem-dataset-470 = Fourmarierite +names-golem-dataset-471 = Fraipontite +names-golem-dataset-472 = Francevillite +names-golem-dataset-473 = Franckeite +names-golem-dataset-474 = Frankamenite +names-golem-dataset-475 = Frankdicksonite +names-golem-dataset-476 = Frankhawthorneite +names-golem-dataset-477 = Franklinite +names-golem-dataset-478 = Franklinphilite +names-golem-dataset-479 = Freibergite +names-golem-dataset-480 = Freieslebenite +names-golem-dataset-481 = Fukuchilite +names-golem-dataset-482 = Gabrielite +names-golem-dataset-483 = Gadolinite +names-golem-dataset-484 = Gagarinite +names-golem-dataset-485 = Gahnite +names-golem-dataset-486 = Galaxite +names-golem-dataset-487 = Galena +names-golem-dataset-488 = Galkhaite +names-golem-dataset-489 = Gananite +names-golem-dataset-490 = Garnet +names-golem-dataset-491 = Gaspeite +names-golem-dataset-492 = Gatehouseite +names-golem-dataset-493 = Gaylussite +names-golem-dataset-494 = Gedrite +names-golem-dataset-495 = Geerite +names-golem-dataset-496 = Gehlenite +names-golem-dataset-497 = Geigerite +names-golem-dataset-498 = Geikielite +names-golem-dataset-499 = Geocronite +names-golem-dataset-500 = Georgerobinsonite +names-golem-dataset-501 = Germanite +names-golem-dataset-502 = Gersdorffite +names-golem-dataset-503 = Getchellite +names-golem-dataset-504 = Gibbsite +names-golem-dataset-505 = Gilalite +names-golem-dataset-506 = Gismondine +names-golem-dataset-507 = Glauberite +names-golem-dataset-508 = Glaucochroite +names-golem-dataset-509 = Glaucodot +names-golem-dataset-510 = Glauconite +names-golem-dataset-511 = Glaucophane +names-golem-dataset-512 = Gmelinite +names-golem-dataset-513 = Godovikovite +names-golem-dataset-514 = Goethite +names-golem-dataset-515 = Gold +names-golem-dataset-516 = Goldmanite +names-golem-dataset-517 = Gonnardite +names-golem-dataset-518 = Gordaite +names-golem-dataset-519 = Gormanite +names-golem-dataset-520 = Goslarite +names-golem-dataset-521 = Graftonite +names-golem-dataset-522 = Grandidierite +names-golem-dataset-523 = Grandreefite +names-golem-dataset-524 = Graphite +names-golem-dataset-525 = Gratonite +names-golem-dataset-526 = Greenalite +names-golem-dataset-527 = Greenockite +names-golem-dataset-528 = Gregoryite +names-golem-dataset-529 = Greifensteinite +names-golem-dataset-530 = Greigite +names-golem-dataset-531 = Grossite +names-golem-dataset-532 = Grossular +names-golem-dataset-533 = Groutite +names-golem-dataset-534 = Grunerite +names-golem-dataset-535 = Guettardite +names-golem-dataset-536 = Gugiaite +names-golem-dataset-537 = Guilleminite +names-golem-dataset-538 = Gunningite +names-golem-dataset-539 = Guyanaite +names-golem-dataset-540 = Gwihabaite +names-golem-dataset-541 = Gypsum +names-golem-dataset-542 = Hafnon +names-golem-dataset-543 = Hagendorfite +names-golem-dataset-544 = Haggertyite +names-golem-dataset-545 = Haidingerite +names-golem-dataset-546 = Haiweeite +names-golem-dataset-547 = Haleniusite +names-golem-dataset-548 = Halite +names-golem-dataset-549 = Halloysite +names-golem-dataset-550 = Halotrichite +names-golem-dataset-551 = Hambergite +names-golem-dataset-552 = Hanksite +names-golem-dataset-553 = Hapkeite +names-golem-dataset-554 = Hardystonite +names-golem-dataset-555 = Harmotome +names-golem-dataset-556 = Hauerite +names-golem-dataset-557 = Hausmannite +names-golem-dataset-558 = Hauyne +names-golem-dataset-559 = Hawleyite +names-golem-dataset-560 = Haxonite +names-golem-dataset-561 = Hazenite +names-golem-dataset-562 = Heazlewoodite +names-golem-dataset-563 = Hectorite +names-golem-dataset-564 = Hedenbergite +names-golem-dataset-565 = Hellyerite +names-golem-dataset-566 = Hematite +names-golem-dataset-567 = Hemihedrite +names-golem-dataset-568 = Hemimorphite +names-golem-dataset-569 = Hemusite +names-golem-dataset-570 = Herbertsmithite +names-golem-dataset-571 = Hercynite +names-golem-dataset-572 = Herderite +names-golem-dataset-573 = Hessite +names-golem-dataset-574 = Heulandite +names-golem-dataset-575 = Hexaferrum +names-golem-dataset-576 = Hiarneite +names-golem-dataset-577 = Hibonite +names-golem-dataset-578 = Hidalgoite +names-golem-dataset-579 = Hilgardite +names-golem-dataset-580 = Hisingerite +names-golem-dataset-581 = Hodgkinsonite +names-golem-dataset-582 = Hoelite +names-golem-dataset-583 = Hollandite +names-golem-dataset-584 = Holmquistite +names-golem-dataset-585 = Homilite +names-golem-dataset-586 = Hopeite +names-golem-dataset-587 = Hornblende +names-golem-dataset-588 = Howlite +names-golem-dataset-589 = Hsianghualite +names-golem-dataset-590 = Hubeite +names-golem-dataset-591 = Hubnerite +names-golem-dataset-592 = Huemulite +names-golem-dataset-593 = Humite +names-golem-dataset-594 = Huntite +names-golem-dataset-595 = Hureaulite +names-golem-dataset-596 = Hutchinsonite +names-golem-dataset-597 = Huttonite +names-golem-dataset-598 = Hydroboracite +names-golem-dataset-599 = Hydrogrossular +names-golem-dataset-600 = Hydrohalite +names-golem-dataset-601 = Hydrokenoelsmoreite +names-golem-dataset-602 = Hydromagnesite +names-golem-dataset-603 = Hydrotalcite +names-golem-dataset-604 = Hydroxylapatite +names-golem-dataset-605 = Hydrozincite +names-golem-dataset-606 = Ianbruceite +names-golem-dataset-607 = Ice +names-golem-dataset-608 = Icosahedrite +names-golem-dataset-609 = Idrialite +names-golem-dataset-610 = Ikaite +names-golem-dataset-611 = Illite +names-golem-dataset-612 = Ilmenite +names-golem-dataset-613 = Ilvaite +names-golem-dataset-614 = Imogolite +names-golem-dataset-615 = Indite +names-golem-dataset-616 = Indium +names-golem-dataset-617 = Inyoite +names-golem-dataset-618 = Iodargyrite +names-golem-dataset-619 = Iranite +names-golem-dataset-620 = Iridium +names-golem-dataset-621 = Iron +names-golem-dataset-622 = Ixiolite +names-golem-dataset-623 = Jacobsite +names-golem-dataset-624 = Jadarite +names-golem-dataset-625 = Jadeite +names-golem-dataset-626 = Jaffeite +names-golem-dataset-627 = Jalpaite +names-golem-dataset-628 = Jamesonite +names-golem-dataset-629 = Janggunite +names-golem-dataset-630 = Jarosewichite +names-golem-dataset-631 = Jarosite +names-golem-dataset-632 = Jennite +names-golem-dataset-633 = Jeremejevite +names-golem-dataset-634 = Jerrygibbsite +names-golem-dataset-635 = Jimthompsonite +names-golem-dataset-636 = Johannite +names-golem-dataset-637 = Jolliffeite +names-golem-dataset-638 = Jonesite +names-golem-dataset-639 = Jordanite +names-golem-dataset-640 = Julgoldite +names-golem-dataset-641 = Junitoite +names-golem-dataset-642 = Jurbanite +names-golem-dataset-643 = Kaatialaite +names-golem-dataset-644 = Kadyrelite +names-golem-dataset-645 = Kaersutite +names-golem-dataset-646 = Kainite +names-golem-dataset-647 = Kainosite +names-golem-dataset-648 = Kalininite +names-golem-dataset-649 = Kalinite +names-golem-dataset-650 = Kalsilite +names-golem-dataset-651 = Kamacite +names-golem-dataset-652 = Kambaldaite +names-golem-dataset-653 = Kamiokite +names-golem-dataset-654 = Kampfite +names-golem-dataset-655 = Kankite +names-golem-dataset-656 = Kanoite +names-golem-dataset-657 = Kaolinite +names-golem-dataset-658 = Karlite +names-golem-dataset-659 = Kassite +names-golem-dataset-660 = Kegelite +names-golem-dataset-661 = Keilite +names-golem-dataset-662 = Kermesite +names-golem-dataset-663 = Kernite +names-golem-dataset-664 = Kesterite +names-golem-dataset-665 = Keyite +names-golem-dataset-666 = Khatyrkite +names-golem-dataset-667 = Kieserite +names-golem-dataset-668 = Kinoite +names-golem-dataset-669 = Knebelite +names-golem-dataset-670 = Knorringite +names-golem-dataset-671 = Kobellite +names-golem-dataset-672 = Kochite +names-golem-dataset-673 = Kogarkoite +names-golem-dataset-674 = Kolbeckite +names-golem-dataset-675 = Kornerupine +names-golem-dataset-676 = Kosmochlor +names-golem-dataset-677 = Kostovite +names-golem-dataset-678 = Kottigite +names-golem-dataset-679 = Kovdorskite +names-golem-dataset-680 = Kratochv�lite +names-golem-dataset-681 = Kremersite +names-golem-dataset-682 = Krennerite +names-golem-dataset-683 = Krieselite +names-golem-dataset-684 = Krohnkite +names-golem-dataset-685 = Krotite +names-golem-dataset-686 = Krutovite +names-golem-dataset-687 = Kukharenkoite +names-golem-dataset-688 = Kuratite +names-golem-dataset-689 = Kurnakovite +names-golem-dataset-690 = Kutnohorite +names-golem-dataset-691 = Kyanite +names-golem-dataset-692 = Labradorite +names-golem-dataset-693 = Lanarkite +names-golem-dataset-694 = Langbeinite +names-golem-dataset-695 = Langite +names-golem-dataset-696 = Lansfordite +names-golem-dataset-697 = Lanthanite +names-golem-dataset-698 = Laplandite +names-golem-dataset-699 = Larnite +names-golem-dataset-700 = Laumontite +names-golem-dataset-701 = Laurionite +names-golem-dataset-702 = Laurite +names-golem-dataset-703 = Lautite +names-golem-dataset-704 = Lavendulan +names-golem-dataset-705 = Lawsonite +names-golem-dataset-706 = Lazulite +names-golem-dataset-707 = Lazurite +names-golem-dataset-708 = Lead +names-golem-dataset-709 = Leadhillite +names-golem-dataset-710 = Legrandite +names-golem-dataset-711 = Leifite +names-golem-dataset-712 = Leightonite +names-golem-dataset-713 = Lepidocrocite +names-golem-dataset-714 = Lepidolite +names-golem-dataset-715 = Letovicite +names-golem-dataset-716 = Leucite +names-golem-dataset-717 = Leucophanite +names-golem-dataset-718 = Leucophoenicite +names-golem-dataset-719 = Levyne +names-golem-dataset-720 = Libethenite +names-golem-dataset-721 = Liebigite +names-golem-dataset-722 = Linarite +names-golem-dataset-723 = Lindgrenite +names-golem-dataset-724 = Linnaeite +names-golem-dataset-725 = Lipscombite +names-golem-dataset-726 = Liroconite +names-golem-dataset-727 = Litharge +names-golem-dataset-728 = Lithiophilite +names-golem-dataset-729 = Livingstonite +names-golem-dataset-730 = Lizardite +names-golem-dataset-731 = Loellingite +names-golem-dataset-732 = Lonsdaleite +names-golem-dataset-733 = Loparite +names-golem-dataset-734 = Lopezite +names-golem-dataset-735 = Lorandite +names-golem-dataset-736 = Lorenzenite +names-golem-dataset-737 = Loveringite +names-golem-dataset-738 = Ludlamite +names-golem-dataset-739 = Ludwigite +names-golem-dataset-740 = Lulzacite +names-golem-dataset-741 = Lyonsite +names-golem-dataset-742 = Macaulayite +names-golem-dataset-743 = Macdonaldite +names-golem-dataset-744 = Mackinawite +names-golem-dataset-745 = Madocite +names-golem-dataset-746 = Magadiite +names-golem-dataset-747 = Maghemite +names-golem-dataset-748 = Magnesioferrite +names-golem-dataset-749 = Magnesiohastingsite +names-golem-dataset-750 = Magnesiopascoite +names-golem-dataset-751 = Magnesite +names-golem-dataset-752 = Magnetite +names-golem-dataset-753 = Majorite +names-golem-dataset-754 = Malachite +names-golem-dataset-755 = Malayaite +names-golem-dataset-756 = Manganite +names-golem-dataset-757 = Manganosite +names-golem-dataset-758 = Manganvesuvianite +names-golem-dataset-759 = Marcasite +names-golem-dataset-760 = Margaritasite +names-golem-dataset-761 = Margarite +names-golem-dataset-762 = Marialite +names-golem-dataset-763 = Maricite +names-golem-dataset-764 = Marrite +names-golem-dataset-765 = Marthozite +names-golem-dataset-766 = Mascagnite +names-golem-dataset-767 = Massicot +names-golem-dataset-768 = Masuyite +names-golem-dataset-769 = Matlockite +names-golem-dataset-770 = Maucherite +names-golem-dataset-771 = Mawsonite +names-golem-dataset-772 = Mckelveyite +names-golem-dataset-773 = Meionite +names-golem-dataset-774 = Melanophlogite +names-golem-dataset-775 = Melanterite +names-golem-dataset-776 = Melilite +names-golem-dataset-777 = Mellite +names-golem-dataset-778 = Melonite +names-golem-dataset-779 = Mendipite +names-golem-dataset-780 = Mendozite +names-golem-dataset-781 = Meneghinite +names-golem-dataset-782 = Mercury +names-golem-dataset-783 = Mereheadite +names-golem-dataset-784 = Merenskyite +names-golem-dataset-785 = Meridianiite +names-golem-dataset-786 = Merrillite +names-golem-dataset-787 = Mesolite +names-golem-dataset-788 = Messelite +names-golem-dataset-789 = Metacinnabar +names-golem-dataset-790 = Metatorbernite +names-golem-dataset-791 = Metazeunerite +names-golem-dataset-792 = Meyerhofferite +names-golem-dataset-793 = Miargyrite +names-golem-dataset-794 = Mica +names-golem-dataset-795 = Microcline +names-golem-dataset-796 = Microlite +names-golem-dataset-797 = Millerite +names-golem-dataset-798 = Millosevichite +names-golem-dataset-799 = Mimetite +names-golem-dataset-800 = Minium +names-golem-dataset-801 = Minnesotaite +names-golem-dataset-802 = Minyulite +names-golem-dataset-803 = Mirabilite +names-golem-dataset-804 = Mixite +names-golem-dataset-805 = Moganite +names-golem-dataset-806 = Mohite +names-golem-dataset-807 = Mohrite +names-golem-dataset-808 = Moissanite +names-golem-dataset-809 = Molybdenite +names-golem-dataset-810 = Molybdite +names-golem-dataset-811 = Monazite +names-golem-dataset-812 = Monohydrocalcite +names-golem-dataset-813 = Monticellite +names-golem-dataset-814 = Montmorillonite +names-golem-dataset-815 = Mooihoekite +names-golem-dataset-816 = Moolooite +names-golem-dataset-817 = Mordenite +names-golem-dataset-818 = Moschellandsbergite +names-golem-dataset-819 = Mosesite +names-golem-dataset-820 = Mottramite +names-golem-dataset-821 = Motukoreaite +names-golem-dataset-822 = Mullite +names-golem-dataset-823 = Mundite +names-golem-dataset-824 = Murdochite +names-golem-dataset-825 = Muscovite +names-golem-dataset-826 = Musgravite +names-golem-dataset-827 = Nabalamprophyllite +names-golem-dataset-828 = Nabesite +names-golem-dataset-829 = Nacrite +names-golem-dataset-830 = Nadorite +names-golem-dataset-831 = Nagyagite +names-golem-dataset-832 = Nahcolite +names-golem-dataset-833 = Naldrettite +names-golem-dataset-834 = Nambulite +names-golem-dataset-835 = Narsarsukite +names-golem-dataset-836 = Native copper +names-golem-dataset-837 = Natrolite +names-golem-dataset-838 = Natron +names-golem-dataset-839 = Natrophilite +names-golem-dataset-840 = Nekrasovite +names-golem-dataset-841 = Nelenite +names-golem-dataset-842 = Nenadkevichite +names-golem-dataset-843 = Nepheline +names-golem-dataset-844 = Nepouite +names-golem-dataset-845 = Neptunite +names-golem-dataset-846 = Nichromite +names-golem-dataset-847 = Nickel +names-golem-dataset-848 = Nickeline +names-golem-dataset-849 = Niedermayrite +names-golem-dataset-850 = Niningerite +names-golem-dataset-851 = Nissonite +names-golem-dataset-852 = Niter +names-golem-dataset-853 = Nitratine +names-golem-dataset-854 = Nobleite +names-golem-dataset-855 = Nontronite +names-golem-dataset-856 = Norbergite +names-golem-dataset-857 = Normandite +names-golem-dataset-858 = Northupite +names-golem-dataset-859 = Nosean +names-golem-dataset-860 = Nsutite +names-golem-dataset-861 = Nyerereite +names-golem-dataset-862 = kenite +names-golem-dataset-863 = Oldhamite +names-golem-dataset-864 = Olgite +names-golem-dataset-865 = Olivenite +names-golem-dataset-866 = Olivine +names-golem-dataset-867 = Omphacite +names-golem-dataset-868 = Ordonezite +names-golem-dataset-869 = Oregonite +names-golem-dataset-870 = Orpiment +names-golem-dataset-871 = Orthoclase +names-golem-dataset-872 = Osarizawaite +names-golem-dataset-873 = Osmium +names-golem-dataset-874 = Osumilite +names-golem-dataset-875 = Otavite +names-golem-dataset-876 = Ottrelite +names-golem-dataset-877 = Otwayite +names-golem-dataset-878 = Paakkonenite +names-golem-dataset-879 = Pabstite +names-golem-dataset-880 = Painite +names-golem-dataset-881 = Palladium +names-golem-dataset-882 = Palygorskite +names-golem-dataset-883 = Panethite +names-golem-dataset-884 = Panguite +names-golem-dataset-885 = Papagoite +names-golem-dataset-886 = Paragonite +names-golem-dataset-887 = Paralaurionite +names-golem-dataset-888 = Paramelaconite +names-golem-dataset-889 = Pararealgar +names-golem-dataset-890 = Pargasite +names-golem-dataset-891 = Parisite +names-golem-dataset-892 = Parsonsite +names-golem-dataset-893 = Partheite +names-golem-dataset-894 = Pascoite +names-golem-dataset-895 = Patronite +names-golem-dataset-896 = Paulingite +names-golem-dataset-897 = Paulscherrerite +names-golem-dataset-898 = Pearceite +names-golem-dataset-899 = Pecoraite +names-golem-dataset-900 = Pectolite +names-golem-dataset-901 = Penikisite +names-golem-dataset-902 = Penroseite +names-golem-dataset-903 = Pentagonite +names-golem-dataset-904 = Pentlandite +names-golem-dataset-905 = Perhamite +names-golem-dataset-906 = Periclase +names-golem-dataset-907 = Perite +names-golem-dataset-908 = Perovskite +names-golem-dataset-909 = Petalite +names-golem-dataset-910 = Petzite +names-golem-dataset-911 = Pezzottaite +names-golem-dataset-912 = Pharmacolite +names-golem-dataset-913 = Pharmacosiderite +names-golem-dataset-914 = Phenakite +names-golem-dataset-915 = Phillipsite +names-golem-dataset-916 = Phlogopite +names-golem-dataset-917 = Phoenicochroite +names-golem-dataset-918 = Phosgenite +names-golem-dataset-919 = Phosphophyllite +names-golem-dataset-920 = Phosphuranylite +names-golem-dataset-921 = Pickeringite +names-golem-dataset-922 = Picropharmacolite +names-golem-dataset-923 = Piemontite +names-golem-dataset-924 = Pigeonite +names-golem-dataset-925 = Pinalite +names-golem-dataset-926 = Pinnoite +names-golem-dataset-927 = Piypite +names-golem-dataset-928 = Plagioclase +names-golem-dataset-929 = Plancheite +names-golem-dataset-930 = Platinum +names-golem-dataset-931 = Plattnerite +names-golem-dataset-932 = Playfairite +names-golem-dataset-933 = Plumbogummite +names-golem-dataset-934 = Polarite +names-golem-dataset-935 = Pollucite +names-golem-dataset-936 = Polybasite +names-golem-dataset-937 = Polycrase +names-golem-dataset-938 = Polydymite +names-golem-dataset-939 = Polyhalite +names-golem-dataset-940 = Portlandite +names-golem-dataset-941 = Posnjakite +names-golem-dataset-942 = Poudretteite +names-golem-dataset-943 = Povondraite +names-golem-dataset-944 = Powellite +names-golem-dataset-945 = Prehnite +names-golem-dataset-946 = Proustite +names-golem-dataset-947 = Pseudobrookite +names-golem-dataset-948 = Pseudomalachite +names-golem-dataset-949 = Pseudowollastonite +names-golem-dataset-950 = Pumpellyite +names-golem-dataset-951 = Purpurite +names-golem-dataset-952 = Putnisite +names-golem-dataset-953 = Pyrargyrite +names-golem-dataset-954 = Pyrite +names-golem-dataset-955 = Pyrochlore +names-golem-dataset-956 = Pyrolusite +names-golem-dataset-957 = Pyromorphite +names-golem-dataset-958 = Pyrope +names-golem-dataset-959 = Pyrophanite +names-golem-dataset-960 = Pyrophyllite +names-golem-dataset-961 = Pyroxene +names-golem-dataset-962 = Pyroxferroite +names-golem-dataset-963 = Pyroxmangite +names-golem-dataset-964 = Pyrrhotite +names-golem-dataset-965 = Rambergite +names-golem-dataset-966 = Rameauite +names-golem-dataset-967 = Rammelsbergite +names-golem-dataset-968 = Rapidcreekite +names-golem-dataset-969 = Raspite +names-golem-dataset-970 = Realgar +names-golem-dataset-971 = Reidite +names-golem-dataset-972 = Reinerite +names-golem-dataset-973 = Renierite +names-golem-dataset-974 = Rheniite +names-golem-dataset-975 = Rhodium +names-golem-dataset-976 = Rhodochrosite +names-golem-dataset-977 = Rhodonite +names-golem-dataset-978 = Rhodplumsite +names-golem-dataset-979 = Rhomboclase +names-golem-dataset-980 = Richterite +names-golem-dataset-981 = Rickardite +names-golem-dataset-982 = Riebeckite +names-golem-dataset-983 = Ringwoodite +names-golem-dataset-984 = Roaldite +names-golem-dataset-985 = Robertsite +names-golem-dataset-986 = Rodalquilarite +names-golem-dataset-987 = Romanechite +names-golem-dataset-988 = Romeite +names-golem-dataset-989 = Rosasite +names-golem-dataset-990 = Roscoelite +names-golem-dataset-991 = Roselite +names-golem-dataset-992 = Rosenbergite +names-golem-dataset-993 = Rosickyite +names-golem-dataset-994 = Routhierite +names-golem-dataset-995 = Rozenite +names-golem-dataset-996 = Rubicline +names-golem-dataset-997 = Ruizite +names-golem-dataset-998 = Russellite +names-golem-dataset-999 = Ruthenium +names-golem-dataset-1000 = Rutherfordine +names-golem-dataset-1001 = Rutile +names-golem-dataset-1002 = Rynersonite +names-golem-dataset-1003 = Sabatierite +names-golem-dataset-1004 = Sabieite +names-golem-dataset-1005 = Sabinaite +names-golem-dataset-1006 = Sacrofanite +names-golem-dataset-1007 = Safflorite +names-golem-dataset-1008 = Sal Ammoniac +names-golem-dataset-1009 = Saleeite +names-golem-dataset-1010 = Saliotite +names-golem-dataset-1011 = Salzburgite +names-golem-dataset-1012 = Samarskite +names-golem-dataset-1013 = Sampleite +names-golem-dataset-1014 = Samsonite +names-golem-dataset-1015 = Samuelsonite +names-golem-dataset-1016 = Sanbornite +names-golem-dataset-1017 = Saneroite +names-golem-dataset-1018 = Sanidine +names-golem-dataset-1019 = Santabarbaraite +names-golem-dataset-1020 = Santite +names-golem-dataset-1021 = Saponite +names-golem-dataset-1022 = Sapphirine +names-golem-dataset-1023 = Sarabauite +names-golem-dataset-1024 = Sarkinite +names-golem-dataset-1025 = Sassolite +names-golem-dataset-1026 = Satterlyite +names-golem-dataset-1027 = Sauconite +names-golem-dataset-1028 = Sborgite +names-golem-dataset-1029 = Scapolite +names-golem-dataset-1030 = Schaferite +names-golem-dataset-1031 = Scheelite +names-golem-dataset-1032 = Schmiederite +names-golem-dataset-1033 = Schoepite +names-golem-dataset-1034 = Schorl +names-golem-dataset-1035 = Schreibersite +names-golem-dataset-1036 = Schreyerite +names-golem-dataset-1037 = Schrockingerite +names-golem-dataset-1038 = Schwertmannite +names-golem-dataset-1039 = Scolecite +names-golem-dataset-1040 = Scorodite +names-golem-dataset-1041 = Scorzalite +names-golem-dataset-1042 = Scrutinyite +names-golem-dataset-1043 = Seamanite +names-golem-dataset-1044 = Searlesite +names-golem-dataset-1045 = Seeligerite +names-golem-dataset-1046 = Segelerite +names-golem-dataset-1047 = Seifertite +names-golem-dataset-1048 = Sekaninaite +names-golem-dataset-1049 = Selenium +names-golem-dataset-1050 = Seligmannite +names-golem-dataset-1051 = Sellaite +names-golem-dataset-1052 = Semseyite +names-golem-dataset-1053 = Senarmontite +names-golem-dataset-1054 = Sepiolite +names-golem-dataset-1055 = Serandite +names-golem-dataset-1056 = Serendibite +names-golem-dataset-1057 = Serpentine +names-golem-dataset-1058 = Serpierite +names-golem-dataset-1059 = Sewardite +names-golem-dataset-1060 = Shandite +names-golem-dataset-1061 = Shattuckite +names-golem-dataset-1062 = Shigaite +names-golem-dataset-1063 = Shortite +names-golem-dataset-1064 = Siderite +names-golem-dataset-1065 = Siderophyllite +names-golem-dataset-1066 = Siderotil +names-golem-dataset-1067 = Siegenite +names-golem-dataset-1068 = Silicon +names-golem-dataset-1069 = Sillimanite +names-golem-dataset-1070 = Silver +names-golem-dataset-1071 = Simonellite +names-golem-dataset-1072 = Simpsonite +names-golem-dataset-1073 = Sincosite +names-golem-dataset-1074 = Sinkankasite +names-golem-dataset-1075 = Sinoite +names-golem-dataset-1076 = Skaergaardite +names-golem-dataset-1077 = Sklodowskite +names-golem-dataset-1078 = Skutterudite +names-golem-dataset-1079 = Smaltite +names-golem-dataset-1080 = Smectite +names-golem-dataset-1081 = Smithsonite +names-golem-dataset-1082 = Sodalite +names-golem-dataset-1083 = Soddyite +names-golem-dataset-1084 = Sonolite +names-golem-dataset-1085 = Sperrylite +names-golem-dataset-1086 = Spertiniite +names-golem-dataset-1087 = Spessartine +names-golem-dataset-1088 = Sphalerite +names-golem-dataset-1089 = Spherocobaltite +names-golem-dataset-1090 = Spinel +names-golem-dataset-1091 = Spodumene +names-golem-dataset-1092 = Spurrite +names-golem-dataset-1093 = Stannite +names-golem-dataset-1094 = Stannoidite +names-golem-dataset-1095 = Staurolite +names-golem-dataset-1096 = Steacyite +names-golem-dataset-1097 = Stellerite +names-golem-dataset-1098 = Stephanite +names-golem-dataset-1099 = Stercorite +names-golem-dataset-1100 = Stibarsen +names-golem-dataset-1101 = Stibiconite +names-golem-dataset-1102 = Stibiopalladinite +names-golem-dataset-1103 = Stibnite +names-golem-dataset-1104 = Stichtite +names-golem-dataset-1105 = Stilbite +names-golem-dataset-1106 = Stilleite +names-golem-dataset-1107 = Stillwaterite +names-golem-dataset-1108 = Stillwellite +names-golem-dataset-1109 = Stilpnomelane +names-golem-dataset-1110 = Stishovite +names-golem-dataset-1111 = Stolzite +names-golem-dataset-1112 = Strashimirite +names-golem-dataset-1113 = Strengite +names-golem-dataset-1114 = Stromeyerite +names-golem-dataset-1115 = Strontianite +names-golem-dataset-1116 = Struvite +names-golem-dataset-1117 = Studenitsite +names-golem-dataset-1118 = Studtite +names-golem-dataset-1119 = Stutzite +names-golem-dataset-1120 = Suanite +names-golem-dataset-1121 = Suessite +names-golem-dataset-1122 = Sugilite +names-golem-dataset-1123 = Sulfur +names-golem-dataset-1124 = Sursassite +names-golem-dataset-1125 = Susannite +names-golem-dataset-1126 = Sussexite +names-golem-dataset-1127 = Svanbergite +names-golem-dataset-1128 = Sweetite +names-golem-dataset-1129 = Switzerite +names-golem-dataset-1130 = Sylvanite +names-golem-dataset-1131 = Sylvite +names-golem-dataset-1132 = Synchysite +names-golem-dataset-1133 = Syngenite +names-golem-dataset-1134 = Taaffeite +names-golem-dataset-1135 = Tachyhydrite +names-golem-dataset-1136 = Taenite +names-golem-dataset-1137 = Talc +names-golem-dataset-1138 = Talmessite +names-golem-dataset-1139 = Talnakhite +names-golem-dataset-1140 = Tamarugite +names-golem-dataset-1141 = Tangeite +names-golem-dataset-1142 = Tantalite +names-golem-dataset-1143 = Tantite +names-golem-dataset-1144 = Tapiolite +names-golem-dataset-1145 = Taranakite +names-golem-dataset-1146 = Tarapacaite +names-golem-dataset-1147 = Tarbuttite +names-golem-dataset-1148 = Tausonite +names-golem-dataset-1149 = Teallite +names-golem-dataset-1150 = Tellurite +names-golem-dataset-1151 = Tellurium +names-golem-dataset-1152 = Tellurobismuthite +names-golem-dataset-1153 = Temagamite +names-golem-dataset-1154 = Tennantite +names-golem-dataset-1155 = Tenorite +names-golem-dataset-1156 = Tephroite +names-golem-dataset-1157 = Terlinguaite +names-golem-dataset-1158 = Teruggite +names-golem-dataset-1159 = Tetradymite +names-golem-dataset-1160 = Tetrahedrite +names-golem-dataset-1161 = Tetrataenite +names-golem-dataset-1162 = Thaumasite +names-golem-dataset-1163 = Thenardite +names-golem-dataset-1164 = Thermonatrite +names-golem-dataset-1165 = Thiospinel +names-golem-dataset-1166 = Thomasclarkite +names-golem-dataset-1167 = Thomsenolite +names-golem-dataset-1168 = Thomsonite +names-golem-dataset-1169 = Thorianite +names-golem-dataset-1170 = Thorite +names-golem-dataset-1171 = Thortveitite +names-golem-dataset-1172 = Tiemannite +names-golem-dataset-1173 = Tienshanite +names-golem-dataset-1174 = Tin +names-golem-dataset-1175 = Tinaksite +names-golem-dataset-1176 = Tincalconite +names-golem-dataset-1177 = Titanite +names-golem-dataset-1178 = Titanium +names-golem-dataset-1179 = Titanowodginite +names-golem-dataset-1180 = Tobermorite +names-golem-dataset-1181 = Todorokite +names-golem-dataset-1182 = Tokyoite +names-golem-dataset-1183 = Tongbaite +names-golem-dataset-1184 = Topaz +names-golem-dataset-1185 = Torbernite +names-golem-dataset-1186 = Tourmaline +names-golem-dataset-1187 = Tranquillityite +names-golem-dataset-1188 = Tremolite +names-golem-dataset-1189 = Trevorite +names-golem-dataset-1190 = Tridymite +names-golem-dataset-1191 = Triphylite +names-golem-dataset-1192 = Triplite +names-golem-dataset-1193 = Triploidite +names-golem-dataset-1194 = Tripuhyite +names-golem-dataset-1195 = Troilite +names-golem-dataset-1196 = Trona +names-golem-dataset-1197 = Tschermakite +names-golem-dataset-1198 = Tschermigite +names-golem-dataset-1199 = Tsumcorite +names-golem-dataset-1200 = Tsumebite +names-golem-dataset-1201 = Tugtupite +names-golem-dataset-1202 = Tungsten +names-golem-dataset-1203 = Tungstite +names-golem-dataset-1204 = Tuperssuatsiaite +names-golem-dataset-1205 = Turquoise +names-golem-dataset-1206 = Tusionite +names-golem-dataset-1207 = Tyrolite +names-golem-dataset-1208 = Tyrrellite +names-golem-dataset-1209 = Tyuyamunite +names-golem-dataset-1210 = Uchucchacuaite +names-golem-dataset-1211 = Uklonskovite +names-golem-dataset-1212 = Ulexite +names-golem-dataset-1213 = Ullmannite +names-golem-dataset-1214 = Ulrichite +names-golem-dataset-1215 = Ulvospinel +names-golem-dataset-1216 = Umangite +names-golem-dataset-1217 = Umbite +names-golem-dataset-1218 = Upalite +names-golem-dataset-1219 = Uraninite +names-golem-dataset-1220 = Uranocircite +names-golem-dataset-1221 = Uranophane +names-golem-dataset-1222 = Uranopilite +names-golem-dataset-1223 = Urea +names-golem-dataset-1224 = Uricite +names-golem-dataset-1225 = Urusovite +names-golem-dataset-1226 = Ussingite +names-golem-dataset-1227 = Utahite +names-golem-dataset-1228 = Uvarovite +names-golem-dataset-1229 = Uytenbogaardtite +names-golem-dataset-1230 = Vaesite +names-golem-dataset-1231 = Valentinite +names-golem-dataset-1232 = Valleriite +names-golem-dataset-1233 = Vanadinite +names-golem-dataset-1234 = Vanadiocarpholite +names-golem-dataset-1235 = Vanadium +names-golem-dataset-1236 = Vantasselite +names-golem-dataset-1237 = Vanuralite +names-golem-dataset-1238 = Variscite +names-golem-dataset-1239 = Vaterite +names-golem-dataset-1240 = Vauquelinite +names-golem-dataset-1241 = Vauxite +names-golem-dataset-1242 = Veatchite +names-golem-dataset-1243 = Vermiculite +names-golem-dataset-1244 = Vesuvianite +names-golem-dataset-1245 = Villiaumite +names-golem-dataset-1246 = Violarite +names-golem-dataset-1247 = Vishnevite +names-golem-dataset-1248 = Vivianite +names-golem-dataset-1249 = Vladimirite +names-golem-dataset-1250 = Vlasovite +names-golem-dataset-1251 = Volborthite +names-golem-dataset-1252 = Vulcanite +names-golem-dataset-1253 = Wadsleyite +names-golem-dataset-1254 = Wagnerite +names-golem-dataset-1255 = Wairakite +names-golem-dataset-1256 = Wakabayashilite +names-golem-dataset-1257 = Wakefieldite +names-golem-dataset-1258 = Walfordite +names-golem-dataset-1259 = Wardite +names-golem-dataset-1260 = Warikahnite +names-golem-dataset-1261 = Warwickite +names-golem-dataset-1262 = Wassonite +names-golem-dataset-1263 = Wavellite +names-golem-dataset-1264 = Weddellite +names-golem-dataset-1265 = Weeksite +names-golem-dataset-1266 = Weilite +names-golem-dataset-1267 = Weissite +names-golem-dataset-1268 = Weloganite +names-golem-dataset-1269 = Whewellite +names-golem-dataset-1270 = Whiteite +names-golem-dataset-1271 = Whitlockite +names-golem-dataset-1272 = Willemite +names-golem-dataset-1273 = Wiluite +names-golem-dataset-1274 = Witherite +names-golem-dataset-1275 = Wodginite +names-golem-dataset-1276 = Wolframite +names-golem-dataset-1277 = Wollastonite +names-golem-dataset-1278 = Woodhouseite +names-golem-dataset-1279 = Wulfenite +names-golem-dataset-1280 = Wurtzite +names-golem-dataset-1281 = Wustite +names-golem-dataset-1282 = Wyartite +names-golem-dataset-1283 = Xanthiosite +names-golem-dataset-1284 = Xanthoconite +names-golem-dataset-1285 = Xanthoxenite +names-golem-dataset-1286 = Xenophyllite +names-golem-dataset-1287 = Xenotime +names-golem-dataset-1288 = Xiangjiangite +names-golem-dataset-1289 = Xieite +names-golem-dataset-1290 = Xifengite +names-golem-dataset-1291 = Xilingolite +names-golem-dataset-1292 = Ximengite +names-golem-dataset-1293 = Xingzhongite +names-golem-dataset-1294 = Xitieshanite +names-golem-dataset-1295 = Xocolatlite +names-golem-dataset-1296 = Xocomecatlite +names-golem-dataset-1297 = Xonotlite +names-golem-dataset-1298 = Ye'elimite +names-golem-dataset-1299 = Yttrialite +names-golem-dataset-1300 = Yttropyrochlore +names-golem-dataset-1301 = Yuksporite +names-golem-dataset-1302 = Zabuyelite +names-golem-dataset-1303 = Zaccagnaite +names-golem-dataset-1304 = Zaherite +names-golem-dataset-1305 = Zairite +names-golem-dataset-1306 = Zakharovite +names-golem-dataset-1307 = Zanazziite +names-golem-dataset-1308 = Zaratite +names-golem-dataset-1309 = Zektzerite +names-golem-dataset-1310 = Zemannite +names-golem-dataset-1311 = Zeolite +names-golem-dataset-1312 = Zeunerite +names-golem-dataset-1313 = Zhanghengite +names-golem-dataset-1314 = Zharchikhite +names-golem-dataset-1315 = Zhemchuzhnikovite +names-golem-dataset-1316 = Ziesite +names-golem-dataset-1317 = Zimbabweite +names-golem-dataset-1318 = Zincite +names-golem-dataset-1319 = Zinclipscombite +names-golem-dataset-1320 = Zincmelanterite +names-golem-dataset-1321 = Zincobotryogen +names-golem-dataset-1322 = Zincochromite +names-golem-dataset-1323 = Zincolivenite +names-golem-dataset-1324 = Zinkenite +names-golem-dataset-1325 = Zinnwaldite +names-golem-dataset-1326 = Zippeite +names-golem-dataset-1327 = Zircon +names-golem-dataset-1328 = Zirconolite +names-golem-dataset-1329 = Zircophyllite +names-golem-dataset-1330 = Zirkelite +names-golem-dataset-1331 = Znucalite +names-golem-dataset-1332 = Zoisite +names-golem-dataset-1333 = Zorite +names-golem-dataset-1334 = Zunyite +names-golem-dataset-1335 = Zussmanite +names-golem-dataset-1336 = Zykaite diff --git a/Resources/Prototypes/Datasets/Names/golem.yml b/Resources/Prototypes/Datasets/Names/golem.yml new file mode 100644 index 00000000000..2c237eec433 --- /dev/null +++ b/Resources/Prototypes/Datasets/Names/golem.yml @@ -0,0 +1,5 @@ +- type: localizedDataset + id: NamesGolem + values: + prefix: names-golem-dataset- + count: 1336 From cc726bec256457ce821d8cfb15c343b643f7c318 Mon Sep 17 00:00:00 2001 From: Vanessa Date: Fri, 21 Nov 2025 18:31:07 -0600 Subject: [PATCH 324/340] Updated various non-upstream entities components. Fixed YAML Linter errors. --- .../Prototypes/Entities/Clothing/Head/misc.yml | 2 -- .../Objects/Weapons/Guns/Battery/battery_guns.yml | 2 -- .../_DV/Entities/Objects/Devices/shock_collar.yml | 1 - .../Objects/Specific/Chemistry/skimmer.yml | 5 +++-- Resources/Prototypes/_DV/Objectives/asakim.yml | 11 ++++++++++- .../Prototypes/_DV/Objectives/menaceskeleton.yml | 12 ++++++++++-- Resources/Prototypes/_DV/Objectives/skia.yml | 7 ++++++- Resources/Prototypes/_DV/Objectives/traitor.yml | 11 ++++++++++- Resources/Prototypes/_DV/Objectives/wizard.yml | 14 ++++++++++++-- .../Entities/Mobs/Anomalites/anomalites.yml | 2 +- .../Structures/Storage/Crates/emergency_pod.yml | 1 - Resources/Prototypes/name_identifier_groups.yml | 6 +++--- 12 files changed, 55 insertions(+), 19 deletions(-) diff --git a/Resources/Prototypes/Entities/Clothing/Head/misc.yml b/Resources/Prototypes/Entities/Clothing/Head/misc.yml index 094e60a7c9b..2e5e0b65845 100644 --- a/Resources/Prototypes/Entities/Clothing/Head/misc.yml +++ b/Resources/Prototypes/Entities/Clothing/Head/misc.yml @@ -196,8 +196,6 @@ sprite: Clothing/Head/Misc/fancycrown.rsi - type: Clothing sprite: Clothing/Head/Misc/fancycrown.rsi - - type: TypingIndicatorClothing - proto: regal - type: StaticPrice price: 3000 # - type: AddAccentClothing # DeltaV - remove clothing-forced accents diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Battery/battery_guns.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Battery/battery_guns.yml index 490d73db4cf..1b473c56884 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Battery/battery_guns.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Battery/battery_guns.yml @@ -258,8 +258,6 @@ fireCost: 50 #Delta-V was 62.5 - type: StaticPrice price: 420 - proto: RedLaser - fireCost: 62.5 - type: entity name: practice laser carbine diff --git a/Resources/Prototypes/_DV/Entities/Objects/Devices/shock_collar.yml b/Resources/Prototypes/_DV/Entities/Objects/Devices/shock_collar.yml index de99ddbfe8f..4dfbb2f7eb1 100644 --- a/Resources/Prototypes/_DV/Entities/Objects/Devices/shock_collar.yml +++ b/Resources/Prototypes/_DV/Entities/Objects/Devices/shock_collar.yml @@ -27,7 +27,6 @@ - type: ShockOnTrigger damage: 5 duration: 3 - cooldown: 4 - type: TriggerOnSignal - type: DeviceLinkSink ports: diff --git a/Resources/Prototypes/_DV/Entities/Objects/Specific/Chemistry/skimmer.yml b/Resources/Prototypes/_DV/Entities/Objects/Specific/Chemistry/skimmer.yml index 7f213a430fd..05abc869b6a 100644 --- a/Resources/Prototypes/_DV/Entities/Objects/Specific/Chemistry/skimmer.yml +++ b/Resources/Prototypes/_DV/Entities/Objects/Specific/Chemistry/skimmer.yml @@ -13,8 +13,9 @@ visible: false - type: Injector targetSmallest: true - minTransferAmount: 5 - transferAmount: 5 + transferAmounts: + - 5 + currentTransferAmount: 5 - type: Item sprite: _DV/Objects/Specific/Chemistry/skimmer.rsi - type: SolutionContainerVisuals diff --git a/Resources/Prototypes/_DV/Objectives/asakim.yml b/Resources/Prototypes/_DV/Objectives/asakim.yml index 5f26741d3bd..5d35de88f33 100644 --- a/Resources/Prototypes/_DV/Objectives/asakim.yml +++ b/Resources/Prototypes/_DV/Objectives/asakim.yml @@ -30,7 +30,16 @@ - type: TargetObjective title: objective-condition-asakim-terminate-title - type: PickRandomPerson - onlyChoosableJobs: true + filters: + - !type:BodyMindFilter + whitelist: + components: + - CommandStaff + # Can't have multiple objectives to kill the same person. + - !type:TargetObjectiveMindFilter + blacklist: + components: + - KillPersonCondition - type: RerollAfterCompletion rerollObjectivePrototype: AsakimKillObjective rerollObjectiveMessage: objective-condition-asakim-terminate-reroll-message diff --git a/Resources/Prototypes/_DV/Objectives/menaceskeleton.yml b/Resources/Prototypes/_DV/Objectives/menaceskeleton.yml index 6e97a3c2372..f81377bee00 100644 --- a/Resources/Prototypes/_DV/Objectives/menaceskeleton.yml +++ b/Resources/Prototypes/_DV/Objectives/menaceskeleton.yml @@ -37,7 +37,11 @@ - type: TargetObjective title: objective-skeleton-haunt-title - type: PickRandomPerson - onlyChoosableJobs: true + filters: + - !type:TargetObjectiveMindFilter + blacklist: + components: + - KillPersonCondition - type: entity parent: SkeletonBaseObjective @@ -52,7 +56,11 @@ - type: TargetObjective title: objective-skeleton-frame-title - type: PickRandomPerson - onlyChoosableJobs: true + filters: + - !type:BodyMindFilter + whitelist: + components: + - CommandStaff - type: entity parent: SkeletonBaseObjective diff --git a/Resources/Prototypes/_DV/Objectives/skia.yml b/Resources/Prototypes/_DV/Objectives/skia.yml index 4c31fb0a027..927e0c4ed2c 100644 --- a/Resources/Prototypes/_DV/Objectives/skia.yml +++ b/Resources/Prototypes/_DV/Objectives/skia.yml @@ -19,7 +19,12 @@ - type: TargetObjective title: objective-condition-reap-soul-title - type: PickRandomPerson - onlyChoosableJobs: true + filters: + # Can't have multiple objectives to kill the same person. + - !type:TargetObjectiveMindFilter + blacklist: + components: + - KillPersonCondition - type: RerollAfterCompletion rerollObjectivePrototype: SkiaReapObjective rerollObjectiveMessage: objective-condition-reap-soul-reroll-message diff --git a/Resources/Prototypes/_DV/Objectives/traitor.yml b/Resources/Prototypes/_DV/Objectives/traitor.yml index 910da7e5854..1e080e647bd 100644 --- a/Resources/Prototypes/_DV/Objectives/traitor.yml +++ b/Resources/Prototypes/_DV/Objectives/traitor.yml @@ -100,7 +100,16 @@ - type: TargetObjective title: objective-condition-teach-person-title - type: PickRandomPerson - onlyChoosableJobs: true + filters: + - !type:BodyMindFilter + whitelist: + components: + - CommandStaff + # Can't have multiple objectives to kill the same person. + - !type:TargetObjectiveMindFilter + blacklist: + components: + - KillPersonCondition # Kill fellow traitor objective - type: entity diff --git a/Resources/Prototypes/_DV/Objectives/wizard.yml b/Resources/Prototypes/_DV/Objectives/wizard.yml index f33e4c03988..748038c7072 100644 --- a/Resources/Prototypes/_DV/Objectives/wizard.yml +++ b/Resources/Prototypes/_DV/Objectives/wizard.yml @@ -88,7 +88,12 @@ - type: TargetObjective title: objective-condition-wizard-preserve-person-title - type: PickRandomPerson - onlyChoosableJobs: true + filters: + - !type:BodyMindFilter + whitelist: + components: + - CommandStaff + - KillPersonCondition # Should also choose those who have targets on their heads by other antags :3 - type: entity parent: [BaseWizardObjective, BaseKillObjective] @@ -102,7 +107,12 @@ - type: TargetObjective title: objective-condition-wizard-kill-person-title - type: PickRandomPerson - onlyChoosableJobs: true + filters: + # Can't have multiple objectives to kill the same person. + - !type:TargetObjectiveMindFilter + blacklist: + components: + - KillPersonCondition - type: KillPersonCondition requireDead: true diff --git a/Resources/Prototypes/_Impstation/Entities/Mobs/Anomalites/anomalites.yml b/Resources/Prototypes/_Impstation/Entities/Mobs/Anomalites/anomalites.yml index 7e899e2b35d..c64be9915b6 100644 --- a/Resources/Prototypes/_Impstation/Entities/Mobs/Anomalites/anomalites.yml +++ b/Resources/Prototypes/_Impstation/Entities/Mobs/Anomalites/anomalites.yml @@ -147,7 +147,7 @@ # apid-type always weightless movement - type: MovementAlwaysTouching - type: MovementIgnoreGravity - gravityState: true + weightless: true - type: Physics bodyStatus: InAir - type: CanMoveInAir diff --git a/Resources/Prototypes/_NF/Entities/Structures/Storage/Crates/emergency_pod.yml b/Resources/Prototypes/_NF/Entities/Structures/Storage/Crates/emergency_pod.yml index 3a70437ecff..69ee63053be 100644 --- a/Resources/Prototypes/_NF/Entities/Structures/Storage/Crates/emergency_pod.yml +++ b/Resources/Prototypes/_NF/Entities/Structures/Storage/Crates/emergency_pod.yml @@ -60,7 +60,6 @@ tags: - VimPilot # Pets - CanPilot # People - forceWhitelist: true # Frontier - force whitelist - type: Damageable damageContainer: StructuralInorganic damageModifierSet: Metallic diff --git a/Resources/Prototypes/name_identifier_groups.yml b/Resources/Prototypes/name_identifier_groups.yml index 847508938cc..be0d3daefd9 100644 --- a/Resources/Prototypes/name_identifier_groups.yml +++ b/Resources/Prototypes/name_identifier_groups.yml @@ -31,7 +31,7 @@ - type: nameIdentifierGroup id: Xenoborg - format: name-identifier-format-xenoborg + prefix: XI # DeltaV - was don't have Format: Was name-identifier-format-xenoborg minValue: 1000 maxValue: 9999 @@ -55,9 +55,9 @@ prefix: TELE minValue: 0 maxValue: 999 - + - type: nameIdentifierGroup id: XenoArtifactNode prefix: XAN minValue: 1 - maxValue: 999 \ No newline at end of file + maxValue: 999 From da8f09e0a41748a1e5f4b4824ecab621fe65438f Mon Sep 17 00:00:00 2001 From: Vanessa Date: Fri, 21 Nov 2025 18:48:33 -0600 Subject: [PATCH 325/340] Nuked invalid entity from nukieplanet.yml --- Resources/Maps/Nonstations/nukieplanet.yml | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/Resources/Maps/Nonstations/nukieplanet.yml b/Resources/Maps/Nonstations/nukieplanet.yml index 1249440268f..23c1782cc92 100644 --- a/Resources/Maps/Nonstations/nukieplanet.yml +++ b/Resources/Maps/Nonstations/nukieplanet.yml @@ -10312,21 +10312,6 @@ entities: - type: Transform pos: -2.530845,-16.461567 parent: 104 -- proto: ClothingNeckStethoscope - entities: - - uid: 1336 - components: - - type: Transform - pos: -2.327716,-12.470306 - parent: 104 - - type: Stethoscope - actionEntity: 1739 - - type: ActionsContainer - - type: ContainerContainer - containers: - actions: !type:Container - ents: - - 1739 - proto: ClothingShoesBootsSalvage entities: - uid: 542 From 952c50e4c3a01734d3904280403cc59d9489bc8e Mon Sep 17 00:00:00 2001 From: Vanessa Date: Sat, 22 Nov 2025 11:41:07 -0600 Subject: [PATCH 326/340] Added a migration for SoapBorg, since it was mapped. --- .../AddComponentsImplant/AddComponentsImplantSystem.cs | 2 -- Content.Shared/_DV/Implants/Radio/SharedRadioImplantSystem.cs | 2 -- Resources/Migrations/migration.yml | 3 +++ 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/Content.Shared/_DV/Implants/AddComponentsImplant/AddComponentsImplantSystem.cs b/Content.Shared/_DV/Implants/AddComponentsImplant/AddComponentsImplantSystem.cs index 6ed173c11dd..d8bc47f248f 100644 --- a/Content.Shared/_DV/Implants/AddComponentsImplant/AddComponentsImplantSystem.cs +++ b/Content.Shared/_DV/Implants/AddComponentsImplant/AddComponentsImplantSystem.cs @@ -15,8 +15,6 @@ public sealed class AddComponentsImplantSystem : EntitySystem private void OnImplantImplantedEvent(Entity ent, ref ImplantImplantedEvent args) { - //if (args.Implanted is not {} target) // TODO: AUM - Cleanup - // return; var target = args.Implanted; foreach (var component in ent.Comp.ComponentsToAdd) diff --git a/Content.Shared/_DV/Implants/Radio/SharedRadioImplantSystem.cs b/Content.Shared/_DV/Implants/Radio/SharedRadioImplantSystem.cs index 644cc95f504..03668f7c897 100644 --- a/Content.Shared/_DV/Implants/Radio/SharedRadioImplantSystem.cs +++ b/Content.Shared/_DV/Implants/Radio/SharedRadioImplantSystem.cs @@ -22,8 +22,6 @@ public abstract class SharedRadioImplantSystem : EntitySystem /// private void OnImplanted(Entity ent, ref ImplantImplantedEvent args) { - //if (args.Implanted is not {} user) // TODO: AUM - Cleanup - // return; var user = args.Implanted; ent.Comp.Implantee = user; diff --git a/Resources/Migrations/migration.yml b/Resources/Migrations/migration.yml index 987088aa619..5e6929617f8 100644 --- a/Resources/Migrations/migration.yml +++ b/Resources/Migrations/migration.yml @@ -671,3 +671,6 @@ MediumXenoArtifact: ComplexXenoArtifact SimpleXenoArtifactItem: ComplexXenoArtifactItem MediumXenoArtifactItem: ComplexXenoArtifactItem VariedXenoArtifactItem: ComplexXenoArtifactItem + +# 2025-11-22 - DeltaV +SoapBorg: SoapNT From 614584080dd07beec34cc1c0c7c6c0cd88d388af Mon Sep 17 00:00:00 2001 From: Vanessa Date: Sat, 22 Nov 2025 11:51:13 -0600 Subject: [PATCH 327/340] Cleaned up some old comments. --- .../_DV/Implants/AddFactions/AddFactionsImplantSystem.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/Content.Shared/_DV/Implants/AddFactions/AddFactionsImplantSystem.cs b/Content.Shared/_DV/Implants/AddFactions/AddFactionsImplantSystem.cs index 5ef42da95e6..de975716bf8 100644 --- a/Content.Shared/_DV/Implants/AddFactions/AddFactionsImplantSystem.cs +++ b/Content.Shared/_DV/Implants/AddFactions/AddFactionsImplantSystem.cs @@ -16,8 +16,6 @@ public sealed class AddFactionsImplantSystem : EntitySystem private void OnImplantImplantedEvent(Entity ent, ref ImplantImplantedEvent args) { - //if (args.Implanted is not {} target) // TODO: AUM - Cleanup - // return; var target = args.Implanted; foreach (var faction in ent.Comp.Factions) From 6f342ad71285551d76681dd20702ad1399d7d1d5 Mon Sep 17 00:00:00 2001 From: Vanessa Date: Sat, 22 Nov 2025 11:51:40 -0600 Subject: [PATCH 328/340] Fixed borg dataset entries after name removal --- Resources/Locale/en-US/datasets/names/borg.ftl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Resources/Locale/en-US/datasets/names/borg.ftl b/Resources/Locale/en-US/datasets/names/borg.ftl index a6682b65999..23f5ef7a8ae 100644 --- a/Resources/Locale/en-US/datasets/names/borg.ftl +++ b/Resources/Locale/en-US/datasets/names/borg.ftl @@ -37,6 +37,6 @@ names-borg-dataset-36 = Makeshifter names-borg-dataset-37 = Twin names-borg-dataset-38 = S.A.U.L names-borg-dataset-39 = Honker -names-borg-dataset-41 = Is-The-Robot -names-borg-dataset-42 = 9 of 7 -names-borg-dataset-43 = Dank bot +names-borg-dataset-40 = Is-The-Robot +names-borg-dataset-41 = 9 of 7 +names-borg-dataset-42 = Dank bot From 3c8e54d127c7f434dde9cd95cfecf9354a0bdd1d Mon Sep 17 00:00:00 2001 From: Vanessa Date: Sat, 22 Nov 2025 11:52:30 -0600 Subject: [PATCH 329/340] Changed price of NanoMed restock box after it kept failing NoCargoOrderArbitrage test --- Resources/Prototypes/Catalog/Cargo/cargo_vending.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Resources/Prototypes/Catalog/Cargo/cargo_vending.yml b/Resources/Prototypes/Catalog/Cargo/cargo_vending.yml index e7c364709bb..137e6e6ded5 100644 --- a/Resources/Prototypes/Catalog/Cargo/cargo_vending.yml +++ b/Resources/Prototypes/Catalog/Cargo/cargo_vending.yml @@ -102,7 +102,7 @@ sprite: Objects/Specific/Service/vending_machine_restock.rsi state: base product: CrateVendingMachineRestockMedicalFilled - cost: 1750 + cost: 1800 # DeltaV - Was 1750 but needs to be more due to NoCargoOrderArbitrage test category: cargoproduct-category-name-medical group: market From 537e2fa03ca2f9c9acd3341c11d64c3779a5f446 Mon Sep 17 00:00:00 2001 From: Vanessa Date: Sat, 22 Nov 2025 11:53:07 -0600 Subject: [PATCH 330/340] Added CableApcStackLingering10 to migration --- Resources/Migrations/migration.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/Resources/Migrations/migration.yml b/Resources/Migrations/migration.yml index 5e6929617f8..aa33e6f0c9c 100644 --- a/Resources/Migrations/migration.yml +++ b/Resources/Migrations/migration.yml @@ -674,3 +674,4 @@ VariedXenoArtifactItem: ComplexXenoArtifactItem # 2025-11-22 - DeltaV SoapBorg: SoapNT +CableApcStackLingering10: CableApcStack From cece56a5b7fe8c9b9bff9a31f4ce6a26ca217888 Mon Sep 17 00:00:00 2001 From: Princess Cheeseballs <66055347+Princess-Cheeseballs@users.noreply.github.com> Date: Tue, 16 Sep 2025 15:25:53 -0700 Subject: [PATCH 331/340] Mothership Core Prototype Cleanup (#40410) * I cannot escape bodysystem no matter how hard I try * Move 2 things --------- Co-authored-by: Princess Cheeseballs <66055347+Pronana@users.noreply.github.com> --- .../Prototypes/Specific/mothershipcore.yml | 20 ------------- .../Entities/Mobs/Player/mothershipcore.yml | 20 +++++++++---- Resources/Prototypes/Entities/Mobs/base.yml | 30 ++++++++++++------- 3 files changed, 35 insertions(+), 35 deletions(-) delete mode 100644 Resources/Prototypes/Body/Prototypes/Specific/mothershipcore.yml diff --git a/Resources/Prototypes/Body/Prototypes/Specific/mothershipcore.yml b/Resources/Prototypes/Body/Prototypes/Specific/mothershipcore.yml deleted file mode 100644 index 234f950a036..00000000000 --- a/Resources/Prototypes/Body/Prototypes/Specific/mothershipcore.yml +++ /dev/null @@ -1,20 +0,0 @@ -- type: body - id: MothershipCoreBody - name: "core" - root: torso - slots: - torso: - part: TorsoBorg - connections: - - right2hand - - right1hand - - left1hand - - left2hand - left1hand: - part: LeftArmBorg - left2hand: - part: LeftArmBorg - right1hand: - part: RightArmBorg - right2hand: - part: RightArmBorg diff --git a/Resources/Prototypes/Entities/Mobs/Player/mothershipcore.yml b/Resources/Prototypes/Entities/Mobs/Player/mothershipcore.yml index 3535a55e7ff..6ebf622e9fd 100644 --- a/Resources/Prototypes/Entities/Mobs/Player/mothershipcore.yml +++ b/Resources/Prototypes/Entities/Mobs/Player/mothershipcore.yml @@ -5,9 +5,7 @@ - Omnitool - type: entity - parent: - - BaseMachinePowered - - BaseMob + parent: [ BaseControllable, BaseMachinePowered ] id: MothershipCore name: mothership core description: A sentient machine that can produce Xenoborgs. Without this the Xenoborgs are doomed. @@ -165,9 +163,21 @@ - type: NpcFactionMember factions: - Xenoborg - - type: Body - prototype: MothershipCoreBody - type: Hands + hands: + hand_right1: + location: Right + hand_right2: + location: Right + hand_left1: + location: Left + hand_left2: + location: Left + sortedHands: + - hand_right1 + - hand_right2 + - hand_left1 + - hand_left2 # - type: Puller # use the conveyor - type: Eye drawFov: false diff --git a/Resources/Prototypes/Entities/Mobs/base.yml b/Resources/Prototypes/Entities/Mobs/base.yml index f54a4c2093e..9f46161fd88 100644 --- a/Resources/Prototypes/Entities/Mobs/base.yml +++ b/Resources/Prototypes/Entities/Mobs/base.yml @@ -1,17 +1,14 @@ -# The progenitor. This should only container the most basic components possible. -# Only put things on here if every mob *must* have it. This includes ghosts. +# The literal bare minimum needed to be a controllable mob. Cannot move but can interact. - type: entity - save: false - id: BaseMob abstract: true + save: false + id: BaseControllable components: - type: Sprite noRot: true drawdepth: Mobs - - type: MobCollision - type: GravityAffected - type: Physics - bodyType: KinematicController - type: Fixtures fixtures: fix1: @@ -25,11 +22,8 @@ - MobLayer - type: Clickable - type: InteractionOutline - - type: InputMover - type: Input context: "human" - - type: LagCompensation - - type: MobMover - type: Actions - type: Alerts - type: Appearance @@ -42,12 +36,27 @@ - type: ContentEye - type: CameraRecoil - type: MindContainer - - type: MovementSpeedModifier - type: RequireProjectileTarget active: False - type: AnimatedEmotes # goob edit - animated emotes #- type: StunVisuals # DeltaV - disabled stun visuals for now +# The progenitor. This should only container the most basic components possible. +# Only put things on here if every mob *must* have it. This includes ghosts. +- type: entity + abstract: true + save: false + parent: BaseControllable + id: BaseMob + components: + - type: MobCollision + - type: Physics + bodyType: KinematicController + - type: InputMover + - type: MobMover + - type: MovementSpeedModifier + - type: LagCompensation + - type: entity save: false id: MobPolymorphable @@ -103,6 +112,7 @@ - !type:VomitBehavior - type: RadiationReceiver - type: Stamina + - type: StunVisuals - type: MobState - type: MobThresholds thresholds: From 7d7d4e4c459a3267bca7f255dc71001447707e62 Mon Sep 17 00:00:00 2001 From: Vanessa Date: Sat, 22 Nov 2025 13:26:43 -0600 Subject: [PATCH 332/340] Changed Normality Crystal recipe to include holy water because the recipe for Lye (water+ash) was making it impossible to make normality --- Resources/Prototypes/_DV/Recipes/Reactions/psionic.yml | 4 ++-- .../ServerInfo/Nyanotrasen/Guidebook/Epistemics/Psionics.xml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Resources/Prototypes/_DV/Recipes/Reactions/psionic.yml b/Resources/Prototypes/_DV/Recipes/Reactions/psionic.yml index b087c69f8cb..123d3bcf46d 100644 --- a/Resources/Prototypes/_DV/Recipes/Reactions/psionic.yml +++ b/Resources/Prototypes/_DV/Recipes/Reactions/psionic.yml @@ -13,14 +13,14 @@ # LotophagoiOil: 1 - type: reaction - id: CreateNormalityCrystal + id: CrystalNormality impact: Low quantized: true minTemp: 400 reactants: Ash: amount: 5 - Water: + Holywater: amount: 5 Blood: amount: 5 diff --git a/Resources/ServerInfo/Nyanotrasen/Guidebook/Epistemics/Psionics.xml b/Resources/ServerInfo/Nyanotrasen/Guidebook/Epistemics/Psionics.xml index 2911dae1557..29a53fa0b50 100644 --- a/Resources/ServerInfo/Nyanotrasen/Guidebook/Epistemics/Psionics.xml +++ b/Resources/ServerInfo/Nyanotrasen/Guidebook/Epistemics/Psionics.xml @@ -68,6 +68,6 @@ Metabolizing 20u or more of [color=#a4885c]mindbreaker[/color] will remove psion [color=#a4885c]Soulbreaker[/color] shells will remove psionics from psychics they hit. -[color=#a4885c]Ectoplasm[/color], combined in a beaker with equal parts water, ash, blood, and plasma, will produce a normality crystal when heated enough. [color=#fcdf03]Use a hot plate for this.[/color] +[color=#a4885c]Ectoplasm[/color], combined in a beaker with equal parts holy water, ash, blood, and plasma, will produce a normality crystal when heated enough. [color=#fcdf03]Use a hot plate for this.[/color] From a3caa2b6f9600d05e1ecc8c19258bee808868af8 Mon Sep 17 00:00:00 2001 From: ArtisticRoomba <145879011+ArtisticRoomba@users.noreply.github.com> Date: Tue, 14 Oct 2025 15:35:25 -0700 Subject: [PATCH 333/340] Fix Atmospherics dP not trolling partially airtight entities (#40435) * Fix dP not trolling partially airtight entities * Assumptions in atmospherics are the root of all evil --- .../Tests/Atmos/DeltaPressureTest.cs | 6 ++++++ .../Components/DeltaPressureComponent.cs | 9 ++------- .../EntitySystems/AtmosphereSystem.API.cs | 4 ---- .../AtmosphereSystem.DeltaPressure.cs | 19 ++++++++++++++++++- .../EntitySystems/DeltaPressureSystem.cs | 15 +-------------- 5 files changed, 27 insertions(+), 26 deletions(-) diff --git a/Content.IntegrationTests/Tests/Atmos/DeltaPressureTest.cs b/Content.IntegrationTests/Tests/Atmos/DeltaPressureTest.cs index 9dda130847d..839e0ea8972 100644 --- a/Content.IntegrationTests/Tests/Atmos/DeltaPressureTest.cs +++ b/Content.IntegrationTests/Tests/Atmos/DeltaPressureTest.cs @@ -93,6 +93,12 @@ public sealed class DeltaPressureTest private readonly ResPath _testMap = new("Maps/Test/Atmospherics/DeltaPressure/deltapressuretest.yml"); + // TODO ATMOS TESTS + // - Check for directional windows (partial airtight ents) properly computing pressure differences + // - Check for multi-tick damage (window with n damage threshold should take n ticks to destroy) + // - Check that all maps do not explode into a million pieces on load due to dP + // - Ensure that all tests work for a map that has an origin at a non zero coordinate + /// /// Asserts that an entity with a DeltaPressureComponent with autoJoinProcessingList /// set to true is automatically added to the DeltaPressure processing list diff --git a/Content.Server/Atmos/Components/DeltaPressureComponent.cs b/Content.Server/Atmos/Components/DeltaPressureComponent.cs index f90c133dea7..1bebf75b843 100644 --- a/Content.Server/Atmos/Components/DeltaPressureComponent.cs +++ b/Content.Server/Atmos/Components/DeltaPressureComponent.cs @@ -33,18 +33,13 @@ public sealed partial class DeltaPressureComponent : Component [Access(typeof(DeltaPressureSystem), typeof(AtmosphereSystem))] public bool IsTakingDamage; - /// - /// The current cached position of this entity on the grid. - /// Updated via MoveEvent. - /// - [DataField(readOnly: true)] - public Vector2i CurrentPosition = Vector2i.Zero; - /// /// The grid this entity is currently joined to for processing. /// Required for proper deletion, as we cannot reference the grid /// for removal while the entity is being deleted. /// + /// Note that while already stores the grid, + /// we cannot trust it to be available on init or when the entity is being deleted. Tragic. [DataField] public EntityUid? GridUid; diff --git a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.API.cs b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.API.cs index 87cfce135d7..29f091f3407 100644 --- a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.API.cs +++ b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.API.cs @@ -355,10 +355,6 @@ public partial class AtmosphereSystem grid.Comp.DeltaPressureEntityLookup[ent.Owner] = grid.Comp.DeltaPressureEntities.Count; grid.Comp.DeltaPressureEntities.Add(ent); - ent.Comp.CurrentPosition = _map.CoordinatesToTile(grid, - Comp(grid), - xform.Coordinates); - ent.Comp.GridUid = grid.Owner; ent.Comp.InProcessingList = true; diff --git a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.DeltaPressure.cs b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.DeltaPressure.cs index 207589e5545..974636d3aec 100644 --- a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.DeltaPressure.cs +++ b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.DeltaPressure.cs @@ -39,11 +39,13 @@ public sealed partial class AtmosphereSystem so simple vector operations like min/max/abs can be performed on them. */ + var airtightComp = _airtightQuery.Comp(ent); + var currentPos = airtightComp.LastPosition.Tile; var tiles = new TileAtmosphere?[Atmospherics.Directions]; for (var i = 0; i < Atmospherics.Directions; i++) { var direction = (AtmosDirection)(1 << i); - var offset = ent.Comp.CurrentPosition.Offset(direction); + var offset = currentPos.Offset(direction); tiles[i] = gridAtmosComp.Tiles.GetValueOrDefault(offset); } @@ -51,6 +53,21 @@ public sealed partial class AtmosphereSystem GetBulkTileAtmospherePressures(tiles, pressures); + // This entity could be airtight but still be able to contain air on the tile it's on (ex. directional windows). + // As such, substitute the pressure of the pressure on top of the entity for the directions that it can accept air from. + // (Or rather, don't do so for directions that it blocks air from.) + if (!airtightComp.NoAirWhenFullyAirBlocked) + { + for (var i = 0; i < Atmospherics.Directions; i++) + { + var direction = (AtmosDirection)(1 << i); + if (!airtightComp.AirBlockedDirection.HasFlag(direction)) + { + pressures[i] = gridAtmosComp.Tiles.GetValueOrDefault(currentPos)?.Air?.Pressure ?? 0f; + } + } + } + Span opposingGroupA = stackalloc float[DeltaPressurePairCount]; Span opposingGroupB = stackalloc float[DeltaPressurePairCount]; Span opposingGroupMax = stackalloc float[DeltaPressurePairCount]; diff --git a/Content.Server/Atmos/EntitySystems/DeltaPressureSystem.cs b/Content.Server/Atmos/EntitySystems/DeltaPressureSystem.cs index a6cbec0d0c8..dd7091c270f 100644 --- a/Content.Server/Atmos/EntitySystems/DeltaPressureSystem.cs +++ b/Content.Server/Atmos/EntitySystems/DeltaPressureSystem.cs @@ -17,7 +17,6 @@ namespace Content.Server.Atmos.EntitySystems; public sealed class DeltaPressureSystem : EntitySystem { [Dependency] private readonly AtmosphereSystem _atmosphereSystem = default!; - [Dependency] private readonly SharedMapSystem _map = default!; public override void Initialize() { @@ -26,29 +25,17 @@ public sealed class DeltaPressureSystem : EntitySystem SubscribeLocalEvent(OnComponentInit); SubscribeLocalEvent(OnComponentShutdown); SubscribeLocalEvent(OnExamined); - SubscribeLocalEvent(OnMoveEvent); SubscribeLocalEvent(OnGridChanged); } - private void OnMoveEvent(Entity ent, ref MoveEvent args) - { - var xform = Transform(ent); - // May move off-grid, so, might as well protect against that. - if (!TryComp(xform.GridUid, out var mapGridComponent)) - { - return; - } - - ent.Comp.CurrentPosition = _map.CoordinatesToTile(xform.GridUid.Value, mapGridComponent, args.NewPosition); - } - private void OnComponentInit(Entity ent, ref ComponentInit args) { var xform = Transform(ent); if (xform.GridUid == null) return; + EnsureComp(ent); _atmosphereSystem.TryAddDeltaPressureEntity(xform.GridUid.Value, ent); } From 460e572785d2d7da707c516def7bc62b57436220 Mon Sep 17 00:00:00 2001 From: Vanessa Date: Sun, 23 Nov 2025 10:44:09 -0600 Subject: [PATCH 334/340] Updated Wizden Changelog --- Resources/Changelog/Changelog.yml | 3512 +++++++++++++++-------------- 1 file changed, 1769 insertions(+), 1743 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 1db6eabfd77..66f7bf7fe29 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,1739 +1,4 @@ Entries: -- author: ArtisticRoomba - changes: - - message: Certain randomly filled bags will now have the correct number of contents - inside of them. - type: Fix - id: 8184 - time: '2025-04-14T21:02:49.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/36155 -- author: Will-Oliver-Br - changes: - - message: Now you can see if there's a beaker in the chemmaster. - type: Tweak - id: 8185 - time: '2025-04-14T23:27:47.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/36472 -- author: EmoGarbage404, Fildrance - changes: - - message: new ui for analysis console, new ui for node scanner. Artifact node activation - is now different. - type: Add - - message: artifacts cannot create massive distruction events, become guns or music - instruments. Sentient artifacts cannot activate nodes. - type: Remove - id: 8186 - time: '2025-04-15T00:34:53.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/33370 -- author: EmoGarbage404 - changes: - - message: Skeletons once again become living skulls on death. - type: Fix - id: 8187 - time: '2025-04-15T03:38:31.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/36571 -- author: Crazydave91920 - changes: - - message: Fixed Zookeeper not being on the double barrel shotgun contraband list - type: Fix - id: 8188 - time: '2025-04-15T18:27:29.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/36583 -- author: Minemoder5000 - changes: - - message: The Syndicate Elite Hardsuit and Cybersun Juggernaut Suit have been restricted - to Nuclear Operative uplinks. - type: Tweak - - message: The Elite Web Vest has been added to the uplink for 5 tc. It has reduced - pierce resistance, but increased heat, radiation, blunt, slash, and caustic - resistance compared to the normal web vest. - type: Add - id: 8189 - time: '2025-04-15T21:39:18.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/36225 -- author: EmoGarbage404 - changes: - - message: Sentient artifacts can once again activate themselves. - type: Tweak - - message: Increased sentient artifact self activation cooldown. - type: Tweak - id: 8190 - time: '2025-04-15T22:24:58.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/36598 -- author: EmoGarbage404 - changes: - - message: When an artifact's node is unlocked, the effect will now also occur. - Effects can still be triggered manually through interaction. - type: Add - - message: Artifacts will now have more nodes on average. - type: Tweak - - message: Higher-class artifact nodes now grant significantly more points. - type: Tweak - id: 8191 - time: '2025-04-15T22:38:26.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/36604 -- author: EmoGarbage404 - changes: - - message: Restored Artifexium's interaction with artifacts. Now, a single spray - will randomly activate one of the triggers for a node, allowing you to subvert - puzzling artifacts. - type: Add - id: 8192 - time: '2025-04-15T22:49:58.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/36595 -- author: slarticodefast, Flareguy - changes: - - message: Added the Desynchronizer, an experimental device that allows the user - to temporarily make themselves invincible, invisible, & immobile. Unlock it - through experimental science today! - type: Add - - message: Gravity Manipulation technology is now a tier 2 technology. - type: Tweak - id: 8193 - time: '2025-04-16T01:33:39.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/35752 -- author: RedBookcase - changes: - - message: Minor blueprint tweaks and a new stored sprite for blueprints. - type: Tweak - id: 8194 - time: '2025-04-16T10:12:22.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/36609 -- author: SlamBamActionman - changes: - - message: Unfolded bandanas/lab coats now fit in crates again. - type: Fix - id: 8195 - time: '2025-04-16T11:54:42.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/36625 -- author: metalgearsloth - changes: - - message: Fixes tippy messages being too sh- - type: Fix - id: 8196 - time: '2025-04-16T12:23:41.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/36616 -- author: SlamBamActionman - changes: - - message: Closed pet carriers no longer push players or lockers. - type: Fix - id: 8197 - time: '2025-04-16T14:12:30.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/36627 -- author: Flareguy, ArtisticRoomba - changes: - - message: Added the Temperature Gun. It can shoot body-temperature-changing bolts. - Unlock them through arsenal science today! - type: Add - - message: Experimental Battery Ammo technology is no longer available to research.. - type: Remove - id: 8198 - time: '2025-04-16T17:58:35.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/35447 -- author: UpAndLeaves - changes: - - message: Most clothing will no longer provide protection against zombification - type: Tweak - - message: Blunt/Slash/Piercing resistance will now provide weak protection against - zombification. - type: Tweak - - message: Winter coats are now moderately effective against zombification. - type: Tweak - - message: Bio suits are now very effective against zombification. - type: Tweak - - message: Security bio suits are now lightly armored. - type: Tweak - - message: Bio suits now only have 5% slowdown. - type: Tweak - id: 8199 - time: '2025-04-16T18:21:45.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/36485 -- author: ScarKy0 - changes: - - message: A basic sheet crate can now be ordered for 1660 spesos. It contains 30 - steel, glass and plastic. - type: Add - id: 8200 - time: '2025-04-16T19:20:36.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/36419 -- author: sowelipililimute - changes: - - message: The medical and security techfabs now announce new recipes that they - can fabricate as they are researched - type: Add - id: 8201 - time: '2025-04-16T19:29:25.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/34959 -- author: Linkbro1 - changes: - - message: changed MV and HV cable item sprites, changed MV cable structure sprites - type: Tweak - id: 8202 - time: '2025-04-16T20:26:25.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/34955 -- author: ciaran - changes: - - message: Fixed duplicate crew monitor console entries for crew with tracking implants - type: Fix - id: 8203 - time: '2025-04-16T21:14:05.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/35918 -- author: Seam_Less - changes: - - message: Standardized the In-Hand Sprites for all gloves - type: Tweak - id: 8204 - time: '2025-04-16T22:15:38.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/35997 -- author: DissidentBullet - changes: - - message: Monkeys can now wear juggernaut suits - type: Add - id: 8205 - time: '2025-04-16T23:14:28.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/34121 -- author: SpaceRox1244 - changes: - - message: Cargo can now order handheld artifact containers for transporting small - artifacts. - type: Add - id: 8206 - time: '2025-04-16T23:35:57.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/33327 -- author: ScarKy0 - changes: - - message: Hydroponics tray flatpacks can now be bought for 750 spesos. - type: Add - id: 8207 - time: '2025-04-16T23:51:00.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/36630 -- author: EmoGarbage404 - changes: - - message: Fixed artifacts sometimes having negative research values. - type: Fix - id: 8208 - time: '2025-04-17T03:14:17.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/36642 -- author: VerinSenpai - changes: - - message: You can now use actions within the action window. - type: Add - id: 8209 - time: '2025-04-17T10:08:09.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/35642 -- author: ElectroJr - changes: - - message: Fixed some intense explosion types using incorrect overlay sprites. - type: Fix - id: 8210 - time: '2025-04-17T10:12:14.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/36644 -- author: Beck Thompson, SlamBamActionman - changes: - - message: Fixed trash bag visuals. The appearance will now update correctly depending - on how many items it contains! - type: Fix - id: 8211 - time: '2025-04-17T10:36:23.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/32386 -- author: Callmore - changes: - - message: Cyborgs now require being pryed to open/close the panel instead of screwed. - type: Tweak - id: 8212 - time: '2025-04-17T10:38:00.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/32796 -- author: Errant - changes: - - message: Handheld geiger counters can now by heard by everyone nearby. - type: Tweak - id: 8213 - time: '2025-04-17T11:24:47.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/30463 -- author: Centronias - changes: - - message: Tank harnesses can be made at lathes, similar to utility belts. - type: Add - - message: Tank harnesses take up a 1x2 space in inventories, half of their previous - 2x2. - type: Tweak - id: 8214 - time: '2025-04-17T12:33:31.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/35590 -- author: Jacktastic09 - changes: - - message: Added the Solid Headband, available via hacked ClothesMate vending machines - type: Add - id: 8215 - time: '2025-04-17T13:43:44.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/36650 -- author: Hoodie42 - changes: - - message: The banjo can now be worn on the back or suit storage slots. - type: Tweak - id: 8216 - time: '2025-04-17T14:05:27.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/34057 -- author: muburu - changes: - - message: Space Dragons now have randomly generated names. - type: Add - id: 8217 - time: '2025-04-17T21:05:14.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/36656 -- author: archee1 - changes: - - message: Cats can walk slowly to avoid slipping on puddles. - type: Tweak - - message: Cak's (cake cats) previously incorrect sprinting and walking speeds have - been corrected - type: Fix - id: 8218 - time: '2025-04-18T01:15:25.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/36542 -- author: Killerqu00 - changes: - - message: Contraband examine icon now shows whether or not you are allowed to possess - the item. - type: Add - - message: Contraband examine activates by hovering instead of clicking. - type: Tweak - id: 8219 - time: '2025-04-18T01:23:02.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/36032 -- author: mjarduk - changes: - - message: Torches can now be refueled. - type: Tweak - - message: Burnt torches/glowsticks names' can now display if they're glued, cluwnified, - etc. - type: Fix - id: 8220 - time: '2025-04-18T01:59:41.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/36209 -- author: lzk228 - changes: - - message: Borgs, clowns and mimes now can choose a custom name in loadouts. - type: Tweak - id: 8222 - time: '2025-04-18T02:32:03.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/35170 -- author: DogZeroX - changes: - - message: Added Experiment plushie from the game Scav Prototype! - type: Add - id: 8223 - time: '2025-04-18T02:38:34.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/36663 -- author: slarticodefast - changes: - - message: Fire extinguishers and sprays now allow you to push the grids you are - standing on when you have magboots on. - type: Add - id: 8224 - time: '2025-04-18T03:41:27.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/31754 -- author: aada - changes: - - message: Filter categories added to the security techfab. - type: Add - id: 8225 - time: '2025-04-18T03:52:05.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/35594 -- author: Fildrance - changes: - - message: returned deconstruct to the top level option on RCD - type: Fix - id: 8226 - time: '2025-04-18T04:50:15.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/36486 -- author: ciaran - changes: - - message: Added a button to scroll back to the bottom of the chat box - type: Add - id: 8227 - time: '2025-04-18T07:43:00.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/35913 -- author: Tayrtahn - changes: - - message: The popup when pointing at an item in a character's inventory now mentions - that character. - type: Tweak - id: 8228 - time: '2025-04-18T12:09:49.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/36252 -- author: slarticodefast - changes: - - message: Punching lights while wearing insulated gloves will no longer electrocute - you. - type: Fix - id: 8229 - time: '2025-04-18T12:26:48.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/36686 -- author: Minemoder - changes: - - message: Rainbow Cannabis Leaves no longer emit light due to a renderer limitation. - type: Remove - id: 8230 - time: '2025-04-18T14:12:26.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/36479 -- author: IProduceWidgets - changes: - - message: Holobarrier projectors are now more power efficient. - type: Tweak - id: 8231 - time: '2025-04-18T16:10:12.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/34473 -- author: K-Dynamic - changes: - - message: Removed egg-plant from MegaSeed Servitor. (Egg-plant seeds can still - be obtained by mutation or exotic seed crate.) - type: Remove - id: 8232 - time: '2025-04-18T16:42:50.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/36579 -- author: Failed, Centronias - changes: - - message: The drink shaker now has in-hand sprites - type: Tweak - id: 8233 - time: '2025-04-18T17:12:37.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/36382 -- author: IProduceWidgets - changes: - - message: filing cabinets no longer have whitelists. - type: Tweak - id: 8234 - time: '2025-04-18T17:37:56.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/36185 -- author: aada - changes: - - message: Egg-plants now have 6 reagent per egg at 20 potency, up from 3. - type: Tweak - id: 8235 - time: '2025-04-18T19:52:12.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/36693 -- author: Nox38 - changes: - - message: Nuclear operative agent is renamed to nuclear operative corpsman. - type: Tweak - id: 8236 - time: '2025-04-18T19:56:57.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/34627 -- author: Ilya246 - changes: - - message: The actions hotbar now has up to 10 more hotkeys accessible through the - shift key. - type: Add - id: 8237 - time: '2025-04-18T22:45:20.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/33872 -- author: lzk228 - changes: - - message: Fixed breaking small mobs (e.g. mice) mask after getting into an air - flow. - type: Fix - id: 8238 - time: '2025-04-18T22:52:09.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/33888 -- author: YoungThugSS14 - changes: - - message: The Diona and Gingerbread species now get unique typing indicators - type: Add - id: 8239 - time: '2025-04-18T23:19:05.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/36126 -- author: Rainbeon - changes: - - message: Fixed Revolvers not correctly reloading from Speedloaders when the Revolver - is partially loaded. - type: Fix - - message: Speedloaders will now prioritize loading the active and upcoming chambers - in a Revolver when the Speedloader is only partially filled, rather than the - ones farthest away. - type: Fix - id: 8240 - time: '2025-04-18T23:26:44.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/32396 -- author: ScarKy0 - changes: - - message: Changed the air vent and scrubber sprites. - type: Tweak - id: 8241 - time: '2025-04-18T23:34:59.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/34223 -- author: EmoGarbage404 - changes: - - message: Added the material silo. This machine allows nearby machines to share - a pool of resources, cutting down on micromanagement. - type: Add - id: 8242 - time: '2025-04-18T23:43:17.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/36492 -- author: Onezero0 - changes: - - message: Modular Grenades can now fit inside Security belts and carriers. - type: Tweak - id: 8243 - time: '2025-04-19T00:04:44.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/34169 -- author: Alpaccalypse - changes: - - message: The cocktail "Irish slammer" has been renamed to "Grenade Penguin". - type: Tweak - id: 8244 - time: '2025-04-19T00:24:26.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/34181 -- author: ScarKy0 - changes: - - message: Added a couple more tools to the artifact borg module. - type: Tweak - id: 8245 - time: '2025-04-19T00:25:29.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/33338 -- author: august-sun - changes: - - message: Resprited the Chief Engineer's mantle. - type: Tweak - id: 8246 - time: '2025-04-19T00:26:24.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/36697 -- author: IProduceWidgets - changes: - - message: Vox are no longer immune to the zombie virus under certain circumstances - type: Fix - - message: The zombie virus no longer provides non-Initial Infected an undue grace - period before poisoning them. - type: Fix - id: 8247 - time: '2025-04-19T00:38:33.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/34472 -- author: Booblesnoot42 - changes: - - message: Airlocks will now animate properly after crushing someone. - type: Fix - id: 8248 - time: '2025-04-19T00:57:17.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/34523 -- author: SlamBamActionman - changes: - - message: Fingerprints and fibers are now always applied to items being held, regardless - of how they got into your hands. - type: Fix - - message: Changing gloves now correctly applies new fibers/fingerprints on held - items. - type: Fix - id: 8249 - time: '2025-04-19T01:02:41.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/30609 -- author: Coolsurf6 - changes: - - message: Attachbodypart command now functions as intended. - type: Fix - id: 8250 - time: '2025-04-19T01:23:58.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/34577 -- author: metalgearsloth - changes: - - message: Fix disarm swing sound even if a disarm isn't possible on the target. - type: Fix - id: 8251 - time: '2025-04-19T01:38:22.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/36546 -- author: metalgearsloth - changes: - - message: Predict gas volume pumps. - type: Tweak - id: 8252 - time: '2025-04-19T01:48:41.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/33835 -- author: SharkSnake98 - changes: - - message: Added 12 new, varied drinks for the bartender to mix during shifts. - type: Add - id: 8253 - time: '2025-04-19T05:12:11.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/36287 -- author: Ko4erga - changes: - - message: Added new color turtlenecks in WinterDrobe. - type: Add - id: 8254 - time: '2025-04-19T05:14:50.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/32920 -- author: metalgearsloth - changes: - - message: Virtual items (e.g. wielding) are now predicted. - type: Add - id: 8255 - time: '2025-04-19T06:51:12.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/36617 -- author: metalgearsloth - changes: - - message: Fix charges sometimes breaking for auto-recharge devices such as RCDs. - type: Fix - id: 8256 - time: '2025-04-19T08:49:02.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/36714 -- author: Boaz1111 - changes: - - message: Reduced the range at which security radios pick up noise from 4 tiles - to 1 tile. - type: Tweak - id: 8257 - time: '2025-04-19T13:10:43.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/34878 -- author: Quantus - changes: - - message: Fixed the unusual delay in production after de-aging a plant with cryoxadone. - type: Fix - id: 8258 - time: '2025-04-19T13:43:05.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/34668 -- author: ArtisticRoomba - changes: - - message: The Go Go Hat now checks if your message matches either the name of the - item or the label of the item. This allows people with accents to name their - items according to how their character would say the item, or for a faster retrieval - without having to type out the full name. - type: Tweak - id: 8259 - time: '2025-04-19T14:11:55.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/35658 -- author: GrownSamoyedDog - changes: - - message: Pineapple Juice Cartons are new and added to Booze-O-Mat. - type: Add - id: 8260 - time: '2025-04-19T14:25:09.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/34769 -- author: claustro305 - changes: - - message: Fixed a bug where dragged objects would collide with wall mounted lights - and cameras. - type: Fix - id: 8261 - time: '2025-04-19T14:29:36.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/35908 -- author: metalgearsloth - changes: - - message: Fix detailed examine buttons sometimes showing up incorrectly. - type: Fix - id: 8262 - time: '2025-04-19T14:37:45.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/33814 -- author: sowelipililimute - changes: - - message: Servers with the number of open inventories set to two have a new alignment - that doesn't shift as much when opening and closing multiple inventories - type: Tweak - id: 8263 - time: '2025-04-19T14:40:49.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/35041 -- author: ps3moira - changes: - - message: Removed interior shuttle walls - type: Remove - id: 8264 - time: '2025-04-19T14:41:35.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/34261 -- author: Minemoder - changes: - - message: Most roles on the station now require significantly less playtime playtime - to unlock. - type: Tweak - id: 8265 - time: '2025-04-19T15:31:38.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/36666 -- author: Fildrance - changes: - - message: fixed spessman getting stuck after unlocking portal node - type: Fix - id: 8266 - time: '2025-04-19T17:07:23.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/36719 -- author: VlaDOS1408 - changes: - - message: Fixed Gravity gen menu resizing! Now it looks like it should. - type: Fix - id: 8267 - time: '2025-04-19T20:20:32.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/34036 -- author: coffeeware, MilenVolf - changes: - - message: Most common mobs without hands now can't dump containers wtih solution - by drag and dropping. - type: Tweak - id: 8268 - time: '2025-04-19T20:32:17.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/33350 -- author: ScarKy0 - changes: - - message: Salvage borgs now start with a tool module - type: Add - id: 8269 - time: '2025-04-19T20:33:54.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/33336 -- author: Seam_Less - changes: - - message: Standardized the Sprites of most scarfs - type: Tweak - id: 8270 - time: '2025-04-20T00:17:38.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/35446 -- author: ArtisticRoomba - changes: - - message: Fixed backpack water tanks (spray nozzle) projectiles not properly cleaning - up puddles. - type: Fix - id: 8271 - time: '2025-04-20T02:41:24.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/35950 -- author: Blackern5000 - changes: - - message: Reptilians can now have shark tails and a back fin. - type: Add - id: 8272 - time: '2025-04-20T05:57:01.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/33219 -- author: chromiumboy - changes: - - message: The countdown timer for emergency broadcast cooldowns are now consistent - across holopad UIs - type: Fix - id: 8273 - time: '2025-04-20T05:58:41.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/34115 -- author: ArtisticRoomba - changes: - - message: Filing cabinet drawers have the same internal storage size as tall filing - cabinets. - type: Tweak - id: 8274 - time: '2025-04-20T06:01:28.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/36757 -- author: CubixThree - changes: - - message: Added plural pride pin. - type: Add - id: 8275 - time: '2025-04-20T07:00:33.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/36744 -- author: Helm - changes: - - message: You can now add any reagents to soup! - type: Fix - id: 8276 - time: '2025-04-20T09:32:02.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/34633 -- author: Nox38, BurgerMoth, ArtisticRoomba - changes: - - message: Added descriptions to all .35 auto cartridges, magazines, and ammo boxes. - type: Add - id: 8277 - time: '2025-04-20T11:51:27.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/36085 -- author: Pgriha - changes: - - message: SWAT, ERT, Riot and some other helmets are now hiding head markings. - type: Fix - id: 8278 - time: '2025-04-20T11:52:31.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/36074 -- author: RedBookcase - changes: - - message: More items can be processed by the station's Recyclers. - type: Add - id: 8279 - time: '2025-04-20T11:53:38.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/35800 -- author: Alice4267 - changes: - - message: Changed the amount of glass sheets needed to create beakers to 2 on normal - autolathe and 1 on hyperconvectional autolathe. - type: Tweak - - message: Changed the amount of glass sheets needed to create large beakers to - 4 on normal autolathe and 2 on hyperconvectional autolathe. - type: Tweak - id: 8280 - time: '2025-04-20T12:01:08.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/34441 -- author: Pgriha - changes: - - message: Heterochromia for Moth. - type: Add - id: 8281 - time: '2025-04-20T12:03:37.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/36061 -- author: BackeTako - changes: - - message: New Salvage doors - type: Add - id: 8282 - time: '2025-04-20T12:03:46.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/36375 -- author: HyperB1 - changes: - - message: Departmental shelves can now contain a wider variety of items. - type: Tweak - id: 8283 - time: '2025-04-20T12:19:11.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/34292 -- author: ScarKy0 - changes: - - message: Cargo will receive slightly less mail, but will earn more spesos from - it. Overall earnings are still on average the same. - type: Tweak - id: 8284 - time: '2025-04-20T13:55:23.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/36767 -- author: HyperB1 - changes: - - message: ERT engineering hardsuit now features proper fire protection. - type: Fix - id: 8285 - time: '2025-04-20T14:06:14.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/34949 -- author: K-Dynamic - changes: - - message: Nonlethal throwables crate can be ordered from cargo (2500 spesos) and - contains 4x bolas, 4x flashbang grenades, 4x tear gas grenades, 4x stinger grenades. - type: Add - id: 8286 - time: '2025-04-20T14:08:02.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/35808 -- author: RedBookcase - changes: - - message: Updated Pirate weapons & hardsuits to be more inline with similar items. - type: Tweak - id: 8287 - time: '2025-04-20T20:55:42.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/35986 -- author: Booblesnoot42 - changes: - - message: The sprites for the main chapel altars have been adjusted. - type: Tweak - id: 8289 - time: '2025-04-20T21:09:01.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/35685 -- author: UBlueberry - changes: - - message: Beanies can now be found in WinterDrobes, don'tchaknow. - type: Add - id: 8290 - time: '2025-04-20T21:15:34.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/32946 -- author: Lanedon - changes: - - message: Santa hats can now be folded to remove the beard. - type: Tweak - id: 8291 - time: '2025-04-20T21:17:12.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/36510 -- author: Princess Cheeseballs - changes: - - message: Items now slip on slippery surfaces - type: Add - - message: Puddle slipperiness has been tweaked to be more intuitive - type: Tweak - id: 8292 - time: '2025-04-20T21:27:12.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/35845 -- author: uhbg - changes: - - message: The Bartender can now make Eggnog by shaking an egg, milk, and rum. - type: Add - id: 8293 - time: '2025-04-20T21:27:35.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/34065 -- author: notquitehadouken - changes: - - message: Kill objectives will now always require you to maroon your target. - type: Tweak - id: 8294 - time: '2025-04-20T21:34:19.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/35825 -- author: Entvari - changes: - - message: Added a new Wizard headset. - type: Add - - message: The Wizard now starts with the Wizard headset. - type: Tweak - id: 8295 - time: '2025-04-20T21:38:30.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/35732 -- author: aada - changes: - - message: Filter categories added to the circuit imprinter. - type: Add - id: 8296 - time: '2025-04-20T22:27:49.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/35713 -- author: ScarKy0 - changes: - - message: Mail spawning has been reworked. The mail teleporter now has to be manually - emptied to take all the mail out. (You can do it by alt-clicking it or using - a verb) - type: Tweak - - message: The mail teleporter now has an internal capacity of 20. It will not spawn - mail past that until emptied by someone. - type: Add - id: 8297 - time: '2025-04-21T09:32:18.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/36774 -- author: ScarKy0 - changes: - - message: Default cargo split is now 50% instead of 75%. Lockboxes remain unchanged. - type: Tweak - id: 8298 - time: '2025-04-21T10:32:14.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/36800 -- author: Phooooooooooooooooooooooooooooooosphate - changes: - - message: Add the medical HUDs to medical's loadout. - type: Add - id: 8299 - time: '2025-04-21T12:07:33.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/32847 -- author: aada - changes: - - message: Hotplates and kitchen grills can now be anchored on tables. - type: Fix - - message: Hotplates and kitchen grills now collide with walls. - type: Fix - id: 8300 - time: '2025-04-21T15:38:23.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/34776 -- author: insoPL - changes: - - message: being able to drag certain food items onto drain and chemmasters - type: Fix - id: 8301 - time: '2025-04-21T15:50:07.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/34683 -- author: Hrosts - changes: - - message: Added rehydratable mop bucket cube, replacing the big and unwieldy yellow - bucket in the janitorial supplies crate. - type: Add - id: 8302 - time: '2025-04-21T17:16:25.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/34586 -- author: K-Dynamic - changes: - - message: Increased ratio of crew to thieves from 15 to 20. - type: Tweak - id: 8303 - time: '2025-04-21T17:24:28.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/36531 -- author: centcomofficer24 - changes: - - message: Added a genderfluid pin! - type: Add - id: 8304 - time: '2025-04-21T17:46:34.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/35854 -- author: ScarKy0 - changes: - - message: Station AI now has a name identifier appended after their name. - type: Tweak - id: 8305 - time: '2025-04-21T17:54:51.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/36801 -- author: lzk228 - changes: - - message: Fix identity reveal for creaming and meat spike popups. - type: Fix - id: 8306 - time: '2025-04-21T20:15:20.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/32003 -- author: ShadowCommander - changes: - - message: Added firelock lights for pressure and temperature warnings. - type: Add - id: 8307 - time: '2025-04-21T22:39:29.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/28339 -- author: lzk228 - changes: - - message: Bots now can examine, use zoom and see their alerts (health & stamina). - type: Tweak - - message: Added borgs emotes to bots. - type: Tweak - id: 8308 - time: '2025-04-21T22:49:43.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/29949 -- author: Ghagliiarghii - changes: - - message: The monkey version of captain uniforms and the hamster version of captain - hats updated to match humanoid versions - type: Tweak - id: 8309 - time: '2025-04-22T01:03:36.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/36804 -- author: Doc-Michael - changes: - - message: Changed protection values of Security Hardsuits - type: Tweak - - message: Made Warden/HoS coats slightly more protective to better fit their position - type: Tweak - id: 8310 - time: '2025-04-22T03:22:56.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/30212 -- author: K-Dynamic - changes: - - message: Changed instances of 3.5 second grenade timers to 3 seconds, including - clusterbangs and atmos metal foam grenades. - type: Tweak - - message: Atmos metal foam grenades have been reworked to disperse foam in a 5x5 - diamond pattern and harden within two seconds. - type: Tweak - - message: Reduced hardened metal foam health (breakable in 6 crowbar swings). - type: Tweak - - message: Changed syndicate trickbomb timer from 3.5 seconds to 5 seconds to match - minibombs. - type: Tweak - id: 8311 - time: '2025-04-22T05:51:21.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/34579 -- author: muburu - changes: - - message: Dragons can now pry open doors, including firelocks. - type: Tweak - id: 8312 - time: '2025-04-22T06:33:00.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/36811 -- author: sowelipililimute - changes: - - message: The Funding Allocation Computer can now adjust the cut Cargo takes from - lockbox sales - type: Add - - message: The Funding Allocation Computer doesn't show Cargo separately from its - 75% cut - type: Tweak - id: 8313 - time: '2025-04-22T12:34:53.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/36790 -- author: yuitop - changes: - - message: Fingerless gloves no more blocking taking the fingerprint. - type: Tweak - id: 8314 - time: '2025-04-22T18:15:12.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/31864 -- author: GoldenCan - changes: - - message: Heads of Personnel can now fabricate generic command-themed clothes using - their uniform printer. - type: Add - id: 8315 - time: '2025-04-22T18:35:43.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/32103 -- author: Ilya246 - changes: - - message: Numerous cargo orders have been made cheaper. - type: Tweak - id: 8316 - time: '2025-04-22T18:38:33.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/32375 -- author: Southbridge - changes: - - message: Solar Panels can now be randomly damaged or unfinished at the beginning - of the round. - type: Add - id: 8317 - time: '2025-04-22T19:46:38.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/36825 -- author: Kickguy223 - changes: - - message: Reduced the price of firelock electronics to half the price of the input - materials - type: Tweak - id: 8318 - time: '2025-04-22T23:53:42.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/33469 -- author: murolem - changes: - - message: Building orientation on fences, diagonal grilles and the diagonal shuttle - wall is now respected. - type: Fix - id: 8319 - time: '2025-04-23T01:58:42.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/36488 -- author: kosticia - changes: - - message: Added analog of donk-pockets for moth - moth-pockets - type: Add - id: 8320 - time: '2025-04-23T05:36:55.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/34517 -- author: AgentSmithRadio - changes: - - message: New food crates are now available for purchase from the automated trade - station! - type: Add - - message: You can no longer use Sweetie's Pistachios to fulfill cargo's generic - fruit bounty. - type: Remove - id: 8321 - time: '2025-04-23T05:37:10.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/33286 -- author: SaphireLattice - changes: - - message: Steel sheets no longer have unintuitively wasteful plating placement - that can be done with steel tiles instead - type: Remove - id: 8322 - time: '2025-04-23T11:08:03.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/33443 -- author: ArchRBX - changes: - - message: pAI's can now install a variety of useful software through their new - Software Catalog. - type: Add - - message: pAI's no longer start with a Station Map or MIDI Player, and must purchase - these through the shop. - type: Tweak - id: 8323 - time: '2025-04-23T23:55:36.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/36857 -- author: NoElkaTheGod - changes: - - message: Toysword now actually looks almost like the real thing, as advertised - in the description - type: Tweak - id: 8324 - time: '2025-04-24T01:21:35.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/34199 -- author: Pronana - changes: - - message: Moths can now eat pills - type: Tweak - id: 8325 - time: '2025-04-24T02:28:34.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/35609 -- author: Coolsurf6 - changes: - - message: Updated more contraband items for Syndicate and Security. - type: Tweak - id: 8326 - time: '2025-04-24T02:57:54.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/35102 -- author: Beck Thompson - changes: - - message: You can how hide items inside cake by using a knife! Eating a cake with - an item inside will do minor damage. - type: Add - id: 8327 - time: '2025-04-24T03:00:51.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/31015 -- author: RedBookcase - changes: - - message: Added Advanced Circular Saw as a Medical Doctor specific uplink item. - type: Add - - message: Removed Syndicate Surgery Duffel Bag from uplink. - type: Remove - id: 8328 - time: '2025-04-24T03:01:29.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/35915 -- author: AgentSmithRadio, MadeOfHeartAndStone - changes: - - message: Added cotton grilled cheese sandwich entity and recipe. - type: Add - id: 8329 - time: '2025-04-24T03:24:37.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/36135 -- author: SG6732 - changes: - - message: Added meat patties. Get the charcoal and let's start grillin. - type: Add - id: 8330 - time: '2025-04-24T03:45:27.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/34896 -- author: DrMelon, EmoGarbage404 - changes: - - message: Added turnstiles, gates able to limit the flow of foot traffic. The station's - flow is at your fingertips. - type: Add - id: 8331 - time: '2025-04-24T11:39:40.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/36313 -- author: EmoGarbage404 - changes: - - message: Added prisoner closets. These create automatic ID's which allow you to - quickly handle the transfer of prisoners in and out of genpop cells while keeping - their belongings secure. Imprison people today! - type: Add - id: 8332 - time: '2025-04-24T14:32:11.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/36392 -- author: Southbridge - changes: - - message: Colorful Light Crates have been added and can be ordered. - type: Add - id: 8333 - time: '2025-04-24T17:41:55.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/36750 -- author: ScarKy0, Jbsundown - changes: - - message: Letters and Packages can now be cut open with sharp objects. Be wary, - this makes cargo lose money! - type: Add - id: 8334 - time: '2025-04-24T19:47:46.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/36815 -- author: EmoGarbage404 - changes: - - message: Fixed situations where using the QSI would send the player into an esoteric - space realm. - type: Fix - id: 8335 - time: '2025-04-24T21:18:26.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/36834 -- author: thetolbean - changes: - - message: Specific outer clothing now correctly blocks your identity. - type: Fix - id: 8336 - time: '2025-04-24T23:42:27.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/33085 -- author: SlamBamActionman - changes: - - message: Changed 2 posters to be rules-compliant. - type: Tweak - id: 8337 - time: '2025-04-24T23:44:55.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/32734 -- author: Nox38 - changes: - - message: Rebalanced cyborg modules and made more of them starting equipment. - type: Tweak - - message: Added new advanced mining and advanced chemical modules. - type: Add - id: 8338 - time: '2025-04-25T02:29:16.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/34186 -- author: AgentSmithRadio - changes: - - message: Reptilians can now eat orange creamsicles. - type: Tweak - - message: Berry creamsicles can no longer be used in cargo's generic fruit bounty. - type: Fix - id: 8339 - time: '2025-04-25T03:53:13.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/36890 -- author: Vexerot - changes: - - message: Goliaths now have a bloodstream and can bleed. - type: Tweak - id: 8340 - time: '2025-04-25T04:02:03.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/33305 -- author: Blackern5000 - changes: - - message: The mining hardsuit has had it's armor tweaked to be more effective against - fish and less effective against bullets and/or bombs - type: Tweak - id: 8341 - time: '2025-04-25T04:05:29.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/31450 -- author: Krzeszny - changes: - - message: Rewrote the controls guide. - type: Tweak - id: 8342 - time: '2025-04-25T04:49:35.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/36363 -- author: ScarKy0 - changes: - - message: Interdyne cigs now cost 1TC instead of 2TC. - type: Tweak - id: 8343 - time: '2025-04-25T04:52:20.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/36841 -- author: lzk228 - changes: - - message: Seashell is small size. - type: Tweak - id: 8344 - time: '2025-04-25T05:54:49.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/32262 -- author: Blackern5000 - changes: - - message: Inaprovaline now heals slower, but lingers in the bloodstream for much - longer, making it much more useful for stabilizing critical patients for an - extended duration rather than outright treating damage. - type: Tweak - id: 8345 - time: '2025-04-25T06:03:04.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/32293 -- author: kosticia - changes: - - message: Moths can no longer eat rubber toys. - type: Fix - id: 8346 - time: '2025-04-25T07:20:09.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/34543 -- author: chromiumboy - changes: - - message: Gas vent under-pressure lockout releases are now performed using the - right-click menu - a screwdriver is no longer required - type: Tweak - id: 8347 - time: '2025-04-25T07:21:00.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/36910 -- author: chromiumboy - changes: - - message: Ghosts will now follow the AI when it activates a holopad or answers - a holo-call - type: Fix - id: 8348 - time: '2025-04-25T10:30:40.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/36355 -- author: Radezolid - changes: - - message: Fixed some donuts not counting towards the donuts bounty for cargo. - type: Fix - id: 8349 - time: '2025-04-25T15:07:50.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/36903 -- author: Kiri-Yoshikage - changes: - - message: Atomic Bomb cocktail is now mixed in 10u instead of 11. - type: Tweak - id: 8350 - time: '2025-04-25T15:33:14.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/36921 -- author: EmoGarbage404 - changes: - - message: Added 3 modkits for the proto-kinetic accelerator, granting increased - damage, range, and fire rate. They can be researched via the new "Kinetic Modifications" - arsenal tech. - type: Add - - message: Reduced damage and range on the proto-kinetic accelerator. - type: Tweak - id: 8351 - time: '2025-04-25T18:18:24.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/31247 -- author: Wolfkey-SomeoneElseTookMyUsername - changes: - - message: Added cotton buns, which can be be used for the creation of custom burgers - that can be eaten by moths. - type: Add - id: 8352 - time: '2025-04-26T01:54:14.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/36405 -- author: Booblesnoot42 - changes: - - message: Due to a lack of functionality, light-switches have temporarily been - removed from the construction menu. - type: Remove - id: 8353 - time: '2025-04-26T01:54:23.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/34664 -- author: OnyxTheBrave - changes: - - message: Cloth is now able to be made in the Sheet-Meister 2000 - type: Add - id: 8354 - time: '2025-04-26T03:22:52.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/32676 -- author: SyaoranFox - changes: - - message: Pulse Pistol, Pulse Carbine, and Pulse Rifle now share the same sound - file. - type: Tweak - id: 8355 - time: '2025-04-26T13:36:51.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/36952 -- author: RedBookcase - changes: - - message: Various changes to edged weapons, including new storage sprites and new - storage options. - type: Add - id: 8356 - time: '2025-04-26T20:45:08.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/36564 -- author: archee1, Beck - changes: - - message: Inflatable walls no longer instantly deconstruct if canceled. - type: Fix - id: 8357 - time: '2025-04-26T20:56:18.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/36937 -- author: ScarKy0 - changes: - - message: Deliveries now have a random multiplier added to them, slightly modifying - their earnings. - type: Add - - message: Deliveries now show how many spesos they grant on examine. - type: Tweak - id: 8358 - time: '2025-04-26T21:42:27.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/36918 -- author: sowelipililimute - changes: - - message: Medical and security techfab will no longer announce more than five recipes - at once, avoiding chat flooding - type: Tweak - id: 8359 - time: '2025-04-26T21:45:53.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/36945 -- author: Nox38 - changes: - - message: Added descriptions for the .30 caliber and weapons. - type: Add - id: 8360 - time: '2025-04-26T21:48:40.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/36958 -- author: UpAndLeaves - changes: - - message: The CMO's hardsuit has been redesigned with extra durathread to withstand - zombie bites more effectively. - type: Tweak - id: 8361 - time: '2025-04-26T21:49:01.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/36957 -- author: Centronias - changes: - - message: Parcel wrap, purchasable from cargo, which allows you to wrap items in - paper so you can give people surprise gifts... like bombs. - type: Add - id: 8362 - time: '2025-04-26T23:24:25.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/34471 -- author: TiniestShark - changes: - - message: Inhand sprites for (most) ammo mags and speedloaders. - type: Add - id: 8363 - time: '2025-04-26T23:36:01.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/34235 -- author: UpAndLeaves - changes: - - message: Due to recent budget improvements, science now gets custom bio suit lockers. - type: Add - id: 8364 - time: '2025-04-26T23:45:10.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/36929 -- author: ScarKy0 - changes: - - message: Deliveries can now spawn as priority-type! Deliver them within their - time limit to earn a nice speso bonus. - type: Add - id: 8365 - time: '2025-04-27T09:13:52.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/36968 -- author: PJB3005 - changes: - - message: SMES and substations now have an (extremely fancy) interface to control - them with. - type: Add - id: 8366 - time: '2025-04-27T11:08:34.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/36386 -- author: metalgearsloth - changes: - - message: Tweak mob collision values in line with RMC14. - type: Tweak - id: 8367 - time: '2025-04-27T14:47:18.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/36851 -- author: Fildrance - changes: - - message: node scanner now dislplays live artifact info (while in range) after - linking to artifact - type: Tweak - id: 8368 - time: '2025-04-27T15:11:13.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/36635 -- author: ArtisticRoomba - changes: - - message: A new Mapping changelog has been added. You can find it in a different - "Mapping" tab under the changelog menu. - type: Add - id: 8369 - time: '2025-04-27T20:15:17.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/34848 -- author: ScarKy0 - changes: - - message: Deliveries can now spawn as fragile-type! Deliver them intact to earn - a minor speso bonus. - type: Add - id: 8370 - time: '2025-04-27T23:04:40.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/36980 -- author: Bokser815 - changes: - - message: Cargo buy and sell pallets aboard the ATS can no longer be destroyed, - so cargo workers will no longer be unable to perform their job entirely for - the rest of the round. - type: Tweak - id: 8371 - time: '2025-04-28T00:59:54.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/34195 -- author: lzk228 - changes: - - message: Shelves don't have whitelists. But still max item size you can fit is - Normal. - type: Tweak - id: 8372 - time: '2025-04-28T01:00:49.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/36986 -- author: KingFroozy - changes: - - message: Mime's suits were resprited. - type: Tweak - id: 8373 - time: '2025-04-28T02:40:21.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/36702 -- author: Southbridge - changes: - - message: Amber Station - Added Genpop - type: Add - - message: Amber Station - Ensured a lot of doorways had tiles and decals under - them. - type: Tweak - id: 8374 - time: '2025-04-28T06:56:39.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/36997 -- author: lzk228 - changes: - - message: Scrubber now will turn on widenet in panic mode. - type: Tweak - id: 8375 - time: '2025-04-28T19:22:05.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/37013 -- author: KingFroozy - changes: - - message: Changed the shoulder-length and shoulder-length over eye hairstyles. - type: Tweak - id: 8376 - time: '2025-04-28T21:00:10.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/37000 -- author: ScarKy0 - changes: - - message: Cutting mail now correctly cancels when someone drags it away. - type: Fix - id: 8377 - time: '2025-04-28T21:16:14.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/37019 -- author: themias - changes: - - message: cable terminals are now visually layered below floors, like other cables - type: Fix - id: 8378 - time: '2025-04-28T23:43:40.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/37018 -- author: Vexerot - changes: - - message: Entities that are weightless or in the air are no longer slowed by puddles. - type: Tweak - id: 8379 - time: '2025-04-29T00:24:12.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/33299 -- author: themias - changes: - - message: Theatre workers (clown/mime/musician) now have access to the Service - Request Computer - type: Tweak - id: 8380 - time: '2025-04-29T00:26:23.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/37003 -- author: Thatonestomf - changes: - - message: Added slugs to both the bulldog and ammo bundle. - type: Add - - message: Slugs are alot more powerful than they were before, now dealing 40 pierce - and 15 structural - type: Tweak - - message: Basic shells now deal structural damage - type: Tweak - id: 8381 - time: '2025-04-29T03:13:01.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/33517 -- author: EmoGarbage404 - changes: - - message: Space debris now have a chance for landmines to spawn on them. - type: Add - - message: Adjusted the loot table on space debris to have more useful equipment - and items. - type: Tweak - - message: Round-start space debris now better mimics what the salvage magnet can - pull in. - type: Tweak - - message: Removed round-start space asteroids. - type: Remove - id: 8382 - time: '2025-04-29T03:37:39.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/37025 -- author: drakewill-CRL - changes: - - message: You can now see mutations on plants and produce. - type: Tweak - id: 8383 - time: '2025-04-29T04:45:11.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/32650 -- author: lzk228 - changes: - - message: When an entity becomes SSD, it will be forced to sleep after 10 minutes. - It can be awakened if no more SSD. - type: Tweak - id: 8384 - time: '2025-04-29T05:24:34.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/34039 -- author: TytosB - changes: - - message: adjusted pka damage and range - type: Tweak - id: 8385 - time: '2025-04-29T10:00:56.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/37012 -- author: abadaba695 - changes: - - message: Added 15u, 20u, and 30u transfer buttons in the chem master. - type: Add - id: 8386 - time: '2025-04-29T10:24:57.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/36995 -- author: Thinbug0 - changes: - - message: Science developed the Push-Horn, capable of pushing people away with - each honk! - type: Add - id: 8387 - time: '2025-04-29T13:07:59.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/36009 -- author: SlamBamActionman - changes: - - message: The "Toggle Walk" alert no longer gets removed when it shouldn't. - type: Fix - id: 8388 - time: '2025-04-29T13:32:18.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/37033 -- author: Boaz1111 - changes: - - message: Added sharkminnow tooth spears and carp tooth arrows. Happy salvaging! - type: Add - - message: Sharkminnow teeth now deal 15 damage instead of 10. - type: Tweak - id: 8389 - time: '2025-04-29T16:36:53.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/31257 -- author: whatston3 - changes: - - message: Speso stacks now show different denominations depending on their size. - type: Add - id: 8390 - time: '2025-04-29T21:44:47.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/37030 -- author: themias - changes: - - message: Toolboxes have new sound effects - type: Tweak - id: 8391 - time: '2025-04-29T22:17:32.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/37048 -- author: ScarKy0 - changes: - - message: Priority mail now indicates whether it was delivered on time or not. - type: Tweak - id: 8392 - time: '2025-04-29T22:55:48.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/37049 -- author: PJB3005 - changes: - - message: Wallmount substations now have an interface too. - type: Fix - id: 8393 - time: '2025-04-30T00:34:21.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/37047 -- author: EmoGarbage404 - changes: - - message: Fixed NPCs stalling out when too many exist. - type: Fix - id: 8394 - time: '2025-04-30T00:51:42.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/37056 -- author: BIGZi0348, slarticodefast - changes: - - message: Reflective vest now reflects lasers only while equipped. - type: Tweak - - message: Energy katana now reflects lasers and projectiles only while in hands. - type: Tweak - id: 8395 - time: '2025-04-30T14:10:54.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/37039 -- author: themias - changes: - - message: Firelocks can now close over turnstiles - type: Fix - id: 8396 - time: '2025-04-30T15:51:23.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/37074 -- author: themias - changes: - - message: Skeletons wearing gloves now leave fiber evidence - type: Fix - id: 8397 - time: '2025-04-30T19:56:28.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/37077 -- author: metalgearsloth - changes: - - message: Fix action additions / removals sometimes not being predicted. - type: Fix - id: 8398 - time: '2025-05-01T00:11:35.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/37076 -- author: imatsoup - changes: - - message: Battery weapons with multiple fire-modes (Energy Shotgun, Temperature - Gun) will no longer change their fire-modes when wielded by activating them - in your hand. - type: Fix - id: 8399 - time: '2025-05-01T05:35:13.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/37085 -- author: MissKay1994 - changes: - - message: Vox can now eat trash and drink welding fuel! - type: Add - id: 8400 - time: '2025-05-01T18:16:51.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/35681 -- author: slarticodefast - changes: - - message: Added noir glasses, which make everything black and white. You can find - them in the detective's locker. - type: Add - id: 8401 - time: '2025-05-01T22:07:47.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/36923 -- author: Nikitosych - changes: - - message: Fixed abrupt stamina damage reset and abrupt speed recovery after 3 seconds - (especially noticeable at high damage levels) - type: Fix - - message: Stamina damage no longer instantly resets when exiting critical state; - it now regenerates gradually. - type: Tweak - id: 8402 - time: '2025-05-01T23:01:17.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/36336 -- author: YoungThugSS14 - changes: - - message: The Wizard Helmet is now obtainable from the magic vend. - type: Tweak - id: 8403 - time: '2025-05-02T01:56:54.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/37084 -- author: Pronana - changes: - - message: Items can now slide on ice crust - type: Add - id: 8404 - time: '2025-05-02T08:18:09.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/36847 - author: metalgearsloth changes: - message: Predict gas canisters, gas tanks, and internals. @@ -1770,14 +35,6 @@ id: 8409 time: '2025-05-02T18:31:49.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/37109 -- author: Unkn0wnGh0st333 - changes: - - message: Knuckle Dusters have arrived to Space Station 14. QM can now rule cargo - with a golden-covered fist! - type: Add - id: 8411 - time: '2025-05-03T04:18:08.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/33470 - author: Errant changes: - message: Visiting Command and Security ghostroles, as well as some other rare @@ -3896,6 +2153,13 @@ id: 8694 time: '2025-06-19T15:06:11.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/38443 +- author: Sparlight + changes: + - message: Smart corgis can now wear various hardsuits, armors, and glasses items. + type: Add + id: 8695 + time: '2025-06-19T19:49:09.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/36875 - author: VerinSenpai changes: - message: Handcuffs no longer interfere with your daily tail wagging activities. @@ -3903,3 +2167,1765 @@ id: 8696 time: '2025-06-19T22:42:21.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/38454 +- author: BigfootBravo + changes: + - message: Chameleon Controller Implants can be deimplanted. + type: Fix + id: 8697 + time: '2025-06-20T22:41:11.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/38439 +- author: FairlySadPanda + changes: + - message: A new poster. + type: Add + - message: A new (very expensive) crate to order from cargo, worth 25,000 spesos + and containing a hydrated scurret. The hydrated scurret is a ghost role - a + non-antagonistic emotional support scurret. + type: Add + id: 8698 + time: '2025-06-20T23:39:08.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/38218 +- author: Tayrtahn + changes: + - message: Sloths... now... speak... slowly... + type: Add + id: 8699 + time: '2025-06-21T06:32:30.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/38142 +- author: whatston3 + changes: + - message: Locked buttons must now be unlocked to trigger. + type: Fix + id: 8700 + time: '2025-06-21T09:41:04.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/38474 +- author: slarticodefast + changes: + - message: Fixed wallmount interaction rotation. + type: Fix + id: 8701 + time: '2025-06-21T13:11:17.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/38111 +- author: Prole0 + changes: + - message: Flask Visuals & Sounds! + type: Add + - message: Flasks now need to be opened to be drunk from. + type: Tweak + id: 8702 + time: '2025-06-21T14:52:36.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/38032 +- author: qrwas + changes: + - message: Loadout item group UI improvements + type: Tweak + id: 8703 + time: '2025-06-21T22:20:34.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/38488 +- author: perryprog + changes: + - message: Wet mops no longer have zero melee damage. + type: Fix + id: 8704 + time: '2025-06-21T22:23:39.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/38486 +- author: Cojoke-dot + changes: + - message: Pacifists can now use the Staff of Healing + type: Tweak + id: 8706 + time: '2025-06-22T19:38:22.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/38509 +- author: slarticodefast + changes: + - message: The interrogator lamp and flash lantern now properly flash when toggled + on. + type: Fix + id: 8707 + time: '2025-06-23T11:32:57.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/37640 +- author: metalgearsloth + changes: + - message: Added ambient occlusion to walls so they have shadows around them. + type: Add + id: 8708 + time: '2025-06-24T07:56:15.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/38276 +- author: BramvanZijp + changes: + - message: Added Stamina Damage resistance to the raid/hard-suits used by Nuclear + Operatives and Emergency Response Teams. + type: Tweak + id: 8709 + time: '2025-06-24T13:04:15.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/38526 +- author: Kittygyat + changes: + - message: Added a handheld station map to the borg thruster module! + type: Add + id: 8710 + time: '2025-06-24T15:35:39.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/38541 +- author: PJB3005 + changes: + - message: Fixed various worn clothing items being invisible when seen through UI, + such as the examine popups. + type: Fix + id: 8711 + time: '2025-06-24T20:47:29.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/38042 +- author: AreYouConfused + changes: + - message: Bulldog bundle now accurately says what is included + type: Fix + id: 8712 + time: '2025-06-24T21:58:58.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/38558 +- author: Dragonjspider + changes: + - message: The Cutter Machine no longer makes Dark Techmaints floor tiles for free + type: Fix + id: 8713 + time: '2025-06-25T01:46:17.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/38557 +- author: rumaks-xyz + changes: + - message: The action of reverting from a polymorph now has to be confirmed. + type: Tweak + id: 8714 + time: '2025-06-25T17:52:32.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/38570 +- author: Lukasz825700516 + changes: + - message: Closed eyes and binoculars no longer allow you to see through walls. + type: Fix + id: 8715 + time: '2025-06-25T20:22:05.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/38534 +- author: Hitlinemoss + changes: + - message: Various hats have had their descriptions updated. + type: Tweak + id: 8716 + time: '2025-06-25T20:27:27.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/38156 +- author: slarticodefast + changes: + - message: Multi-handed items can be picked up again. + type: Fix + id: 8717 + time: '2025-06-26T15:29:22.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/38603 +- author: slarticodefast + changes: + - message: Fixed smart equip not retrieving items. + type: Fix + id: 8718 + time: '2025-06-26T16:17:26.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/38605 +- author: Hitlinemoss + changes: + - message: The Quartermaster's PDA now comes with AstroNav preinstalled. + type: Tweak + id: 8719 + time: '2025-06-26T22:09:36.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/38445 +- author: BigfootBravo + changes: + - message: Bladed flatcaps are now minor contraband. + type: Tweak + id: 8720 + time: '2025-06-26T22:57:46.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/38597 +- author: TiniestShark + changes: + - message: Added inhand sprites to all plushies/toys and the ability to wear (most) + of them in either your head or neck slot. + type: Add + - message: Nar'sie, Ratvar and Revenant plushies now require two hands to hold. + type: Tweak + id: 8721 + time: '2025-06-27T01:07:29.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/38514 +- author: maland1 + changes: + - message: Updating Thief guidebook page including making guidebook and thieving + satchel images more consistent + type: Tweak + id: 8722 + time: '2025-06-27T02:03:24.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/38586 +- author: slarticodefast + changes: + - message: Fixed RCD ghosts not disappearing when dropping the RCD. + type: Fix + id: 8723 + time: '2025-06-27T16:39:49.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/38622 +- author: Tayrtahn + changes: + - message: Solution containers (beakers, glasses, etc) no longer rapidly flicker + through different fill level visuals when transferring their contents. + type: Fix + id: 8724 + time: '2025-06-28T00:13:24.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/34838 +- author: Boaz1111 + changes: + - message: Headphone sprites have been changed a bit, and they are now wearable + on the head, ears and neck. + type: Tweak + id: 8725 + time: '2025-06-28T14:01:29.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/38479 +- author: slarticodefast + changes: + - message: Fixed smart equip not being able to insert items into item slots (for + example for the sabre sheath). + type: Fix + id: 8726 + time: '2025-06-29T14:33:58.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/38655 +- author: BramvanZijp + changes: + - message: Added the custom door remote, it does not have any built-in access, instead + inheriting the ID access that the user has. + type: Add + - message: The captain's locker now comes with a custom door remote instead of a + command door remote. + type: Tweak + id: 8727 + time: '2025-06-29T16:21:15.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/35536 +- author: slarticodefast + changes: + - message: Fixed water cups not being able to be picked up from water coolers. + type: Fix + id: 8728 + time: '2025-07-01T10:25:52.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/38681 +- author: maland1 + changes: + - message: Fixed Wizard recalling nuke disk from inside an armed nuke making it + impossible to defuse + type: Fix + id: 8729 + time: '2025-07-02T20:50:22.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/38661 +- author: Blackern5000 + changes: + - message: Most salvage enemies have had their HP reduced + type: Tweak + - message: Most salvage weapons have had their damage reduced + type: Tweak + id: 8730 + time: '2025-07-03T00:54:02.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/38131 +- author: TrixxedHeart + changes: + - message: Made HSV the default color selector for character customization. + type: Tweak + id: 8731 + time: '2025-07-03T01:08:07.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/38434 +- author: ArtisticRoomba + changes: + - message: A new atmospherics valve has been added, the Inlet Pressure Regulator! + You can learn more about its behavior and potential uses in the Engineering + Guidebook. + type: Add + id: 8732 + time: '2025-07-03T16:00:35.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/36708 +- author: SlamBamActionman + changes: + - message: Xeno tables can now be dismantled. + type: Fix + - message: Broken cryo pods can now be unanchored, allowing them to be scrapped. + type: Fix + id: 8733 + time: '2025-07-03T18:51:40.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/38689 +- author: TrixxedHeart + changes: + - message: Moved Syndicate Uplink TC purchase button beneath the respective item's + icon. + type: Tweak + id: 8734 + time: '2025-07-03T23:49:27.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/38596 +- author: maland1 + changes: + - message: Updating a number of guidebook pages to be more easily readable and accurate + type: Tweak + id: 8735 + time: '2025-07-04T00:04:27.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/38699 +- author: TiniestShark + changes: + - message: Added a Wire Brush to the Janitor's tool kit for scrubbing unsightly + rust off of the station's walls! + type: Add + id: 8736 + time: '2025-07-04T02:02:35.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/38667 +- author: Velken + changes: + - message: Revenants' malfunction ability now properly works on MediBots and Stasis + Beds again. + type: Fix + id: 8737 + time: '2025-07-04T05:08:45.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/38664 +- author: perryprog + changes: + - message: You can now mop space lube, letting it evaporate faster than it would + on its own. + type: Tweak + id: 8738 + time: '2025-07-04T21:50:44.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/38743 +- author: TrixxedHeart + changes: + - message: Vox now have scar markings. + type: Add + id: 8739 + time: '2025-07-04T23:06:55.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/38592 +- author: perryprog + changes: + - message: Spellbooks with infinite charges work again. + type: Fix + id: 8740 + time: '2025-07-05T06:28:56.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/38376 +- author: beck-thompson + changes: + - message: The escape menu ui has been updated slightly. + type: Tweak + id: 8741 + time: '2025-07-05T09:28:59.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/38650 +- author: EmoGarbage404 + changes: + - message: Fixed people asphyxiating if left on a stasis bed. + type: Fix + id: 8742 + time: '2025-07-06T00:59:31.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/38762 +- author: slarticodefast + changes: + - message: You can now catch basketballs, footballs and beach balls that are thrown + at you! + type: Add + id: 8743 + time: '2025-07-06T16:54:20.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/37702 +- author: ArtisticRoomba + changes: + - message: The Go Go Hat now correctly retrieves and deposits items again. + type: Fix + id: 8744 + time: '2025-07-06T23:42:14.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/38810 +- author: maland1 + changes: + - message: Reduced the size of the go go hat inventory + type: Tweak + id: 8745 + time: '2025-07-06T23:50:11.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/38808 +- author: AsnDen + changes: + - message: Golden PAI was added. It is extremely rare and expensive. This PAI can + be found in maint lockers + type: Add + id: 8746 + time: '2025-07-07T05:07:52.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/38549 +- author: Smugman + changes: + - message: Many new lighters can now be found in both Maints loot and the Syndicate + Uplink. + type: Add + id: 8747 + time: '2025-07-07T18:53:17.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/35514 +- author: Jopaglazik, Golub + changes: + - message: Added Jump Boots In T1 "Salvage Equipment" technology. + type: Add + id: 8748 + time: '2025-07-07T19:19:28.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/36862 +- author: slarticodefast, EmoGarbage404 + changes: + - message: 'Added a new science gadget: The H.A.R.M.P.A.C.K., a backpack that gives + you two extra hands when worn. Unlocked with a T2 arsenal research and printable + at the protolathe and secfab.' + type: Fix + id: 8749 + time: '2025-07-07T21:43:33.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/38824 +- author: kosticia + changes: + - message: Added new reagent for artifact researching - artifact glue! Use it on + the artefact with active node for repair its durability. + type: Add + id: 8750 + time: '2025-07-08T01:45:46.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/38670 +- author: maland1 + changes: + - message: Updated contraband tags on pulse weapons, temp gun, portable particle + decelerator, tesla gun and makeshift laser pistol to be more consistent with + their intended owners and legality + type: Tweak + id: 8751 + time: '2025-07-08T11:55:55.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/38698 +- author: TrixxedHeart + changes: + - message: Vox can now have heterochromia in the overlays category under markings. + type: Add + id: 8752 + time: '2025-07-08T23:22:13.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/38595 +- author: Quantum-cross + changes: + - message: Fix lingering ghost entities after taking ghost roles. + type: Fix + id: 8753 + time: '2025-07-09T11:07:41.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/38788 +- author: Sparlight + changes: + - message: Dragons no longer destroy non-humanoid mobs upon eating them. + type: Tweak + id: 8754 + time: '2025-07-09T12:43:35.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/38087 +- author: Crude Oil + changes: + - message: Parrots now parrot nearby speech, sometimes even using the radio if they + have one equipped + type: Add + - message: Polly the Parrot, CE's pet parrot, may be found on some maps parroting + things into an engineering headset. + type: Add + id: 8755 + time: '2025-07-09T19:04:58.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/38243 +- author: slarticodefast + changes: + - message: Added VV buttons to the solution editor. + type: Add + id: 8756 + time: '2025-07-10T06:31:39.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/38889 +- author: Toby222 + changes: + - message: pAIs can emote like borgs now + type: Add + id: 8757 + time: '2025-07-10T07:56:17.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/38425 +- author: Quantum-cross, slarticodefast + changes: + - message: The flash effect is now replaced with a reduced motion variant if the + accessibility setting is enabled in the game options. + type: Add + id: 8758 + time: '2025-07-10T09:30:58.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/37824 +- author: K-Dynamic + changes: + - message: Minigun now has inhand sprites. + type: Add + - message: Miniguns and other HMGs now require two hands to pick up and slows you + by 20%. + type: Tweak + id: 8759 + time: '2025-07-10T12:42:02.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/35344 +- author: ScarKy0 + changes: + - message: SecTech vendor now starts with a few bolas. + type: Add + id: 8760 + time: '2025-07-10T14:47:41.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/38902 +- author: Hitlinemoss + changes: + - message: The station AI can now pick kobold/monkey holograms as customization + options. + type: Add + id: 8761 + time: '2025-07-10T17:11:23.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/38888 +- author: slarticodefast + changes: + - message: Fixed clones not getting the thieving skill. + type: Fix + id: 8762 + time: '2025-07-10T21:37:50.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/38914 +- author: Ertanic and whatston3 + changes: + - message: The spray painter can now paint gas canisters, crates, lockers, and floor + decals. + type: Add + - message: The spray painter now consumes compressed paint, available from the YouTool + or printable in the autolathe. + type: Tweak + id: 8763 + time: '2025-07-11T00:36:58.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/37341 +- author: Princess-Cheeseballs + changes: + - message: Added Stamina and Stun animations + type: Add + id: 8764 + time: '2025-07-11T12:13:11.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/37196 +- author: Centronias + changes: + - message: Muzzles now prevent wearers from screaming and suppress sounds on audio + emotes. + type: Tweak + id: 8765 + time: '2025-07-11T17:18:15.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/32588 +- author: TiniestShark + changes: + - message: Added inhand sprites to all bottled drinks. + type: Add + id: 8766 + time: '2025-07-12T14:28:22.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/38937 +- author: Velken + changes: + - message: Ian and McGriff are more fashionable by letting them wear hats and glasses. + type: Add + id: 8767 + time: '2025-07-13T16:11:00.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/38634 +- author: Toast_Enjoyer, huaqas + changes: + - message: The Purchaseable Scurret now comes in a livestock crate instead of a + plastic one. Wawa! + type: Fix + id: 8768 + time: '2025-07-13T16:48:39.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/38951 +- author: lzk228 + changes: + - message: Changed ocarina's size from Normal to Small + type: Tweak + id: 8769 + time: '2025-07-13T19:31:44.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/38971 +- author: ToastEnjoyer + changes: + - message: The nukeop war declarator is now syndicate contraband. + type: Tweak + id: 8770 + time: '2025-07-13T20:50:53.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/38972 +- author: Flareguy + changes: + - message: Added several new vox customization options, including additional tails, + hairstyles, and tattoos. + type: Add + - message: Added eyeshadow markings. They're available on every species except for + Moth and Arachnid. + type: Add + id: 8771 + time: '2025-07-14T02:49:25.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/38906 +- author: Trosling + changes: + - message: Moved Bible/Holy Book choice to loadout options for chaplain. + type: Tweak + - message: Implemented new holy book sprites, as well as one existing one (space + quran). + type: Add + id: 8772 + time: '2025-07-15T00:49:09.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/38986 +- author: RedBookcase + changes: + - message: The Kardashev-Mosin's bayonet can now be used while the weapon is wielded. + Tally ho! + type: Add + id: 8773 + time: '2025-07-15T00:49:27.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/38295 +- author: SlamBamActionman + changes: + - message: Throwable item hitboxes have been updated to better reflect their sprites. + type: Tweak + id: 8774 + time: '2025-07-15T00:51:14.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/38985 +- author: Velken + changes: + - message: Moproaches have been added to the game. + type: Add + - message: Moproaches can sometimes appear from the station's sewage system. + type: Add + id: 8775 + time: '2025-07-15T02:47:47.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/38700 +- author: nabegator + changes: + - message: You can now put remote signallers into utility belts. + type: Tweak + id: 8776 + time: '2025-07-16T00:43:20.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/35212 +- author: ArtisticRoomba + changes: + - message: Firelocks will now properly drop fast enough to prevent the spacing of + an entire atmos volume. + type: Fix + - message: Only the necessary firelocks required to stop a spacing will drop when + a spacing is triggered, instead of all firelocks in a spaced volume. + type: Fix + id: 8777 + time: '2025-07-16T03:18:55.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/38918 +- author: ScarKy0 + changes: + - message: Wizard's Mjollnir can no longer stun when thrown off-cooldown. + type: Fix + id: 8778 + time: '2025-07-16T20:27:21.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/39018 +- author: SlamBamActionman + changes: + - message: Grilles under diagonal windows no longer electrocute you. + type: Fix + id: 8779 + time: '2025-07-17T13:33:47.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/39032 +- author: qwerltaz + changes: + - message: NPC spiders now spin webs sometimes! + type: Add + id: 8780 + time: '2025-07-17T16:34:00.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/38319 +- author: Quantum-cross + changes: + - message: Anomalies make anomalous noises if you let them go supercritical + type: Add + id: 8781 + time: '2025-07-17T17:01:37.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/36425 +- author: ScarKy0 + changes: + - message: There have been major tweaks to the contraband and emag vendor tables. + Mainly emagged inventories now only contain syndie flavor items(clothing and + similiar), while the rest has either been moved to the contraband inventory + or removed. + type: Tweak + id: 8782 + time: '2025-07-17T21:36:28.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/36839 +- author: ScarKy0 + changes: + - message: Added the acolyte armor to the chaplain's uplink. + type: Add + - message: Syndicate bundles are now correctly marked as syndicate contraband. + type: Fix + id: 8783 + time: '2025-07-17T22:00:05.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/36843 +- author: SeaWyrm + changes: + - message: Four varieties of marble tile can now be produced at Cutter lathes. + type: Add + id: 8784 + time: '2025-07-17T23:44:28.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/38007 +- author: august-sun + changes: + - message: Added Estoc magazines to the syndicate ammo bundle. + type: Add + id: 8785 + time: '2025-07-18T10:35:08.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/38413 +- author: Kowlin + changes: + - message: The access configurator can now set GenPop enter and leave accesses on + doors and turnstiles. + type: Tweak + id: 8786 + time: '2025-07-18T10:53:45.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/39043 +- author: Quantum-cross + changes: + - message: The bartender's mailing unit on plasma is properly configured. + type: Fix + id: 8787 + time: '2025-07-18T10:54:34.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/38098 +- author: Quantum-cross + changes: + - message: Unwarmed honk pockets no longer contain omnizine + type: Fix + - message: Honk pockets make you honk + type: Fix + id: 8788 + time: '2025-07-18T11:03:15.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/38152 +- author: TeenSarlacc + changes: + - message: Lowered Double Barrel shotgun spread to 60%. + type: Tweak + - message: Increased Sawn Off shotgun spread to 140%. + type: Tweak + id: 8789 + time: '2025-07-18T11:41:44.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/37731 +- author: notquitehadouken + changes: + - message: Mass scanner now shows any grid's distance from the current grid/entity + in tiles instead of from the top left corner of the UI in pixels + type: Fix + id: 8790 + time: '2025-07-18T15:33:24.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/39041 +- author: Pyrovi + changes: + - message: Changed some outdated info in the guidebook + type: Tweak + id: 8791 + time: '2025-07-19T01:41:16.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/38987 +- author: TiniestShark + changes: + - message: Adds a new slot for the Golden Plunger on the Janitor Trolley. + type: Add + - message: Holo and Magicarp plushies now show up in the mop bucket properly. + type: Tweak + id: 8792 + time: '2025-07-19T15:33:01.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/38494 +- author: Boaz1111 + changes: + - message: More atmos devices can now be constructed on layers from the construction + menu. + type: Add + id: 8793 + time: '2025-07-19T22:04:16.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/38672 +- author: IgorAnt028 + changes: + - message: The color of the pipe in a hand now matches the real color of the pipe + type: Fix + id: 8794 + time: '2025-07-19T22:10:38.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/30645 +- author: Princess-Cheeseballs + changes: + - message: Added crawling! + type: Add + id: 8795 + time: '2025-07-19T23:54:42.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/36881 +- author: Princess-Cheeseballs + changes: + - message: Turrets and NPCs can now shoot downed targets. + type: Tweak + id: 8796 + time: '2025-07-20T21:23:25.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/39085 +- author: sowelipililimute + changes: + - message: SmartFridges are now implemented. You can store large amounts of chemicals + and plants within them for people to take. + type: Add + id: 8797 + time: '2025-07-21T03:21:28.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/38648 +- author: ArtisticRoomba + changes: + - message: China-lake fragmentation grenades now spew fragmentation in all directions + upon impact. They now do reduced explosion damage. + type: Tweak + - message: China-lake blast grenades no longer cause spacing. + type: Tweak + id: 8798 + time: '2025-07-22T15:05:46.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/39106 +- author: perryprog + changes: + - message: Void applause should now function as expected again. + type: Fix + id: 8799 + time: '2025-07-22T19:34:39.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/38731 +- author: treytipton + changes: + - message: Made NukeOps elimination announcement less wordy. + type: Tweak + id: 8800 + time: '2025-07-23T02:58:07.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/39158 +- author: lzk228 + changes: + - message: The customvote command results now show the title the command had. + type: Tweak + id: 8801 + time: '2025-07-23T14:15:30.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/39137 +- author: FairlySadPanda + changes: + - message: Almost every instrument has been updated to a new soundfont (GeneralUser-GS), + unifying all operating systems and massively improving the sound of certain + instruments. + type: Add + id: 8802 + time: '2025-07-23T15:51:53.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/39142 +- author: slarticodefast + changes: + - message: Enabled the "showrot", "showvel" and "showangvel" commands for debug + permissions. + type: Tweak + - message: Fixed the "showplayervelocity" command permissions. + type: Tweak + id: 8803 + time: '2025-07-23T18:06:32.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/39167 +- author: Lokachop + changes: + - message: The engineering & chief engineer's hardsuit now properly glow in the + dark + type: Fix + id: 8804 + time: '2025-07-24T03:04:29.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/39153 +- author: K-Dynamic + changes: + - message: Cold slowdowns are now less impactful. + type: Tweak + id: 8805 + time: '2025-07-24T09:44:55.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/36316 +- author: B-Kirill + changes: + - message: The AI eye now has a postscript with the name of AI itself. + type: Add + id: 8806 + time: '2025-07-24T11:24:19.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/39177 +- author: SlamBamActionman + changes: + - message: Potassium-water explosion damage scaling has been tweaked to be less + potent. + type: Tweak + id: 8807 + time: '2025-07-25T16:04:27.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/37924 +- author: SlamBamActionman + changes: + - message: Chemistry foam and smoke reactions now trigger after regular mix reactions. + type: Tweak + - message: Foam, smoke and explosion reactions no longer transfer the reagents' + energies to the container. + type: Tweak + id: 8808 + time: '2025-07-25T16:33:44.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/37915 +- author: Quantum-cross + changes: + - message: Fixed pinpointer arrow not being centered properly. + type: Fix + id: 8809 + time: '2025-07-25T19:46:42.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/38657 +- author: PJB3005 + changes: + - message: Made most plushie sounds quieter, and made plushies slower to use. + type: Tweak + id: 8811 + time: '2025-07-28T07:11:21.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/39250 +- author: EmoGarbage404 + changes: + - message: Fixed being unable to fold certain clothing while worn. + type: Fix + id: 8812 + time: '2025-07-28T10:19:17.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/39257 +- author: lzk228 + changes: + - message: Janibelt can hold the golden plunger now. + type: Fix + id: 8813 + time: '2025-07-28T12:59:41.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/39213 +- author: SuperGDPWYL + changes: + - message: The Warden now starts with a network configurator in their locker. + type: Add + id: 8814 + time: '2025-07-28T16:09:17.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/39254 +- author: TrixxedHeart + changes: + - message: Several strange sprite issues with Vox have been fixed, most notably + jumpsuits and many neck items overlapping the face, as well as a layering issue + where their tank would appear over their hair. + type: Fix + id: 8815 + time: '2025-07-28T21:28:15.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/39219 +- author: K-Dynamic + changes: + - message: Quartermaster job and ID icons are now based on Cargo Technicians. + type: Tweak + id: 8816 + time: '2025-07-29T07:34:47.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/39259 +- author: Alkheemist + changes: + - message: Protected Grids can now again have their hull and tiles repaired (Evac, + ATS, etc) + type: Fix + - message: Protected Grids can no longer be expanded outside of their original size. + type: Fix + id: 8817 + time: '2025-07-29T12:01:40.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/39271 +- author: Admiral-Obvious-001 + changes: + - message: Several advanced chemicals now act slower, but with raised OD thresholds + and lowered OD damage. The healing per unit remains largely the same. + type: Tweak + - message: Bicaradine no longer makes razorium when mixed with advanced brute chems. + Advanced brute chems still mix and create razorium when combined. + type: Tweak + id: 8818 + time: '2025-07-29T18:52:42.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/38811 +- author: aada + changes: + - message: Lipolicide now continues to poison at 0 hunger. + type: Fix + - message: Tricordrazine now also heals at exactly 50 damage instead of needing + to be below 50. Similar thresholds on other reagents tweaked the same. + type: Tweak + id: 8819 + time: '2025-07-30T06:44:46.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/36289 +- author: Disp-Dev + changes: + - message: A new recipe has been added, moth-edible cotton cakes. + type: Add + id: 8820 + time: '2025-07-30T22:51:21.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/39222 +- author: spanky-spanky + changes: + - message: The wizard now spawns in a den instead of a shuttle. + type: Tweak + id: 8821 + time: '2025-07-31T04:08:05.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/37701 +- author: perryprog + changes: + - message: Fixed board game areas sometimes overlapping with those of other board + games. + type: Fix + id: 8822 + time: '2025-08-01T21:48:40.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/39327 +- author: Krosus + changes: + - message: Fixed crash when loading saved character profiles + type: Fix + id: 8823 + time: '2025-08-02T15:14:17.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/39333 +- author: FairlySadPanda + changes: + - message: A new cake, berry delight, that is made with a cake base, berries and + milk. + type: Add + id: 8824 + time: '2025-08-02T18:35:09.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/38881 +- author: DrSmugleaf + changes: + - message: Fixed rotate verbs being delayed when used, and your right click UI bounce + when they appear after a short delay. + type: Fix + id: 8825 + time: '2025-08-03T00:34:37.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/38165 +- author: alexalexmax + changes: + - message: Updated the syndicate throwing knives uplink entry to include the fact + that they ignore armor. + type: Tweak + id: 8826 + time: '2025-08-04T19:19:20.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/39374 +- author: TrixxedHeart + changes: + - message: Added canes to the trinkets loadout tab. + type: Add + - message: Added offset canes for roleplay flair. They can be crafted in the medical + lathe. + type: Add + id: 8827 + time: '2025-08-04T23:39:40.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/39272 +- author: qwerltaz + changes: + - message: The air alarm window scrubber controller now has buttons to select and + deselect all gases. + type: Add + id: 8828 + time: '2025-08-05T00:34:10.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/39296 +- author: perryprog + changes: + - message: Players no longer have the ability to cycle a timer in the verb menu + on a cyborg. + type: Fix + id: 8829 + time: '2025-08-05T03:26:02.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/39388 +- author: Luxeator + changes: + - message: Fixed error upon exploding buckled mobs (and other near instantaneous + changes) + type: Fix + id: 8830 + time: '2025-08-05T23:15:16.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/39410 +- author: ScarKy0, beck-thompson + changes: + - message: Various canines will now sometimes clumsily spill things they drink. + type: Add + id: 8831 + time: '2025-08-06T13:00:32.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/38852 +- author: aada + changes: + - message: You can examine fuel tanks to see how much they're filled. + type: Add + id: 8832 + time: '2025-08-06T16:11:19.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/39362 +- author: Tao7891 + changes: + - message: Craftable cardboard structures and equipment. + type: Add + id: 8833 + time: '2025-08-06T16:58:07.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/37363 +- author: slarticodefast + changes: + - message: Fixed inventory sprites flickering when hovering over the slot with an + item. + type: Fix + id: 8834 + time: '2025-08-06T20:14:29.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/39379 +- author: Thinbug0 + changes: + - message: New onion mutation, Bloonions! floating balloon-like onions. + type: Add + id: 8835 + time: '2025-08-07T01:51:30.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/33375 +- author: Kittygyat + changes: + - message: Made baseball bats 1x4 instead of 2x2 + type: Tweak + - message: New baseball bat inventory icon sprites + type: Add + id: 8836 + time: '2025-08-07T03:03:11.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/38392 +- author: lolman360 + changes: + - message: Fixed certain items (like pickaxes) failing to insert into containers + that have enough space to store them, sometimes. + type: Fix + id: 8837 + time: '2025-08-07T16:01:18.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/38896 +- author: chromiumboy + changes: + - message: The station AI will receive chat notifications when its sentry turrets + start firing upon hostile targets. + type: Add + id: 8838 + time: '2025-08-08T18:56:01.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/35277 +- author: K-Dynamic + changes: + - message: Captain and Head of Personnel starts with administration glasses and + hud respectively. + type: Add + id: 8839 + time: '2025-08-08T19:00:41.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/35531 +- author: perryprog + changes: + - message: The emote radial menu now shows the correct icons for its subcategories. + type: Fix + id: 8840 + time: '2025-08-08T19:27:46.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/39481 +- author: Flareguy + changes: + - message: Updated moth displacement maps to fix missing pixels, among other various + issues. + type: Fix + id: 8841 + time: '2025-08-09T21:52:06.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/39174 +- author: Princess-Cheeseballs + changes: + - message: Mobs such as borgs, dragons, etc can no longer crawl. + type: Tweak + id: 8842 + time: '2025-08-10T17:49:29.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/39084 +- author: beck-thompson + changes: + - message: Various syndicate items can now be "locked" with your voice to hide their + true identity. The items are, all chameleon clothing, voice masks, no slips, + agent IDs, cane swords, and e daggers. + type: Add + - message: e dagger now has a slightly longer activation cool down (1s -> 1.5s). + type: Tweak + - message: Voice triggered items now properly display the trigger text when examined. + type: Fix + id: 8843 + time: '2025-08-10T18:10:13.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/39310 +- author: jessicamaybe + changes: + - message: 'Added a rare Hamlet variant: Fragile Hamlet' + type: Add + id: 8844 + time: '2025-08-10T22:20:26.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/39531 +- author: perryprog + changes: + - message: "Diona\_nymphs that reform inside of a locker will no longer be invisible." + type: Fix + id: 8845 + time: '2025-08-11T11:00:12.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/39505 +- author: Samuka + changes: + - message: The Robotics Console now correctly displays the brain installed information + if the borg has a empty MMI + type: Fix + - message: The Robotics Console now shows the borg physical integrity + type: Tweak + - message: Changed the colors for the battery display in the robotics console so + it easier to read the percentage + type: Tweak + id: 8846 + time: '2025-08-11T18:57:39.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/38023 +- author: metalgearsloth + changes: + - message: Inserting lights now plays an insert animation. + type: Add + id: 8847 + time: '2025-08-11T21:06:28.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/36541 +- author: sowelipililimute + changes: + - message: Borg modules can now have hands! + type: Add + - message: The generic cables module can now throw and mix and match cables in its + slots + type: Tweak + - message: The engineering construction module can now hold any material in its + materials slots, any floor tile in its floor tile slots, and now has slots for + holding any circuitboard and flatpack + type: Tweak + - message: The janitor custodial module can now throw its soap and pick up new and + better varieties of soap + type: Tweak + - message: The janitor advanced cleaning module can now throw and pick up beakers + in its slot + type: Tweak + - message: The medical topicals module can now hold any type of topicals in its + topicals slots + type: Tweak + - message: The medical chemical module can now drop and pick up its vials, and hold + other small containers + type: Tweak + - message: The medical advanced chemical module can now drop and pick up its beakers, + and hold other larger containers + type: Tweak + - message: The science artifact module can drop and pick up its vial, and hold other + small containers + type: Tweak + - message: The service service module can now drop and pick up its shaker, and pick + up other drink containers. It also has a spoon now.l containers + type: Tweak + - message: The science anomaly module can now throw its reinforced and reinforced + plasma glass + type: Tweak + - message: The service service module now has a book bag, and two slots for books + and paper + type: Tweak + - message: The service service module can now drop and pick up its shaker, and pick + up other drink containers. It also has a spoon now. + type: Tweak + - message: The service musique module can now drop and pick up instruments. + type: Tweak + id: 8848 + time: '2025-08-12T22:21:42.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/38668 +- author: perryprog + changes: + - message: Fixed lights sometimes not emitting light when spawning them or when + they enter PVS. + type: Fix + id: 8849 + time: '2025-08-12T23:00:36.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/39585 +- author: Nox38 + changes: + - message: Resized every firearm. + type: Tweak + id: 8850 + time: '2025-08-13T17:13:14.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/36473 +- author: slarticodefast + changes: + - message: Fixed light bulb color. + type: Fix + id: 8851 + time: '2025-08-13T22:45:51.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/39623 +- author: Bhijn and Myr + changes: + - message: Those within the SS13 and SS14 community who have passed are now explicitly + memorialized within the game's credits, accessible within the lobby. May their + names and legacies live on. + type: Add + id: 8852 + time: '2025-08-14T01:21:36.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/39621 +- author: rumaks-xyz, SlamBamActionman + changes: + - message: Advanced Brute chemicals, Insuzine, Ultravasculine and Sigynate have + had changes to their healing, metabolism rates and behaviors. + type: Tweak + - message: Bicardine and Advanced Brute Chemicals once again create Razorium when + mixed. + type: Tweak + id: 8853 + time: '2025-08-14T17:32:22.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/39472 +- author: ScholarNZL + changes: + - message: Added IC visibility of "animal organs", e.g "animal lungs" etc, to facilitate + recipe creation. + type: Tweak + id: 8854 + time: '2025-08-15T04:21:51.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/39228 +- author: FlipBrooke + changes: + - message: Banana peels and their variants can now be worn as headgear + type: Add + - message: Banana peels will correctly render when selected using chameleon headgear + type: Fix + - message: Banana peels will no longer render as headgear when off a player's head + type: Fix + - message: Banana peels as headgear now correctly displays in the change log + type: Fix + id: 8855 + time: '2025-08-15T05:56:19.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/39457 +- author: CoolioDudio + changes: + - message: Added baby and cube hair + type: Add + id: 8856 + time: '2025-08-16T01:50:13.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/39680 +- author: CaramelOrdnance + changes: + - message: Lye reagent + type: Add + - message: Recipes for all soap bars + type: Add + id: 8857 + time: '2025-08-16T06:59:58.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/39303 +- author: youtissoum + changes: + - message: The usage delay of the bananium horn is now 3 seconds. + type: Tweak + id: 8858 + time: '2025-08-16T23:04:12.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/39674 +- author: august-sun + changes: + - message: Pacifists can now use the practice disabler, practice laser rifle, disabler, + and disabler SMG. + type: Tweak + id: 8859 + time: '2025-08-17T19:25:31.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/37164 +- author: Velcroboy + changes: + - message: Changed hamster crates are now able to be placed on top of tables. + type: Tweak + id: 8860 + time: '2025-08-17T19:30:41.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/37953 +- author: psykana + changes: + - message: Ninja now spawns breathing from his gas tank instead of jetpack + type: Fix + id: 8861 + time: '2025-08-18T00:25:26.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/35067 +- author: ScarKy0 + changes: + - message: Jump boots can no longer be used when knocked down. + type: Fix + id: 8862 + time: '2025-08-18T12:22:36.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/39710 +- author: SlamBamActionman + changes: + - message: Stamina resistance has been removed from cardboard armor and gorillas. + type: Tweak + id: 8863 + time: '2025-08-18T14:33:16.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/39727 +- author: SlamBamActionman + changes: + - message: Aiming with the Hristov is now working correctly when using the Separated + Chat HUD mode. + type: Fix + - message: Cursor targetting with the Hristov now correctly selects the target underneath + the cursor. + type: Fix + id: 8864 + time: '2025-08-18T18:22:02.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/35087 +- author: Zokkie + changes: + - message: Lone Operative is now assigned the Solo Antagonist role ingame instead + of the Team Antagonist role. + type: Fix + id: 8865 + time: '2025-08-18T18:57:30.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/36521 +- author: beck-thompson, slarticodefast + changes: + - message: Fixed rebinding keys crashing the client. + type: Fix + id: 8866 + time: '2025-08-18T18:58:30.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/39732 +- author: Princess-Cheeseballs + changes: + - message: Being a Lightweight drunk no longer extends your bloodloss + type: Fix + id: 8867 + time: '2025-08-18T20:26:29.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/38678 +- author: SlamBamActionman + changes: + - message: Auto-injector/medipen pop-ups now show the correct identity when injecting + someone else. + type: Fix + id: 8868 + time: '2025-08-18T20:42:41.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/39735 +- author: Winkarst-cpu + changes: + - message: Meat spikes got an overhaul. + type: Tweak + id: 8869 + time: '2025-08-19T17:56:36.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/38723 +- author: Princess-Cheeseballs + changes: + - message: You can no longer crawl while weightless. + type: Fix + id: 8870 + time: '2025-08-19T19:18:06.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/39099 +- author: Nox38 + changes: + - message: Buffed the Librarian cane sword's damage and price to be more competitive. + Damage 15 -> 17 slash, TC cost 5 -> 3 + type: Tweak + id: 8871 + time: '2025-08-19T20:31:02.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/39586 +- author: Princess-Cheeseballs + changes: + - message: Speed boots no longer affect crawling speed. + type: Remove + - message: Moon boots don't work unless you're standing + type: Tweak + id: 8872 + time: '2025-08-20T11:08:31.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/39648 +- author: Kowlin + changes: + - message: Fixed Syndicate tricky grenades not playing sounds on explosion. + type: Fix + id: 8873 + time: '2025-08-20T23:34:40.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/39792 +- author: TrixxedHeart + changes: + - message: Added the Impaired Mobility disability trait which reduces movement speed + unless using a mobility aid such as a cane and increases stand-up time. + type: Add + id: 8874 + time: '2025-08-21T00:43:06.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/39398 +- author: TheFlyingSentry + changes: + - message: 'Added a new trait: Hemophilia!' + type: Add + id: 8875 + time: '2025-08-21T01:02:54.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/38224 +- author: DinnerCalzone + changes: + - message: Fixed more grenades not playing sounds on explosion. + type: Fix + id: 8876 + time: '2025-08-22T10:04:29.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/39815 +- author: Alkheemist + changes: + - message: Added stencil lettering decals to the spraypainter. + type: Add + id: 8877 + time: '2025-08-22T10:11:07.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/39701 +- author: Kittygyat + changes: + - message: Made moths less susceptible to flames and heat. (4x Fire Damage -> 2x + Fire damage) (1.3x heat -> 1.2x heat). + type: Tweak + id: 8878 + time: '2025-08-22T22:08:35.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/39672 +- author: JimmyToor + changes: + - message: Fixed only being able to vape with a blocked mouth. + type: Fix + id: 8879 + time: '2025-08-22T22:26:48.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/39834 +- author: _miket, RedBookcase + changes: + - message: Added new Derelict Cyborg ghost roles, including the Derelict Engineer, + Janitor, Salvage, Medical, and Assault Cyborg! + type: Add + id: 8880 + time: '2025-08-23T20:32:15.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/38159 +- author: FungiFellow + changes: + - message: Added the Inflatable Module for borgs. + type: Add + id: 8881 + time: '2025-08-23T22:15:28.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/35100 +- author: whatston3 + changes: + - message: Lathes now batch items into jobs, which can be moved around in priority + or deleted. + type: Add + id: 8882 + time: '2025-08-24T15:02:47.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/38624 +- author: Princess-Cheeseballs + changes: + - message: Topicals now correctly scale their self heal time with the damage you + have taken. + type: Fix + id: 8883 + time: '2025-08-25T18:05:55.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/39883 +- author: ToastEnjoyer + changes: + - message: Pacifists can no longer use the laser rifle + type: Fix + id: 8884 + time: '2025-08-26T00:44:01.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/39891 +- author: GR1231 + changes: + - message: hats on Smile the slime should be correctly displaced + type: Fix + id: 8885 + time: '2025-08-26T00:48:31.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/39824 +- author: perryprog + changes: + - message: Items and borgs can no longer become stuck in mechs. + type: Fix + id: 8886 + time: '2025-08-26T10:29:13.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/37942 +- author: beck-thompson + changes: + - message: You can now select no lock when locking syndicate items + type: Tweak + id: 8887 + time: '2025-08-26T14:18:10.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/39532 +- author: slarticodefast + changes: + - message: Removed the dynamic game mode from player votes. + type: Tweak + id: 8888 + time: '2025-08-26T19:42:18.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/39902 +- author: FungiFellow + changes: + - message: Engiborg can no longer pickup AI lawboards + type: Fix + id: 8889 + time: '2025-08-26T20:59:23.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/39730 +- author: beck-thompson + changes: + - message: Locked chameleon storage items can now still be used as storage even + when locked. + type: Fix + id: 8890 + time: '2025-08-26T21:50:19.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/39784 +- author: StormyDragon + changes: + - message: Modular Grenades with a chemical payload now correctly wait out their + delay before activating. + type: Tweak + id: 8891 + time: '2025-08-26T22:26:13.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/39905 +- author: ToastEnjoyer + changes: + - message: Wizards can no longer teleport to the arrivals terminal + type: Fix + id: 8892 + time: '2025-08-26T23:43:50.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/39901 +- author: Hitlinemoss + changes: + - message: Clipboards can now be printed by autolathes. + type: Add + - message: Plastic clipboards have been added for aspiring paperwork enthusiasts. + They can be printed by autolathes or dispensed from the Head of Personnel's + PTech machine. + type: Add + - message: Bureaucracy crates no longer have their folders/clipboards contain paper. + The amount of paper in the crate itself has been increased to compensate. + type: Tweak + - message: Filing cabinets can now contain green folders. + type: Fix + - message: Roles that spawn with a clipboard always have that clipboard contain + exactly three sheets of paper, rather than a random quantity. + type: Fix + - message: CentComm Officials now spawn with a proper CentComm clipboard instead + of a generic black folder. + type: Tweak + id: 8893 + time: '2025-08-27T07:07:33.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/37705 +- author: slarticodefast + changes: + - message: Syndicate stealth items now have a selection of tool locks you can choose + from to hide their activation from others. + type: Add + id: 8894 + time: '2025-08-27T14:45:59.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/39900 +- author: chromiumboy + changes: + - message: Many station structures and fixtures, such as walls and airlocks, can + now be re-anchored to the floor if they happen to be dislodged by an explosion + or other shenanigans + type: Tweak + id: 8895 + time: '2025-08-27T15:04:39.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/39542 +- author: PavlockBlaine03 + changes: + - message: Fixed bug where items would not drop if a dispenser was deconstructed. + type: Fix + id: 8896 + time: '2025-08-27T21:06:51.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/39676 +- author: Winkarst-cpu + changes: + - message: Living beings are now vomiting from being irradiated. Also, irradiated + players will see a popup about tasting something metallic. + type: Add + id: 8897 + time: '2025-08-27T21:56:10.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/39805 +- author: aada + changes: + - message: Fixed audio mispredict when quick inserting. + type: Fix + id: 8898 + time: '2025-08-28T16:54:06.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/39930 +- author: Hitlinemoss + changes: + - message: Descriptions for cardboard weapons have been adjusted. + type: Tweak + id: 8899 + time: '2025-08-28T17:14:44.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/39927 +- author: FungiFellow + changes: + - message: Sentience Event no longer targets Zombified creatures + type: Fix + id: 8900 + time: '2025-08-29T11:48:31.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/39950 +- author: Dutch-VanDerLinde + changes: + - message: The forensic scanner no longer leaks fingerprints or glove prints onto + the scanning object if you use the right-click scan verb. + type: Fix + id: 8901 + time: '2025-08-30T14:00:47.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/39964 +- author: FairlySadPanda + changes: + - message: 'Scurrets can wear a few items on their backs: pet bags, mail bags and + spears' + type: Add + - message: Corgis can now wear mail bags. + type: Add + id: 8902 + time: '2025-08-30T14:42:43.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/38774 +- author: Kowlin + changes: + - message: Derelict cyborgs can no longer duplicate their ghost role. + type: Fix + id: 8903 + time: '2025-08-30T17:17:50.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/39992 +- author: aada + changes: + - message: Clown bags are squeakier. + type: Add + id: 8904 + time: '2025-08-30T18:10:34.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/39931 +- author: AndrewFenriz + changes: + - message: when assembling mech, parts now cannot be removed with a crowbar + type: Remove + id: 8905 + time: '2025-08-31T12:54:45.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/39027 +- author: quasr-9 + changes: + - message: Moths can now properly remove knives and other items from military boots. + type: Fix + id: 8906 + time: '2025-09-01T15:07:43.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/40049 +- author: slarticodefast + changes: + - message: Dropper and mini-syringe transfer amounts can now be set to more options. + type: Tweak + id: 8907 + time: '2025-09-01T15:24:37.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/39976 +- author: IProduceWidgets + changes: + - message: there are now civilian versions of nanomed vendors. + type: Add + - message: nanomed inventories have been increased some. + type: Tweak + id: 8908 + time: '2025-09-01T23:39:18.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/39718 +- author: M4rchy-S + changes: + - message: dead mobs will no longer vomit from radiation damage + type: Fix + id: 8909 + time: '2025-09-02T00:07:37.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/40020 +- author: SolidSyn + changes: + - message: Detectives noir-tech glasses are now contraband, but now include a noir + secHUD! + type: Tweak + id: 8910 + time: '2025-09-02T13:32:18.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/39859 +- author: FungiFellow + changes: + - message: Sentience Event can no longer target Corgis, Smile or Mothroaches + type: Tweak + id: 8911 + time: '2025-09-03T12:00:07.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/39810 +- author: TiniestShark + changes: + - message: Reptilians now have Mask/Helmet displacements. Snoots are no longer smushed. + type: Add + id: 8912 + time: '2025-09-03T16:45:18.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/39351 +- author: TiniestShark + changes: + - message: Added unique tail sprites to Hard/Softsuits for reptilians! (Wagging + animation not supported) + type: Add + id: 8913 + time: '2025-09-03T16:45:49.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/35842 +- author: TrixxedHeart & Flareguy + changes: + - message: Three new tails for Vox. + type: Add + id: 8914 + time: '2025-09-03T18:05:48.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/39083 +- author: MissKay1994 + changes: + - message: Interns will no longer be hired infinitely + type: Tweak + id: 8915 + time: '2025-09-03T20:16:07.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/40001 +- author: breeplayx3 + changes: + - message: Berry delight now requires blueberry cake as a precursor + type: Tweak + id: 8917 + time: '2025-09-03T21:06:05.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/40085 From e98d55795c033b0f96f13c5a9f33281149b6eb6b Mon Sep 17 00:00:00 2001 From: Vanessa Date: Sun, 23 Nov 2025 10:47:42 -0600 Subject: [PATCH 335/340] Added reinforced plasma window levels of DeltaPressure resistance to Malign windows. --- Resources/Prototypes/_DV/CosmicCult/Tileset/walls.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Resources/Prototypes/_DV/CosmicCult/Tileset/walls.yml b/Resources/Prototypes/_DV/CosmicCult/Tileset/walls.yml index 7b5cd410f73..0bc87d895ae 100644 --- a/Resources/Prototypes/_DV/CosmicCult/Tileset/walls.yml +++ b/Resources/Prototypes/_DV/CosmicCult/Tileset/walls.yml @@ -94,6 +94,9 @@ sprite: Structures/Windows/cracks.rsi - type: RadiationBlocker resistance: 5 + - type: DeltaPressure # Plasma Reinforced Window levels, in case a rift appears by the burn chamber. + minPressure: 150000 + minPressureDelta: 100000 - type: entity id: WindowCosmicCultDark From 92a7949a30cfb09851fa751edf2ed8e8b79c4d5e Mon Sep 17 00:00:00 2001 From: Vanessa Date: Sun, 23 Nov 2025 12:32:02 -0600 Subject: [PATCH 336/340] Fixed server crash if skeleton head spawning in Captain's locker was blown up by the nuke. Wat? --- Resources/Prototypes/Body/Parts/skeleton.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Resources/Prototypes/Body/Parts/skeleton.yml b/Resources/Prototypes/Body/Parts/skeleton.yml index d858a411e5d..e0e7f1ecea7 100644 --- a/Resources/Prototypes/Body/Parts/skeleton.yml +++ b/Resources/Prototypes/Body/Parts/skeleton.yml @@ -15,7 +15,8 @@ damageType: Blunt damage: 110 behaviors: - - !type:GibPartBehavior + - !type:DoActsBehavior # For some reason, if this is GibPartBehavior and spawned skeleton part gets gibbed (by like the nuke), the server crashes. + acts: [ "Destruction" ] - type: BodyPart species: Skeleton # Shitmed Change - type: StaticPrice From 0f0b950ed8fb078c7917a25f51d8eb5a70a35398 Mon Sep 17 00:00:00 2001 From: Vanessa Date: Sun, 23 Nov 2025 13:11:44 -0600 Subject: [PATCH 337/340] Added soap to surgery module so medical borgs can clean their tools. --- .../Entities/Objects/Specific/Robotics/borg_modules.yml | 1 + .../Entities/Objects/Specific/Robotics/borg_modules.yml | 7 +++++++ 2 files changed, 8 insertions(+) diff --git a/Resources/Prototypes/Entities/Objects/Specific/Robotics/borg_modules.yml b/Resources/Prototypes/Entities/Objects/Specific/Robotics/borg_modules.yml index 34e64cb84cf..03adda4590d 100644 --- a/Resources/Prototypes/Entities/Objects/Specific/Robotics/borg_modules.yml +++ b/Resources/Prototypes/Entities/Objects/Specific/Robotics/borg_modules.yml @@ -774,6 +774,7 @@ hands: - item: AdvMopItem - item: BorgMegaSprayBottle + - item: WireBrush # DeltaV - item: HoloprojectorBorg - item: BorgDropper - item: Beaker diff --git a/Resources/Prototypes/_Shitmed/Entities/Objects/Specific/Robotics/borg_modules.yml b/Resources/Prototypes/_Shitmed/Entities/Objects/Specific/Robotics/borg_modules.yml index 0751af85fba..54d40db4a24 100644 --- a/Resources/Prototypes/_Shitmed/Entities/Objects/Specific/Robotics/borg_modules.yml +++ b/Resources/Prototypes/_Shitmed/Entities/Objects/Specific/Robotics/borg_modules.yml @@ -18,6 +18,13 @@ - item: SawElectric - item: Drill - item: BoneGel + - item: SoapNT + hand: + emptyLabel: borg-slot-soap-empty + emptyRepresentative: SoapNT + whitelist: + tags: + - Soap - type: BorgModuleIcon icon: { sprite: _Shitmed/Interface/Actions/actions_borg.rsi, state: surgery-module } From 4009fee358a20c3b6d703aadcda9ee9e5d092565 Mon Sep 17 00:00:00 2001 From: Vanessa Date: Sun, 23 Nov 2025 13:24:24 -0600 Subject: [PATCH 338/340] Fixed prediction in shitmed code for Meat Spike --- Content.Shared/Kitchen/SharedKitchenSpikeSystem.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Content.Shared/Kitchen/SharedKitchenSpikeSystem.cs b/Content.Shared/Kitchen/SharedKitchenSpikeSystem.cs index e91b1c6d173..2ceeb8a320e 100644 --- a/Content.Shared/Kitchen/SharedKitchenSpikeSystem.cs +++ b/Content.Shared/Kitchen/SharedKitchenSpikeSystem.cs @@ -317,7 +317,7 @@ public sealed class SharedKitchenSpikeSystem : EntitySystem foreach (var gib in gibs) { if (HasComp(gib)) - QueueDel(gib); + PredictedQueueDel(gib); } // END DeltaV From 341f9c118bd01ce572895a734dad73325e02748d Mon Sep 17 00:00:00 2001 From: Vanessa Date: Sun, 23 Nov 2025 13:32:38 -0600 Subject: [PATCH 339/340] Fixed prediction in Bluespace Lifeline trigger --- .../_Goobstation/Trigger/Systems/DeleteParentOnTriggerSystem.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Content.Shared/_Goobstation/Trigger/Systems/DeleteParentOnTriggerSystem.cs b/Content.Shared/_Goobstation/Trigger/Systems/DeleteParentOnTriggerSystem.cs index 453159fc630..fadc3f2e623 100644 --- a/Content.Shared/_Goobstation/Trigger/Systems/DeleteParentOnTriggerSystem.cs +++ b/Content.Shared/_Goobstation/Trigger/Systems/DeleteParentOnTriggerSystem.cs @@ -32,7 +32,7 @@ public sealed class DeleteParentOnTriggerSystem : EntitySystem if (userXform.ParentUid == userXform.GridUid || userXform.ParentUid == userXform.MapUid) return; - EntityManager.QueueDeleteEntity(userXform.ParentUid); + EntityManager.PredictedQueueDeleteEntity(userXform.ParentUid); args.Handled = true; } } From b55d11dcdaf80a4ec52430a665ed6ceeae147ba6 Mon Sep 17 00:00:00 2001 From: Vanessa Date: Sun, 23 Nov 2025 15:10:03 -0600 Subject: [PATCH 340/340] Reverted keybinds to Wizden default --- Resources/keybinds.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Resources/keybinds.yml b/Resources/keybinds.yml index af34b4bed39..b8cdde314a0 100644 --- a/Resources/keybinds.yml +++ b/Resources/keybinds.yml @@ -212,7 +212,7 @@ binds: mod1: Alt - function: OpenCharacterMenu type: State - key: C + key: U - function: OpenEmotesMenu type: State key: Y @@ -553,7 +553,7 @@ binds: key: Z - function: ToggleKnockdown type: State - key: R + key: C - function: OpenAbilitiesMenu type: State key: K