From d87cb63a4e1120f33383220371c35dc7c4a82122 Mon Sep 17 00:00:00 2001 From: HerCoyote23 <131214189+HerCoyote23@users.noreply.github.com> Date: Sat, 7 Oct 2023 07:05:40 -0600 Subject: [PATCH 001/127] Spiders inject toxin (#19497) * Spider poison * No more double damage * add toxin regeneration --------- Co-authored-by: Slava0135 --- .../Prototypes/Entities/Mobs/NPCs/animals.yml | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml b/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml index fc75798b947..7af84db8e58 100644 --- a/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml +++ b/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml @@ -1633,7 +1633,19 @@ damage: types: Piercing: 6 - Poison: 6 + - type: SolutionContainerManager + solutions: + melee: + maxVol: 30 + - type: SolutionRegeneration + solution: melee + generated: + reagents: + - ReagentId: Toxin + Quantity: 1 + - type: MeleeChemicalInjector + transferAmount: 0.75 + solution: melee - type: ReplacementAccent accent: xeno - type: InteractionPopup @@ -1710,7 +1722,6 @@ damage: types: Piercing: 8 - Poison: 6 - type: FootstepModifier footstepSoundCollection: collection: FootstepClownFast From c4c24d4c2d41c0261c92a858c525fd94f6b120f7 Mon Sep 17 00:00:00 2001 From: PJBot Date: Sat, 7 Oct 2023 09:06:47 -0400 Subject: [PATCH 002/127] Automatic changelog update --- Resources/Changelog/Changelog.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 0de6e14f45d..b403091c57b 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,10 +1,4 @@ Entries: -- author: Flareguy - changes: - - {message: 'The bleeding alert sprite is now drawn at double the resolution, as - to fit in with everything else in the game.', type: Tweak} - id: 4469 - time: '2023-08-06T23:49:28.0000000+00:00' - author: EmoGarbage404 changes: - {message: Chemical analysis goggles no longer require silver to create., type: Tweak} @@ -2952,3 +2946,9 @@ Entries: type: Add} id: 4968 time: '2023-10-07T00:56:18.0000000+00:00' +- author: HerCoyote23 + changes: + - {message: Tarantulas now inject real toxins into victims and they can pass through + armour., type: Tweak} + id: 4969 + time: '2023-10-07T13:05:40.0000000+00:00' From 29a77bc54e39c7d8b9e26d6b0f8f0d873420aa92 Mon Sep 17 00:00:00 2001 From: Arimah Greene <30327355+arimah@users.noreply.github.com> Date: Sat, 7 Oct 2023 16:46:57 +0200 Subject: [PATCH 003/127] Tag tinned peaches and meat with Fruit and Meat, respectively (#20814) --- .../Entities/Objects/Consumable/Food/Containers/tin.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Resources/Prototypes/Entities/Objects/Consumable/Food/Containers/tin.yml b/Resources/Prototypes/Entities/Objects/Consumable/Food/Containers/tin.yml index 764356ad687..4e63ca5012e 100644 --- a/Resources/Prototypes/Entities/Objects/Consumable/Food/Containers/tin.yml +++ b/Resources/Prototypes/Entities/Objects/Consumable/Food/Containers/tin.yml @@ -89,6 +89,9 @@ - funny - type: Food trash: FoodTinPeachesTrash + - type: Tag + tags: + - Fruit - type: entity parent: FoodTinBaseTrash @@ -174,6 +177,9 @@ - cheap - type: Food trash: FoodTinMRETrash + - type: Tag + tags: + - Meat - type: entity parent: FoodTinBaseTrash From 3101e5a18d15bda422e85a06aa967ade65009df5 Mon Sep 17 00:00:00 2001 From: Leon Friedrich <60421075+ElectroJr@users.noreply.github.com> Date: Sun, 8 Oct 2023 06:08:13 +1100 Subject: [PATCH 004/127] Fix action-granting items not being predicted (#20778) * Ensure actions are predicted * Fix test fail --- Content.Server/Bed/BedSystem.cs | 1 + .../EntitySystems/UnpoweredFlashlightSystem.cs | 8 ++++++++ Content.Shared/Blocking/BlockingSystem.cs | 11 +++++++++++ .../Blocking/Components/BlockingComponent.cs | 9 +++++---- .../Components/StealthClothingComponent.cs | 2 +- .../EntitySystems/StealthClothingSystem.cs | 8 ++++++++ Content.Shared/Clothing/SharedMagbootsSystem.cs | 10 +++++++++- .../CombatMode/SharedCombatModeSystem.cs | 1 + .../Movement/Components/JetpackComponent.cs | 4 ++-- .../Movement/Systems/SharedJetpackSystem.cs | 8 ++++++++ .../Ninja/Components/DashAbilityComponent.cs | 11 ++++++----- .../Ninja/Components/NinjaGlovesComponent.cs | 2 +- .../Ninja/Components/NinjaSuitComponent.cs | 6 +++--- Content.Shared/Ninja/Systems/DashAbilitySystem.cs | 10 ++++++++-- .../Ninja/Systems/SharedNinjaGlovesSystem.cs | 14 ++++++++------ .../Ninja/Systems/SharedNinjaSuitSystem.cs | 14 ++++++++++---- .../Entities/Objects/Weapons/Melee/sword.yml | 3 +-- 17 files changed, 91 insertions(+), 31 deletions(-) diff --git a/Content.Server/Bed/BedSystem.cs b/Content.Server/Bed/BedSystem.cs index 915bf7de29e..12eda65f84e 100644 --- a/Content.Server/Bed/BedSystem.cs +++ b/Content.Server/Bed/BedSystem.cs @@ -44,6 +44,7 @@ private void ManageUpdateList(EntityUid uid, HealOnBuckleComponent component, re AddComp(uid); component.NextHealTime = _timing.CurTime + TimeSpan.FromSeconds(component.HealTime); _actionsSystem.AddAction(args.BuckledEntity, ref component.SleepAction, SleepingSystem.SleepActionId, uid); + Dirty(uid, component); return; } diff --git a/Content.Server/Light/EntitySystems/UnpoweredFlashlightSystem.cs b/Content.Server/Light/EntitySystems/UnpoweredFlashlightSystem.cs index 2be870ff0da..c24966aba82 100644 --- a/Content.Server/Light/EntitySystems/UnpoweredFlashlightSystem.cs +++ b/Content.Server/Light/EntitySystems/UnpoweredFlashlightSystem.cs @@ -18,6 +18,7 @@ public sealed class UnpoweredFlashlightSystem : EntitySystem [Dependency] private readonly IPrototypeManager _prototypeManager = default!; [Dependency] private readonly IRobustRandom _random = default!; [Dependency] private readonly SharedActionsSystem _actionsSystem = default!; + [Dependency] private readonly ActionContainerSystem _actionContainer = default!; [Dependency] private readonly SharedAppearanceSystem _appearance = default!; [Dependency] private readonly SharedAudioSystem _audioSystem = default!; [Dependency] private readonly SharedPointLightSystem _light = default!; @@ -31,6 +32,13 @@ public override void Initialize() SubscribeLocalEvent(OnToggleAction); SubscribeLocalEvent(OnMindAdded); SubscribeLocalEvent(OnGotEmagged); + SubscribeLocalEvent(OnMapInit); + } + + private void OnMapInit(EntityUid uid, UnpoweredFlashlightComponent component, MapInitEvent args) + { + _actionContainer.EnsureAction(uid, ref component.ToggleActionEntity, component.ToggleAction); + Dirty(uid, component); } private void OnToggleAction(EntityUid uid, UnpoweredFlashlightComponent component, ToggleActionEvent args) diff --git a/Content.Shared/Blocking/BlockingSystem.cs b/Content.Shared/Blocking/BlockingSystem.cs index 37350581540..f46b202aaae 100644 --- a/Content.Shared/Blocking/BlockingSystem.cs +++ b/Content.Shared/Blocking/BlockingSystem.cs @@ -27,6 +27,7 @@ public sealed partial class BlockingSystem : EntitySystem { [Dependency] private readonly IPrototypeManager _proto = default!; [Dependency] private readonly SharedActionsSystem _actionsSystem = default!; + [Dependency] private readonly ActionContainerSystem _actionContainer = default!; [Dependency] private readonly SharedTransformSystem _transformSystem = default!; [Dependency] private readonly FixtureSystem _fixtureSystem = default!; [Dependency] private readonly SharedHandsSystem _handsSystem = default!; @@ -51,11 +52,19 @@ public override void Initialize() SubscribeLocalEvent(OnShutdown); SubscribeLocalEvent>(OnVerbExamine); + SubscribeLocalEvent(OnMapInit); + } + + private void OnMapInit(EntityUid uid, BlockingComponent component, MapInitEvent args) + { + _actionContainer.EnsureAction(uid, ref component.BlockingToggleActionEntity, component.BlockingToggleAction); + Dirty(uid, component); } private void OnEquip(EntityUid uid, BlockingComponent component, GotEquippedHandEvent args) { component.User = args.User; + Dirty(uid, component); //To make sure that this bodytype doesn't get set as anything but the original if (TryComp(args.User, out var physicsComponent) && physicsComponent.BodyType != BodyType.Static && !HasComp(args.User)) @@ -201,6 +210,7 @@ public bool StartBlocking(EntityUid item, BlockingComponent component, EntityUid } component.IsBlocking = true; + Dirty(item, component); return true; } @@ -254,6 +264,7 @@ public bool StopBlocking(EntityUid item, BlockingComponent component, EntityUid } component.IsBlocking = false; + Dirty(item, component); return true; } diff --git a/Content.Shared/Blocking/Components/BlockingComponent.cs b/Content.Shared/Blocking/Components/BlockingComponent.cs index b33a7d7a734..9a379a29e97 100644 --- a/Content.Shared/Blocking/Components/BlockingComponent.cs +++ b/Content.Shared/Blocking/Components/BlockingComponent.cs @@ -1,5 +1,6 @@ using Content.Shared.Damage; using Robust.Shared.Audio; +using Robust.Shared.GameStates; using Robust.Shared.Physics.Collision.Shapes; using Robust.Shared.Prototypes; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; @@ -9,19 +10,19 @@ namespace Content.Shared.Blocking; /// /// This component goes on an item that you want to use to block /// -[RegisterComponent] +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] public sealed partial class BlockingComponent : Component { /// /// The entity that's blocking /// - [ViewVariables] + [ViewVariables, AutoNetworkedField] public EntityUid? User; /// /// Is it currently blocking? /// - [ViewVariables] + [ViewVariables, AutoNetworkedField] public bool IsBlocking; /// @@ -50,7 +51,7 @@ public sealed partial class BlockingComponent : Component [DataField("blockingToggleAction", customTypeSerializer: typeof(PrototypeIdSerializer))] public string BlockingToggleAction = "ActionToggleBlock"; - [DataField("blockingToggleActionEntity")] + [DataField, AutoNetworkedField] public EntityUid? BlockingToggleActionEntity; /// diff --git a/Content.Shared/Clothing/Components/StealthClothingComponent.cs b/Content.Shared/Clothing/Components/StealthClothingComponent.cs index fe84fbe76c7..fedf48b36ed 100644 --- a/Content.Shared/Clothing/Components/StealthClothingComponent.cs +++ b/Content.Shared/Clothing/Components/StealthClothingComponent.cs @@ -30,7 +30,7 @@ public sealed partial class StealthClothingComponent : Component /// /// The action for enabling and disabling stealth. /// - [DataField("toggleActionEntity")] public EntityUid? ToggleActionEntity; + [DataField, AutoNetworkedField] public EntityUid? ToggleActionEntity; } /// diff --git a/Content.Shared/Clothing/EntitySystems/StealthClothingSystem.cs b/Content.Shared/Clothing/EntitySystems/StealthClothingSystem.cs index 2fbaa6ea20b..4bf2f76ca34 100644 --- a/Content.Shared/Clothing/EntitySystems/StealthClothingSystem.cs +++ b/Content.Shared/Clothing/EntitySystems/StealthClothingSystem.cs @@ -12,6 +12,7 @@ namespace Content.Shared.Clothing.EntitySystems; public sealed class StealthClothingSystem : EntitySystem { [Dependency] private readonly SharedStealthSystem _stealth = default!; + [Dependency] private readonly ActionContainerSystem _actionContainer = default!; public override void Initialize() { @@ -21,6 +22,13 @@ public override void Initialize() SubscribeLocalEvent(OnToggleStealth); SubscribeLocalEvent(OnHandleState); SubscribeLocalEvent(OnUnequipped); + SubscribeLocalEvent(OnMapInit); + } + + private void OnMapInit(EntityUid uid, StealthClothingComponent component, MapInitEvent args) + { + _actionContainer.EnsureAction(uid, ref component.ToggleActionEntity, component.ToggleAction); + Dirty(uid, component); } /// diff --git a/Content.Shared/Clothing/SharedMagbootsSystem.cs b/Content.Shared/Clothing/SharedMagbootsSystem.cs index 69b78499928..7a6da7c9928 100644 --- a/Content.Shared/Clothing/SharedMagbootsSystem.cs +++ b/Content.Shared/Clothing/SharedMagbootsSystem.cs @@ -15,6 +15,7 @@ public abstract class SharedMagbootsSystem : EntitySystem [Dependency] private readonly ClothingSystem _clothing = default!; [Dependency] private readonly InventorySystem _inventory = default!; [Dependency] private readonly SharedActionsSystem _sharedActions = default!; + [Dependency] private readonly SharedActionsSystem _actionContainer = default!; [Dependency] private readonly SharedAppearanceSystem _appearance = default!; [Dependency] private readonly SharedContainerSystem _sharedContainer = default!; [Dependency] private readonly SharedItemSystem _item = default!; @@ -27,6 +28,13 @@ public override void Initialize() SubscribeLocalEvent>(OnSlipAttempt); SubscribeLocalEvent(OnGetActions); SubscribeLocalEvent(OnToggleMagboots); + SubscribeLocalEvent(OnMapInit); + } + + private void OnMapInit(EntityUid uid, MagbootsComponent component, MapInitEvent args) + { + _actionContainer.AddAction(uid, ref component.ToggleActionEntity, component.ToggleAction); + Dirty(uid, component); } private void OnToggleMagboots(EntityUid uid, MagbootsComponent component, ToggleMagbootsEvent args) @@ -55,7 +63,7 @@ private void ToggleMagboots(EntityUid uid, MagbootsComponent magboots) _appearance.SetData(uid, ToggleVisuals.Toggled, magboots.On); OnChanged(uid, magboots); - Dirty(magboots); + Dirty(uid, magboots); } protected virtual void UpdateMagbootEffects(EntityUid parent, EntityUid uid, bool state, MagbootsComponent? component) { } diff --git a/Content.Shared/CombatMode/SharedCombatModeSystem.cs b/Content.Shared/CombatMode/SharedCombatModeSystem.cs index 66b31d01ffb..0b57840addd 100644 --- a/Content.Shared/CombatMode/SharedCombatModeSystem.cs +++ b/Content.Shared/CombatMode/SharedCombatModeSystem.cs @@ -27,6 +27,7 @@ public override void Initialize() private void OnMapInit(EntityUid uid, CombatModeComponent component, MapInitEvent args) { _actionsSystem.AddAction(uid, ref component.CombatToggleActionEntity, component.CombatToggleAction); + Dirty(uid, component); } private void OnShutdown(EntityUid uid, CombatModeComponent component, ComponentShutdown args) diff --git a/Content.Shared/Movement/Components/JetpackComponent.cs b/Content.Shared/Movement/Components/JetpackComponent.cs index 0215e5a861f..336f4a353c2 100644 --- a/Content.Shared/Movement/Components/JetpackComponent.cs +++ b/Content.Shared/Movement/Components/JetpackComponent.cs @@ -4,7 +4,7 @@ namespace Content.Shared.Movement.Components; -[RegisterComponent, NetworkedComponent] +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] public sealed partial class JetpackComponent : Component { [ViewVariables(VVAccess.ReadWrite), DataField("moleUsage")] @@ -12,7 +12,7 @@ public sealed partial class JetpackComponent : Component [DataField] public EntProtoId ToggleAction = "ActionToggleJetpack"; - [DataField("toggleActionEntity")] public EntityUid? ToggleActionEntity; + [DataField, AutoNetworkedField] public EntityUid? ToggleActionEntity; [ViewVariables(VVAccess.ReadWrite), DataField("acceleration")] public float Acceleration = 1f; diff --git a/Content.Shared/Movement/Systems/SharedJetpackSystem.cs b/Content.Shared/Movement/Systems/SharedJetpackSystem.cs index f624f6c4ce4..abe12b79d1a 100644 --- a/Content.Shared/Movement/Systems/SharedJetpackSystem.cs +++ b/Content.Shared/Movement/Systems/SharedJetpackSystem.cs @@ -19,6 +19,7 @@ public abstract class SharedJetpackSystem : EntitySystem [Dependency] private readonly SharedMoverController _mover = default!; [Dependency] private readonly SharedPopupSystem _popup = default!; [Dependency] private readonly SharedPhysicsSystem _physics = default!; + [Dependency] private readonly ActionContainerSystem _actionContainer = default!; public override void Initialize() { @@ -32,6 +33,13 @@ public override void Initialize() SubscribeLocalEvent(OnJetpackUserEntParentChanged); SubscribeLocalEvent(OnJetpackUserGravityChanged); + SubscribeLocalEvent(OnMapInit); + } + + private void OnMapInit(EntityUid uid, JetpackComponent component, MapInitEvent args) + { + _actionContainer.EnsureAction(uid, ref component.ToggleActionEntity, component.ToggleAction); + Dirty(uid, component); } private void OnJetpackCanWeightlessMove(EntityUid uid, JetpackComponent component, ref CanWeightlessMoveEvent args) diff --git a/Content.Shared/Ninja/Components/DashAbilityComponent.cs b/Content.Shared/Ninja/Components/DashAbilityComponent.cs index 85e0963af1e..ba4060c7035 100644 --- a/Content.Shared/Ninja/Components/DashAbilityComponent.cs +++ b/Content.Shared/Ninja/Components/DashAbilityComponent.cs @@ -3,21 +3,22 @@ using Robust.Shared.Audio; using Robust.Shared.GameStates; using Robust.Shared.Prototypes; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; + +namespace Content.Shared.Ninja.Components; /// /// Adds an action to dash, teleport to clicked position, when this item is held. /// -[RegisterComponent, NetworkedComponent, Access(typeof(DashAbilitySystem))] +[RegisterComponent, NetworkedComponent, Access(typeof(DashAbilitySystem)), AutoGenerateComponentState] public sealed partial class DashAbilityComponent : Component { /// /// The action id for dashing. /// - [DataField("dashAction", required: true, customTypeSerializer: typeof(PrototypeIdSerializer)), ViewVariables(VVAccess.ReadWrite)] - public string DashAction = string.Empty; + [DataField] + public EntProtoId DashAction = "ActionEnergyKatanaDash"; - [DataField("dashActionEntity")] + [DataField, AutoNetworkedField] public EntityUid? DashActionEntity; /// diff --git a/Content.Shared/Ninja/Components/NinjaGlovesComponent.cs b/Content.Shared/Ninja/Components/NinjaGlovesComponent.cs index b104312b204..7b57926330b 100644 --- a/Content.Shared/Ninja/Components/NinjaGlovesComponent.cs +++ b/Content.Shared/Ninja/Components/NinjaGlovesComponent.cs @@ -31,7 +31,7 @@ public sealed partial class NinjaGlovesComponent : Component [DataField("toggleAction", customTypeSerializer: typeof(PrototypeIdSerializer))] public string ToggleAction = "ActionToggleNinjaGloves"; - [DataField("toggleActionEntity")] + [DataField, AutoNetworkedField] public EntityUid? ToggleActionEntity; /// diff --git a/Content.Shared/Ninja/Components/NinjaSuitComponent.cs b/Content.Shared/Ninja/Components/NinjaSuitComponent.cs index 816cc9d731b..73de2526907 100644 --- a/Content.Shared/Ninja/Components/NinjaSuitComponent.cs +++ b/Content.Shared/Ninja/Components/NinjaSuitComponent.cs @@ -47,7 +47,7 @@ public sealed partial class NinjaSuitComponent : Component [DataField("createThrowingStarAction", customTypeSerializer: typeof(PrototypeIdSerializer))] public string CreateThrowingStarAction = "ActionCreateThrowingStar"; - [DataField("createThrowingStarActionEntity")] + [DataField, AutoNetworkedField] public EntityUid? CreateThrowingStarActionEntity; /// @@ -68,7 +68,7 @@ public sealed partial class NinjaSuitComponent : Component [DataField("recallKatanaAction", customTypeSerializer: typeof(PrototypeIdSerializer))] public string RecallKatanaAction = "ActionRecallKatana"; - [DataField("recallKatanaActionEntity")] + [DataField, AutoNetworkedField] public EntityUid? RecallKatanaActionEntity; /// @@ -84,7 +84,7 @@ public sealed partial class NinjaSuitComponent : Component [DataField("empAction", customTypeSerializer: typeof(PrototypeIdSerializer))] public string EmpAction = "ActionNinjaEmp"; - [DataField("empActionEntity")] + [DataField, AutoNetworkedField] public EntityUid? EmpActionEntity; /// diff --git a/Content.Shared/Ninja/Systems/DashAbilitySystem.cs b/Content.Shared/Ninja/Systems/DashAbilitySystem.cs index bd6320de68a..d376d05724b 100644 --- a/Content.Shared/Ninja/Systems/DashAbilitySystem.cs +++ b/Content.Shared/Ninja/Systems/DashAbilitySystem.cs @@ -6,8 +6,6 @@ using Content.Shared.Ninja.Components; using Content.Shared.Physics; using Content.Shared.Popups; -using Robust.Shared.Audio; -using Robust.Shared.GameObjects; using Robust.Shared.Timing; namespace Content.Shared.Ninja.Systems; @@ -24,6 +22,7 @@ public sealed class DashAbilitySystem : EntitySystem [Dependency] private readonly SharedInteractionSystem _interaction = default!; [Dependency] private readonly SharedPopupSystem _popup = default!; [Dependency] private readonly SharedTransformSystem _transform = default!; + [Dependency] private readonly ActionContainerSystem _actionContainer = default!; public override void Initialize() { @@ -31,6 +30,13 @@ public override void Initialize() SubscribeLocalEvent(OnGetItemActions); SubscribeLocalEvent(OnDash); + SubscribeLocalEvent(OnMapInit); + } + + private void OnMapInit(EntityUid uid, DashAbilityComponent component, MapInitEvent args) + { + _actionContainer.EnsureAction(uid, ref component.DashActionEntity, component.DashAction); + Dirty(uid, component); } private void OnGetItemActions(EntityUid uid, DashAbilityComponent comp, GetItemActionsEvent args) diff --git a/Content.Shared/Ninja/Systems/SharedNinjaGlovesSystem.cs b/Content.Shared/Ninja/Systems/SharedNinjaGlovesSystem.cs index 45c97fd1aa7..639d3f13467 100644 --- a/Content.Shared/Ninja/Systems/SharedNinjaGlovesSystem.cs +++ b/Content.Shared/Ninja/Systems/SharedNinjaGlovesSystem.cs @@ -1,11 +1,8 @@ using Content.Shared.Actions; using Content.Shared.CombatMode; using Content.Shared.Communications; -using Content.Shared.Doors.Components; -using Content.Shared.DoAfter; using Content.Shared.Examine; using Content.Shared.Hands.Components; -using Content.Shared.IdentityManagement; using Content.Shared.Interaction; using Content.Shared.Inventory.Events; using Content.Shared.Ninja.Components; @@ -14,7 +11,6 @@ using Content.Shared.Timing; using Content.Shared.Toggleable; using Robust.Shared.Timing; -using System.Diagnostics.CodeAnalysis; namespace Content.Shared.Ninja.Systems; @@ -26,11 +22,10 @@ public abstract class SharedNinjaGlovesSystem : EntitySystem [Dependency] private readonly IGameTiming _timing = default!; [Dependency] protected readonly SharedAppearanceSystem Appearance = default!; [Dependency] private readonly SharedCombatModeSystem _combatMode = default!; - [Dependency] protected readonly SharedDoAfterSystem _doAfter = default!; [Dependency] protected readonly SharedInteractionSystem Interaction = default!; - [Dependency] private readonly SharedSpaceNinjaSystem _ninja = default!; [Dependency] protected readonly SharedPopupSystem Popup = default!; [Dependency] private readonly UseDelaySystem _useDelay = default!; + [Dependency] private readonly ActionContainerSystem _actionContainer = default!; public override void Initialize() { @@ -39,6 +34,13 @@ public override void Initialize() SubscribeLocalEvent(OnGetItemActions); SubscribeLocalEvent(OnExamined); SubscribeLocalEvent(OnUnequipped); + SubscribeLocalEvent(OnMapInit); + } + + private void OnMapInit(EntityUid uid, NinjaGlovesComponent component, MapInitEvent args) + { + _actionContainer.EnsureAction(uid, ref component.ToggleActionEntity, component.ToggleAction); + Dirty(uid, component); } /// diff --git a/Content.Shared/Ninja/Systems/SharedNinjaSuitSystem.cs b/Content.Shared/Ninja/Systems/SharedNinjaSuitSystem.cs index 83fcba4ac60..6bcd3432a91 100644 --- a/Content.Shared/Ninja/Systems/SharedNinjaSuitSystem.cs +++ b/Content.Shared/Ninja/Systems/SharedNinjaSuitSystem.cs @@ -4,10 +4,6 @@ using Content.Shared.Inventory.Events; using Content.Shared.Ninja.Components; using Content.Shared.Timing; -using Robust.Shared.Audio; -using Robust.Shared.Network; -using Robust.Shared.Prototypes; -using Robust.Shared.Serialization; namespace Content.Shared.Ninja.Systems; @@ -21,6 +17,7 @@ public abstract class SharedNinjaSuitSystem : EntitySystem [Dependency] protected readonly SharedSpaceNinjaSystem _ninja = default!; [Dependency] protected readonly StealthClothingSystem StealthClothing = default!; [Dependency] protected readonly UseDelaySystem UseDelay = default!; + [Dependency] private readonly ActionContainerSystem _actionContainer = default!; public override void Initialize() { @@ -30,6 +27,15 @@ public override void Initialize() SubscribeLocalEvent(OnGetItemActions); SubscribeLocalEvent(OnAddStealthAction); SubscribeLocalEvent(OnUnequipped); + SubscribeLocalEvent(OnMapInit); + } + + private void OnMapInit(EntityUid uid, NinjaSuitComponent component, MapInitEvent args) + { + _actionContainer.EnsureAction(uid, ref component.RecallKatanaActionEntity, component.RecallKatanaAction); + _actionContainer.EnsureAction(uid, ref component.CreateThrowingStarActionEntity, component.CreateThrowingStarAction); + _actionContainer.EnsureAction(uid, ref component.EmpActionEntity, component.EmpAction); + Dirty(uid, component); } /// diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Melee/sword.yml b/Resources/Prototypes/Entities/Objects/Weapons/Melee/sword.yml index dbbe0febfdf..2e733cf658a 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Melee/sword.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Melee/sword.yml @@ -18,7 +18,7 @@ - type: Reflect enabled: true reflectProb: .5 - spread: 90 + spread: 90 - type: Item size: 15 sprite: Objects/Weapons/Melee/captain_sabre.rsi @@ -69,7 +69,6 @@ sprite: Objects/Weapons/Melee/energykatana.rsi - type: EnergyKatana - type: DashAbility - dashAction: ActionEnergyKatanaDash - type: LimitedCharges maxCharges: 3 charges: 3 From e4c4d9b0a4053d5dad734d128862471fd66f71e0 Mon Sep 17 00:00:00 2001 From: DrSmugleaf Date: Sat, 7 Oct 2023 12:11:02 -0700 Subject: [PATCH 005/127] Fix sleeping action not working (#20813) --- Content.Server/Bed/Sleep/SleepingSystem.cs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/Content.Server/Bed/Sleep/SleepingSystem.cs b/Content.Server/Bed/Sleep/SleepingSystem.cs index 30e3a99eeab..17fe4d5effb 100644 --- a/Content.Server/Bed/Sleep/SleepingSystem.cs +++ b/Content.Server/Bed/Sleep/SleepingSystem.cs @@ -1,6 +1,6 @@ -using Content.Server.Actions; using Content.Server.Popups; using Content.Server.Sound.Components; +using Content.Shared.Actions; using Content.Shared.Audio; using Content.Shared.Bed.Sleep; using Content.Shared.Damage; @@ -36,6 +36,7 @@ public override void Initialize() SubscribeLocalEvent(OnSleepStateChanged); SubscribeLocalEvent(OnDamageChanged); SubscribeLocalEvent(OnSleepAction); + SubscribeLocalEvent(OnBedSleepAction); SubscribeLocalEvent(OnWakeAction); SubscribeLocalEvent(OnMobStateChanged); SubscribeLocalEvent>(AddWakeVerb); @@ -93,6 +94,11 @@ private void OnSleepAction(EntityUid uid, MobStateComponent component, SleepActi TrySleeping(uid); } + private void OnBedSleepAction(EntityUid uid, ActionsContainerComponent component, SleepActionEvent args) + { + TrySleeping(args.Performer); + } + private void OnWakeAction(EntityUid uid, MobStateComponent component, WakeActionEvent args) { if (!TryWakeCooldown(uid)) From 0b4555eb0536f4a6df274691b8e4d1e32d96627c Mon Sep 17 00:00:00 2001 From: PJBot Date: Sat, 7 Oct 2023 15:12:12 -0400 Subject: [PATCH 006/127] Automatic changelog update --- Resources/Changelog/Changelog.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index b403091c57b..c9036196bb1 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,9 +1,4 @@ Entries: -- author: EmoGarbage404 - changes: - - {message: Chemical analysis goggles no longer require silver to create., type: Tweak} - id: 4470 - time: '2023-08-07T03:44:25.0000000+00:00' - author: mirrorcult changes: - {message: Renamed spacebucks to spesos, type: Tweak} @@ -2952,3 +2947,8 @@ Entries: armour., type: Tweak} id: 4969 time: '2023-10-07T13:05:40.0000000+00:00' +- author: DrSmugleaf + changes: + - {message: Fixed not being able to sleep on a bed., type: Fix} + id: 4970 + time: '2023-10-07T19:11:03.0000000+00:00' From 8377094b289cce5d054b404cdb04abedf02c22d8 Mon Sep 17 00:00:00 2001 From: JoeHammad1844 <130668733+JoeHammad1844@users.noreply.github.com> Date: Sun, 8 Oct 2023 06:15:57 +1100 Subject: [PATCH 007/127] Tweaked secret weights (#20807) --- Resources/Prototypes/secret_weights.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Resources/Prototypes/secret_weights.yml b/Resources/Prototypes/secret_weights.yml index 6c7cc12ce1a..4c20d52daf8 100644 --- a/Resources/Prototypes/secret_weights.yml +++ b/Resources/Prototypes/secret_weights.yml @@ -1,8 +1,8 @@ - type: weightedRandom id: Secret weights: - Nukeops: 0.15 - Traitor: 0.60 + Nukeops: 0.20 + Traitor: 0.50 Zombie: 0.10 - Revolutionary: 0.15 + Revolutionary: 0.20 \ No newline at end of file From 99a4ee9da5c9dd23464dbf5a4a8b2a3a4e0376a3 Mon Sep 17 00:00:00 2001 From: PJBot Date: Sat, 7 Oct 2023 15:17:01 -0400 Subject: [PATCH 008/127] Automatic changelog update --- Resources/Changelog/Changelog.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index c9036196bb1..31f0b1603eb 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,9 +1,4 @@ Entries: -- author: mirrorcult - changes: - - {message: Renamed spacebucks to spesos, type: Tweak} - id: 4471 - time: '2023-08-07T05:43:35.0000000+00:00' - author: Slava0135 changes: - {message: You can now examine throw damage on items., type: Add} @@ -2952,3 +2947,8 @@ Entries: - {message: Fixed not being able to sleep on a bed., type: Fix} id: 4970 time: '2023-10-07T19:11:03.0000000+00:00' +- author: JoeHammad + changes: + - {message: 'traitor gamemode is rarer, nukies and revs are more common', type: Tweak} + id: 4971 + time: '2023-10-07T19:15:57.0000000+00:00' From d691ddae64ff178d346255c1e0acfdc693f70e9a Mon Sep 17 00:00:00 2001 From: LankLTE <135308300+LankLTE@users.noreply.github.com> Date: Sat, 7 Oct 2023 12:34:32 -0700 Subject: [PATCH 009/127] Give player species slight passive regen (#20638) * Implementation * Reviews --- .../Components/PassiveDamageComponent.cs | 40 ++++++++++++++ .../Damage/Systems/PassiveDamageSystem.cs | 55 +++++++++++++++++++ .../Prototypes/Entities/Mobs/Species/base.yml | 9 +++ 3 files changed, 104 insertions(+) create mode 100644 Content.Shared/Damage/Components/PassiveDamageComponent.cs create mode 100644 Content.Shared/Damage/Systems/PassiveDamageSystem.cs diff --git a/Content.Shared/Damage/Components/PassiveDamageComponent.cs b/Content.Shared/Damage/Components/PassiveDamageComponent.cs new file mode 100644 index 00000000000..269960adac4 --- /dev/null +++ b/Content.Shared/Damage/Components/PassiveDamageComponent.cs @@ -0,0 +1,40 @@ +using Content.Shared.Mobs; +using Content.Shared.FixedPoint; +using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom; +using Robust.Shared.GameStates; + +namespace Content.Shared.Damage.Components; + +/// +/// Passively damages the entity on a specified interval. +/// +[RegisterComponent, NetworkedComponent] +public sealed partial class PassiveDamageComponent : Component +{ + /// + /// The entitys' states that passive damage will apply in + /// + [DataField, ViewVariables(VVAccess.ReadWrite)] + public List AllowedStates = new(); + + /// + /// Damage / Healing per interval dealt to the entity every interval + /// + [DataField, ViewVariables(VVAccess.ReadWrite)] + public DamageSpecifier Damage = new(); + + /// + /// Delay between damage events in seconds + /// + [DataField, ViewVariables(VVAccess.ReadWrite)] + public float Interval = 1f; + + /// + /// The maximum HP the damage will be given to. If 0, disabled. + /// + [DataField, ViewVariables(VVAccess.ReadWrite)] + public FixedPoint2 DamageCap = 0; + + [DataField("nextDamage", customTypeSerializer: typeof(TimeOffsetSerializer)), ViewVariables(VVAccess.ReadWrite)] + public TimeSpan NextDamage = TimeSpan.Zero; +} diff --git a/Content.Shared/Damage/Systems/PassiveDamageSystem.cs b/Content.Shared/Damage/Systems/PassiveDamageSystem.cs new file mode 100644 index 00000000000..5a37d6a6e6c --- /dev/null +++ b/Content.Shared/Damage/Systems/PassiveDamageSystem.cs @@ -0,0 +1,55 @@ +using Content.Shared.Damage.Components; +using Content.Shared.Mobs.Systems; +using Content.Shared.Mobs.Components; +using Content.Shared.FixedPoint; +using Robust.Shared.Timing; + +namespace Content.Shared.Damage; + +public sealed class PassiveDamageSystem : EntitySystem +{ + [Dependency] private readonly DamageableSystem _damageable = default!; + [Dependency] private readonly IGameTiming _timing = default!; + [Dependency] private readonly MobStateSystem _mobState = default!; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnPendingMapInit); + } + + private void OnPendingMapInit(EntityUid uid, PassiveDamageComponent component, MapInitEvent args) + { + component.NextDamage = _timing.CurTime + TimeSpan.FromSeconds(1f); + } + + // Every tick, attempt to damage entities + public override void Update(float frameTime) + { + base.Update(frameTime); + var curTime = _timing.CurTime; + + // Go through every entity with the component + var query = EntityQueryEnumerator(); + while (query.MoveNext(out var uid, out var comp, out var damage, out var mobState)) + { + // Make sure they're up for a damage tick + if (comp.NextDamage > curTime) + continue; + + if (comp.DamageCap != 0 && damage.TotalDamage >= comp.DamageCap) + continue; + + // Set the next time they can take damage + comp.NextDamage = curTime + TimeSpan.FromSeconds(1f); + + // Damage them + foreach (var allowedState in comp.AllowedStates) + { + if(allowedState == mobState.CurrentState) + _damageable.TryChangeDamage(uid, comp.Damage, true, false, damage); + } + } + } +} diff --git a/Resources/Prototypes/Entities/Mobs/Species/base.yml b/Resources/Prototypes/Entities/Mobs/Species/base.yml index 422e1aa4e16..74c676eb688 100644 --- a/Resources/Prototypes/Entities/Mobs/Species/base.yml +++ b/Resources/Prototypes/Entities/Mobs/Species/base.yml @@ -237,6 +237,15 @@ damage: types: Blunt: 0.55 #per second, scales with pressure and other constants. + - type: PassiveDamage # Slight passive regen. Assuming one damage type, comes out to about 4 damage a minute. + allowedStates: + - Alive + damageCap: 20 + damage: + types: + Heat: -0.07 + groups: + Brute: -0.07 # Organs - type: StatusEffects allowed: From a487bd42c3d9299cd2720552e51c6dc7aecd4987 Mon Sep 17 00:00:00 2001 From: PJBot Date: Sat, 7 Oct 2023 15:35:35 -0400 Subject: [PATCH 010/127] Automatic changelog update --- Resources/Changelog/Changelog.yml | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 31f0b1603eb..0d6b8a1df71 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,11 +1,4 @@ Entries: -- author: Slava0135 - changes: - - {message: You can now examine throw damage on items., type: Add} - - {message: Fixed examine damage verbs of different types conflicting with each - other., type: Fix} - id: 4472 - time: '2023-08-07T09:09:35.0000000+00:00' - author: metalgearsloth changes: - {message: Reproducible entities now have a capacity in confined areas., type: Fix} @@ -2952,3 +2945,9 @@ Entries: - {message: 'traitor gamemode is rarer, nukies and revs are more common', type: Tweak} id: 4971 time: '2023-10-07T19:15:57.0000000+00:00' +- author: Lank + changes: + - {message: Humanoid species now passively regenerate small bruises and burns., + type: Tweak} + id: 4972 + time: '2023-10-07T19:34:32.0000000+00:00' From 2a75e7213e84c4f84a866d45ad69e8635c227e14 Mon Sep 17 00:00:00 2001 From: Nemanja <98561806+EmoGarbage404@users.noreply.github.com> Date: Sat, 7 Oct 2023 15:59:39 -0400 Subject: [PATCH 011/127] Wow kudzu is back! (#20822) --- .../Botany/Systems/MutationSystem.cs | 7 +++--- Resources/Prototypes/GameRules/events.yml | 24 +++++++++---------- 2 files changed, 15 insertions(+), 16 deletions(-) diff --git a/Content.Server/Botany/Systems/MutationSystem.cs b/Content.Server/Botany/Systems/MutationSystem.cs index 94a450ebeff..672139fbca2 100644 --- a/Content.Server/Botany/Systems/MutationSystem.cs +++ b/Content.Server/Botany/Systems/MutationSystem.cs @@ -37,7 +37,7 @@ public void MutateSeed(ref SeedData seed, float severity) } // Add up everything in the bits column and put the number here. - const int totalbits = 265; + const int totalbits = 270; // Tolerances (55) MutateFloat(ref seed.NutrientConsumption , 0.05f, 1.2f, 5, totalbits, severity); @@ -69,8 +69,7 @@ public void MutateSeed(ref SeedData seed, float severity) MutateBool(ref seed.Sentient , true , 10, totalbits, severity); MutateBool(ref seed.Ligneous , true , 10, totalbits, severity); MutateBool(ref seed.Bioluminescent, true , 10, totalbits, severity); - // Kudzu disabled until superkudzu bug is fixed - // MutateBool(ref seed.TurnIntoKudzu , true , 10, totalbits, severity); + MutateBool(ref seed.TurnIntoKudzu , true , 10, totalbits, severity); MutateBool(ref seed.CanScream , true , 10, totalbits, severity); seed.BioluminescentColor = RandomColor(seed.BioluminescentColor, 10, totalbits, severity); @@ -119,7 +118,7 @@ public SeedData Cross(SeedData a, SeedData b) CrossBool(ref result.Sentient, a.Sentient); CrossBool(ref result.Ligneous, a.Ligneous); CrossBool(ref result.Bioluminescent, a.Bioluminescent); - // CrossBool(ref result.TurnIntoKudzu, a.TurnIntoKudzu); + CrossBool(ref result.TurnIntoKudzu, a.TurnIntoKudzu); CrossBool(ref result.CanScream, a.CanScream); CrossGasses(ref result.ExudeGasses, a.ExudeGasses); diff --git a/Resources/Prototypes/GameRules/events.yml b/Resources/Prototypes/GameRules/events.yml index 927aea0973f..e15d65b5089 100644 --- a/Resources/Prototypes/GameRules/events.yml +++ b/Resources/Prototypes/GameRules/events.yml @@ -132,18 +132,18 @@ startDelay: 20 - type: GasLeakRule -#- type: entity -# id: KudzuGrowth -# parent: BaseGameRule -# noSpawn: true -# components: -# - type: StationEvent -# earliestStart: 15 -# minimumPlayers: 15 -# weight: 5 -# startDelay: 50 -# duration: 240 -# - type: KudzuGrowthRule +- type: entity + id: KudzuGrowth + parent: BaseGameRule + noSpawn: true + components: + - type: StationEvent + earliestStart: 15 + minimumPlayers: 15 + weight: 5 + startDelay: 50 + duration: 240 + - type: KudzuGrowthRule - type: entity id: MeteorSwarm From cc47fb2712b7d8211b8cd2597392272b96f79d55 Mon Sep 17 00:00:00 2001 From: TsjipTsjip <19798667+TsjipTsjip@users.noreply.github.com> Date: Sat, 7 Oct 2023 22:00:34 +0200 Subject: [PATCH 012/127] Kettle update (#20808) * Kettle map upload * Kettle map proto upload --- Resources/Maps/kettle.yml | 171 +++++++++++++-------------- Resources/Prototypes/Maps/kettle.yml | 1 + 2 files changed, 86 insertions(+), 86 deletions(-) diff --git a/Resources/Maps/kettle.yml b/Resources/Maps/kettle.yml index 306b339e2b3..c8194474d0b 100644 --- a/Resources/Maps/kettle.yml +++ b/Resources/Maps/kettle.yml @@ -2314,6 +2314,16 @@ entities: 4793: 72,0 4794: 73,0 4795: 73,-1 + - node: + color: '#0E7F1BFF' + id: Delivery + decals: + 4993: 37,-12 + - node: + color: '#1861D5FF' + id: Delivery + decals: + 4991: 34,-13 - node: color: '#334E6DC8' id: Delivery @@ -2331,6 +2341,16 @@ entities: 3302: 75,16 3303: 76,16 3304: 77,16 + - node: + color: '#951710FF' + id: Delivery + decals: + 4992: 34,-12 + - node: + color: '#D58C18FF' + id: Delivery + decals: + 4994: 38,-12 - node: color: '#EFB34196' id: Delivery @@ -3203,7 +3223,6 @@ entities: 2411: 62,-21 2412: 61,-22 2413: 60,-19 - 2414: 43,-16 2415: 41,-16 2416: 38,-16 2417: 37,-16 @@ -3910,7 +3929,6 @@ entities: 3040: 80,6 3041: 53,-2 3042: 46,-16 - 3043: 38,-12 3044: 35,-6 3045: 32,-4 3046: 26,-5 @@ -4526,6 +4544,16 @@ entities: 609: -12,45 610: -11,45 611: -10,45 + - node: + color: '#0E7F1BFF' + id: HalfTileOverlayGreyscale180 + decals: + 4983: 43,-17 + - node: + color: '#1861D5FF' + id: HalfTileOverlayGreyscale180 + decals: + 4981: 37,-17 - node: color: '#334E6DC8' id: HalfTileOverlayGreyscale180 @@ -4567,6 +4595,11 @@ entities: 4883: -33,-45 4884: -34,-45 4885: -35,-45 + - node: + color: '#951710FF' + id: HalfTileOverlayGreyscale180 + decals: + 4982: 40,-17 - node: color: '#A4610696' id: HalfTileOverlayGreyscale180 @@ -4740,6 +4773,11 @@ entities: 935: 67,2 936: 68,2 937: 69,2 + - node: + color: '#D58C18FF' + id: HalfTileOverlayGreyscale180 + decals: + 4984: 46,-17 - node: color: '#DE3A3A96' id: HalfTileOverlayGreyscale180 @@ -4750,16 +4788,11 @@ entities: 333: 44,-1 334: 45,-1 335: 46,-1 - 377: 46,-17 378: 45,-17 - 379: 44,-17 - 380: 43,-17 381: 42,-17 382: 41,-17 - 383: 40,-17 384: 39,-17 385: 38,-17 - 386: 37,-17 510: -32,25 511: -31,25 512: -30,25 @@ -4774,6 +4807,8 @@ entities: 1605: 60,-23 1606: 61,-23 1607: 62,-23 + 4980: 44,-17 + 4986: 34,-13 - node: color: '#EFB34196' id: HalfTileOverlayGreyscale180 @@ -4944,8 +4979,6 @@ entities: 354: 34,-9 355: 34,-10 356: 34,-11 - 357: 34,-12 - 358: 34,-13 359: 35,-14 360: 35,-15 361: 36,-16 @@ -4955,6 +4988,8 @@ entities: 1217: -64,50 1461: 35,49 1462: 35,50 + 4987: 34,-13 + 4988: 34,-12 - node: color: '#EFB34196' id: HalfTileOverlayGreyscale270 @@ -5147,6 +5182,11 @@ entities: 896: 29,-1 897: 29,0 898: 29,1 + - node: + color: '#D58C18FF' + id: HalfTileOverlayGreyscale90 + decals: + 4985: 46,-17 - node: color: '#DE3A3A96' id: HalfTileOverlayGreyscale90 @@ -5695,7 +5735,6 @@ entities: decals: 238: -27,-40 336: 43,-1 - 371: 34,-13 372: 35,-15 373: 36,-17 374: 33,-8 @@ -6029,8 +6068,6 @@ entities: 415: 41,-12 416: 40,-12 417: 39,-12 - 418: 38,-12 - 419: 37,-12 435: 56,-3 436: 56,-2 437: 56,-1 @@ -6050,7 +6087,8 @@ entities: 461: 58,0 521: -26,25 522: -30,26 - 1611: 46,-17 + 4989: 37,-12 + 4990: 38,-12 - node: color: '#EFB34196' id: QuarterTileOverlayGreyscale90 @@ -67894,6 +67932,13 @@ entities: occludes: True ent: null type: ContainerContainer +- proto: CrateMindShieldImplants + entities: + - uid: 18366 + components: + - pos: 58.5,-7.5 + parent: 82 + type: Transform - proto: CrateNPCBee entities: - uid: 22551 @@ -68140,7 +68185,7 @@ entities: type: Transform - uid: 8707 components: - - pos: 60.495476,-8.848388 + - pos: 60.47793,-8.497251 parent: 82 type: Transform - uid: 10774 @@ -118101,73 +118146,19 @@ entities: type: EntityStorage - uid: 3658 components: - - pos: 38.5,-16.5 + - pos: 46.5,-7.5 parent: 82 type: Transform - - air: - volume: 200 - immutable: False - temperature: 293.1496 - moles: - - 1.6971024 - - 6.3843384 - - 0 - - 0 - - 0 - - 0 - - 0 - - 0 - - 0 - - 0 - - 0 - - 0 - type: EntityStorage - uid: 3659 components: - - pos: 41.5,-16.5 + - pos: 46.5,-6.5 parent: 82 type: Transform - - air: - volume: 200 - immutable: False - temperature: 293.1496 - moles: - - 1.6971024 - - 6.3843384 - - 0 - - 0 - - 0 - - 0 - - 0 - - 0 - - 0 - - 0 - - 0 - - 0 - type: EntityStorage - uid: 3660 components: - - pos: 44.5,-16.5 + - pos: 38.5,-11.5 parent: 82 type: Transform - - air: - volume: 200 - immutable: False - temperature: 293.1496 - moles: - - 1.6971024 - - 6.3843384 - - 0 - - 0 - - 0 - - 0 - - 0 - - 0 - - 0 - - 0 - - 0 - - 0 - type: EntityStorage - uid: 8370 components: - pos: -63.5,51.5 @@ -118237,6 +118228,11 @@ entities: - 0 - 0 type: EntityStorage + - uid: 17130 + components: + - pos: 37.5,-11.5 + parent: 82 + type: Transform - uid: 17785 components: - pos: 34.5,-11.5 @@ -122133,13 +122129,6 @@ entities: - pos: 29.5,33.5 parent: 82 type: Transform -- proto: PosterContrabandVoteWeh - entities: - - uid: 22463 - components: - - pos: 33.5,-11.5 - parent: 82 - type: Transform - proto: PosterContrabandWehWatches entities: - uid: 22340 @@ -134899,6 +134888,11 @@ entities: - pos: 3.6323419,-16.35247 parent: 82 type: Transform + - uid: 17131 + components: + - pos: 60.709972,-8.613329 + parent: 82 + type: Transform - uid: 19393 components: - pos: 40.646282,29.698788 @@ -134932,7 +134926,7 @@ entities: type: Transform - uid: 22192 components: - - pos: 60.38359,-8.403477 + - pos: 60.40058,-8.604193 parent: 82 type: Transform - proto: RubberStampHop @@ -134942,13 +134936,6 @@ entities: - pos: -6.5865464,1.3825479 parent: 82 type: Transform -- proto: RubberStampHos - entities: - - uid: 22194 - components: - - pos: 60.647476,-8.593557 - parent: 82 - type: Transform - proto: RubberStampSyndicate entities: - uid: 8619 @@ -140663,6 +140650,18 @@ entities: - pos: -16.5,-8.5 parent: 82 type: Transform +- proto: SpawnPointBorg + entities: + - uid: 18367 + components: + - pos: 12.5,57.5 + parent: 82 + type: Transform + - uid: 22194 + components: + - pos: 13.5,56.5 + parent: 82 + type: Transform - proto: SpawnPointBotanist entities: - uid: 22261 diff --git a/Resources/Prototypes/Maps/kettle.yml b/Resources/Prototypes/Maps/kettle.yml index 3e8cba3a224..54e96aeaa21 100644 --- a/Resources/Prototypes/Maps/kettle.yml +++ b/Resources/Prototypes/Maps/kettle.yml @@ -48,6 +48,7 @@ SeniorResearcher: [ 1, 1 ] Scientist: [ 4, 6 ] ResearchAssistant: [ 8, 8 ] + Borg: [ 2, 2 ] #security HeadOfSecurity: [ 1, 1 ] Warden: [ 1, 1 ] From 70246ae10eff287ca83193cce73b79e7424c7e4a Mon Sep 17 00:00:00 2001 From: PJBot Date: Sat, 7 Oct 2023 16:00:44 -0400 Subject: [PATCH 013/127] Automatic changelog update --- Resources/Changelog/Changelog.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 0d6b8a1df71..09e8bf1bf5b 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,9 +1,4 @@ Entries: -- author: metalgearsloth - changes: - - {message: Reproducible entities now have a capacity in confined areas., type: Fix} - id: 4473 - time: '2023-08-07T09:48:47.0000000+00:00' - author: ubis1 changes: - {message: some lathes can be emagged now; emaggable recipes list has been added @@ -2951,3 +2946,8 @@ Entries: type: Tweak} id: 4972 time: '2023-10-07T19:34:32.0000000+00:00' +- author: EmoGarbage404 + changes: + - {message: Kudzu has been reenabled., type: Add} + id: 4973 + time: '2023-10-07T19:59:39.0000000+00:00' From 364c9b7f0a9784641417ba6f49a932a23aeaa318 Mon Sep 17 00:00:00 2001 From: Leon Friedrich <60421075+ElectroJr@users.noreply.github.com> Date: Mon, 9 Oct 2023 03:27:41 +1100 Subject: [PATCH 014/127] DamageableSystem cleanup & performance improvements (#20820) --- Content.Server/Bible/BibleSystem.cs | 2 +- .../Electrocution/ElectrocutionSystem.cs | 4 +- .../Projectiles/ProjectileSystem.cs | 2 +- .../Weapons/Melee/MeleeWeaponSystem.cs | 2 +- .../Ranged/Systems/GunSystem.Battery.cs | 2 +- .../Ranged/Systems/GunSystem.Cartridges.cs | 2 +- .../Weapons/Ranged/Systems/GunSystem.cs | 2 +- Content.Shared/Damage/DamageModifierSet.cs | 6 +- Content.Shared/Damage/DamageSpecifier.cs | 109 ++++++++++++------ .../Damage/Systems/DamageableSystem.cs | 65 +++++++---- .../Weapons/Melee/SharedMeleeWeaponSystem.cs | 4 +- Content.Tests/Shared/DamageTest.cs | 10 +- 12 files changed, 134 insertions(+), 76 deletions(-) diff --git a/Content.Server/Bible/BibleSystem.cs b/Content.Server/Bible/BibleSystem.cs index 18f34ba1cc1..e2cdc8c7440 100644 --- a/Content.Server/Bible/BibleSystem.cs +++ b/Content.Server/Bible/BibleSystem.cs @@ -133,7 +133,7 @@ private void OnAfterInteract(EntityUid uid, BibleComponent component, AfterInter var damage = _damageableSystem.TryChangeDamage(args.Target.Value, component.Damage, true, origin: uid); - if (damage == null || damage.Total == 0) + if (damage == null || damage.Empty) { var othersMessage = Loc.GetString(component.LocPrefix + "-heal-success-none-others", ("user", Identity.Entity(args.User, EntityManager)),("target", Identity.Entity(args.Target.Value, EntityManager)),("bible", uid)); _popupSystem.PopupEntity(othersMessage, args.User, Filter.PvsExcept(args.User), true, PopupType.Medium); diff --git a/Content.Server/Electrocution/ElectrocutionSystem.cs b/Content.Server/Electrocution/ElectrocutionSystem.cs index 844d526c58e..48415c39533 100644 --- a/Content.Server/Electrocution/ElectrocutionSystem.cs +++ b/Content.Server/Electrocution/ElectrocutionSystem.cs @@ -177,7 +177,7 @@ private void OnElectrifiedAttacked(EntityUid uid, ElectrifiedComponent electrifi if (!electrified.OnAttacked) return; - if (_meleeWeapon.GetDamage(args.Used, args.User).Total == 0) + if (!_meleeWeapon.GetDamage(args.Used, args.User).Any()) return; TryDoElectrifiedAct(uid, args.User, 1, electrified); @@ -192,7 +192,7 @@ private void OnElectrifiedHandInteract(EntityUid uid, ElectrifiedComponent elect private void OnLightAttacked(EntityUid uid, PoweredLightComponent component, AttackedEvent args) { - if (_meleeWeapon.GetDamage(args.Used, args.User).Total == 0) + if (!_meleeWeapon.GetDamage(args.Used, args.User).Any()) return; if (args.Used != args.User) diff --git a/Content.Server/Projectiles/ProjectileSystem.cs b/Content.Server/Projectiles/ProjectileSystem.cs index 60fc0c3b5cd..c52e712e741 100644 --- a/Content.Server/Projectiles/ProjectileSystem.cs +++ b/Content.Server/Projectiles/ProjectileSystem.cs @@ -53,7 +53,7 @@ private void OnStartCollide(EntityUid uid, ProjectileComponent component, ref St if (modifiedDamage is not null && EntityManager.EntityExists(component.Shooter)) { - if (modifiedDamage.Total > FixedPoint2.Zero && !deleted) + if (modifiedDamage.Any() && !deleted) { _color.RaiseEffect(Color.Red, new List { target }, Filter.Pvs(target, entityManager: EntityManager)); } diff --git a/Content.Server/Weapons/Melee/MeleeWeaponSystem.cs b/Content.Server/Weapons/Melee/MeleeWeaponSystem.cs index a0a3f6d5d7b..94ddc09e732 100644 --- a/Content.Server/Weapons/Melee/MeleeWeaponSystem.cs +++ b/Content.Server/Weapons/Melee/MeleeWeaponSystem.cs @@ -62,7 +62,7 @@ private void OnMeleeExamineDamage(EntityUid uid, MeleeWeaponComponent component, var damageSpec = GetDamage(uid, args.User, component); - if (damageSpec.Total == FixedPoint2.Zero) + if (damageSpec.Empty) return; _damageExamine.AddDamageExamine(args.Message, damageSpec, Loc.GetString("damage-melee")); diff --git a/Content.Server/Weapons/Ranged/Systems/GunSystem.Battery.cs b/Content.Server/Weapons/Ranged/Systems/GunSystem.Battery.cs index ab2553e31bf..f4deffd1133 100644 --- a/Content.Server/Weapons/Ranged/Systems/GunSystem.Battery.cs +++ b/Content.Server/Weapons/Ranged/Systems/GunSystem.Battery.cs @@ -85,7 +85,7 @@ private void OnBatteryDamageExamine(EntityUid uid, BatteryAmmoProviderComponent { var p = (ProjectileComponent) projectile.Component; - if (p.Damage.Total > FixedPoint2.Zero) + if (!p.Damage.Empty) { return p.Damage; } diff --git a/Content.Server/Weapons/Ranged/Systems/GunSystem.Cartridges.cs b/Content.Server/Weapons/Ranged/Systems/GunSystem.Cartridges.cs index 6a5dd2d02d8..e7bd3683d38 100644 --- a/Content.Server/Weapons/Ranged/Systems/GunSystem.Cartridges.cs +++ b/Content.Server/Weapons/Ranged/Systems/GunSystem.Cartridges.cs @@ -37,7 +37,7 @@ private void OnCartridgeDamageExamine(EntityUid uid, CartridgeAmmoComponent comp { var p = (ProjectileComponent) projectile.Component; - if (p.Damage.Total > FixedPoint2.Zero) + if (!p.Damage.Empty) { return p.Damage; } diff --git a/Content.Server/Weapons/Ranged/Systems/GunSystem.cs b/Content.Server/Weapons/Ranged/Systems/GunSystem.cs index 0859cb94427..adda6a94e3c 100644 --- a/Content.Server/Weapons/Ranged/Systems/GunSystem.cs +++ b/Content.Server/Weapons/Ranged/Systems/GunSystem.cs @@ -239,7 +239,7 @@ public override void Shoot(EntityUid gunUid, GunComponent gun, List<(EntityUid? { if (!Deleted(hitEntity)) { - if (dmg.Total > FixedPoint2.Zero) + if (dmg.Any()) { _color.RaiseEffect(Color.Red, new List() { hitEntity }, Filter.Pvs(hitEntity, entityManager: EntityManager)); } diff --git a/Content.Shared/Damage/DamageModifierSet.cs b/Content.Shared/Damage/DamageModifierSet.cs index 2dfc38715e4..bd074ec30f8 100644 --- a/Content.Shared/Damage/DamageModifierSet.cs +++ b/Content.Shared/Damage/DamageModifierSet.cs @@ -5,11 +5,15 @@ namespace Content.Shared.Damage { /// - /// A set of coefficients or flat modifiers to damage types.. Can be applied to using using . This can be done several times as the /// is passed to it's final target. By default the receiving , will /// also apply it's own . /// + /// + /// The modifier will only ever be applied to damage that is being dealt. Healing is unmodified. + /// The modifier can also never convert damage into healing. + /// [DataDefinition] [Serializable, NetSerializable] [Virtual] diff --git a/Content.Shared/Damage/DamageSpecifier.cs b/Content.Shared/Damage/DamageSpecifier.cs index 903ee605f1a..b7181e297f6 100644 --- a/Content.Shared/Damage/DamageSpecifier.cs +++ b/Content.Shared/Damage/DamageSpecifier.cs @@ -37,16 +37,42 @@ public sealed partial class DamageSpecifier : IEquatable [IncludeDataField(customTypeSerializer: typeof(DamageSpecifierDictionarySerializer), readOnly: true)] public Dictionary DamageDict { get; set; } = new(); + [JsonIgnore] + [Obsolete("Use GetTotal()")] + public FixedPoint2 Total => GetTotal(); + /// - /// Sum of the damage values. + /// Returns a sum of the damage values. /// /// /// Note that this being zero does not mean this damage has no effect. Healing in one type may cancel damage - /// in another. For this purpose, you should instead use and then check the property. + /// in another. Consider using or instead. /// - [JsonIgnore] - public FixedPoint2 Total => DamageDict.Values.Sum(); + public FixedPoint2 GetTotal() + { + var total = FixedPoint2.Zero; + foreach (var value in DamageDict.Values) + { + total += value; + } + return total; + } + + /// + /// Returns true if the specifier contains any positive damage values. + /// Differs from as a damage specifier might contain entries with zeroes. + /// This also returns false if the specifier only contains negative values. + /// + public bool Any() + { + foreach (var value in DamageDict.Values) + { + if (value > FixedPoint2.Zero) + return true; + } + + return false; + } /// /// Whether this damage specifier has any entries. @@ -100,41 +126,39 @@ public DamageSpecifier(DamageGroupPrototype group, FixedPoint2 value) /// /// /// Only applies resistance to a damage type if it is dealing damage, not healing. + /// This will never convert damage into healing. /// public static DamageSpecifier ApplyModifierSet(DamageSpecifier damageSpec, DamageModifierSet modifierSet) { // Make a copy of the given data. Don't modify the one passed to this function. I did this before, and weapons became // duller as you hit walls. Neat, but not FixedPoint2ended. And confusing, when you realize your fists don't work no // more cause they're just bloody stumps. - DamageSpecifier newDamage = new(damageSpec); + DamageSpecifier newDamage = new(); + newDamage.DamageDict.EnsureCapacity(damageSpec.DamageDict.Count); - foreach (var entry in newDamage.DamageDict) + foreach (var (key, value) in damageSpec.DamageDict) { - if (entry.Value <= 0) continue; - - float newValue = entry.Value.Float(); + if (value == 0) + continue; - if (modifierSet.FlatReduction.TryGetValue(entry.Key, out var reduction)) + if (value < 0) { - newValue -= reduction; - if (newValue <= 0) - { - // flat reductions cannot heal you - newDamage.DamageDict[entry.Key] = FixedPoint2.Zero; - continue; - } + newDamage.DamageDict[key] = value; + continue; } - if (modifierSet.Coefficients.TryGetValue(entry.Key, out var coefficient)) - { - // negative coefficients **can** heal you. - newValue = newValue * coefficient; - } + float newValue = value.Float(); + + if (modifierSet.FlatReduction.TryGetValue(key, out var reduction)) + newValue -= reduction; + + if (modifierSet.Coefficients.TryGetValue(key, out var coefficient)) + newValue *= coefficient; - newDamage.DamageDict[entry.Key] = FixedPoint2.New(newValue); + if (newValue > 0) + newDamage.DamageDict[key] = FixedPoint2.New(newValue); } - newDamage.TrimZeros(); return newDamage; } @@ -146,13 +170,19 @@ public static DamageSpecifier ApplyModifierSet(DamageSpecifier damageSpec, Damag /// public static DamageSpecifier ApplyModifierSets(DamageSpecifier damageSpec, IEnumerable modifierSets) { - DamageSpecifier newDamage = new(damageSpec); + bool any = false; + DamageSpecifier newDamage = damageSpec; foreach (var set in modifierSets) { - // this is probably really inefficient. just don't call this in a hot path I guess. + // This creates a new damageSpec for each modifier when we really onlt need to create one. + // This is quite inefficient, but hopefully this shouldn't ever be called frequently. newDamage = ApplyModifierSet(newDamage, set); + any = true; } + if (!any) + newDamage = new DamageSpecifier(damageSpec); + return newDamage; } @@ -224,9 +254,10 @@ public void ExclusiveAdd(DamageSpecifier other) { foreach (var (type, value) in other.DamageDict) { - if (DamageDict.ContainsKey(type)) + // CollectionsMarshal my beloved. + if (DamageDict.TryGetValue(type, out var existing)) { - DamageDict[type] += value; + DamageDict[type] = existing + value; } } } @@ -262,18 +293,22 @@ public bool TryGetDamageInGroup(DamageGroupPrototype group, out FixedPoint2 tota /// total of each group. If no members of a group are present in this , the /// group is not included in the resulting dictionary. /// - public Dictionary GetDamagePerGroup(IPrototypeManager? protoManager = null) + public Dictionary GetDamagePerGroup(IPrototypeManager protoManager) + { + var dict = new Dictionary(); + GetDamagePerGroup(protoManager, dict); + return dict; + } + + /// + public void GetDamagePerGroup(IPrototypeManager protoManager, Dictionary dict) { - IoCManager.Resolve(ref protoManager); - var damageGroupDict = new Dictionary(); + dict.Clear(); foreach (var group in protoManager.EnumeratePrototypes()) { if (TryGetDamageInGroup(group, out var value)) - { - damageGroupDict.Add(group.ID, value); - } + dict.Add(group.ID, value); } - return damageGroupDict; } #region Operators @@ -372,6 +407,8 @@ public bool Equals(DamageSpecifier? other) return true; } + + public FixedPoint2 this[string key] => DamageDict[key]; } #endregion } diff --git a/Content.Shared/Damage/Systems/DamageableSystem.cs b/Content.Shared/Damage/Systems/DamageableSystem.cs index a3cdd14ef7b..8f6ccc20e62 100644 --- a/Content.Shared/Damage/Systems/DamageableSystem.cs +++ b/Content.Shared/Damage/Systems/DamageableSystem.cs @@ -20,6 +20,9 @@ public sealed class DamageableSystem : EntitySystem [Dependency] private readonly INetManager _netMan = default!; [Dependency] private readonly MobThresholdSystem _mobThreshold = default!; + private EntityQuery _appearanceQuery; + private EntityQuery _damageableQuery; + public override void Initialize() { SubscribeLocalEvent(DamageableInit); @@ -27,6 +30,9 @@ public override void Initialize() SubscribeLocalEvent(DamageableGetState); SubscribeLocalEvent(OnIrradiated); SubscribeLocalEvent(OnRejuvenate); + + _appearanceQuery = GetEntityQuery(); + _damageableQuery = GetEntityQuery(); } /// @@ -45,9 +51,9 @@ private void DamageableInit(EntityUid uid, DamageableComponent component, Compon component.Damage.DamageDict.TryAdd(type, FixedPoint2.Zero); } - foreach (var groupID in damageContainerPrototype.SupportedGroups) + foreach (var groupId in damageContainerPrototype.SupportedGroups) { - var group = _prototypeManager.Index(groupID); + var group = _prototypeManager.Index(groupId); foreach (var type in group.DamageTypes) { component.Damage.DamageDict.TryAdd(type, FixedPoint2.Zero); @@ -63,8 +69,8 @@ private void DamageableInit(EntityUid uid, DamageableComponent component, Compon } } - component.DamagePerGroup = component.Damage.GetDamagePerGroup(_prototypeManager); - component.TotalDamage = component.Damage.Total; + component.Damage.GetDamagePerGroup(_prototypeManager, component.DamagePerGroup); + component.TotalDamage = component.Damage.GetTotal(); } /// @@ -90,11 +96,11 @@ public void SetDamage(EntityUid uid, DamageableComponent damageable, DamageSpeci public void DamageChanged(EntityUid uid, DamageableComponent component, DamageSpecifier? damageDelta = null, bool interruptsDoAfters = true, EntityUid? origin = null) { - component.DamagePerGroup = component.Damage.GetDamagePerGroup(_prototypeManager); - component.TotalDamage = component.Damage.Total; - Dirty(component); + component.Damage.GetDamagePerGroup(_prototypeManager, component.DamagePerGroup); + component.TotalDamage = component.Damage.GetTotal(); + Dirty(uid, component); - if (EntityManager.TryGetComponent(uid, out var appearance) && damageDelta != null) + if (_appearanceQuery.TryGetComponent(uid, out var appearance) && damageDelta != null) { var data = new DamageVisualizerGroupData(component.DamagePerGroup.Keys.ToList()); _appearance.SetData(uid, DamageVisualizerKeys.DamageUpdateGroups, data, appearance); @@ -117,7 +123,7 @@ public void DamageChanged(EntityUid uid, DamageableComponent component, DamageSp public DamageSpecifier? TryChangeDamage(EntityUid? uid, DamageSpecifier damage, bool ignoreResistances = false, bool interruptsDoAfters = true, DamageableComponent? damageable = null, EntityUid? origin = null) { - if (!uid.HasValue || !Resolve(uid.Value, ref damageable, false)) + if (!uid.HasValue || !_damageableQuery.Resolve(uid.Value, ref damageable, false)) { // TODO BODY SYSTEM pass damage onto body system return null; @@ -140,6 +146,8 @@ public void DamageChanged(EntityUid uid, DamageableComponent component, DamageSp if (damageable.DamageModifierSetId != null && _prototypeManager.TryIndex(damageable.DamageModifierSetId, out var modifierSet)) { + // TODO DAMAGE PERFORMANCE + // use a local private field instead of creating a new dictionary here.. damage = DamageSpecifier.ApplyModifierSet(damage, modifierSet); } @@ -153,20 +161,30 @@ public void DamageChanged(EntityUid uid, DamageableComponent component, DamageSp } } - // Copy the current damage, for calculating the difference - DamageSpecifier oldDamage = new(damageable.Damage); + // TODO DAMAGE PERFORMANCE + // Consider using a local private field instead of creating a new dictionary here. + // Would need to check that nothing ever tries to cache the delta. + var delta = new DamageSpecifier(); + delta.DamageDict.EnsureCapacity(damage.DamageDict.Count); - damageable.Damage.ExclusiveAdd(damage); - damageable.Damage.ClampMin(FixedPoint2.Zero); + var dict = damageable.Damage.DamageDict; + foreach (var (type, value) in damage.DamageDict) + { + // CollectionsMarshal my beloved. + if (!dict.TryGetValue(type, out var oldValue)) + continue; - var delta = damageable.Damage - oldDamage; - delta.TrimZeros(); + var newValue = FixedPoint2.Max(FixedPoint2.Zero, oldValue + value); + if (newValue == oldValue) + continue; - if (!delta.Empty) - { - DamageChanged(uid.Value, damageable, delta, interruptsDoAfters, origin); + dict[type] = newValue; + delta.DamageDict[type] = newValue - oldValue; } + if (delta.DamageDict.Count > 0) + DamageChanged(uid.Value, damageable, delta, interruptsDoAfters, origin); + return delta; } @@ -196,12 +214,11 @@ public void SetAllDamage(EntityUid uid, DamageableComponent component, FixedPoin public void SetDamageModifierSetId(EntityUid uid, string damageModifierSetId, DamageableComponent? comp = null) { - if (!Resolve(uid, ref comp)) + if (!_damageableQuery.Resolve(uid, ref comp)) return; comp.DamageModifierSetId = damageModifierSetId; - - Dirty(comp); + Dirty(uid, comp); } private void DamageableGetState(EntityUid uid, DamageableComponent component, ref ComponentGetState args) @@ -265,7 +282,7 @@ private void DamageableHandleState(EntityUid uid, DamageableComponent component, /// Raised before damage is done, so stuff can cancel it if necessary. /// [ByRefEvent] - public record struct BeforeDamageChangedEvent(DamageSpecifier Delta, EntityUid? Origin = null, bool Cancelled = false); + public record struct BeforeDamageChangedEvent(DamageSpecifier Damage, EntityUid? Origin = null, bool Cancelled = false); /// /// Raised on an entity when damage is about to be dealt, @@ -312,14 +329,14 @@ public sealed class DamageChangedEvent : EntityEventArgs /// /// Was any of the damage change dealing damage, or was it all healing? /// - public readonly bool DamageIncreased = false; + public readonly bool DamageIncreased; /// /// Does this event interrupt DoAfters? /// Note: As provided in the constructor, this *does not* account for DamageIncreased. /// As written into the event, this *does* account for DamageIncreased. /// - public readonly bool InterruptsDoAfters = false; + public readonly bool InterruptsDoAfters; /// /// Contains the entity which caused the change in damage, if any was responsible. diff --git a/Content.Shared/Weapons/Melee/SharedMeleeWeaponSystem.cs b/Content.Shared/Weapons/Melee/SharedMeleeWeaponSystem.cs index 9b61fd03b7d..ebe1a21e679 100644 --- a/Content.Shared/Weapons/Melee/SharedMeleeWeaponSystem.cs +++ b/Content.Shared/Weapons/Melee/SharedMeleeWeaponSystem.cs @@ -495,7 +495,7 @@ protected virtual void DoLightAttack(EntityUid user, LightAttackEvent ev, Entity var modifiedDamage = DamageSpecifier.ApplyModifierSets(damage + hitEvent.BonusDamage + attackedEvent.BonusDamage, hitEvent.ModifiersList); var damageResult = Damageable.TryChangeDamage(target, modifiedDamage, origin:user); - if (damageResult != null && damageResult.Total > FixedPoint2.Zero) + if (damageResult != null && damageResult.Any()) { // If the target has stamina and is taking blunt damage, they should also take stamina damage based on their blunt to stamina factor if (damageResult.DamageDict.TryGetValue("Blunt", out var bluntDamage)) @@ -522,7 +522,7 @@ protected virtual void DoLightAttack(EntityUid user, LightAttackEvent ev, Entity { Audio.PlayPredicted(hitEvent.HitSoundOverride, meleeUid, user); } - else if (GetDamage(meleeUid, user, component).Total.Equals(FixedPoint2.Zero) && component.HitSound != null) + else if (!GetDamage(meleeUid, user, component).Any() && component.HitSound != null) { Audio.PlayPredicted(component.HitSound, meleeUid, user); } diff --git a/Content.Tests/Shared/DamageTest.cs b/Content.Tests/Shared/DamageTest.cs index 4f8647b3e40..4221ff25a25 100644 --- a/Content.Tests/Shared/DamageTest.cs +++ b/Content.Tests/Shared/DamageTest.cs @@ -17,15 +17,15 @@ namespace Content.Tests.Shared public sealed class DamageTest : ContentUnitTest { - static private Dictionary _resistanceCoefficientDict = new() + private static Dictionary _resistanceCoefficientDict = new() { // "missing" blunt entry - { "Piercing", -2 },// Turn Piercing into Healing + { "Piercing", -2 }, // negative multipliers just cause the damage to be ignored. { "Slash", 3 }, { "Radiation", 1.5f }, }; - static private Dictionary _resistanceReductionDict = new() + private static Dictionary _resistanceReductionDict = new() { { "Blunt", - 5 }, // "missing" piercing entry @@ -152,14 +152,14 @@ public void ModifierSetTest() // Apply once damageSpec = DamageSpecifier.ApplyModifierSet(damageSpec, modifierSet); Assert.That(damageSpec.DamageDict["Blunt"], Is.EqualTo(FixedPoint2.New(25))); - Assert.That(damageSpec.DamageDict["Piercing"], Is.EqualTo(FixedPoint2.New(-40))); // became healing + Assert.That(!damageSpec.DamageDict.ContainsKey("Piercing")); // Cannot convert damage into healing. Assert.That(damageSpec.DamageDict["Slash"], Is.EqualTo(FixedPoint2.New(6))); Assert.That(damageSpec.DamageDict["Radiation"], Is.EqualTo(FixedPoint2.New(44.25))); // And again, checking for some other behavior damageSpec = DamageSpecifier.ApplyModifierSet(damageSpec, modifierSet); Assert.That(damageSpec.DamageDict["Blunt"], Is.EqualTo(FixedPoint2.New(30))); - Assert.That(damageSpec.DamageDict["Piercing"], Is.EqualTo(FixedPoint2.New(-40))); // resistances don't apply to healing + Assert.That(!damageSpec.DamageDict.ContainsKey("Piercing")); Assert.That(!damageSpec.DamageDict.ContainsKey("Slash")); // Reduction reduced to 0, and removed from specifier Assert.That(damageSpec.DamageDict["Radiation"], Is.EqualTo(FixedPoint2.New(65.63))); } From 00642e87a37d288003e116f3cc4940808a10a229 Mon Sep 17 00:00:00 2001 From: Leon Friedrich <60421075+ElectroJr@users.noreply.github.com> Date: Mon, 9 Oct 2023 03:28:04 +1100 Subject: [PATCH 015/127] Changes for SplitContainer Engine PR (#20383) --- .../Controls/RecordedSplitContainer.cs | 24 ------------------- .../Screens/SeparatedChatGameScreen.xaml.cs | 2 +- 2 files changed, 1 insertion(+), 25 deletions(-) diff --git a/Content.Client/UserInterface/Controls/RecordedSplitContainer.cs b/Content.Client/UserInterface/Controls/RecordedSplitContainer.cs index b255ac15a30..fd217bc7e86 100644 --- a/Content.Client/UserInterface/Controls/RecordedSplitContainer.cs +++ b/Content.Client/UserInterface/Controls/RecordedSplitContainer.cs @@ -1,7 +1,5 @@ using System.Numerics; -using Robust.Client.UserInterface; using Robust.Client.UserInterface.Controls; -using Robust.Shared.Input; namespace Content.Client.UserInterface.Controls; @@ -10,8 +8,6 @@ namespace Content.Client.UserInterface.Controls; /// public sealed class RecordedSplitContainer : SplitContainer { - public Action? OnSplitResizeFinish; - public double? DesiredSplitCenter; protected override Vector2 ArrangeOverride(Vector2 finalSize) @@ -30,24 +26,4 @@ protected override Vector2 ArrangeOverride(Vector2 finalSize) return base.ArrangeOverride(finalSize); } - - protected override void KeyBindUp(GUIBoundKeyEventArgs args) - { - base.KeyBindUp(args); - - if (args.Function != EngineKeyFunctions.UIClick) - { - return; - } - - if (ChildCount != 2) - { - return; - } - - var first = GetChild(0); - var second = GetChild(1); - - OnSplitResizeFinish?.Invoke(first.Size, second.Size); - } } diff --git a/Content.Client/UserInterface/Screens/SeparatedChatGameScreen.xaml.cs b/Content.Client/UserInterface/Screens/SeparatedChatGameScreen.xaml.cs index 9aef78fd856..41c4a85e7ee 100644 --- a/Content.Client/UserInterface/Screens/SeparatedChatGameScreen.xaml.cs +++ b/Content.Client/UserInterface/Screens/SeparatedChatGameScreen.xaml.cs @@ -24,7 +24,7 @@ public SeparatedChatGameScreen() SetAnchorAndMarginPreset(Hotbar, LayoutPreset.BottomWide, margin: 5); SetAnchorAndMarginPreset(Alerts, LayoutPreset.CenterRight, margin: 10); - ScreenContainer.OnSplitResizeFinish += (first, second) => + ScreenContainer.OnSplitResizeFinished += () => OnChatResized?.Invoke(new Vector2(ScreenContainer.SplitFraction, 0)); } From ba15d998944e5995b191b34f9e7f064760d15508 Mon Sep 17 00:00:00 2001 From: Leon Friedrich <60421075+ElectroJr@users.noreply.github.com> Date: Mon, 9 Oct 2023 03:43:30 +1100 Subject: [PATCH 016/127] Update engine to v165.0.0 (#20837) --- RobustToolbox | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RobustToolbox b/RobustToolbox index 58aa6e5c756..a8ddd837c84 160000 --- a/RobustToolbox +++ b/RobustToolbox @@ -1 +1 @@ -Subproject commit 58aa6e5c7563c40baa51460a9def164a7ebc1791 +Subproject commit a8ddd837c847f7cd8e71ae4926418a992b6ff4a3 From 35f41742a749745f1bfae02401ba79d85d6af8a2 Mon Sep 17 00:00:00 2001 From: kerisargit <108146620+kerisargit@users.noreply.github.com> Date: Sun, 8 Oct 2023 20:08:20 +0300 Subject: [PATCH 017/127] fix: Incendiary bullets no longer deal cold, acid, or shock damage that ignores all armor. (#20836) --- .../Weapons/Guns/Ammunition/Projectiles/light_rifle.yml | 5 +++-- .../Objects/Weapons/Guns/Ammunition/Projectiles/magnum.yml | 7 ++++--- .../Objects/Weapons/Guns/Ammunition/Projectiles/pistol.yml | 5 +++-- .../Objects/Weapons/Guns/Ammunition/Projectiles/rifle.yml | 6 ++++-- .../Weapons/Guns/Ammunition/Projectiles/shotgun.yml | 5 +++-- 5 files changed, 17 insertions(+), 11 deletions(-) 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 315f1af7e19..6350b77094f 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 @@ -39,5 +39,6 @@ components: - type: Projectile damage: - groups: - Burn: 17 + types: + Blunt: 3 + Heat: 16 diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Projectiles/magnum.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Projectiles/magnum.yml index 2da1e190d9d..8b30bfe1820 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Projectiles/magnum.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Projectiles/magnum.yml @@ -41,9 +41,10 @@ components: - type: Projectile damage: - groups: - Burn: 32 - + types: + Blunt: 3 + Heat: 32 + - type: entity id: BulletMagnumAP name: bullet (.45 magnum armor-piercing) diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Projectiles/pistol.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Projectiles/pistol.yml index f3e7d1e6bac..0e6c08c3dfd 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Projectiles/pistol.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Projectiles/pistol.yml @@ -39,5 +39,6 @@ components: - type: Projectile damage: - groups: - Burn: 14 + types: + Blunt: 2 + Heat: 14 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 009ab6bbb4f..768fec3c428 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Projectiles/rifle.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Projectiles/rifle.yml @@ -39,5 +39,7 @@ components: - type: Projectile damage: - groups: - Burn: 15 + types: + Blunt: 2 + Heat: 15 + diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Projectiles/shotgun.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Projectiles/shotgun.yml index ec23d3063a0..887295b4b1c 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Projectiles/shotgun.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Projectiles/shotgun.yml @@ -53,8 +53,9 @@ state: buckshot-flare - type: Projectile damage: - groups: - Burn: 7 + types: + Blunt: 1 + Heat: 7 - type: entity id: PelletShotgunPractice From 1a5cf370e797f6bc9fd31b0a113d24b9a887400f Mon Sep 17 00:00:00 2001 From: Leon Friedrich <60421075+ElectroJr@users.noreply.github.com> Date: Mon, 9 Oct 2023 07:37:09 +1100 Subject: [PATCH 018/127] Slightly improve action ui performance (#20799) --- Content.Client/Actions/ActionsSystem.cs | 1 - .../Systems/Actions/ActionUIController.cs | 96 ++++++++++++------- .../Systems/Actions/Controls/ActionButton.cs | 81 ++++++++-------- .../Actions/Controls/ActionButtonContainer.cs | 5 +- .../Actions/Widgets/ActionsBar.xaml.cs | 6 +- .../Actions/Windows/ActionsWindow.xaml.cs | 5 + 6 files changed, 118 insertions(+), 76 deletions(-) diff --git a/Content.Client/Actions/ActionsSystem.cs b/Content.Client/Actions/ActionsSystem.cs index 41db0ad7ceb..83d927c94bb 100644 --- a/Content.Client/Actions/ActionsSystem.cs +++ b/Content.Client/Actions/ActionsSystem.cs @@ -29,7 +29,6 @@ public sealed class ActionsSystem : SharedActionsSystem public event Action? OnActionAdded; public event Action? OnActionRemoved; - public event OnActionReplaced? ActionReplaced; public event Action? ActionsUpdated; public event Action? LinkActions; public event Action? UnlinkActions; diff --git a/Content.Client/UserInterface/Systems/Actions/ActionUIController.cs b/Content.Client/UserInterface/Systems/Actions/ActionUIController.cs index fcacc1b0527..bb83e370fe4 100644 --- a/Content.Client/UserInterface/Systems/Actions/ActionUIController.cs +++ b/Content.Client/UserInterface/Systems/Actions/ActionUIController.cs @@ -42,6 +42,7 @@ public sealed class ActionUIController : UIController, IOnStateChanged actions) { - if (_window == null) + if (_window is not { Disposed: false, IsOpen: true }) return; - ClearList(); + if (_actionsSystem == null) + return; + + _window.UpdateNeeded = false; + + List existing = new(_window.ResultsGrid.ChildCount); + foreach (var child in _window.ResultsGrid.Children) + { + if (child is ActionButton button) + existing.Add(button); + } + int i = 0; foreach (var action in actions) { - var button = new ActionButton {Locked = true}; + if (i < existing.Count) + { + existing[i++].UpdateData(action.Id, _actionsSystem); + continue; + } - button.UpdateData(action.Id); + var button = new ActionButton(_entMan, _spriteSystem, this) {Locked = true}; button.ActionPressed += OnWindowActionPressed; button.ActionUnpressed += OnWindowActionUnPressed; button.ActionFocusExited += OnWindowActionFocusExisted; - + button.UpdateData(action.Id, _actionsSystem); _window.ResultsGrid.AddChild(button); } + + for (; i < existing.Count; i++) + { + existing[i].Dispose(); + } + } + + public void QueueWindowUpdate() + { + if (_window != null) + _window.UpdateNeeded = true; } private void SearchAndDisplay() { - if (_window is not { Disposed: false } || _actionsSystem == null) + if (_window is not { Disposed: false, IsOpen: true }) + return; + + if (_actionsSystem == null) return; if (_playerManager.LocalPlayer?.ControlledEntity is not { } player) @@ -598,6 +617,9 @@ private void SearchAndDisplay() private void SetAction(ActionButton button, EntityUid? actionId) { + if (_actionsSystem == null) + return; + int position; if (actionId == null) @@ -611,7 +633,7 @@ private void SetAction(ActionButton button, EntityUid? actionId) return; } - if (button.TryReplaceWith(actionId.Value) && + if (button.TryReplaceWith(actionId.Value, _actionsSystem) && _container != null && _container.TryGetButtonIndex(button, out position)) { @@ -648,18 +670,18 @@ private void OnClearPressed(ButtonEventArgs args) _window.SearchBar.Clear(); _window.FilterButton.DeselectAll(); UpdateFilterLabel(); - SearchAndDisplay(); + QueueWindowUpdate(); } private void OnSearchChanged(LineEditEventArgs args) { - SearchAndDisplay(); + QueueWindowUpdate(); } private void OnFilterSelected(ItemPressedEventArgs args) { UpdateFilterLabel(); - SearchAndDisplay(); + QueueWindowUpdate(); } private void OnWindowActionPressed(GUIBoundKeyEventArgs args, ActionButton action) @@ -849,12 +871,15 @@ private void ClearActions() private void AssignSlots(List assignments) { + if (_actionsSystem == null) + return; + foreach (ref var assignment in CollectionsMarshal.AsSpan(assignments)) { _pages[assignment.Hotbar][assignment.Slot] = assignment.ActionId; } - _container?.SetActionData(_pages[_currentPageIndex]); + _container?.SetActionData(_actionsSystem, _pages[_currentPageIndex]); } public void RemoveActionContainer() @@ -881,19 +906,24 @@ public void OnSystemUnloaded(ActionsSystem system) public override void FrameUpdate(FrameEventArgs args) { _menuDragHelper.Update(args.DeltaSeconds); + if (_window is {UpdateNeeded: true}) + SearchAndDisplay(); } private void OnComponentLinked(ActionsComponent component) { + if (_actionsSystem == null) + return; + LoadDefaultActions(component); - _container?.SetActionData(_pages[DefaultPageIndex]); - SearchAndDisplay(); + _container?.SetActionData(_actionsSystem, _pages[DefaultPageIndex]); + QueueWindowUpdate(); } private void OnComponentUnlinked() { _container?.ClearActionData(); - SearchAndDisplay(); + QueueWindowUpdate(); StopTargeting(); } diff --git a/Content.Client/UserInterface/Systems/Actions/Controls/ActionButton.cs b/Content.Client/UserInterface/Systems/Actions/Controls/ActionButton.cs index e4521cecaa9..31c5a28e520 100644 --- a/Content.Client/UserInterface/Systems/Actions/Controls/ActionButton.cs +++ b/Content.Client/UserInterface/Systems/Actions/Controls/ActionButton.cs @@ -8,8 +8,6 @@ using Robust.Client.Graphics; using Robust.Client.UserInterface; using Robust.Client.UserInterface.Controls; -using Robust.Client.Utility; -using Robust.Shared.Graphics; using Robust.Shared.Input; using Robust.Shared.Timing; using Robust.Shared.Utility; @@ -21,11 +19,9 @@ namespace Content.Client.UserInterface.Systems.Actions.Controls; public sealed class ActionButton : Control, IEntityControl { - private IEntityManager? _entities; - - private ActionUIController Controller => UserInterfaceManager.GetUIController(); - private IEntityManager Entities => _entities ??= IoCManager.Resolve(); - private ActionsSystem Actions => Entities.System(); + private IEntityManager _entities; + private SpriteSystem? _spriteSys; + private ActionUIController? _controller; private bool _beingHovered; private bool _depressed; private bool _toggled; @@ -54,14 +50,21 @@ public BoundKeyFunction? KeyBind private readonly SpriteView _bigItemSpriteView; public EntityUid? ActionId { get; private set; } + private BaseActionComponent? _action; public bool Locked { get; set; } public event Action? ActionPressed; public event Action? ActionUnpressed; public event Action? ActionFocusExited; - public ActionButton() + public ActionButton(IEntityManager entities, SpriteSystem? spriteSys = null, ActionUIController? controller = null) { + // TODO why is this constructor so slooooow. The rest of the code is fine + + _entities = entities; + _spriteSys = spriteSys; + _controller = controller; + MouseFilter = MouseFilterMode.Pass; Button = new TextureRect { @@ -180,7 +183,7 @@ private void OnUnpressed(GUIBoundKeyEventArgs args) private Control? SupplyTooltip(Control sender) { - if (!Entities.TryGetComponent(ActionId, out MetaDataComponent? metadata)) + if (!_entities.TryGetComponent(ActionId, out MetaDataComponent? metadata)) return null; var name = FormattedMessage.FromMarkupPermissive(Loc.GetString(metadata.EntityName)); @@ -196,9 +199,8 @@ protected override void ControlFocusExited() private void UpdateItemIcon() { - if (!Actions.TryGetActionData(ActionId, out var action) || - action is not {EntityIcon: { } entity} || - !Entities.HasComponent(entity)) + if (_action is not {EntityIcon: { } entity} || + !_entities.HasComponent(entity)) { _bigItemSpriteView.Visible = false; _bigItemSpriteView.SetEntity(null); @@ -207,7 +209,7 @@ private void UpdateItemIcon() } else { - switch (action.ItemIconStyle) + switch (_action.ItemIconStyle) { case ItemActionIconStyle.BigItem: _bigItemSpriteView.Visible = true; @@ -233,17 +235,17 @@ private void UpdateItemIcon() private void SetActionIcon(Texture? texture) { - if (!Actions.TryGetActionData(ActionId, out var action) || texture == null) + if (_action == null || texture == null) { _bigActionIcon.Texture = null; _bigActionIcon.Visible = false; _smallActionIcon.Texture = null; _smallActionIcon.Visible = false; } - else if (action.EntityIcon != null && action.ItemIconStyle == ItemActionIconStyle.BigItem) + else if (_action.EntityIcon != null && _action.ItemIconStyle == ItemActionIconStyle.BigItem) { _smallActionIcon.Texture = texture; - _smallActionIcon.Modulate = action.IconColor; + _smallActionIcon.Modulate = _action.IconColor; _smallActionIcon.Visible = true; _bigActionIcon.Texture = null; _bigActionIcon.Visible = false; @@ -251,7 +253,7 @@ private void SetActionIcon(Texture? texture) else { _bigActionIcon.Texture = texture; - _bigActionIcon.Modulate = action.IconColor; + _bigActionIcon.Modulate = _action.IconColor; _bigActionIcon.Visible = true; _smallActionIcon.Texture = null; _smallActionIcon.Visible = false; @@ -262,39 +264,43 @@ public void UpdateIcons() { UpdateItemIcon(); - if (!Actions.TryGetActionData(ActionId, out var action)) + if (_action == null) { SetActionIcon(null); return; } - if ((Controller.SelectingTargetFor == ActionId || action.Toggled) && action.IconOn != null) - SetActionIcon(action.IconOn.Frame0()); + _controller ??= UserInterfaceManager.GetUIController(); + _spriteSys ??= _entities.System(); + if ((_controller.SelectingTargetFor == ActionId || _action.Toggled) && _action.IconOn != null) + SetActionIcon(_spriteSys.Frame0(_action.IconOn)); else - SetActionIcon(action.Icon?.Frame0()); + SetActionIcon(_action.Icon != null ? _spriteSys.Frame0(_action.Icon) : null); } - public bool TryReplaceWith(EntityUid actionId) + public bool TryReplaceWith(EntityUid actionId, ActionsSystem system) { if (Locked) { return false; } - UpdateData(actionId); + UpdateData(actionId, system); return true; } - public void UpdateData(EntityUid actionId) + public void UpdateData(EntityUid? actionId, ActionsSystem system) { ActionId = actionId; - Label.Visible = true; + system.TryGetActionData(actionId, out _action); + Label.Visible = actionId != null; UpdateIcons(); } public void ClearData() { ActionId = null; + _action = null; Cooldown.Visible = false; Cooldown.Progress = 1; Label.Visible = false; @@ -305,19 +311,17 @@ protected override void FrameUpdate(FrameEventArgs args) { base.FrameUpdate(args); - if (!Actions.TryGetActionData(ActionId, out var action)) - { + if (_action == null) return; - } - if (action.Cooldown != null) + if (_action.Cooldown != null) { - Cooldown.FromTime(action.Cooldown.Value.Start, action.Cooldown.Value.End); + Cooldown.FromTime(_action.Cooldown.Value.Start, _action.Cooldown.Value.End); } - if (ActionId != null && _toggled != action.Toggled) + if (ActionId != null && _toggled != _action.Toggled) { - _toggled = action.Toggled; + _toggled = _action.Toggled; } } @@ -344,7 +348,7 @@ protected override void MouseExited() public void Depress(GUIBoundKeyEventArgs args, bool depress) { // action can still be toggled if it's allowed to stay selected - if (!Actions.TryGetActionData(ActionId, out var action) || action is not {Enabled: true}) + if (_action is not {Enabled: true}) return; if (_depressed && !depress) @@ -362,14 +366,15 @@ public void DrawModeChanged() HighlightRect.Visible = _beingHovered; // always show the normal empty button style if no action in this slot - if (!Actions.TryGetActionData(ActionId, out var action)) + if (_action == null) { SetOnlyStylePseudoClass(ContainerButton.StylePseudoClassNormal); return; } // show a hover only if the action is usable or another action is being dragged on top of this - if (_beingHovered && (Controller.IsDragging || action.Enabled)) + _controller ??= UserInterfaceManager.GetUIController(); + if (_beingHovered && (_controller.IsDragging || _action.Enabled)) { SetOnlyStylePseudoClass(ContainerButton.StylePseudoClassHover); } @@ -384,16 +389,16 @@ public void DrawModeChanged() } // if it's toggled on, always show the toggled on style (currently same as depressed style) - if (action.Toggled || Controller.SelectingTargetFor == ActionId) + if (_action.Toggled || _controller.SelectingTargetFor == ActionId) { // when there's a toggle sprite, we're showing that sprite instead of highlighting this slot - SetOnlyStylePseudoClass(action.IconOn != null + SetOnlyStylePseudoClass(_action.IconOn != null ? ContainerButton.StylePseudoClassNormal : ContainerButton.StylePseudoClassPressed); return; } - if (!action.Enabled) + if (!_action.Enabled) { SetOnlyStylePseudoClass(ContainerButton.StylePseudoClassDisabled); return; diff --git a/Content.Client/UserInterface/Systems/Actions/Controls/ActionButtonContainer.cs b/Content.Client/UserInterface/Systems/Actions/Controls/ActionButtonContainer.cs index 5d6ad5c8de4..9986c61ad63 100644 --- a/Content.Client/UserInterface/Systems/Actions/Controls/ActionButtonContainer.cs +++ b/Content.Client/UserInterface/Systems/Actions/Controls/ActionButtonContainer.cs @@ -1,3 +1,4 @@ +using Content.Client.Actions; using Robust.Client.UserInterface; using Robust.Client.UserInterface.Controls; @@ -21,7 +22,7 @@ public ActionButton this[int index] get => (ActionButton) GetChild(index); } - public void SetActionData(params EntityUid?[] actionTypes) + public void SetActionData(ActionsSystem system, params EntityUid?[] actionTypes) { ClearActionData(); @@ -31,7 +32,7 @@ public void SetActionData(params EntityUid?[] actionTypes) if (action == null) continue; - ((ActionButton) GetChild(i)).UpdateData(action.Value); + ((ActionButton) GetChild(i)).UpdateData(action.Value, system); } } diff --git a/Content.Client/UserInterface/Systems/Actions/Widgets/ActionsBar.xaml.cs b/Content.Client/UserInterface/Systems/Actions/Widgets/ActionsBar.xaml.cs index c752a8b3ac1..ff3c32cc0e6 100644 --- a/Content.Client/UserInterface/Systems/Actions/Widgets/ActionsBar.xaml.cs +++ b/Content.Client/UserInterface/Systems/Actions/Widgets/ActionsBar.xaml.cs @@ -3,16 +3,18 @@ using Robust.Client.AutoGenerated; using Robust.Client.UserInterface.Controls; using Robust.Client.UserInterface.XAML; -using Robust.Shared.Input; namespace Content.Client.UserInterface.Systems.Actions.Widgets; [GenerateTypedNameReferences] public sealed partial class ActionsBar : UIWidget { + [Dependency] private readonly IEntityManager _entity = default!; + public ActionsBar() { RobustXamlLoader.Load(this); + IoCManager.InjectDependencies(this); var keys = ContentKeyFunctions.GetHotbarBoundKeys(); for (var index = 1; index < keys.Length; index++) @@ -24,7 +26,7 @@ public ActionsBar() ActionButton MakeButton(int index) { var boundKey = keys[index]; - var button = new ActionButton(); + var button = new ActionButton(_entity); button.KeyBind = boundKey; button.Label.Text = index.ToString(); return button; diff --git a/Content.Client/UserInterface/Systems/Actions/Windows/ActionsWindow.xaml.cs b/Content.Client/UserInterface/Systems/Actions/Windows/ActionsWindow.xaml.cs index 8c39883296b..fbe1e71535d 100644 --- a/Content.Client/UserInterface/Systems/Actions/Windows/ActionsWindow.xaml.cs +++ b/Content.Client/UserInterface/Systems/Actions/Windows/ActionsWindow.xaml.cs @@ -10,6 +10,11 @@ public sealed partial class ActionsWindow : DefaultWindow { public MultiselectOptionButton FilterButton { get; private set; } + /// + /// Whether the displayed actions or search filter needs updating. + /// + public bool UpdateNeeded; + public ActionsWindow() { RobustXamlLoader.Load(this); From 7adbf78b1245dd90ad809db33d03775f605a3db5 Mon Sep 17 00:00:00 2001 From: Whisper <121047731+QuietlyWhisper@users.noreply.github.com> Date: Sun, 8 Oct 2023 16:37:45 -0400 Subject: [PATCH 019/127] suffix additions: Pinpointer, thruster, gyro (#20818) * seperates the anchored and unachored versions of the gyro and thruster with a suffix. * add station suffix for station pinpointer * more suffixes for briefcases --- Resources/Prototypes/Catalog/Fills/Items/briefcases.yml | 4 ++-- Resources/Prototypes/Entities/Objects/Devices/pinpointer.yml | 1 + Resources/Prototypes/Entities/Objects/Misc/briefcases.yml | 1 + .../Prototypes/Entities/Structures/Shuttles/thrusters.yml | 2 ++ 4 files changed, 6 insertions(+), 2 deletions(-) diff --git a/Resources/Prototypes/Catalog/Fills/Items/briefcases.yml b/Resources/Prototypes/Catalog/Fills/Items/briefcases.yml index afc5095d191..c487909a4b1 100644 --- a/Resources/Prototypes/Catalog/Fills/Items/briefcases.yml +++ b/Resources/Prototypes/Catalog/Fills/Items/briefcases.yml @@ -2,7 +2,7 @@ id: BriefcaseBrownFilled name: brown briefcase parent: BriefcaseBrown - suffix: Filled + suffix: Filled, Paper components: - type: StorageFill contents: @@ -27,7 +27,7 @@ id: BriefcaseSyndieLobbyingBundleFilled name: brown briefcase parent: BriefcaseSyndie - suffix: Filled, Spesos + suffix: Syndicate, Spesos components: - type: StorageFill contents: diff --git a/Resources/Prototypes/Entities/Objects/Devices/pinpointer.yml b/Resources/Prototypes/Entities/Objects/Devices/pinpointer.yml index e00ba1ed089..92e882571b8 100644 --- a/Resources/Prototypes/Entities/Objects/Devices/pinpointer.yml +++ b/Resources/Prototypes/Entities/Objects/Devices/pinpointer.yml @@ -58,6 +58,7 @@ - type: entity parent: PinpointerBase id: PinpointerStation + suffix: Station components: - type: Pinpointer component: BecomesStation diff --git a/Resources/Prototypes/Entities/Objects/Misc/briefcases.yml b/Resources/Prototypes/Entities/Objects/Misc/briefcases.yml index f8d8aa0edd4..1866d3513e0 100644 --- a/Resources/Prototypes/Entities/Objects/Misc/briefcases.yml +++ b/Resources/Prototypes/Entities/Objects/Misc/briefcases.yml @@ -28,6 +28,7 @@ parent: BaseStorageItem abstract: true id: BriefcaseSyndieBase + suffix: Syndicate, Empty description: Useful for carrying items in your hands. components: - type: Item diff --git a/Resources/Prototypes/Entities/Structures/Shuttles/thrusters.yml b/Resources/Prototypes/Entities/Structures/Shuttles/thrusters.yml index 73b78875396..d53226f88c7 100644 --- a/Resources/Prototypes/Entities/Structures/Shuttles/thrusters.yml +++ b/Resources/Prototypes/Entities/Structures/Shuttles/thrusters.yml @@ -68,6 +68,7 @@ - type: entity id: ThrusterUnanchored parent: Thruster + suffix: Unanchored components: - type: Transform anchored: false @@ -147,6 +148,7 @@ - type: entity id: GyroscopeUnanchored parent: Gyroscope + suffix: Unanchored components: - type: Transform anchored: false From 25a691266726065cff463880407d6bf09bca81e6 Mon Sep 17 00:00:00 2001 From: Nemanja <98561806+EmoGarbage404@users.noreply.github.com> Date: Sun, 8 Oct 2023 17:01:18 -0400 Subject: [PATCH 020/127] Reformat hand examine text (#20842) --- .../SharedHandsSystem.Interactions.cs | 21 ++++++++++++++----- Resources/Locale/en-US/hands/hands-system.ftl | 4 +++- 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/Content.Shared/Hands/EntitySystems/SharedHandsSystem.Interactions.cs b/Content.Shared/Hands/EntitySystems/SharedHandsSystem.Interactions.cs index 1cd9ad9d6e6..d0c3be3b311 100644 --- a/Content.Shared/Hands/EntitySystems/SharedHandsSystem.Interactions.cs +++ b/Content.Shared/Hands/EntitySystems/SharedHandsSystem.Interactions.cs @@ -1,7 +1,9 @@ +using System.Linq; using Content.Shared.Examine; using Content.Shared.Hands.Components; using Content.Shared.IdentityManagement; using Content.Shared.Input; +using Content.Shared.Localizations; using Robust.Shared.Input.Binding; using Robust.Shared.Map; using Robust.Shared.Players; @@ -180,12 +182,21 @@ public bool TryMoveHeldEntityToActiveHand(EntityUid uid, string handName, bool c //TODO: Actually shows all items/clothing/etc. private void HandleExamined(EntityUid uid, HandsComponent handsComp, ExaminedEvent args) { - foreach (var inhand in EnumerateHeld(uid, handsComp)) + var held = EnumerateHeld(uid, handsComp).ToList(); + if (!held.Any()) { - if (HasComp(inhand)) - continue; - - args.PushText(Loc.GetString("comp-hands-examine", ("user", Identity.Entity(handsComp.Owner, EntityManager)), ("item", inhand))); + args.PushText(Loc.GetString("comp-hands-examine-empty", + ("user", Identity.Entity(uid, EntityManager)))); + return; } + + var heldList = ContentLocalizationManager.FormatList(held + .Where(x => !HasComp(x)) + .Select(x => Loc.GetString("comp-hands-examine-wrapper", + ("item", Identity.Entity(x, EntityManager)))).ToList()); + + args.PushMarkup(Loc.GetString("comp-hands-examine", + ("user", Identity.Entity(uid, EntityManager)), + ("items", heldList))); } } diff --git a/Resources/Locale/en-US/hands/hands-system.ftl b/Resources/Locale/en-US/hands/hands-system.ftl index f9372ae7792..7761b0c0ce4 100644 --- a/Resources/Locale/en-US/hands/hands-system.ftl +++ b/Resources/Locale/en-US/hands/hands-system.ftl @@ -4,6 +4,8 @@ hands-system-empty-equipment-slot = There's nothing in your {$slotName} to take # Examine text after when they're holding something (in-hand) -comp-hands-examine = { CAPITALIZE(SUBJECT($user)) } { CONJUGATE-BE($user) } holding a { $item }. +comp-hands-examine = { CAPITALIZE(SUBJECT($user)) } { CONJUGATE-BE($user) } holding { $items }. +comp-hands-examine-empty = { CAPITALIZE(SUBJECT($user)) } { CONJUGATE-BE($user) } not holding anything. +comp-hands-examine-wrapper = { INDEFINITE($item) } [color=paleturquoise]{$item}[/color] hands-system-blocked-by = Blocked by From 99d1d34b671817f3363593356a45e14511a4d47a Mon Sep 17 00:00:00 2001 From: Nemanja <98561806+EmoGarbage404@users.noreply.github.com> Date: Sun, 8 Oct 2023 17:02:46 -0400 Subject: [PATCH 021/127] Standardize species speeds (#20841) --- Resources/Prototypes/Entities/Mobs/Species/diona.yml | 3 --- Resources/Prototypes/Entities/Mobs/Species/moth.yml | 2 -- Resources/Prototypes/Entities/Mobs/Species/reptilian.yml | 3 --- 3 files changed, 8 deletions(-) diff --git a/Resources/Prototypes/Entities/Mobs/Species/diona.yml b/Resources/Prototypes/Entities/Mobs/Species/diona.yml index 0e34ae0ff59..6ca493aedd4 100644 --- a/Resources/Prototypes/Entities/Mobs/Species/diona.yml +++ b/Resources/Prototypes/Entities/Mobs/Species/diona.yml @@ -88,9 +88,6 @@ - MobLayer - type: Inventory templateId: diona - - type: MovementSpeedModifier - baseWalkSpeed : 1.5 - baseSprintSpeed : 3.5 - type: Speech speechVerb: Plant - type: Vocal diff --git a/Resources/Prototypes/Entities/Mobs/Species/moth.yml b/Resources/Prototypes/Entities/Mobs/Species/moth.yml index 0e144b3bf33..4198c605ddf 100644 --- a/Resources/Prototypes/Entities/Mobs/Species/moth.yml +++ b/Resources/Prototypes/Entities/Mobs/Species/moth.yml @@ -38,8 +38,6 @@ Female: UnisexMoth Unsexed: UnisexMoth - type: MovementSpeedModifier - baseWalkSpeed : 2.5 - baseSprintSpeed : 4.5 weightlessAcceleration: 1.5 # Move around more easily in space. weightlessFriction: 1 weightlessModifier: 1 diff --git a/Resources/Prototypes/Entities/Mobs/Species/reptilian.yml b/Resources/Prototypes/Entities/Mobs/Species/reptilian.yml index 43b2932fe23..5a4518c7b50 100644 --- a/Resources/Prototypes/Entities/Mobs/Species/reptilian.yml +++ b/Resources/Prototypes/Entities/Mobs/Species/reptilian.yml @@ -59,9 +59,6 @@ heatDamage: types: Heat : 0.1 #per second, scales with temperature & other constants - - type: MovementSpeedModifier - baseWalkSpeed : 2.5 - baseSprintSpeed : 4.5 - type: entity parent: BaseSpeciesDummy From 483f720bf86c4eda610fe6cc6532ee753db0af01 Mon Sep 17 00:00:00 2001 From: PJBot Date: Sun, 8 Oct 2023 17:03:51 -0400 Subject: [PATCH 022/127] Automatic changelog update --- Resources/Changelog/Changelog.yml | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 09e8bf1bf5b..c732d749b76 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,10 +1,4 @@ Entries: -- author: ubis1 - changes: - - {message: some lathes can be emagged now; emaggable recipes list has been added - for protolathes and autolathes, type: Add} - id: 4474 - time: '2023-08-07T14:21:04.0000000+00:00' - author: metalgearsloth changes: - {message: Fix crusher., type: Fix} @@ -2951,3 +2945,8 @@ Entries: - {message: Kudzu has been reenabled., type: Add} id: 4973 time: '2023-10-07T19:59:39.0000000+00:00' +- author: EmoGarbage404 + changes: + - {message: Diona now move at the same speed as other species., type: Tweak} + id: 4974 + time: '2023-10-08T21:02:46.0000000+00:00' From 3e509d763075bbc9801838100e41505da03d6179 Mon Sep 17 00:00:00 2001 From: DrSmugleaf Date: Sun, 8 Oct 2023 14:25:08 -0700 Subject: [PATCH 023/127] Give ringtone setting a 0.25 second cooldown, style and fixes (#20780) --- .../PDA/Ringer/RingerBoundUserInterface.cs | 14 ++++++-- Content.Client/PDA/Ringer/RingtoneMenu.xaml | 6 ++-- Content.Server/PDA/Ringer/RingerSystem.cs | 33 ++++++++++++++----- 3 files changed, 39 insertions(+), 14 deletions(-) diff --git a/Content.Client/PDA/Ringer/RingerBoundUserInterface.cs b/Content.Client/PDA/Ringer/RingerBoundUserInterface.cs index aee8357cdc3..a0688523f1e 100644 --- a/Content.Client/PDA/Ringer/RingerBoundUserInterface.cs +++ b/Content.Client/PDA/Ringer/RingerBoundUserInterface.cs @@ -1,7 +1,7 @@ using Content.Shared.PDA; using Content.Shared.PDA.Ringer; using JetBrains.Annotations; -using Robust.Client.GameObjects; +using Robust.Shared.Timing; namespace Content.Client.PDA.Ringer { @@ -29,9 +29,17 @@ protected override void Open() _menu.SetRingerButton.OnPressed += _ => { - if (!TryGetRingtone(out var ringtone)) return; + if (!TryGetRingtone(out var ringtone)) + return; SendMessage(new RingerSetRingtoneMessage(ringtone)); + _menu.SetRingerButton.Disabled = true; + + Timer.Spawn(333, () => + { + if (_menu is { Disposed: false, SetRingerButton: { Disposed: false } ringer}) + ringer.Disabled = false; + }); }; } @@ -74,7 +82,7 @@ protected override void UpdateState(BoundUserInterfaceState state) } - _menu.TestRingerButton.Visible = !msg.IsPlaying; + _menu.TestRingerButton.Disabled = msg.IsPlaying; } diff --git a/Content.Client/PDA/Ringer/RingtoneMenu.xaml b/Content.Client/PDA/Ringer/RingtoneMenu.xaml index a361a58dd29..2fff0ab1b56 100644 --- a/Content.Client/PDA/Ringer/RingtoneMenu.xaml +++ b/Content.Client/PDA/Ringer/RingtoneMenu.xaml @@ -79,12 +79,14 @@ Access="Public" Text="{Loc 'comp-ringer-ui-test-ringtone-button'}" HorizontalAlignment="Center" - VerticalAlignment="Center" /> + VerticalAlignment="Center" + StyleClasses="OpenRight" /> [DataField, AutoNetworkedField] public bool ToggleMouseRotator = true; - - [ViewVariables(VVAccess.ReadWrite), DataField("activeZone"), AutoNetworkedField] - public TargetingZone ActiveZone; } } diff --git a/Content.Shared/CombatMode/Events/CombatModeSystemMessages.cs b/Content.Shared/CombatMode/Events/CombatModeSystemMessages.cs deleted file mode 100644 index 819a449349f..00000000000 --- a/Content.Shared/CombatMode/Events/CombatModeSystemMessages.cs +++ /dev/null @@ -1,19 +0,0 @@ -using Content.Shared.Targeting; -using Robust.Shared.Serialization; - -namespace Content.Shared.CombatMode -{ - public static class CombatModeSystemMessages - { - [Serializable, NetSerializable] - public sealed class SetTargetZoneMessage : EntityEventArgs - { - public SetTargetZoneMessage(TargetingZone targetZone) - { - TargetZone = targetZone; - } - - public TargetingZone TargetZone { get; } - } - } -} diff --git a/Content.Shared/CombatMode/SharedCombatModeSystem.cs b/Content.Shared/CombatMode/SharedCombatModeSystem.cs index 0b57840addd..5fe763370fd 100644 --- a/Content.Shared/CombatMode/SharedCombatModeSystem.cs +++ b/Content.Shared/CombatMode/SharedCombatModeSystem.cs @@ -2,7 +2,6 @@ using Content.Shared.MouseRotator; using Content.Shared.Movement.Components; using Content.Shared.Popups; -using Content.Shared.Targeting; using Robust.Shared.Network; using Robust.Shared.Timing; @@ -89,15 +88,6 @@ public virtual void SetInCombatMode(EntityUid entity, bool value, CombatModeComp SetMouseRotatorComponents(entity, value); } - public virtual void SetActiveZone(EntityUid entity, TargetingZone zone, - CombatModeComponent? component = null) - { - if (!Resolve(entity, ref component)) - return; - - component.ActiveZone = zone; - } - private void SetMouseRotatorComponents(EntityUid uid, bool value) { if (value) diff --git a/Content.Shared/Targeting/TargetingZone.cs b/Content.Shared/Targeting/TargetingZone.cs deleted file mode 100644 index 733563d7e49..00000000000 --- a/Content.Shared/Targeting/TargetingZone.cs +++ /dev/null @@ -1,26 +0,0 @@ -using Robust.Shared.Serialization; - -namespace Content.Shared.Targeting -{ - /// - /// Zones the player can target for attacks. - /// - [Serializable, NetSerializable] - public enum TargetingZone - { - /// - /// Torso/arm area. - /// - Middle, - - /// - /// Legs/groin area. - /// - Low, - - /// - /// Go for the head. - /// - High - } -} From eb833335d924ce792a1e3086d09240cdd228a642 Mon Sep 17 00:00:00 2001 From: Vasilis Date: Tue, 10 Oct 2023 01:42:53 +0200 Subject: [PATCH 040/127] Github actions script to update ingame credits for contributors (#20345) --- .github/workflows/update-credits.yml | 32 ++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 .github/workflows/update-credits.yml diff --git a/.github/workflows/update-credits.yml b/.github/workflows/update-credits.yml new file mode 100644 index 00000000000..09844f4c19d --- /dev/null +++ b/.github/workflows/update-credits.yml @@ -0,0 +1,32 @@ +name: Update Contrib and Patreons in credits + +on: + workflow_dispatch: + schedule: + - cron: 0 0 * * 0 + +jobs: + get_credits: + runs-on: ubuntu-latest + # Hey there fork dev! If you like to include your own contributors in this then you can probably just change this to your own repo + # Do this in dump_github_contributors.ps1 too into your own repo + if: github.repository == 'space-wizards/space-station-14' + + steps: + - uses: actions/checkout@v3.6.0 + with: + ref: master + + - name: Get this week's Contributors + shell: pwsh + run: Tools/dump_github_contributors.ps1 > Resources/Credits/GitHub.txt + + # TODO + #- name: Get this week's Patreons + # run: Tools/script2dumppatreons > Resources/Credits/Patrons.yml + + - name: Commit new credit files + uses: stefanzweifel/git-auto-commit-action@v4 + with: + commit_message: Update Credits + commit_author: PJBot From e7a453e022e03cd7105fc0d852952bc9c7b3eb92 Mon Sep 17 00:00:00 2001 From: PJBot Date: Mon, 9 Oct 2023 19:43:57 -0400 Subject: [PATCH 041/127] Automatic changelog update --- Resources/Changelog/Changelog.yml | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 3302e69ee2c..908c31cf7b5 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,9 +1,4 @@ Entries: -- author: Emisse - changes: - - {message: Bounty payouts x10, type: Tweak} - id: 4479 - time: '2023-08-07T21:41:57.0000000+00:00' - author: hord-brayden changes: - {message: Added Syringe Support for Chemical Analysis Goggles, type: Fix} @@ -2951,3 +2946,9 @@ Entries: maint corridor.', type: Add} id: 4978 time: '2023-10-09T15:22:57.0000000+00:00' +- author: Vasilis + changes: + - {message: Contributors are automatically updated now once a week in the credits + section., type: Add} + id: 4979 + time: '2023-10-09T23:42:53.0000000+00:00' From ad17adfb63a933f3258b745741267c72ee9a3e55 Mon Sep 17 00:00:00 2001 From: brainfood1183 <113240905+brainfood1183@users.noreply.github.com> Date: Tue, 10 Oct 2023 00:49:42 +0100 Subject: [PATCH 042/127] Polymorph Artifact Effect (#20660) Co-authored-by: Nemanja <98561806+EmoGarbage404@users.noreply.github.com> --- .../Components/PolyArtifactComponent.cs | 30 ++++++++++++++ .../Effects/Systems/PolyArtifactSystem.cs | 41 +++++++++++++++++++ .../en-US/xenoarchaeology/artifact-hints.ftl | 1 + Resources/Prototypes/Polymorphs/polymorph.yml | 34 +++++++++++++++ .../XenoArch/Effects/normal_effects.yml | 17 +++++++- 5 files changed, 122 insertions(+), 1 deletion(-) create mode 100644 Content.Server/Xenoarchaeology/XenoArtifacts/Effects/Components/PolyArtifactComponent.cs create mode 100644 Content.Server/Xenoarchaeology/XenoArtifacts/Effects/Systems/PolyArtifactSystem.cs diff --git a/Content.Server/Xenoarchaeology/XenoArtifacts/Effects/Components/PolyArtifactComponent.cs b/Content.Server/Xenoarchaeology/XenoArtifacts/Effects/Components/PolyArtifactComponent.cs new file mode 100644 index 00000000000..8edeb77a67b --- /dev/null +++ b/Content.Server/Xenoarchaeology/XenoArtifacts/Effects/Components/PolyArtifactComponent.cs @@ -0,0 +1,30 @@ +using Robust.Shared.Audio; +using Content.Shared.Polymorph; +using Robust.Shared.Prototypes; + +namespace Content.Server.Xenoarchaeology.XenoArtifacts.Effects.Components; + +/// +/// Artifact polymorphs surrounding entities when triggered. +/// +[RegisterComponent] +public sealed partial class PolyArtifactComponent : Component +{ + /// + /// The polymorph effect to trigger. + /// + [DataField] + public ProtoId PolymorphPrototypeName = "ArtifactMonkey"; + + /// + /// range of the effect. + /// + [DataField] + public float Range = 2f; + + /// + /// Sound to play on polymorph. + /// + [DataField] + public SoundSpecifier PolySound = new SoundPathSpecifier("/Audio/Weapons/Guns/Gunshots/Magic/staff_animation.ogg"); +} diff --git a/Content.Server/Xenoarchaeology/XenoArtifacts/Effects/Systems/PolyArtifactSystem.cs b/Content.Server/Xenoarchaeology/XenoArtifacts/Effects/Systems/PolyArtifactSystem.cs new file mode 100644 index 00000000000..d192e928d8f --- /dev/null +++ b/Content.Server/Xenoarchaeology/XenoArtifacts/Effects/Systems/PolyArtifactSystem.cs @@ -0,0 +1,41 @@ +using Content.Server.Xenoarchaeology.XenoArtifacts.Effects.Components; +using Content.Server.Xenoarchaeology.XenoArtifacts.Events; +using Content.Shared.Humanoid; +using Content.Server.Polymorph.Systems; +using Content.Shared.Mobs.Systems; +using Content.Shared.Polymorph; + +namespace Content.Server.Xenoarchaeology.XenoArtifacts.Effects.Systems; + +public sealed class PolyArtifactSystem : EntitySystem +{ + [Dependency] private readonly EntityLookupSystem _lookup = default!; + [Dependency] private readonly MobStateSystem _mob = default!; + [Dependency] private readonly PolymorphSystem _poly = default!; + [Dependency] private readonly SharedAudioSystem _audio = default!; + + /// + /// On effect trigger polymorphs targets in range. + /// + public override void Initialize() + { + SubscribeLocalEvent(OnActivate); + } + + /// + /// Provided target is alive and is not a zombie, polymorphs the target. + /// + private void OnActivate(EntityUid uid, PolyArtifactComponent component, ArtifactActivatedEvent args) + { + var xform = Transform(uid); + foreach (var comp in _lookup.GetComponentsInRange(xform.Coordinates, component.Range)) + { + var target = comp.Owner; + if (_mob.IsAlive(target)) + { + _poly.PolymorphEntity(target, component.PolymorphPrototypeName); + _audio.PlayPvs(component.PolySound, uid); + } + } + } +} diff --git a/Resources/Locale/en-US/xenoarchaeology/artifact-hints.ftl b/Resources/Locale/en-US/xenoarchaeology/artifact-hints.ftl index 1da33c3232b..48a6f49408c 100644 --- a/Resources/Locale/en-US/xenoarchaeology/artifact-hints.ftl +++ b/Resources/Locale/en-US/xenoarchaeology/artifact-hints.ftl @@ -18,6 +18,7 @@ artifact-effect-hint-soap = Lubricated surface artifact-effect-hint-communication = Long-distance communication artifact-effect-hint-phasing = Structural phasing artifact-effect-hint-sentience = Neurological activity +artifact-effect-hint-polymorph = Transmogrificational activity # the triggers should be more obvious than the effects # gives people an idea of what to do: don't be too specific (i.e. no "welders") diff --git a/Resources/Prototypes/Polymorphs/polymorph.yml b/Resources/Prototypes/Polymorphs/polymorph.yml index fe4f80811f8..c710d83cecc 100644 --- a/Resources/Prototypes/Polymorphs/polymorph.yml +++ b/Resources/Prototypes/Polymorphs/polymorph.yml @@ -102,3 +102,37 @@ transferName: true revertOnDeath: true + +# this is the monkey polymorph for artifact. +- type: polymorph + id: ArtifactMonkey + entity: MobMonkey + forced: true + transferName: true + allowRepeatedMorphs: true + inventory: Transfer + revertOnCrit: true + revertOnDeath: true + duration: 20 + +- type: polymorph + id: ArtifactCluwne + entity: MobCluwne + forced: true + transferName: true + transferHumanoidAppearance: true + inventory: None + revertOnDeath: true + revertOnCrit: true + duration: 30 + +- type: polymorph + id: ArtifactLizard + entity: MobLizard + forced: true + transferName: true + transferHumanoidAppearance: true + inventory: None + revertOnDeath: true + revertOnCrit: true + duration: 20 diff --git a/Resources/Prototypes/XenoArch/Effects/normal_effects.yml b/Resources/Prototypes/XenoArch/Effects/normal_effects.yml index 8deeebcc55c..040f688403c 100644 --- a/Resources/Prototypes/XenoArch/Effects/normal_effects.yml +++ b/Resources/Prototypes/XenoArch/Effects/normal_effects.yml @@ -1,4 +1,4 @@ -- type: artifactEffect +- type: artifactEffect id: EffectBadFeeling targetDepth: 0 effectHint: artifact-effect-hint-mental @@ -405,6 +405,21 @@ components: - type: EmpArtifact +- type: artifactEffect + id: EffectPolyMonkey + targetDepth: 2 + effectHint: artifact-effect-hint-polymorph + components: + - type: PolyArtifact + +- type: artifactEffect + id: EffectPolyLizard + targetDepth: 2 + effectHint: artifact-effect-hint-polymorph + components: + - type: PolyArtifact + polymorphPrototypeName: ArtifactLizard + - type: artifactEffect id: EffectHealAll targetDepth: 3 From 4ea05ccfb82b19e7079cbcd4da82b53e11efa8f4 Mon Sep 17 00:00:00 2001 From: Fluffiest Floofers Date: Tue, 10 Oct 2023 04:05:18 +0200 Subject: [PATCH 043/127] Job Spawner icons cleanup (#20872) * icons * minor fixes * another minor fix --- .../Entities/Markers/Spawners/jobs.yml | 54 +++++++++------ .../Markers/jobs.rsi/atmospherics.png | Bin 1071 -> 978 bytes .../Textures/Markers/jobs.rsi/bartender.png | Bin 942 -> 978 bytes .../Textures/Markers/jobs.rsi/botanist.png | Bin 927 -> 1009 bytes Resources/Textures/Markers/jobs.rsi/boxer.png | Bin 734 -> 1056 bytes .../Textures/Markers/jobs.rsi/captain.png | Bin 1028 -> 1112 bytes .../Textures/Markers/jobs.rsi/cargo_tech.png | Bin 923 -> 872 bytes Resources/Textures/Markers/jobs.rsi/ce.png | Bin 1144 -> 1132 bytes .../Textures/Markers/jobs.rsi/centcom.png | Bin 6917 -> 977 bytes .../Textures/Markers/jobs.rsi/chaplain.png | Bin 902 -> 807 bytes Resources/Textures/Markers/jobs.rsi/chef.png | Bin 1006 -> 880 bytes .../Textures/Markers/jobs.rsi/chemist.png | Bin 1035 -> 944 bytes Resources/Textures/Markers/jobs.rsi/clown.png | Bin 921 -> 896 bytes Resources/Textures/Markers/jobs.rsi/cmo.png | Bin 1136 -> 955 bytes .../Textures/Markers/jobs.rsi/cyborg.png | Bin 736 -> 434 bytes .../Textures/Markers/jobs.rsi/detective.png | Bin 965 -> 1031 bytes .../Textures/Markers/jobs.rsi/doctor.png | Bin 1109 -> 899 bytes .../Textures/Markers/jobs.rsi/engineer.png | Bin 1035 -> 1121 bytes .../Textures/Markers/jobs.rsi/ertengineer.png | Bin 1210 -> 1064 bytes .../Markers/jobs.rsi/ertengineereva.png | Bin 1103 -> 932 bytes .../Textures/Markers/jobs.rsi/ertjanitor.png | Bin 1122 -> 1049 bytes .../Markers/jobs.rsi/ertjanitoreva.png | Bin 1209 -> 983 bytes .../Textures/Markers/jobs.rsi/ertleader.png | Bin 1161 -> 1021 bytes .../Markers/jobs.rsi/ertleadereva.png | Bin 1158 -> 969 bytes .../Textures/Markers/jobs.rsi/ertmedical.png | Bin 1128 -> 1029 bytes .../Markers/jobs.rsi/ertmedicaleva.png | Bin 1185 -> 935 bytes .../Textures/Markers/jobs.rsi/ertsecurity.png | Bin 1128 -> 1010 bytes .../Markers/jobs.rsi/ertsecurityeva.png | Bin 1245 -> 902 bytes Resources/Textures/Markers/jobs.rsi/hop.png | Bin 945 -> 948 bytes Resources/Textures/Markers/jobs.rsi/hos.png | Bin 1020 -> 1034 bytes .../Textures/Markers/jobs.rsi/janitor.png | Bin 905 -> 987 bytes .../Textures/Markers/jobs.rsi/lawyer.png | Bin 855 -> 849 bytes .../Textures/Markers/jobs.rsi/librarian.png | Bin 748 -> 893 bytes .../Markers/jobs.rsi/medicalintern.png | Bin 0 -> 831 bytes Resources/Textures/Markers/jobs.rsi/meta.json | 63 +++++++++++------- Resources/Textures/Markers/jobs.rsi/mime.png | Bin 764 -> 795 bytes .../Textures/Markers/jobs.rsi/musician.png | Bin 707 -> 821 bytes .../Textures/Markers/jobs.rsi/paramedic.png | Bin 1143 -> 922 bytes .../Textures/Markers/jobs.rsi/passenger.png | Bin 840 -> 805 bytes .../Textures/Markers/jobs.rsi/prisoner.png | Bin 828 -> 930 bytes .../Markers/jobs.rsi/psychologist.png | Bin 720 -> 812 bytes Resources/Textures/Markers/jobs.rsi/qm.png | Bin 1082 -> 911 bytes Resources/Textures/Markers/jobs.rsi/rd.png | Bin 1046 -> 916 bytes .../Textures/Markers/jobs.rsi/reporter.png | Bin 881 -> 802 bytes .../Markers/jobs.rsi/researchassistant.png | Bin 0 -> 800 bytes .../Markers/jobs.rsi/salvagespecialist.png | Bin 0 -> 881 bytes .../Textures/Markers/jobs.rsi/scientist.png | Bin 982 -> 878 bytes .../Markers/jobs.rsi/security_cadet.png | Bin 1117 -> 889 bytes .../Markers/jobs.rsi/security_officer.png | Bin 1001 -> 1044 bytes .../Markers/jobs.rsi/seniorengineer.png | Bin 1272 -> 1098 bytes .../Markers/jobs.rsi/seniorofficer.png | Bin 1056 -> 1041 bytes .../Markers/jobs.rsi/seniorphysician.png | Bin 1083 -> 990 bytes .../Markers/jobs.rsi/seniorresearcher.png | Bin 1195 -> 957 bytes .../Markers/jobs.rsi/serviceworker.png | Bin 0 -> 861 bytes .../Markers/jobs.rsi/technicalassistant.png | Bin 0 -> 952 bytes .../Textures/Markers/jobs.rsi/warden.png | Bin 1079 -> 1149 bytes .../Textures/Markers/jobs.rsi/zookeeper.png | Bin 4175 -> 931 bytes 57 files changed, 74 insertions(+), 43 deletions(-) create mode 100644 Resources/Textures/Markers/jobs.rsi/medicalintern.png create mode 100644 Resources/Textures/Markers/jobs.rsi/researchassistant.png create mode 100644 Resources/Textures/Markers/jobs.rsi/salvagespecialist.png create mode 100644 Resources/Textures/Markers/jobs.rsi/serviceworker.png create mode 100644 Resources/Textures/Markers/jobs.rsi/technicalassistant.png diff --git a/Resources/Prototypes/Entities/Markers/Spawners/jobs.yml b/Resources/Prototypes/Entities/Markers/Spawners/jobs.yml index 62945a0ed88..1e0ef876a0e 100644 --- a/Resources/Prototypes/Entities/Markers/Spawners/jobs.yml +++ b/Resources/Prototypes/Entities/Markers/Spawners/jobs.yml @@ -73,7 +73,7 @@ - type: Sprite layers: - state: green - - state: miner + - state: salvagespecialist # Civilian @@ -96,6 +96,10 @@ components: - type: SpawnPoint job_id: TechnicalAssistant + - type: Sprite + layers: + - state: green + - state: technicalassistant - type: entity id: SpawnPointMedicalIntern @@ -104,6 +108,10 @@ components: - type: SpawnPoint job_id: MedicalIntern + - type: Sprite + layers: + - state: green + - state: medicalintern - type: entity id: SpawnPointSecurityCadet @@ -124,6 +132,10 @@ components: - type: SpawnPoint job_id: ResearchAssistant + - type: Sprite + layers: + - state: green + - state: researchassistant - type: entity id: SpawnPointServiceWorker @@ -132,6 +144,10 @@ components: - type: SpawnPoint job_id: ServiceWorker + - type: Sprite + layers: + - state: green + - state: serviceworker - type: entity id: SpawnPointBartender @@ -246,24 +262,24 @@ parent: SpawnPointJobBase name: musician components: - - type: SpawnPoint - job_id: Musician - - type: Sprite - layers: - - state: green - - state: musician + - type: SpawnPoint + job_id: Musician + - type: Sprite + layers: + - state: green + - state: musician - type: entity id: SpawnPointBoxer parent: SpawnPointJobBase name: boxer components: - - type: SpawnPoint - job_id: Boxer - - type: Sprite - layers: - - state: green - - state: boxer + - type: SpawnPoint + job_id: Boxer + - type: Sprite + layers: + - state: green + - state: boxer - type: entity id: SpawnPointBorg @@ -349,12 +365,12 @@ parent: SpawnPointJobBase name: atmospherics components: - - type: SpawnPoint - job_id: AtmosphericTechnician - - type: Sprite - layers: - - state: green - - state: atmospherics + - type: SpawnPoint + job_id: AtmosphericTechnician + - type: Sprite + layers: + - state: green + - state: atmospherics # Medical diff --git a/Resources/Textures/Markers/jobs.rsi/atmospherics.png b/Resources/Textures/Markers/jobs.rsi/atmospherics.png index b25133c96d03d88433a010761c1036b3ef3e2d08..3f95cfd233ffa25ad106ebc3bcb7bcf0f35f35c4 100644 GIT binary patch delta 957 zcmV;u148_-2+{|TBYyxHbVXQnQ*UN;cVTj606}DLVr3vnZDD6+Qe|Oed2z{QJOBU# zbV)=(RCwC#S4&8gQ561emXw7vrXpqI_`s4#q#Ue;Ii^AhCYf#o7bUGU3tP1cH$f06 zrVD9NL6MtK(M1+0zN)Ew6p2XUn3D$ioY4|f^!A_Y|Bv(g8h;TYm{wCk<_1&@+~&r9>N z=VlR986*>tp6oW-R;v!z;CyUxG&}(pYyGW)lkBQ@O=7Lzr{VqxZj^BN1%h9{tkN}B zLzJ9$ZBAX{S6Ts#3<3}Gm^MccmIhW(B7!PJL1%pL3(j70F-T8#WUomVh%y)C0q;wN z9N%7|(tlel7M1MOOZMcqp8Mdo0<^1QuRKvsMOG*vAYkE~lNlOj<;ySGk-e+krh(|E zbd0YD)obxK>3mBUjwJ`VqV(vkl(mDa`fVzKE9VLc-7st&kmgoiZmEJfs1A*96LCkn zl(}zm#O_lvPB?vvB&5`bgu*}c2zu(8w1Hykb$=ifgEbSVczO)e-V?Z+9f`we7F;?6 z1nTw)TMAD0l(Z&LJmdHcPu+gl`>gn69m3?FdBJVtGq{lKDfsZ{But@R!k+9Flhy!= z>G7fY(d=6+Cd$YSdpz)cb`Hc9BKcZUFj}oscv$(7x%#;M=v@yIDntno(kZ-2MnIC4 zv44@@Ump^>l7x!X-_3H1bx24^j}y_^R2hWicGdhbT1p-A%SZhG|AK#-Ky&rR);0eu zudQ1S*R=}l`fNObHM^kaagl)H#=c(|8yRsL#>U19-qqdBjz>g@^_G?vr{6(8KV}X& zAfPz>YW~)bpu4k^r=_Qhzy^as6-)_E>o%k(JF?fT0z}Wg*;h15NJwDy_4O<2vV!#j f58PGYuK)u8>CF3|Rxnh|00000NkvXXu0mjf6*JXH delta 1051 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 diff --git a/Resources/Textures/Markers/jobs.rsi/botanist.png b/Resources/Textures/Markers/jobs.rsi/botanist.png index 8e8137721440629e281e05cf9d6beb6c550d2c8a..3cec3fc7dc9c1597371b8d5169e3b6b9f3c59a56 100644 GIT binary patch delta 988 zcmV<210(#O2k{4xBYyxHbVXQnQ*UN;cVTj606}DLVr3vnZDD6+Qe|Oed2z{QJOBU# zlSxEDRCwCNS6xU{K@>idk-KH>Zmx+DySnK^keVopxG33=5J^9l*bhkc7Kvo+Lsp0n z6(ZP!zW9(*m~3JR>5G!0l9Z;IC1$Lyx|ZQjy4MtUBbn}*{eO2?L-%eT7|xuZx!<`n zXU@5oP)cDlX$x#JZF&G(*D~sAAGyd8=Wc>jDrIx(basR%Z9T5pZ~zQ6KG{u2 zS0s*ACN55f9`AR+6CoJ)xy4N{iA<#uiG*+*XHh6(0lM0~4B(ezN|bR>+S6+XC!r^S zjyBji>UGWSlz)G7;%U7gNq8zK5PoxuY;Nv*?!s+)pWOn3!9W!X1sUt^VPMPiCYbmz zz&OgNk2sP{d=>zL=jP^81VJ#rT_TY0S2B*WGA@>EWCzHam5{hTGcA7)ZF=((%w@~K z{hV_oV4w{AZ}`D+^;u|qFhy2mtuQ-);CrLQY@V(?&woH|17#$%qo3eMfDaA7D1+?> zMSQjCg^&Xx2D(kMgK?Bmk9PE1PZ0kMK$PA`o4yV@6w(-YQmkR1Y2_yvM;Y}tLVsK* zSRsm$$>8zr8pz5_cL{<~1K7bAdzV04Qx7r0G8mW~_dW^J?gX=~M{paNIlj7>lK}iX z9FA7mUw^XGuDbRx6Nakipz;1B@#+ZXyO$s(@)(%vqg@|_ptj*e=!gEe&g&ysoc;qN z(+jRjKG{H=t+MB4J$aa`}(u|dUcs4h!unBh5jsGjj}bx@Z*b#^?vMp ztQ&&(|NNL>!B&>axNI1IHfxRvW6YuQD+uzyAsC9D*;jV!?I%nYpn6O?IYAvnO2 z=xwd7pvXDQ=93E)DvC`|mt9MD%jF~`ELFf#KZH1f!Tx@FCL;sXYBdyTI~kZWp^SR8 zqaXSU@=>a*wEP=ZjT${VrKYBmmX;Qew#%VXwoMUN*8VsAE5HDWVXhgmW$nEH0000< KMNUMnLSTZXn%W8g delta 906 zcmV;519klI2cHL!BYy*CNklyUr1DW6vsa|f;$qkjcgc0PBSiCaLSCyhgw{$ zETyIG!6kakqKC5V#gNFr2a)YTSg0A8AR>GzkRj;LLx>qHxiQqHW8qpikXe!ZQ!@QA z9V$-`_v$#VIrmQ4OJ6w5+~4n>b3VV{nctZoeD6}SaVjX^B!BZg2W~&iD%P^Ek$iT1 zsR8CEmuX4+{Ap*2ZHVP|9p*|=6z6)<^0e)oUN6>YhM}dd!@1V7%KFz27Nk8hI zm?a2HjVO?t%f(Y|xH(|-0#_iF^rrEwX&Sn&bMaIgfz`S6jSN}|z4#7PHsr~nGyCWp z=>_2Au|8uWSqiQ|%95pNetjdo96GblQYkW);Prz^wr;2(d1IpjbGlu!G-Y#?ys=T) zx}k#C4}T^zg$6Q|U}Ee817mN~#_n8Si+B6tK^OAN3Sj8MI6ne8fDc5|G-E>TN?&J5{{_S5i2sfp4t66Vnq^;s6ug2C^6nI2Y>OUPVN_|#7quQ92Cm#3Y#TmMiRq{ zgYrM049Z-Be=^(~H=B9XF0(WieCEjZzu|1M#hz`*7J%w4ORZAvN*O?++n8TU0Dz;H zLk7e=J9;@}J2_-|DXp$=;rYK)wEr=xR5s*^+wZ{W7WQR(2PV1~KINYq&m>zrki#I) z{(nkuu@hq-cxJZU90o})6~NU@nq6F^v1)fL~ML=3?h8*7r$i!f*0E!v~jJ((^AKMB$J;Wv5_tbd;M+CN}ca zE}aEt=HPtxN@C(kZmvAaQWgL?udlD?N}+ ztYejU^|u$g&yS&|%!!enUX*Rqjt{6_I6Xe7AAbUg_khPAfIg50y@tUT;KJ%#iG3LvC>G`Dr+ir^j}k26>_c_G$H#0j$~sU0q%H^Fj^J6wNdw zE`OYJ&26l;s)}bTs~?>A3k&$Zt&KIEt>Rf)kv*}F-?p-ZnoyqamPSNQz&i2h_$o6q z%=e2Omxzpn;E~6JmX|gbIUme*4avC+B7qzaibX)USOgInNJ?MD{XxeBtur$$mOLf5 zA;Gk$v3-7iO_t*%P4`&>xGJj(;4*bSuVt5B&enXx$~~8k)t_#01Ay6K;v; z`JSNM+1UxlnTwJZa|jlz6^?(0c}{LFtJs~DybSa?9Q@nrYLu6kM;jAqtJPR*dQh>52eDX? zuYZ7g^P+eYp+b8oJ?J4|J$Ue_h@~Ljy;&7e&;b>+>QQS-t2Hs2+HTWLCY$Wc#_=!_ za>*ubm0tEaJ}}SoexB#^{V=sOP2J3hZff@)Ko6h?&;vmK^?!WyWe8;pExeA?X=?ly?7Jv;`X)tG`{fTv4SW_txqCQ~48@*ZDl{;j>MVUK zEgZu8U3zo{m>y1y&F6-PV$J!hrkd5X57ZNT#9M#@d*EeySc%?A;;7-#&&N=#1 z!$&x#(ndFc4K*+sLOG4|8OvGWe8vZ=wYTmV(cU>=Ie#kM5|{cqr7JNjomKH@-5Yzi zy9XoqbCW4I1c>nX?tbMett@x%V3i-+HRQfsgX$xR)vVBN*K{H-w>v)nYtdKpx&DFJ z1uWuK#Mc8bi?`3V)FNsTM;EwXb>DN1mU=yLaWR)&UDn77li$sG@9SCLH(G`pE1JWJ zBly+E0)OlZa57D6{pgGNt*As5p}kaSF0}kS(-dK8xvhDj;e|7oe1dGLFoym3I8AHE zH}Qe4BAmeQml@x|;e=yXcs|QbVa9^I=(ua3-^E`l(ZPusEMOZ0ZB=giz)x z^C{Nlx8s@N#408_)%zb^$vuUWc<%qQ;(z1m5J1X8rHh9#P)|J4&b?G}YKzTp2w;7L tb#|LxL-YR(;6~!6{}1#4dH_9ue*n>Q0Hvb1_>KSo002ovPDHLkV1khbW%d97 diff --git a/Resources/Textures/Markers/jobs.rsi/captain.png b/Resources/Textures/Markers/jobs.rsi/captain.png index f32f53e4625bc7577f8bc0a5542757f5e9d534f8..9b9b6cd9a992a7ae2385634b4e098a0424a6f78b 100644 GIT binary patch delta 1092 zcmV-K1iSl$2-paaBYyxHbVXQnQ*UN;cVTj606}DLVr3vnZDD6+Qe|Oed2z{QJOBU# z`bk7VRCwC7S8Yg?SrmS*h7760BomdJ%}zNB3l5tYuI6Oq1}*htDWOP{j6htlAX+vv z@L!8XyFvYl=)<;IV=eo+6qu=5nU%#lw2R|fX*soPI*g;tDt~%=&l%ros?p}-^}yxc zd(L_9`Fifh3n?W&)n+2uSv;dKoOP+qLll&-<0Kn)Jh~VdkK6Z%Xx560#`w4~9kol3 z@tk^^tBz>ufb+_6Zo#CxSBHeb9#}1lkdbNOp60|4^?l44uw>_RpR}P$Qq6ByP9oty z7qV`aC?#-mPk(dblbrPUgT9AhWgsjJn9XK+IP*6oA1qd8CdBpLgsvCJyB7}~{E_F@ zuLtUZ(~91qZnMO)EP;;J7&9>9?|Pdri|yYxh|XUpQ~H%K!gt z!KBBBfzBrwYrBqky$);34zNypd%Ktu2ZU)A^p;$S1u$r;f)%*CwGmy;*NlVU6HyZk zlsziu#ebQUNNMY(mmT3=jhy79r+EfwZ+pL7!(;uOT8@^sqDoWC*Kt-nt4sa*f8B!j z`cFcW3{c&JjZ^B$7-2zeYDq{=MEZ;uEkQ_8si`MpAKektrQqnN9gg`fpeQ_>s`;!} zQ_j(cT4f2Cce}67$L8?DrJd}Qwl*s)!=!3_3SJV{_ z$n9Hga9Af}1L4Z_G?|j5L(eNW`d<$UefBoVh*yl0Bkx5&&G&TtF47hmW%^E6`LdM>!-S9iUdS0mC#gu{MZx6}wg-aM<)Cb@BrwRx7 zEq_3Jzq}ze!1sM!6ws%Bt#V`j{D6`8S6xV&uY-5YhsniO#z2#gUyEvaZd|GO91(L+y!*Yz7>-;1Hj!+#*LtT@1)i z9YkT@1$@+=&6ayl49%#2Vs8qpyF0{(uYY4r-vcU9z%Yn&QwO~A+@s%4n- zXSvoCkpqP4Smc^yV5XW!i-m|V@b8<^kcLzq$u)JL``j<|5Jk&VFNOvO8EmIpcEMmU zu)Mjs86_npJa)U?$SXaiG{_XAQLHs5L3zMxQ-Z%84!OCo5H_0)O^uCgESP9cd_9tr z9_efHBy*nk|J&K0xkD-y6cmW2rlydx9iJQcK(g%GH>(401sDMBnL~myY*xqs0000< KMNUMnLSTaJj2QX= delta 1007 zcmV01Ao|(ak6_V1#slv&-v)u zK>%*f4kr~WC7H=nJQalMhXDxH50m1lFiHLE1Y+pwwe#$;n{@TslMMkRkOI4>Qla`` zE=;D<_WK(f>~-m9DSvo{>ekAH(qU1dKOJBvH-*unLspUKV1 z=C?ooHdOz0IFVTNowMR2spfc?Jq9n0oy!1Q$O(i+s_mE z=@-*}&)r$v_fiKnB?WvV7ni3;S-d#3J&Vxc^-Ds*V1H1CVaRj*q%w=j{1%n0FX_b(R#cz7;QB z0l?*Q0e_I0okM!$5}DaKFuK+s8)p^q3Ha(n&b|#n=f3-z*|GDybLK~8$Ig@WV%bKr zIr}WBU|oTUHZ!OBg$GDWOQWmTPFh+T`Gp7mahw&T#xpiP*+xS{26GcD?0IChZ+?EB z%)E!lEH34XY1m&}daM6S(=Xio9{Ijh&Yk;}#(#-K=&Zv`w@p%p!sF?h>9)x*3>k(Y zhu1HM*RQ^Iv)oMEdY{eah%Z-Fvluu9RV|d==p!19a@S)|0dRSG6oAExLm+|8hG7`& z*}a>OKm7!%TEJNXou$cdNHg6wg~!t+Wr(U~1p)z8S67>Ff9gc4`q~ka00ja8flMDO z3V&>ls%G)rr~rb&pzzfRU!8W9?9kE2?E=gz7z}E?&t^zWo>*Dl!cHx-Y}>hJU%HZT z6(n~ibQXfMkmbQwZLxN;NcvF9rT)L)|8oM{g#Rgl^|Eg<4VKZ^h*{&|@pJ*){@mD@ z_`jm%lIiW~5kTw9HRSGEb^BmOw%VfA&1mNO4N?DA4*EpuM$Kk`!53(A4Cl z4(&y;iEE2&I0Nc^Bn;ac3K4b0jDy$X;O7<>#ULK+a zPxn8i-17JJ;%nVQlcBSe(CY$vAjg!`hKd;o27??NW<#5S0h6Se9JeVYOsCWQF#8Az29zU> zhP_l=O@9fD_`0BO^fmPv=i1BY^@1b>12TBx!A;HH?xub21C*SevF2NVUMF%BMGKjj zoLQ#k#?}H~fWse2Te2e(9~)Jd+gI-olkw%kl=kwmSDluSS`CawdU=Oy@&`xspq&Hp{As!9(hCMfoHLEGzau#@f0)-muY z7E99x1_#OK^HF$eii61mYuIree(<+sQ<|K}Ki%U6)zqoCx0i*(Vbg2p58AmHc`laz cH~b^O08)a3xGCvNcmMzZ07*qoM6N<$g0Ebgod5s; delta 901 zcmV;01A6@E2AczF=!iC7{`C7YivnyNOkIf5)=s%ap6J>&Y(;! z8sa51r7aok7Fx1tX%`JH3AisV33v!(a3Ee9YAA*@GzAYWB!i2FVp80p)c6pF+==*% zX+ZG>$*!xs4&n~kO?-DsLWca8d-~qJ@B6*~>3urE>n^32MSo|m9F)6bbCuPea>ZUm z@x9_fibU-dQTr4o4_)x%V-GIT{-;wvsuPhN*j*f8^3Vm;zMh^ybbu%A&Q3r1rMTnz zq%BcY_~2@^M-dso)AW14?zr}TOO>=V#x7k9rLAGBq06@PM zV|wr!$#_49Gk=356bc1~iV2K-oPU|y7cug2hKdOag#xX)cW@ks zQmGUgB9sG;<6xR50JU0;uV>!&A%=bmY1hmHfDmhNu? zaB5iF5jRZ}UDrdo5a__h#)b!@K*xcLpZy7dk&pZLc@B8@dFz7o#$J=QZDZT^Gv}A? zZ!%O&M1Niv8esV7o18dy1j|`x_-IAWRF?p_d&lL}u;x2poLR;&3;<>?SLFVbMlN%J z#pM;geI5W$11Svv%d+_D!^eQi@4q!M>sx&KjRjJ&q;&eg{`XHZkkYW6^)RV}0o-N_ zEt#NZuaZuunf)V&Wm)8MImX7uSp0hu>-cfr+#q--tqyj*pK&HQ~g>gtFIM bnB4yXsfA!CoGG0e00000NkvXXu0mjfcHFx7 diff --git a/Resources/Textures/Markers/jobs.rsi/ce.png b/Resources/Textures/Markers/jobs.rsi/ce.png index ec40156f1f56eedc067192e265ac9427e4e0eeb3..5721c2864669949686526aec95a7ead898488d49 100644 GIT binary patch delta 1112 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 P015yANkvXXu0mjf&**qr delta 880 zcmV-$1CRWt28IWaBYy);NkljAieMV{P@1l`@D|?x4=(7BDb*zQ2%L=XS>Mne|~!YTYuzuwu{6vJr7VU7G-jr zW;b{6SwSA$e<-ocV>b;YjYzRrly!nWRn(S<`GQq;OOXx_4Rcr?>;4nqD0EOPjOvWDwT@N zvY(s4B+BJ7^?DuCG^y2UY*n7{`okGpl_%6{H4MX`UVpDsE|;^q1TxeBfa|(q7zV@P z5P-$S#cMk8+Vb);zVFj&weIE?xUMVtd_EaFj)UiUc>Q;1nuhkdAvul%Kp2MP^Lbp? z&2$^)ZbY_iv$L~<+4(|B(==?`p4U}6fq3^}7%~_PuB=UFWfFtIV6H5rW*`ned8W-~ z6Vo(r)PHZaT1reJ3l?TAZfX(xWf`A|hlJV*3 zDTr{QD3nSibTx;rs(c)cv$#$tFp7i)RpGDE7=OocSX)~Iz_P4F=lSQS<2ZERbkS86 zT~!I9bP_WOGRz*al*X_#NMng=~ltQ5(0EI$9 zOw*LNjfV8PT@ev^QLSeFHP6I!Z*T8Lhx_~c%B;04zW)Y`!lal#fTp diff --git a/Resources/Textures/Markers/jobs.rsi/chef.png b/Resources/Textures/Markers/jobs.rsi/chef.png index f8eae67a886addb0d0a881b4c4da914e28633f7d..61ec06f3c946d70efc4f2f6c96d22c4fa707c0de 100644 GIT binary patch delta 858 zcmV-g1Eu`#2k-`vBYyxHbVXQnQ*UN;cVTj606}DLVr3vnZDD6+Qe|Oed2z{QJOBU# z5=lfsRCwCNSHEvkQ4~J6F%Dt^3JeZXS|#aXqP4itlmruprol=zE`sUcuIWGE3~>;XCKYQF2Cc-w4%U`}#5f2wP-SuO`o8;eU*YzZAAj=DlN`>y=iK|g?;h?w z?>@#kr~fHKy$nt!le|Uvv(voO9j`_Z;cmAFL#CKuJXn!sKG*;VD%K82?ph_?pq;NP)^$*#7G5eX2u=RRfcX-Yd zymEq8-JdlME*UO;LJOt?Y!rPg@5zqD%V!d%;sCN2`{^y^sC+w?Q>^O(8<88 zun_4V*eNKN%iQDfu+Q)EG(LNaDwPVoN!$|_efWJBr`W&<09*s(*AtHfXyL^Za-A9$ z7Jc}uM}~W^YN&(e9O8^fq7K;K1nNSse#8ncO z5YShyiv&|u_v_M3qHh8cT&~WH0DNm}YkV(Ddn7s$=xP(9^rq8kqg}1;w8UL5r}0j} zxNb{z$3lcvL?RIbT)un&*iJAW^N;}4tiDQdE|(K_VPQcW!)9=q3HYF~Sd83mHv@4w zudg~#D1Q_v5C{mXO7q_!+cNd-=Jk|;+Y_hBJG4W0uU$f$O8~iIbuU0ZJy_(9kx_DM z^Dy6%x1rs6O#27*?v#Yia> zZJc$r4m4Lo#ML>S>HuqZD`u?q1OY&v_k#qdK!07JW%q&RoenEijScKpoXKPiAY?*j zLnUI_t=LQ&jRx6lHd8=Ja9|mbvbD7(!2EtcgGC?2{z(QlHa7P8c6WD$4xE5?FBICz zXBh$QEaRd{ueA@7@71a}PdDf1$>DH__{z!(MWa!@0M%;rFqNX2>1lr4g=jOSe;Yn7)l3J4LLrvTW=&%^ kybe*2eDm$U4gUx*0HEF-`k^T89{>OV07*qoM6N<$g7SfvasU7T delta 985 zcmV;~119|N2JQ!tBYy+6NklLZi9KY++xx9De8AbADgWxxe!}7yeHO27?ld#eYOZ^2%T^D6fS?K9suo z8>KkK zH*b($Ti2hmn>R`(P*NWNc>1|3ufDsxTY|x$;iG6M11^_KU@r?Nei`F-TQdMZeA3K` z@XuuJeSLlU`-ein<#LJF>&?;G-?8!axCX#iVGXj~;==wM3(v0~1e6Y00h~LlD^*g%F?RKM- zGF*xS37AYK91aI=x0^s9kn>@AJf0j0aDD0yfj~gH-EM3)TcN!R6PTO(ou;NH=I7^M zvibe~9DkYPH~)YSo6oSYuwaP9zL=gE6WMw!j~;3=JuxOur&A_}LozuW(&vEex}l*# zoKB}qPmIZ~_08A1bAonVH$g z`+pD!h}vakWr^s@GDie7O+zV#h+s0A^v-9r17>0PIvyApP$G(tKWe4Ez8<9%KA%r1 zrKqc`qqVgafWg7RqUv7KNOqVgdLD>Iqc7<)nGBf{=fa{0B$G*!$z(xYF)&=OpYGlj zfNw5ermCt6fYsGiWwlxbU}Iy0?{D1#pi<-F#lt)Q0Kw5w5fMqJQgVNGRxB2aWH+{2 ztzxlQc>@j&4XJ}{Mq>XBnA+Qh*$s-p00000NkvXX Hu0mjfOJ?gp diff --git a/Resources/Textures/Markers/jobs.rsi/chemist.png b/Resources/Textures/Markers/jobs.rsi/chemist.png index d983b91c58bbe590711ca890faaaf1bd45c8c26b..40e22e5cd26d17e1091062d24cfdf8ee3405c0b7 100644 GIT binary patch delta 923 zcmV;M17!S*2(Sl`BYyxHbVXQnQ*UN;cVTj606}DLVr3vnZDD6+Qe|Oed2z{QJOBU# zQb|NXRCwCNSKmuhaTGsaiwcak$_OEwKd>}tAroakn6Y{ZdRY@n>ZJmUX~Ncv|3Dy& zCZq^GWG}r0(Nm8#xR<$=s6!LC5>iLxLzcUhkU@Rh`MU46yMNue>vo3+F6W-}J>UB| zJNJA)=Z;WHVK=1;c3E~kfxX);F1{F++0ES^(ChW=o@Tu}k`&a5L?UlL?kPC|2HIiI z^U<8fN!dge6rV1?0!o5l()&Q3Uw76)bvhl9Bx%cW(gZLmmYKlM%q=mr%fLzfWuVKi z(i;7XZ$z5><$pwJza~w1cVry?NE_^abN0DRbAQE7!JS7>=;MLgWMyiaf&KmQ8@|je zFpW0)n=jZ&#S%bpOaeg=Y|o(sP}5{!8f`lV6)jsPSY0c>Vj9cJoJxHOaLWx1%K$~oRGfIM!|KAQ~P{|p(X(i zfDh-I`BtWw&i3;J)h1B12k>ELdo4uV)vUxQsKd4qu=Wfvo$bdsjL%M@tR_T&$Oj49 zPV1n`Zv+4EC|Iplw&v>YVH$1p<2uG+JnmD=Yy~e~QeM{FQoCF(%9zt;sk>p5LddhJQqoZmm&2Kyuo;-EJ5h9E4CPlowxn ze19?l6H6koqyZIUN!f>q(F@{+0QTxGxaPYG@pxSM*oMP|?>TkLOEjZm+6z<=1j@D9 zY^HsEeT;rNMVCUws;40~9@kiYpU(%;Xf#bkYL8vXpJWKi1;J5TTU%u(pyJ~=x4ieg z_kW0zZztn;$NvkEc=+()g0{B^;b@jXp>kKe2MSTMl25Z9SbRFns90F~1>e`!(t*j( zE~Xb^F>g>U6mna9v%U42*-LAJ;Js<29=Q x%CqH!Vvxh(Ab~(YaqULEo}Gqb75Fc}02HbC!0Bk!hS>lB002ovPDHLkV1mGC!XW?v delta 1014 zcmVzPe>eB9LGPi?(QKiv9UWEs;nX<+buZ+JeY%V z4<^zL(L>2zN-ycb+ya3rh8FbDgHBy~(GZn3CAXOEN_vRUA{4bWZYoHSj)&lQXzDtm zv00J2v+l2l)zyt@cSh~0Ul`uJ@B97U`_AvrTNeKBP!8kN*MD3kuX3OM@cW_mavkRI z%9EY~uJWYkwW5w)Kwoo}_)EP!e`x{m<8K)Np1-v4mwFE+!f^zCQa>m-e0SXCox<(J z_`&QZZ)E0q=a-MDuQ-o)`7!B=^ZYgWnEA}F%*<^%7GOI9`@?Hu@*??=$+z$EBKZ&# z^R;$%;HYx@nt!Y0!R#h)x; z=K>f$>j6CYOTA9E0~{7%Cv;HI zG|hG)78M|aNc;T`48wprzz;s3kFBuAdSx|RVGW+k1ekjnqQhj^9xQXqqNhT3Q%Yb$^{iB7t&!udqU)5SC?8Q&WRwS%gBNyuETAC6P!luj|FO25fXeB9Yje%;bhM zfdFR$0Y15Qjc@MW&5`%^)_48N%F2!=;Jdya-tv0c%xqI%UM8>xz|`a<4HquZ*w_d_ zxvC;NDXK3olb^r+niK94*3;>t0&KOR*X6?NDt`e$zp3+HFbKfJ#02H43L+>&yS62G zT`o2=+jh1tE+CT?+%AQ5cAHz5IthLpB=}Vjbx@_cx*GWcmC)3knCX*r}a;LxFb}iUS!5^kcS65d7 kH~aJ{0R6Xb7tEdFZ$ZYZqZX;r-2eap07*qoM6N<$f@&@DdjJ3c diff --git a/Resources/Textures/Markers/jobs.rsi/clown.png b/Resources/Textures/Markers/jobs.rsi/clown.png index 994a291f68d728a58985df7f98d86cc83b54a217..c9c792006657238b7ffb00f57848e366b152ef31 100644 GIT binary patch delta 874 zcmV-w1C{)l2Y?5VBYyxHbVXQnQ*UN;cVTj606}DLVr3vnZDD6+Qe|Oed2z{QJOBU# zB1uF+RCwCNR!wLVQ4pS2Qc0*<*CwKnLk%dF+>Ge0DR{|2@zCDVgLw23s5e2Z2p$Rw zy?9XY)ZCIo(L)f##G^!y1}dZy0{%2@tRZC4!t>4BeVfhZ?SI?duHeArZD!`pd^2x$ z_7O@c{7;Igl!Oqz{Kmd>mg#s61rXr|Y=6(UVzJ_85*{M{DP<=T9`N{xx=%yu4 zkQ-3U#UQ$I082{;L)Nf8Z}f^O7XeZ>sicoRe#F$_#CLu`~ctqOjE3a9fSzZ z<+v5bL8t(DzJ}-wOAghcPb@dmW+E~2pA)k~ds!t8KM5DiV>Mmob$!gFEL;iOXf*uS zP-HJM%!6)aIYymHqZ(#lUbS3|F6%l8H3>yVBaTq!WRonr1p@!%2#T^&Dk`Ad7Zkwd zr;p&=)qi=|X|`c&yUC)ifNORo!xavt6K7M9NG0L(n|A=WR>C*o^o+)SQ&28PU@`uO zRbbp^5gV~Q3G*yC+9T-DpJSxo`+YbvJq16vn}AcW%u0<6Sz@t}p&spqpuNd;6c=ML zDvp6Wyz>xFb-SJpe`p%)KfcGG-`~D#yb*%|34c6_#q|5GX`J~a^vU);#t3(xgq}Ts zSvT0a>yYm;K54&zF#f`LmS2my;Fkj33HKB_4Bjz0E`WsT0sI_`c|PkHy&Z+axBz6% z0US)qtH0NM!2VG=>HzYQ@kKM}YsTjt!$(ZTPyp=T1wSQ~&3@kiYPFiuc{`UI@szAo zh+|Bq@{!GEy_--KC_m86IWa7^U50i+fKAAPKfls|etG~G^mWLm*DXN#bQ<7UMxGjz zbG_*U_u+o@gZ`X=q(>m8pI?$?>P60}_*Z}d0Pw%=w(;w^zW@LL07*qoM6N<$g6>G5 A*#H0l delta 899 zcmV-}1AP2|2bl+uBYy*6Nklp*|3PF(WRhXtHcaeI?p+(m;-8Rc~ zrlt5i%+6$XvODwJG~$ED%)H<4z4v|pelr9AGbxizyI0WjvL(<%Vz-r6pcGhv{raCKZr?=q%DT% zTRU##!2RSl07?bUgX^9=zSpD#sQ~&JDVEEKC_oTV6w75Jy_cqHwJLST5fKr8VL^m) za21idSe8{3+O4i#4~& z*DLQu@=J4@oLI}ruU~!3)e9dVe(eD+F5i^Nd0V6=Vrwn!b~|EQYmu7BBQ-GSS0>L5mEI-WKg&e=#e**U1Q~*XzI5slGSbms$+im{2 za5>08hZTSb^4;g$+io+KA7*T1hzBjt#B_EE+-EPyzjBnVZ5Mm(Gfs`a#vi}e!F|k; zr;kt{dC zCjdCH)(CVnCZR6?0cjQr(kv82z?kDYSqD;P368f~G=QCi{1Na*?0FQ}0ww@@Wa_{G zl1}^47Vxmc$3h?mlvQ4~L~L@ULuoJeTRZ;SfDAHr1>TC_k4`bCta5Tp7bf3UJ3i2i|! z%q;gqLM;f13Q2;X5*tgLW~h`&NmHk0h3INaqYUEqK6iWD+kcnlzC825<#W%u=iYPP zx%ZrVpTHQSrKDxF#I)oNB!nBZwOsY%b>*i?tyc3slkJ@#642>%2F=Hum>u9ox9$v* zv4Df);RQdXiN5$F5Q<>T_0}9DR}~nTN~IE9E|*)dzL4luN1P7K`nrNv?`K@d-cM}o zu@@n?J?~)RmwyYP<|}dts~b)9+x3I@=il7-LrK19S#bRNE!K4Mm@wYk$Bq5@{);~M zzvBoVa^0St!lF3<<8T5-U~GBn3ex0hIfB>f3x!xBAcU)gp6v3H{@MfP=;@-NbEV{R zeDfW^wAHlnVk@O>+d;jj4hR8UTqY_!@ zCA~ILPk)ld<-pvhahiKL9^?>048*vc4>vC+2dsySQQc^IbdsF*Vy3gdrfSjHjqV1j z-d;t>g`Q z(1+8C)B)6a8D!w=z;ypj%!+q%-ryaAT&wpLT^|_wM>9`%(aP$nX`v@ia?km=F z#{%mtK0aU$ns-h-Ss*RqPN{y<4@|r71revrPbtH&m-9E<$GoWrKr?c@@jaTZm-z@sUYLNKR!T^rCuX{<8(rmHI|J3t4Ap zCx1g<{9 delta 1116 zcmV-i1f%=A2k;1xBYy-pNkl1wg--tSzfJV$%i$ngVGbs&{q%@(X z@uyCq3(dGlLN^Uv2uVSxn?kGUB1NKP(E$U3-85;VVkwCTO^BGf5wnnZry(CteC^2}hu?yt>ZH+Byr1D`e|ZH9i?6C zRaM1evBbR}ad~EHY?C`rvH|EhQ^TOn$g0VTE-i&sla)c8k)AU(0Nixo;{e&W^zg%GU$QaU_L>ek(`oUn19V?0EWCF&Ye2JS0MK;4Ih2mK@wg6LOo0L~pF*Xy#JJhf7OEX>oy1Tn0`T*Xc ze#T~klvh^8wG}ZPxc67`hg}ymJNK3yCQX;gz(NLTx=i+#9oFVQ?7ExH=hEcv~hKei7DB@ObipCPJ5Aq$Phm`2dg4rzO|x^_mEe&-dJQ6S|Q6;Zh^szy8prq-W#qK+ht;6LPSJ5J33_2 z?UqTmTjuBIwRUGmNAgAZPq^Lg=kkv{9)27ch_JlGV2E0T2?+>?!*q6bMsRa;a~h{8 z3LiBzBy>59dvafIuK?JaY!v2fgnc_M%E|qT0L+Ahvln{-sI%FU{!`i#m+f{D5moU| zPs`}Yh#W6PHWQ!RugLLIWOQUi{L|ASB68Vo|MzZ008@TH&CShP|L6ywZ#2fgV0Z0j i>;|s)_ir5>1AhY2MAyXu$5KfE0000VtuN48Wj$v-TBG#S2dt$B>F! zS1#WcJ1ii;dcj!2Wu5Qm|Mzc6?wxqa?z;1#O_Aq33jSpLaCW$~k73bkv9?)L8n)$1 zB#B&N=G?hdu3@X0YUKiUp=YO4r-kz$kT_uZ#X)TOPbroTV4OrWmS6Xnn6}3cTiiXwoy*O|A<*@`SDAdmbb`?cFaP4mdKI;Vst E07_cCd;kCd delta 723 zcmV;^0xbQq1K|~9 zYGVjq>|_ggFeXDV8AYL+AbW;R9kK_!wS)f#(?xR=0)-%wCWMRu^Ab142st&_gE}aB zjT|S|bDOET?VWUY-<|IJp5Vn^?0>gc^9Gt`DY$<=J^emcu7B6_7T(x+&+Y9my4?27j#{p`mEpYv#^j>%BKWC z(^6!NoIL+HI|JZdF7#y#gN_i-2Ouh{>pJ~@f2!}X>HISQx~^l}HUQ0L6M%ZX4nVuz zR!yf)!*aPC0Dlt1<>h6p_`$(}Qch(6`FuXeE-yd$))~X#{NjR>lauEIV49^s(^9hF zo24ZHeqLWoK%O^N(t-t*;+0Ab&l_XgHXR{wT^HAN=?Fo+UdQvsR4TOxD*4v{OtTae z3aj*bS22IFSfp4i#(cfr6@|iTVi1W&HJMD)QrNZ~V}C)r-Ny6AvA86kA`yUcxg6NG z&0sK~)oMuwz#kSs$OOx>NT<^@o6SUwNUQ^c!2lrymSxG#C(W`fgb)~pkutqarv-5BtR3`D{1U5G} zW1VNSD*$wa!1sOmp6~loinG}jMx!CV@5ORFW;2&?clRSZJD=ovd;5dr`F)FYVsGzr zEVk8ZJ()kz4m27yG%ZE7x(0-r0O5s{x#N7~t4vnc(6khdMlDI|*%LTAI>K=rNyWp% z!>RAx@ANU+DgzKgkk98Q6HAMJPM+fYJmM595EXf@_}@rcR|54IniK#4002ovPDHLk FV1k|pQThM? diff --git a/Resources/Textures/Markers/jobs.rsi/detective.png b/Resources/Textures/Markers/jobs.rsi/detective.png index 73d944a0a712a206741fe5acecbec56f155e4379..b2dc8ef4d26c9ce6b8c46a2ee9d0e81bfb82d245 100644 GIT binary patch delta 1010 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 DF!imw delta 1089 zcmV-H1it%&2h|9WBYy-ONkl*7O z36(K%J+!9|b`WHz3ZB-o%QVHqK%0WFLPtF~aY&&;@iH|B<3;3seKWOrQ(0z~DK=_d zP1I)xmlw0P=8u$J_CWake&0O5=lSM&zQ5o52L8AI*pxyyUVm$LNqRm!@k_yR3fg$B z*(FtHOU!kAJ6SM^yf>wjpLrQJvA;gJP%w$2e4MXet~Qh3t$hZ--P&iIc^RhaYzfyd zS4)-!sR^F^#`d0z;&h zA^>}K52Yo==4a3D0bpry5mi<55@JpSd_JFCayS6+dcD|eHumfuPM<1b&+fryv*Go6 z0l4IF;Pd%%CXtnZ&*zg{U0oQ4!Ns~d91aH-iv^p_#((7I;b^f~a5x-XtgFK?3~qIG zuudc2FFg!e*u?7eP z0xW16S6f?iszTNZgmj%iAV5z~kEw2#%S9@c!e+CPN~LhQT&90dPmdA^1PJMRw$K2a z%H|LZ27k?Y`V`dF*Hc$t&zCoE^237%0BD+KexKe~Sy_290&_ooPxXiIv$2!PxaX&* zrf6(x;>wjP090A6sHzGaJ}=g$hNvigkGU7GvJ%Kigz57RP*hw@gWV3mDY zHHiRx(cXTn5RWA=G#gdcwv$9(yfPm&!r^7}=h_->w;M%Ka5|lQ-qyym)&hx7+FL>@-{QS*SMe}YFH z&1@zT`J_1B?%cT}A|i%iNMB!{0QB|siGN`jA|f*A_sjE0M4m??vazvY&IkSe!bSLR zi$o%C#ltHrJRKj;D0xkF^|2z%i$F4&WN>gW16yBTH!(#~_^P8LuQ#HcokvGT%rZ7M zHUdy}{=5>8#ROn_dfN1DYi}?3pVAxcet*A+h{R(tnVp%D(UB2JCyvKrGCDFMvpO>~ z5|711MC5*df6i}2Ikn*Tc%0j}Z)ae0^YZ}o-@BKw&e#41dWi3Tec0db00000NkvXX Hu0mjfgRl{k diff --git a/Resources/Textures/Markers/jobs.rsi/engineer.png b/Resources/Textures/Markers/jobs.rsi/engineer.png index d561f3de462833bc11da7da914ab95b67852687a..353144650a5cec997ee9c2570bc8540637864ed5 100644 GIT binary patch delta 1101 zcmV-T1hV^!2;m5jBYyxHbVXQnQ*UN;cVTj606}DLVr3vnZDD6+Qe|Oed2z{QJOBU$ z14%?dRCwCNR$ok$R}}w!EgC>s@edm+SS{-2vJS9_nv7;qlBooZFU!XTUYQL0>xFBMsu2KRKDSt(+)$;BBZu^zuaP-e- zJjwmeIlp`EJ?A_3-g7TBO+z|uGWw_@Jl$?6jLHu8Ox=*zvo9_JL5olxAOJxQe3*(ufPFxQnb^KIIkT+F;OKY7;*}mKa z=gL>{$>crox{vHQgJ&OE$wy=R2Ae9en z5nl_2Zw27A&coKhMhsc~QqPvs4nXrbG^IvWx(~N#R)5Wb*ux0={C}gVWGl?C4B*{MvNv(;{v#;#+3Aaw7361U8m zg`?ZoO8LXinDXo~H)ILueA~OLq)cZFLMQ5aA8D_^(0?0_;kCL3^fm|3UKB*NzzftMERW0> zZHUQnIcMN@PrS*CD1pU%U6b0T;;G|u3gEMiEv#-B^aU_{+lQarXYux3FV4SJhqCsI zNxN_JmjRE2kT24|qX~_RZ78vo;pXpc#*|_f8o-9Tr$_Kjqy&+{5tu99#QeTX2nvo7 z4Sx$P1=6-yIHx^>HslmULk}?BGDBvd!#9BN<1xwa+>c`YhUtq`dc2yT(7K6ZOXM1Uu@)*-tyU`^7kpH)IJoDgV+kZxL1x^~3#F|3-go zT#ZXmIJ*>~V6Ps8V#prgg~BwSYY)OUKLB4}SnwjrNjg8*?oHz4>0Csle+3u-fo-e| T@l_l500000NkvXXu0mjfHpnDr delta 1014 zcmV0TJhWGIYHa2RxDbPSz-Ef#GVu0xn2Y`A_){0+2h@lGMaw49nHaa1ODui|=w@&0Vg59r8QCAC< z6;M}e=($3&>X?4IkKP7%Wi>3vVM7TIw0peTwc;E2*?L~fjsQJnil{8GQ~$|HuFn+E z=3Gk2p;vm)mVXkQoR4IcGp7;g@dZ4|NdP>_N%Z(aE@`qOV4fZzHm6fuWM^bdqqxXU zY)%KDvcOJHnUd8-wA8Nj;@VOIfVK}$r0m!IXE5!ikJV9Fo|k#D&@Lw@UVIrxNWI8%&-GAhmE+r5CCYbhjV+OxCs>5_;xuZ5}V(rb>GU~z@XvRSZ^h(fmJVy+4^&P z4gHIPr+)!(m+L4pL}H}mrHi4IAHeJ1!rAwrqkHulYj)tqWms+n%~?t?7?hq*22o`2 z5u)7POm|fXMTX#Ecw+!bbC$B)YQ$N=ssyHfgYSPbWJA+V`dSbZwJHE@Rhhn5WtF}b zL_^cgjJUO6Tg_Nk-N|-u4fiLfiO%WVl&4XEl7Au@I)Hb84j6u6k*)4RZptcq#8%qX zX0|-`D1+fKpf`5{CggHQYP}GNGh1e(>*zLI{7Bc)ZGd2Q-UcMuT<$d(z)|uD(K($_Er$N*GQZxNMw?CG+igdiO)wMHX{aut)Mg|4_wPbF>6{51I^8Rc zYJU?9hQ~N`x>o|2|6>V&=)*!^MA%8Pz6IF?qw2^;?99Axs&(KuR~iycYZ? z`dUa84qiYAAy(Eggw@wC9Xb6W0SJXbk|Ze<&Nah23FHg^I{{1YfQe6aH^WELL&mv% z$HVPA(El}r^d#^gD*{<{K=s%NjVC$Su5V=QA8c0$jVDn(S)C_40>}1ygh}GR$ff&P zg(b?z_It$PecJ&@Cg$l6+|96m{zHV9e2-(Zmzi7Q{5Rv49wAEvYFrz+czKW-*G9%B keox7Cdw<|=hTSUu0$(zZsT{E^pa1{>07*qoM6N<$f+&vd2LJ#7 diff --git a/Resources/Textures/Markers/jobs.rsi/ertengineer.png b/Resources/Textures/Markers/jobs.rsi/ertengineer.png index 629bc8078a9e8abebf7543da88f9ff7018285cdb..c6fbb1a540a51c324c154da41c66131c8909fdbe 100644 GIT binary patch delta 1043 zcmV+u1nm2|38)B=B!3xnMObuGZ)S9NVRB^vL1b@YWgtmyVP|DhWnpA_ami&o000BZ zNkln6&U545J?Xf^so>SEcB2NK@ozB zuRRp(K140;t`zi;Jw!bT!5C2znUWOQFOl|-3FRu3LCodtBQsmg~wD?6$6_*z=(|w zsO@LJYP`O_p5@9}6{f6{jKyM%gt@J>UfFkSc?c+5cg{0TQ6KJE!~K3Q&=cx~iN?;L zXKvw8_sVR60e`uHb3^z`IX0(Q8UXI!UZw-_g+oq9sko{K(i z^C>Xt!&{^MG1O|wCIw_buGlG{OxF`lUKzfMnehaMBTvxmZbC*u4*YlaqrAKvU7|~1 zaD^O@gAceIsJCv*vMm7=7nEVw?N~R5!KeKW{ffHJ2$Qt)~ zOEErfZ1~gu$MY6_tI{qR0Ww}&8_*+->02?tMol8)ic$fO$Hg|kbYj^_=ytoM0kdJ8 zj3p9NR--q8T^#KQyd~_M@=YHU25ncfjNE zNQcAm8Tt@AuowalA9k|?UayxwN@!4hNZWzBx_>%3J2Qj)yga;5BoN%8!T0YJv_sk0 z*q&qQoj7^ilH1zakeic(cM}s>rRPmB7!=D&LNZ=dT#O>_X}IwBdEjmnE?xf5(xFSp z=ku}b|ICTVXR+c$6UQqx%89cW^{#ecwRnm$)uUCra9NBXuDqSn?{K~Yfa?CfMH zFMr-V1(TaCnMluEL+fq53uN

2I6D%Y)h2*5S6s_cZLbc30raq0+yscaC?4L8{ zI}oRjRLP1m1A*@Tv3YvbH;~C^J@frY>uuQr`Y1)|TKf~WkG@9Nqt^>`eru>e?&=c6 zUcE4#5Vqui{sLy0JMO(g`8o~HhvPbTGAA;5$GskFoH(sp3Vjk_0ByqK9D8tAYzzPZ N002ovPDHLkV1ne>{h9y( delta 1190 zcmV;X1X=s22)YT7B!2;OQb$4nuFf3k000DZNklD3Kkd4ABZ=j=T1^M1eI^M5?=`!++n?<3~GJ84#eg0OENx>)ygEVHAHW@KapfYz#g<~~f$ zT@OH1lnsCkS0=l6e-IIN*dVvtEhp=p*z9}E=z(hk|A=!q9Cy7B-Eh;^UKAETYza=( zt1Pc8CV!*C3jzgei-?VlB_}7BO|QSfikw_x9S#cCt~2LkRG#IzQkXj&6resz>)tqDZv?CL;75P{mP&%*IWCg4Q9N_K4tp6oILecLeA zaIc*%<}+~hZECX)l3ia&QsRM-SqNQ%-a0%B*MGp(I_xoa5SaDEY(zj^sPfW_FO#}Z z1q}afi?PQ*uLsY9wb1JcNfELWe)8cFmJ~p%wt!Wujj!wKGD>i|;S}0Ajp5-T6lDTk zT^(at5jgsN8&9X4r{M^=)`ZmX?{@qUBH|Dc*bCSy}@pcRViu$q8|^`ufS-S)-iV`GTY*#D8(V zTQ|{MJ8JIFv0Q-UnQ>IL{%$Jo?i-|AA0lu5qn!8YR^Y4&kYgogepk$o=ewVJOi_7B z@l2i;jcabWjum1ET;021aS|>EP2zo*4&#V|q-) zA|ev-QF$9Fj~n1VeJH4EY`nW~a39R406v|T%aN7iFZjRSpIoqZeE1Cl0g^N+W^d7Vjf*8S~r(Oa{ zMj6plAQes!LfuRCpgu$@V-KY_$pw?U^`Ogvd+N5|ncwYBMSpkOot|+y_dDPDcFya#&H8B*}R9csvGlsZ`3Cu!`uu4ya>8d&*(Fv$NAI(uEUnQaFM2 z?rVd!A>i)0xXZZH>7NocExyJEY%!E0fpjrDQT`$k$J;Gk!r=0AmAP3CJ?LW{*4KnU zWV!@(#^@B;M`jsfaEu{8wC@6>9|BYaD#nNMT~Icva>qmM7sTU{Oi**jaMTO{&`NSJRCM%?It*+#yBhgBy^iM~`YXTyuVlsp8n)*P00000Ne4wvM6N<$g6B@bN&o-= delta 1082 zcmV-A1jYNL2hRwQB!2;OQb$4nuFf3k000CDNkl?CW8YNrGiF6X?wszWtW(n|a=6o`3hx_rd?R4YSOY*k=&S z^5>M*BHP7!cstGyJbw_QJI{f82QgmEb3hIvh!hI>SX8`+qB*xDlWAvpWf}6YvN|uX zEYqIZgJq^7D-l`&)38JYs?{1XAa6spR`cg-Z3D@a6zuRygnrO8EU}#ereSS*dm})> zE?}7{q7aCj1Am!xhDXM8?4>(k@dFdwJ<>|SE&$P@5SoA>n1+Q26v-j1e|?D@nzRP{ z56le16fL32?NdmHtdIHAh^Fac8dhZYk;_I)Xi_;>W!_m|OBu(f8F`1q0<40wQ)~;Gk*+I`d&T~iAX5PjHIy%R8dqs z&n4ZKVgAl-R7J)0yiKT%V~4`tvJ)no4T;BXcSu`YY>}rzU>pdL3nhe&Obl+jQTw(a@ zAhffE3vThr9M8q?=) zFn1XqKhxMp!?WP^Y%|K7f}*JCy3R%8Hk<%HhIr!X;JM|gH*ks$i}n)VOkM_{t9t=+S~U8K>cs_N5YJBADFqj#L%84W_}0PP2kl%5U}d~QDC-j zKfQ-Y4*BaV?vY9{)E!SMOsoV#2<}s z1 As{jB1 diff --git a/Resources/Textures/Markers/jobs.rsi/ertjanitor.png b/Resources/Textures/Markers/jobs.rsi/ertjanitor.png index 7d548c26c6d9fd38945d414606e8fc5a7dc1600a..04b805c2c2805c4f0fb6ccab365366b4e7cea536 100644 GIT binary patch delta 1027 zcmV+e1pNEr2$=|wB!3xnMObuGZ)S9NVRB^vL1b@YWgtmyVP|DhWnpA_ami&o000BK zNklg;J_z?d;>dwtqm7(pQ~iGy8UDIy2wQ z&Ta{%6#geAL?cWH*>%)8Nz~CK?Z<15YUPytlu`%FzJ`}x2=2IZjFPAV{ zrdy@CNCs-4aXSTA>A^yyPaV%8uv)9H-#YD{5kTX0b%tQ1?qDh=nNg9@ILGNhqfs%NTb+ox2y=3Br~tEI9F6&W>(an) zT*v)zd0A=ze=OL5U~O%U8A14kNDCN8qsZsxlx#mOT>+e$V@NoiP9jSYE-fuVVqzkj z+wC?f-+xvsNZjLbgHowteL$sB$#V)Y`rO=HSXfv9zuyn)LmH^AHbg`o&Jh8W!#e@> z5CyE|eLHY6?*W{@QVU(r%9*sPnFiV%&fv$H{sC^#peCHDgiIM2bYjJJ|Z7n}jD zDviy(>G{&S*XNU`54h&%Va8^I;qN@SX5A96zTU{V)8&C0T{@FRIh2>B5w*6q5{v>z zPk&Dj!+AL%yt$Bf-ffeA||4(UZ9+`^jE{Mv3 ztgI}W5v&QU?&Ksz=zZ|p4|rNugN3)axEPfK`+AVD0$W>UM-KTv`(F?b+EWU;ySo{; z^cf?BPtWjYfIj1FX?hgyzGeJAALl^`BAMv0BDIel`Pd-+YcEuL$jp+hlZL z;!zuLr|Y5T#|nervP;D69pc4fq?iVLKL+29@*sf5uU!sB9}d5mj;b&e+B=N2;phO7 xB?TA-!raytx>_~b?Q(Bk<1k0)?S=jbFaX;M=E<`ig3AB^002ovPDHLkV1l@U>L&mI delta 1101 zcmV-T1hV^?2;vBkB!2;OQb$4nuFf3k000CWNklj&Opnb0-K6s5+f4=-D0K*4>Pd2#e^q)HX{09_TtP~)G;PQAOi=CIZ7EL zFo-E=MjI#4;=;0Jija(Pd}wJQ8v6S&eeyo^{(k3o&-Z-$J%8t(d*S~+l&v`JFRc+- zdkH^ube`N2mQJffX=#ldd9OYayQ`}YfL+0WjE=TzCZWlpbYG1eIbILZ|BtXrSNCNA z+&yiKj&*3l)TBVF?L`nF?YXC;1O!A1>F&Oa$z;+32WU`WS5~Pw_LSl7X~Sd=2Z{37jn(1fCEK!_d#+1U=}=Y!;AJEE}!lx-i=>->`9zC&cDor=jK zrUKq!P;?CxI*X!4ft{Jp0?`>+1q7$F2u0V3_ka4TDh)O#u+T%`Z5K&N$yhC^AcECu z0fhGUR_r-;zH4s<1dBBl0IMaHq@-j5?;M0XeK84adKTE64|%wgd`*2jFRwt#UVEKuLmrF` z-!L_@Li!6~5e548p2GX{VNIB-kK?rRjUN*nOIdG_~LLLsPykwQP*Aw;bi4Y+5ii zT}mA}(Py`3ojqF%%EqB71qO2o26G7_FcWHs%=kjW8+Mdn*ioXHfNBN0o00F&T}A{# zN^HeHZ#Kvy&J(t%e1_+zGv0S^%dA~4_yr6K;QkOJLYR88V9p(L#f Td(7G000000NkvXXu0mjfdrSa1 diff --git a/Resources/Textures/Markers/jobs.rsi/ertjanitoreva.png b/Resources/Textures/Markers/jobs.rsi/ertjanitoreva.png index 24312247a8456c2c4c77fb14980fac552bf12cba..26d17fb0710afb622551d00b3a1ae03d1f1ad507 100644 GIT binary patch delta 961 zcmV;y13vt@3D*aZB!3xnMObuGZ)S9NVRB^vL1b@YWgtmyVP|DhWnpA_ami&o000Ad zNkl(|;Lrcgr(A&OPTlXXp3( zz9TTkU?*W0>@e)O1AG3p8FY0d(fY;M@xo!!K9I2_F7a>=yKW@7^b14&N6%$WKNqyi~A_Ok5;;8H?^v}L|~9d6ZH)*LA_ z0{A|t?1ANE(tlD{$0B|YeG5mdNx0wH27`~Etw)b*Im=Cm^|oAXUHcyIftf?c36paY zANP&S$Z~cHJR>6l8hQHt7koQVK|I7rBR{sf3S+{UkhN2=l@lii2iZ`4Jy;}qXnr1g zT3W#C^$HoCLp(BDt&L!->0)}lo>p;jG3)SpSzvZn=6~V$cK#n%+9g2a7wjf5o6STQ z6cj+|(h_~UJsw&g-^58S>m|VGG?gxx7_Eko^eZYVf^awtU7ela_xp*~>2y#It$=d+ zn4SfLK_M$mh{n+X8k&ZO#53uh6PC)5MB_ep2=%g-0gMhK7DbV;AM9W-7$6i15qA6S zB!`BT@_(uw;L&ryKgAvx9v-GhmB9HN{_0^Cgp5mYEWe%7o0w_@UQ>*k8@%s$CpRVM zqa4bk9_p*gz?WDXXuu%h^=NtIXiyW1P*W=ToAoZL?*Xf!8{A-Lmut)5{lqGqKe1QB zA|#>#_*p1IRcW5Ga17;n!>Y;vrqFW61h3r9)PHRA3$xI?(hr{&8VJK~Nob`O`tr`f z;r;taCr?`iKJhkOvA&i{=TmnKF_mZ>yBd$&=dWQ{{1K7yscTlk3yaHex*}gbnkbKY zsISTaY$$Hr>2y*PF8vmPJm~b}GgP>1bs&9E{$i6eC6&`TuP! zpPUNF4Tc!$oQ&nEP6c$g(~Ad+n;7Z7Zb+-^Rc8Q=Ve=^gX>uyp8Q6H`Dj%tIU%!kq zfRheBK6oQ4Ur7G)As_d*I}xSj0H274Mmq1&)RPL3kNY$cr8$gjs{}mtiTnVBW8qCD jn2ZLJUd?pjj{pMz$}i{$Z~s})00000NkvXXu0mjfw9(E6vuxXNZM|g zna;=S2S%kc58g~$5@M(o+Rbq>)3Fni_Pwe*@8;fj&%OWizklca?|ldUZ!2hiH6U#} z65>|_($<_1zb_yw#d^%@2A}GeLoKh;yxGgZ?ZY&0@-le)FbEP$4BP%w0zTC*jrH3| zrBamYkdg^X(=Z_uG&D3Kh{O{yOC(Ga@Tqj#VX!IEH9uTSpZzt1lBw@eL&3iD6zh|r%tz?wB{NF?KyFjrYw z+z@KOUS3XrdOy3`=Xv`}VORS+{ptPK?d6u8gM|pRw|{j=IC7Imb8~pAJjCL|1)F|H z2f(NLXb3fOw(E1#xTY3*>r`31I25eM(S5F9&$hJ_iG+&~6Ul@r>}6Bnty4vDC_qkM z2M@Fmj)s|R>)`PZK4h}3gGeOID+gOxSfn_ds9x2S98G9Ia4OEiS6WX2Ff~2JM0$d$ z=_v$Ar+?E(o}|<1G<_SEB;c*}in2iggt@s#IruzqC=le{y=g*$V4h~qFgG^`A~+PK zkh+x3qCHL9n-~}x;CbZ|>Jy(W=YMGeiP<;! zg=17yRN!*C0B}`SfwmcOy^%4PNTp~!+=_lj$1n`ClNpj)a!DV{J{GSXX%ly)i%2w5c=49nrHyE|6Yrf6 zUDxUA=~@=w)N8eG?>7SR!=RhN1L%+445SVaIxcN-hnXoQ*0YmYvXfZ=`Y)Sz4kjb8=Qy^m%hx&CIZQAR#Nluh zozk(vK`;>Hqs|!TFZZ+i9rKlzDFQXsHBwU5!=<5iHp!{t5a-96};lpK{lIV{2qaZHv9MVEZ6=7MmEg_sf=^C00000NkvXXu0mjf D$LK>} diff --git a/Resources/Textures/Markers/jobs.rsi/ertleader.png b/Resources/Textures/Markers/jobs.rsi/ertleader.png index ec540ef750234d8392a75605444c9a9d43fb5991..3c510e68aec5586e87234336af34cbad0402f36c 100644 GIT binary patch delta 999 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 V)fG^BHXi^0002ovPDHLkV1gD{z_9=T delta 1137 zcmV-%1djX32ZjldB!2;OQb$4nuFf3k000C)Nkl7%g5XXPE5#`V(ZsiBPFDs5E`7zOnLT-uOA6~uuP5)@LYTu^UFRZ5faacL@X;6h?M zapE{lxB#`I-L+3KiBk!wLW+mOI-4|6oOJ~!M)L04_vZcQKY#P)&3lIbyLg^tlCDPu zp!#MC?|2M=OeXDMofYHQJSWjZr`40jA`p&9xx7vw&_Ziw&gn1d5!P#o*Ai$UvoPlxx8XVv40cHO z%e`1d!|79%Hgd~Z0M=ZFen-4+6??}--oN~T1Ofqa%YRu^rOo-}ma_x`0Rn*l06k;w zv(OdWo-vVE%nwPXW_T;{Hn(nlL;26LGhQg{79BktAs!##7wrp{u6T~bcSRr^>U+#1 zMb#);Ch>Sb$>falymE{dvRS6U&F7@}wy#A5vfgYCp({S+;eL}G|U zVrZA7qJI$%=|?Vwt8J+5@vu;MfB>dx0D@_n2v8{Gp+*xx(=@E&!Kmz)x)BJ4bWs$| z0p9D5j7|{@c2FIiI&{9OXoQZ4Lfr^d-nYUYZ@@gbLx1ZGT+s2Zm`-DC99sb6;p|-6jRPk|X%; z^wl#_e;0IL6Vdv?^Z9vHO(UI30bjmEJolj_y) zu#%9wdiZv%8v)-$pKV;#xOaD&bAxBt+^9I7elieqyx-iYu(?s;?BE&hO;4k$8lG$C z@qbR#k3d}li`k4vRW*Xa4ggkGegnXN%8$nf^9xx#KEZ#gnVmGXb%bEB9Zl89X6x62 zhU#`l@CA9Xvl9SKZNsz-=e;ApuC9__`@=PEL&x!ncYen)l{!bUXkSN+*!R0SF<{ia zUk%@g)HrMzw$bHLk7xTrMw%38ZnMX&WPf9Lu1~{9KiWGGfrl3OCUwAmKeX7bR8rIZ zHwmoXM2?*X@05;}gt#^ASP<-QD`|W0ozgjW8dh$)BjIWZWX~gR4%cdY4POMyG>OYF z0BI4Zy1$pYBOtJH+qRjWJGjWjl0~s(Ip6ocb!Xf)fv$J)bbTtKUI%URGL~ghDryy- z@zz!aRkaT-^TG{=QgHv{qc0<_3G{S_BvQNtldu~33codYKxZ{_1AxwnOK5+4C@ zC1QaZ?J#4cz{MnN0C5$_Q72O;h&ip-*-Jw zbeU|-#xw)rh9z-21*y#JnfE!ZEQHDH|4R1^w5Mcy2s;I z*4ybMMSli^0m{qM^K(G2*K4y2F#FQdQktEerAQ<~MTJJHt+gf1JW-+o@WY9Sai{{Y ztiH7*l>U!#+kqhAYdUOZU;uJG%YE=m9H;huuBOriU1qKHP$m4Yj zCX=a|5ov-ywXf2eKyyZa?FZ-DIC`3 z9GID&rk`%Nv>l{d$K{I43kELzGeN4e2Mk4W!$S+0xG%}geU64`&1qB5xSHc9)otdGFzYn4j!fsiV zfHyZcmr?@TdXR8{g%{C{J5t_NdgjWnPfkV!+1^J1NbN&B_LeQ zKA(>|ySnIXQxlhR|u? delta 1107 zcmV-Z1g!go2#!-16#(iNc_1KbbLIlcEC8*om$2LIW+09AfFrk502Gz%#^*hwJ6T{Y z%QAMm9a)wM27g-&VVlZ8s5?NBYd1&V+K%K~&xfwt>>K|TVSNyQ{cnCss3)M5#2^_8 zKxl}9qx+RIi0mLt4Z`p&A6XS?{w6D-ZZn^>gfYy`-6?|grBINsBm58m!0~PimoFPj zy-KF0;NXG7N-Fa6VRTG+M#dmNPk9i$cJQ#NDKHeR>VMehZ)bXX8i1d^{#cXe>~d@G ziHV666+Oa{Bkvi)j;pjO>!es=IW~_sJ~18@B-v`!cvH9QxYAn_7e8hbZp=C%Tx~T# z4FLY~0;;QPIDNW_!oqE2W@HiyUB~Bd2VigYbDTPLlA<#m3P3U9N?+_C3{8R8)d)b6 z1wx?#0DroIopc2|BN|HC2L`SIf^Ui&DQT<4$UH6@z{ac-!sV^S>uO|VtR8?hmWSrJ z(`n&)WUL;q3rgB*5w2MQ(B1cZ)J(+8K<|&r7He5)(VgjA!rw_K?4%V*0Q5xcW6|Pc zc&m+}m!E}OZSx#ttjz!c4#yTM_Eh3-sSF{ zJKUFS+ zuI%;4Me#W|y`3`vc>g>`$-S>=@(o*;bANHiC-nU6HjHcPGz2x-v&aoiNP7=Razhi! zm27sNhEXzgBNCB$N9Y@p#zXIce~oOmR8h8Lm$2DVh0T^KRG#{%GBcQ_OVAPMz?tWq z$8+X6appPc2y~c*Ggbn7TDkz3nNgarKh)2hYofA_ysP^1&7pthR%}m87dbhbwM_N! z@Ne9>@yk4&(a})=RtmcSNr1P Z{{?}2k-Fi+OML(U002ovPDHLkV1gc`A|?O; diff --git a/Resources/Textures/Markers/jobs.rsi/ertmedicaleva.png b/Resources/Textures/Markers/jobs.rsi/ertmedicaleva.png index f5633c2b7dbf5dacf44aac84a3a8aafdc8d2aed1..a9f9b92e28f8a082574ea5d76ce33398d6b44779 100644 GIT binary patch delta 913 zcmV;C18)4G38x2;B!3xnMObuGZ)S9NVRB^vL1b@YWgtmyVP|DhWnpA_ami&o0009? zNkl8L{%w?Y>wI2D(!DMfH` zXz0=@&?3#+Y#rB>3@@+{M@_y@Bi=qyZi5c zC0Ul~f5Igr!jdFiI368HhEHP|#A=_9x7@)%5rujJlsMTsztyX!I z%VqT&{8t~|cYg$L&6~uQiV1F>kSd6iUV?6L}WPjG7*8nI7 zM5ECj<=q1SIU@$>N&xEdaf^xJa*4DY~lc5ekKPE}PAgkVkp`SF_WVgp-q#yrEDG5XRJtMLJRp z%_?4i;(u=Wp*`UD`}y?P5GNCgT`m`YBOKk|-7>=1d_FG??1AOwWsd3A))s}sVF}>? ze|>#jmFZT>4M=gjvQ8H3OmD{`#{Kvsd60O$UiJb`pI>^w$}L{43N+@h~*Yea9J)2Fv9>ipBC1%IV9pSI))ho9v$nauDWh{xl6zi~=V zw#K2->GnGK$qmK_hb_8)`wFjt9OSVM>xVJ`2_=-LQmNByZk_d5;KY{>eFl&dMqvHW zg{Y^jKAV>V-+xo)?qv!cUFWL?MZbP_UOyY(%96Gen`S_FiA^Sxe9w`Tu~_HbhwEy@ z0Dr^X5Kt@@)usasx?dwQtr=+n1x6$ou%3crN+A+TS65ei_=47x^+Ugkp$y5VeJN{= z8reUiekB*lsJHtK>;WX0(%HBoYI^}_@G)=XF{0Z5)OWZTkB&ql(N_k1%tKCeO;bZ4 nT#t;`x*Ih3gLK3{0t^6=#$o-p%98Q`015yANkvXXu0mjfzTda- delta 1165 zcmV;81akYQ2cZd&B!2;OQb$4nuFf3k000DANkl&u6%V`MD{ZidIh><%6F2eS&*y#KAAj>M{NF6C56Z3LZ-FPR z56VX4ZR$1ozOe(mntD0Vzi;dSfB+Pno00znAgvF|aAuftd8NfyF0U}08E!VE7l=^8 zW{DLg&KIXnx7B>`(KGx;_vtY*>J1!i>3< z=Vxr*U_9Xefq%=~pE7)au7n!_KtR_95QGv|i@StHp9}$>t``fvSafYb>h*g>qg#kM zO95X^AD~{p2S7Bs1*aHp{(Axd=!++0WalV3D;wy~n8SR3V-|orcUOCg8CpCwd028* zmU_KTf4>&+EiV^|Mxy{Y#lq7En3^~&IXlbVx5l`7?SBgOdcEQCR@>^GRbQLd2QZBc zUtc^QDt1>9R<3U7A2+t z;MS@j_!Tfs@6<~sl2leJ_4*YLbRAT&#XfLpliA)F_qR6#cL<~l7LXDlsWO)$&SHejS2$NsS0g7 z3szBdBZXr*9+0V%*3y_p2FuR1=mjth69CJ$aEb-;iw;9ubpY%|2XkAxZLaoHAP@b( z>uZoqBmppu45neSchB2?;$$M}`#pQu60ec|CgkXaoV)?t6l@HSf7x_1=%!vCof15{U$=s-mhYrR8GBb0GA& zEz@txsPhlA`X;9SdJ%xT)hcmSW#!kofcD45+fV;%cyrPAH^j%Eegb%d^BR_IdCT^(vAH!ju-E6Vw`w|Bmw(SO zY@a5weVWMT*B5b0MNGp$c}Z!}DKQ1pFfa`Rr&MI~Ym00@5^jfe6>0t6JR3vao&Un6 zi;V2pNv&1`ptxL$X#FWsVlifK+yLPH_a*?a@;1fg(i0&<{V%Zdw)dXT`pMUuTdR>@ f$oh$Uv3~)`hWImlc%F&?0000JV7wZl zM-xLl>OuVrtXhZ%VibuDMtwCAq}A6#rL?7w(z@>K<2_m-e1G*7CfUsH?97|p-_FeL zBa~9uP1>^+WkSfhtvgA!yc^?oRxJnucXUM*;fWw{nJ9`R+Tj9_bXVJ}1?5lAEwE4$C=oCPW^%_{BA)LpHw zQh)|%&9VR^odp_w8h-|*c^Tr#&v4s$9SjY1(ERoiw6?awC>bR%S)&Ee$@jb*h_6Oy z%gF#VHMBs_wOf3SK~FgRTO_hxCB&2}rz3}tapi^v8-Gm4rZlxcPy<-osuov1L{ zsM2m40d(Ho9bh|6v!jS|rz)XyL1+V)%g%lNzlf@X(CKti1!l!LI+Nu^t>GBuIA5-> zOAO%0SOJ23KF^&X{K`)KoTF3Zl4RramU=S?jl4Y5WHL!~3BtL#IWQOuydR5AYv;|1 zpT;wpG=JD^c3ubUcDp`VfV=m2JdjGIpin44qr(MVU4e?7mvck__3%zWJ469vdD~eK zCWIbj{0D1inXdPMk1OL&R~5~Sa{jUSG~wG=E)PZ0yNdJ~fu+M6R1zCou_#HMvpnpv`1od@wkj>>_4~v^{I83TaLv-HQ z)CA2wAC%Z)EEWq3$`llf1sIgGoZ}efIFEX$k9NA%f!UcE2!&olU*CDiX0w`n=tPIs zM>)=;9_s5-h=zxU2||wzDH{E$T=o7IXm3Btc5LJv$K~^?4chB^7kJ$JsnKL$@Y;Dn zDt|A<*<2cmOC|U%{i@AffV5bU!DzBV>Q7P&I{rRjae&!^^EG{zm(xN%$8#R}j{O(x z`j1IDnM|ggTL3F2ycLT@@UuL}n-QBT!#>Kfujt#2T0T7*8qyYl9LFlDdT59Cy1WPQqgBH4KOkPsk|e>s!9h6P)5AHE+wBI2!=dS? z#$RsgS+?N<*b5k}tggr7aZQE~j$AHRF_u~7Q*}@u?KVUI1Q-Ar%H-@1N8BO+0000< KMNUMnLSTXn6x@mc delta 1107 zcmV-Z1g!h=2j~cpB!2;OQb$4nuFf3k000CcNkl6vsc)@~~YRT4Cw# zthEVX(1isJNNo90fi9XfEVi*&2wPs-RGX>|hNKVm5730-lRlbMG&X^NP=gQ9lwZqI zT-s8~T2au}GHd~3s4bYZ<@hkmwgl6iK@(p*$>h$Qd(QWK?|*mZp1JV9{l})PC#j<1 zm^_}U0PP*0t_v&9baC%7dAI%plt{VG&Tar+(liMMzcx+6RD#$0w!Bw=ifHvndgr$~ ziTf z;dDODjHVGBF@LVY2E$ZE_-Q;qp=Tcx6TNhNqp|n39s2z_jiR#sAc7!Fo^pfRjGW98ZrAw?Pt5B;aM z5#jI*`T2#>cmb5S2D*xy@LcfWcAbeyBBlbNi=f1vrnJNZtTY-SD=Qm8$a3qWi0&^f z@u0+=CUh|tvJnFF-DpQ@NlZ*4H8l-@)D(SeZ+~y4Ais$Ajy4eVd4ZIaG!mamLOW6m z^Ib6sJh2gFlsshl!2`A?q|w^e0s>Q0lOS;U@+GFeY+xay6oAReNdVf~T6i`!jpU>S zHpFe@TJt|q0AWi)0uHAN5sCf&KCD(NAS`5*0D{$O#Xr~=eLbqGvLzuQ=IUcA5W!<+ zT7ScCcM$r1oW*x zMLYGm&TpOP5W@=e_xC6(g;tu5Zi2}2x)m^GHe0fI_g09_mMk_~vaI-Yzc=bLW5&OM zhy{iN?8@7@%C{?TCxPK1vry&;sH!u%x*w+|SIs^CtU8>gR4{ZVR8^;BXTJ!*>`d+3 z{Cex=s`>ff=6GiN4z_Kxuef9;tQp#lhJw=5pI@`8KknRNCafv8q-04&1x Z_FsV9thoo-i$4GW002ovPDHLkV1i8KB4q#o diff --git a/Resources/Textures/Markers/jobs.rsi/ertsecurityeva.png b/Resources/Textures/Markers/jobs.rsi/ertsecurityeva.png index 7e5450a302cb41899bba857158394238c4f66092..bfc5c0677ae6ebea93b75d455d62499749eb1898 100644 GIT binary patch delta 879 zcmV-#1CadP35ExdB!3xnMObuGZ)S9NVRB^vL1b@YWgtmyVP|DhWnpA_ami&o0009h zNklRl4t`GvHA_NNBAnmE1dZj4Lj>(n>M>mVt?NsMqUcS(a?ITFvW&{$lm*Kl@+E_aO%M51Sr> zoN0&Ri8u{U4u8|Zrvq|qha&GH^zz=L_S5h8*#gaGQ{q%2MLYHmMPEfF##qhgd7cj} z3tFufrPFD$UR#ukr)aCWMJX#K1%qyyCatq|MzsMcVB0nu85!YFL@5KIfQ`rojfpQT zu;cPp&wIeCNVnUG1m$u$+T7gq=z9};5|35Kq>^p<*?*-j1dag+pB8vwVWCa95{y>2 zZOPa7QfwFoU!0#O7<+ej7h{UY<5VaVB*qwh%!3d7eNzCNC4|{Uk)elTa~;OV$J@r3 z2Os!@DiJ6MlgT7}D~k=VTN9);fFTrg2-f*~RzRIz%L1C6ot6D!vFOn|(cE>g0y}XQ zlo;b_fq&uK8NmyM)QSCyDSD++VF*OEZkls;Vhh|A!KF49JFBZ#3Wu3>kUSmMZTBM! zR)laBRQkyg6F!qmz7<#5o(mCNfZQ)kP015~So=t^Sd1LUk@)$a-*i7R?2Uo1Os@dzd7fXIxaj3NOsz2BYxNsh^OU4HR>kLu@V9~) zU*30pq=Mn7*6BhLRQ_EwrOc{3<{B;N{%9xqFEHHzRe@^$uOAZ#E4eqG4j7j-r3U(E z1ZZJ;0a69Yuhc-EWd4$?-vvQ$zn)%1+oHsx#_Q!+m0{2^ANEBQ$O7_3Bm^vq{?p}U zx+7B151`+4-C&f1x@1?Ca%=>~rV7yy8L*(5Rj>?!~N002ovPDHLk FV1f}mo>c$< delta 1225 zcmV;)1UCDI2i*yfB!2;OQb$4nuFf3k000D+Nkl?{8CO6vsap-ykn2gpu8D zt&6ga_1A58cbR~`G5k^!ql}4&Y|cgh2NUBP5&i)aH9>+*Q4>({jr+wLl^9sNu3fty z{0LpU-CLMJNMxgla(vO-vNGD;65e>;JWro{b5m42T=z2Qw#F6EPYRF`65j*|v2%0FlxA-*|IV3z0~e=H`~- znpotvKDUkYfBXi(rOTJN3T&!20Q|YuC}!)x&FEe>s>+IUoqag^>%iFIh{c^W`=%ktBWgIDa>` zTN+4P3E4mR3m3x|0eGjyQyzi}Rd5yL8DQ6r-Q2!)3xI{i1prpBeyT`lsVpuoTKd&E z)_*zx7(6$~WuU1HR#^f*uU{0!NuASK4F7lEe@jC{15Tw5x64gBlg4f7(wQ`dF-K}9 z#r`)Akg=j+7;~6elSDF69RYyut{!pMyNk(}&ZH}u7bTG#U-jV!9|;KQOoo$RpD2s7 z;!XJSo>yeUh8h4SrzY67b2p>W2pelQVt*KOC`!KG4b$q3Oq0aK!%zD#S+O4w@}*_{ zpzG+zbODDnorT54VitUQZm76tvt4w%qHDV7nl97%yG8y5nX*_-S@VA^-Q**-=N0A3 z7s%z$^FU$&dObb?@OpgW_4s6R34!U)?2}lrEgw39Jo`LsdI35-KBj>q2fLTq9e+94 z%_OkTtK95g63279Ldip6RrSe n)?8+j&1Sg*jF$9@D<{E!iSYWAtP%P200000NkvXXu0mjfvCT~o diff --git a/Resources/Textures/Markers/jobs.rsi/hop.png b/Resources/Textures/Markers/jobs.rsi/hop.png index 5c9b2f05c1b5d4c8a92e96069dcb705d97746db5..f8cc9dc402a14e48fe44335dea1df7d45cc77ce5 100644 GIT binary patch delta 927 zcmV;Q17Q5I2eb!}BYyxHbVXQnQ*UN;cVTj606}DLVr3vnZDD6+Qe|Oed2z{QJOBU# zR!KxbRCwCdS4~J%Q561OOe*+aPH9B`faWHHEE#BMN~0hP69;PHq9T+a7gI!K(5`_9 zbQ6Rd-9!`#8EC567qFQWkdnA}lCRGLqYCIs68W~C}fNXvE<_|Y8IS4lC6g2a| zbZ2Y$;%Fam_!J*5ylusv8q4;2aw-HtfP5*EFE(3ZTR_aw+SKb7u(_eFX1CjcgU4C3 zUeCHjQMu6^rhiL}@5^V3{9Hc9`P6i3lO|(+99EVBvVM~ z1P982!Tvu?LQn8?pKFAzjN7DqC^!!`+wJe)@wGG8?@NrIha<{Iq8(~Iu(`6v`;F08 zK|QVed_EWq232*f%7Egk6T;lkFjw~Lrx#yGKJlLBrhkUJ@Or%%7#I-#8V<-tO!xM) z{G;W_$;ju5iPS1qR0W|VXTQhe;r&8iSJ0eSgNpOH4y6Xj%3;38P-EdrU-*^dYy)45 zWJEjz6y<=k`xvWmyK(V~RV=#=vHX&eUjGm-aWCC`8%Rk7ylZ@)_=sNY&}v7XVXU*J8RM0BfS~c+_G(9zZ@HTFKFWd(VbjL#buo9kZw%MiD*vifqdEl zQNZnGGCniJoJW&W4MbCxY62d(U0<*~Q_V_Rdw)a;osd^QAdzz7C!;k90pWa7W~%4`S8y51z1;jH^GQZ)fCJ=G z8kbzVC2&kokgS0+@o*qM5Cu{wDACOWzYqQ36AHzeeh&n>o-#co1ZrtV!jhz%ZmY1| zw0}21Bl-^wh!*bz^FWtS>=T4t^-$d2!lBqPvx=p~MP5%&@0hVSO{%m;@kgYsN%~9r zzRGa(NvAlv!FJ{32&Td`MNq6L1d|gJthTNWMxzmrUw+`q0*U6dPW!}1{F;0ZOm|4{ z{PWr6h)k80m4eM?i?~-`kj33pd^PsJ;TUfL1^^4SEcr2Sou2>z002ovPDHLkV1gHB Bw66dF delta 924 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 delta 883 zcmV-(1C0FJ2Z;xeBYy)>NklkJx)d+1kOz(4%wf~9L%{|YOhYG88VX4|hN40YbxbIvCE;?!LJ{a(DFR7$ zJZQ-4pxjZlu60u4X6YY}@7;Uf_ulW`eV;hN|9ZnxhFz#m&wq(+AKbq^bRN&E7C-KO z5DiRj7i<6gwc{K6@N?kRI^nMP%oS0m=R^*x!e{i1>hzqbGgk)g#6Yh=L4h+PwAyVR zFKq+xcxjtfyA5YXy7AKlupw&o2Hw$8?*IA#@8~GCdSj^Kg9CWF(=T6J#OL$!b~J*| z=jHOX#h&=70e^h*&Nz5H+$-K^&wE!k{#=p*^B%1`N1xLA~QIxUGr!hrys;)z6}3wW_8`6=Bs#E6^X zvu9J(jx6v&EEXda3Xx1E0Z1m3ghC-=u^63BhuV?F?0?x5pvzak>3w&mt36OVve;`H z0GOu9#>NJkrZG7=iKb~7hJk6C0PHo5F04zP2#}xB<(xn66o+mHY?Vr-WBq$ggLD2k zZeB&-4jgvc0NCv`O_QairJgy_Xw>O|JcLa02TzZUwOTD_3D#(y=}WGY-^}bGRv~CEQ?GgTE%`s2F}Kiz%+K>euW_+EJHJfiOSP7T0%Ucq`^>FXOru8+$P zH*9VQz^99g`2BtWDwT>74u=Jx*=+Ld_3Hq9eD&(<{eQ5zzAhpnwf%kB-PsXURmCnG z4u?fmRoUIyk=p*gh=^>iue<&taz(nbvT|&~)zwwyq?nuBe*%;BfgMOi3A|CBY@F0jcLH~pvdeoCA zp;Eml^=QaRkshTVNYQEwX;MNE64Gp~A(qzX{$4WM-6W<>cYi}J4kYtt-pu~y&6|1q zR!AwSozy{XrnU#*X*9X{_Nh%Cx&4Uze!m(^%ialtzzc;!jX!)&9e@Izn5xmqs=}$r z!e+F+>^uYY2w?i!hZ?5vixj;39O3Wb&QK z5!B}UMQN;D)PM7Lr3i0E2WVgarN+NMzp-)Fx2y}I(Ws2a<07@RtiTR;OO#ppsyJlm zN3KtamIVNC1OX6$b^5#%7#>s{^59rRoF)UJ(Mee8E|UU*fHGcKSfIDBzp@?hcImNJ=)fi|o-Wau0DIm!T5mCxrXolcv&_4Rcd|NeSh&BM-`Ek{Mz z-`_78yjUzMT`(9_9CCW}J_R?Po2%ylA+ujLn-z{T05IdH9)yQ7$nL{c6P)$1<6s?c z!OYAIEq|}BP%IX!2}ot*?nj%<1bg_w-%$WJyd~<%eN#QZG5196721tKpWV?+aMr^P z_V9zhD{n*XY_IVjw&_Zx5CH#HgK#Q1qlwB ziS5ckyKod=J=duWR(>1`W3{F+cZ0S1xd?f?Mt|=;7RMdM4GkjaJu=i=PEvB`4{aax znmvw{BmK;|6PkS&G<_ptaHJi83|@T_x^gM~7jX?#&IaiufdAhG$8G_Nua(r)jmX-D z+;a7Fu62RY&$wu+EBR0;Y(8mkZ(z{&rb&j`_$9pGcmW42_aKUxTd?)1pxQ? zG&GwIL4X+CI$sG^xKaaH1=`Mf+}3N$>iLtb9`sj$0RVB9m2j)zb*BIT002ovPDHLk FV1ixfjwS#A delta 833 zcmV-H1HSyx2G<6VBYy)PNklyO=uHA6vuyw;x^WjwnU>C14Y+LT2Z&si=rT2 z(t~&s66r~Vh~hz_PzZt|h#w$$P!aSZSnwoxQ@m8Xl_*$ZHDK6S!C)j=?P@GZ$3s5W zZM2z<_T>LEnK$#^`^}r3nZW-pS36Gkrap*;w$Z`$ZN+lzbboK^gP1i6Hrpz1Pumb~ zr^x|Kqljq~8}?i_!>m#GZDsx`fa39x%VzKg`x-XWDB=(HVH!mgkH=|#X8=FGe+M8^ zN;3YigQH4@@rNBmN=e(e6FJ(mo6o02eZ>ov%Vy~Gc5`gkpre?MDzGqk|BDBUj>~Ad zQwON77JwaxtbgBa%25Skv6ujwwxHgxk1q*8EEW^Gt`kq(Xj*kHn<1XKfv)S0A>;tG zsJQiR69A#oOM?9&fX1;4_J;_SUIK9I-6qhY(h#iyw5Y(RHM***l6{ln#J-)jR#jEY z$EQg{$bSR*>RC^x)A)mZtWXrbj_hWIqTmnqkxr*=^M7QuIDi%v;Ijo)Rh7|GN0>Oiy(NIuO}M7l3xKZcq&oIn1KP=Iav?~$ zs+GTb{(lMpm#$rq3Eg@Nj9C-!s!l!?3{uKA!u~X&nY)CSJ%!|T!r?HXfdNKFMo1~! znxI>$Zg@OYs9?54Be6pKaZU*{;fG{Erium}VK%+1X)Jv~h>muo=Oll%RC zUOKJa%+`-@0r`7CYEmE&XsWAeniL8JS65e;@OqoC-I?1TpcqqN700000 LNkvXXu0mjfKr53Q diff --git a/Resources/Textures/Markers/jobs.rsi/librarian.png b/Resources/Textures/Markers/jobs.rsi/librarian.png index 34b91369510ef4de98b94b936b69a32320024521..c15516afd610ac47e9ad4c0ac2c88cec1e18f2c4 100644 GIT binary patch delta 870 zcmV-s1DX8n1^ot)B!3xnMObuGZ)S9NVRB^vL1b@YWgtmyVP|DhWnpA_ami&o0009Y zNkl45*8V~WZ_E`TQ!UXFHN1YnI>+|Y^}xDJ>T|ScYp7OhWDz_fxGja^PRKb z`Of+7`MygirLdW_1vZ&BJ%EyxCZ)a}mF)6%fyH8BW13exA`|j>JYL|BK5Gtuf$nW7 z&{56C$;m`z6bb6jKruqF#PDE&UT8Q>1wkN*L?WwjGy%LH(iuQxk zFN~v%de@N_vTgw&cxPuPMGyqrYTgDr>T4NCxz^o8){+6TQYXCoVp=74JZ@mdxA$EI z@2(m}-!~G43-7wwxcB6+DiGh%Dq}K$;Fa}eMZR>-4}U}5cNph{^E^mHOP~dBYiomB zpF;2~I?6c8YYk%65@^AZzI|PQ*NOcwH}@N?Rudc&-a>QZcaV~z$_C3}SPAeC(?26B z9cDmjyD~V=qn%-!khI%qMNJ&$qZU<)c|d((H+aQ>O2>)&(fhN+kPPtM&9i`@jW=H^ z;9ReL3x9NPLcaQrW7Uj*zCH_;PqMo9!PWhAl|Z`JgN+Af!&49+3&Vr6ewdN28&Y!o46Ct25_C}BDzmQ!CE2zW`VBIdFUk-Y<&8BGdLBiY-6&t zi_9K_HlzgD=Szj{ECWc_a^OfyOG^b0x61~t^M5|@rt%c=1Rk;)^~mYBYcha@rQmKu*70={7^R2CH zwf+75gs*zt1K2$fBO@LUTe;Gl24esDcR?}2x@&8XvdLuHm;fdxCku4=L8ARAG2}Fq zTVF9=G})EhStlxni;D|TQc?=B=_skLs-c-o8p_I+?+jz(VL~SYycO%u0D_y%f=Y)$ wAaU^g`CPEXkP_f3iq(C!eSv=eLVpDq09rbh>V(Vgu>b%707*qoM6N<$g1*w9zW@LL delta 724 zcmV;_0xSLf2J8ipB!2;OQb$4nuFf3k0007}NklW_J7~7Q%<7_fshxG)F(5!Ssfb< z2r&EwANiM1t{g*6lxVEJ-8bM`VxE$KA6(!%ij{rDus#?70CoO{Wk1~rfEH;*E9`oxBKq^6pO_kouVjE6vYt$ zbH{$z*q{IqUswRgaR!Ww=Xq*Ctgfs803OWEIZb}1pDN3#6s45Xk|fc+OokFdsF9fG zc}fVOdzlO^NfM=$(&bc&`Eklby12M_YQSVN>H50H6;g) zX(I_mC6;{NBEu`OPlloI@{VAM{vyp1}S_gW0#UD%*8= z8Y~tI^||8RF;P$#i^aP6IH%(T2y`q^=i{1C9tD_B8cd*E>oSK|1-lHTtvflU#gqrZ?Y|O?dms9Q-Z)qW;e3H!3ap zyLJk0J$}KT-MPUw78VI?cl!@~`?NwDZS=dw1FUNaAUGz0APCmie-Nx^9Hh~9ct=?$ z6=02+uzI>=i9{mY z=Tm7E9LG4*P60keC=`+x#Z9J^cs#DMrE!eMd9Cb+rWKH$TH4*pD%fncmf||5;zS}r ztzA*h!%B3Vz=Mek$Zn8d`-*+;%FRO>#G`ocD!~0$a@^$jh}{1&_lR4DoG{=#g?EEF zOo(S47lq$t@VnilSw0U>XJ$yFoD>dG!#Iq`q)nk>R#(~C;bHQNCqbTf+-hYPhmI0|xUNkbe+8?{%ly*R6am}q zb`_Wej(!}+IE*)~0w}N7i@HI*p>O~I002ov JPDHLkV1f^8gfRdB literal 0 HcmV?d00001 diff --git a/Resources/Textures/Markers/jobs.rsi/meta.json b/Resources/Textures/Markers/jobs.rsi/meta.json index 2401b27be7d..bca3be1df84 100644 --- a/Resources/Textures/Markers/jobs.rsi/meta.json +++ b/Resources/Textures/Markers/jobs.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from https://github.com/vgstation-coders/vgstation13/blob/e71d6c4fba5a51f99b81c295dcaec4fc2f58fb19/icons/mob/screen1.dmi, librarian by Peptide. cburn and cluwne made by brainfood1183 (github). brigmed made by PuroSlavKing (Github)", + "copyright": "Taken from https://github.com/vgstation-coders/vgstation13/blob/e71d6c4fba5a51f99b81c295dcaec4fc2f58fb19/icons/mob/screen1.dmi | cburn and cluwne made by brainfood1183 (github). brigmed made by PuroSlavKing (Github)", "size": { "x": 32, "y": 32 @@ -13,9 +13,6 @@ { "name": "ai" }, - { - "name": "passenger" - }, { "name": "atmospherics" }, @@ -28,6 +25,9 @@ { "name": "boxer" }, + { + "name": "brigmedic" + }, { "name": "captain" }, @@ -55,6 +55,9 @@ { "name": "clown" }, + { + "name": "cluwne" + }, { "name": "chef" }, @@ -67,6 +70,9 @@ { "name": "detective" }, + { + "name": "doctor" + }, { "name": "ertengineer" }, @@ -97,6 +103,9 @@ { "name": "ertsecurityeva" }, + { + "name": "engineer" + }, { "name": "geneticist" }, @@ -113,13 +122,19 @@ "name": "lawyer" }, { - "name": "doctor" + "name": "librarian" + }, + { + "name": "medicalintern" }, { "name": "mime" }, { - "name": "zookeeper" + "name": "miner" + }, + { + "name": "musician" }, { "name": "reporter" @@ -127,6 +142,9 @@ { "name": "paramedic" }, + { + "name": "passenger" + }, { "name": "prisoner" }, @@ -140,52 +158,49 @@ "name": "rd" }, { - "name": "roboticist" + "name": "researchassistant" }, { - "name": "scientist" + "name": "roboticist" }, { - "name": "security_cadet" + "name": "salvagespecialist" }, { - "name": "security_officer" + "name": "scientist" }, { - "name": "brigmedic" + "name": "security_cadet" }, { - "name": "miner" + "name": "security_officer" }, { - "name": "engineer" + "name": "serviceworker" }, { - "name": "virologist" + "name": "seniorengineer" }, { - "name": "librarian" + "name": "seniorresearcher" }, { - "name": "warden" - }, - { - "name": "cluwne" + "name": "seniorphysician" }, { - "name": "musician" + "name": "seniorofficer" }, { - "name": "seniorengineer" + "name": "technicalassistant" }, { - "name": "seniorresearcher" + "name": "virologist" }, { - "name": "seniorphysician" + "name": "warden" }, { - "name": "seniorofficer" + "name": "zookeeper" } ] } diff --git a/Resources/Textures/Markers/jobs.rsi/mime.png b/Resources/Textures/Markers/jobs.rsi/mime.png index a051ff5117f1ac0d25f05ef58a7efa31bbcc37a8..c9bd4e88c137d09623adc11595df3f91aa0228d2 100644 GIT binary patch delta 772 zcmV+f1N;2^1)BztBYyxHbVXQnQ*UN;cVTj606}DLVr3vnZDD6+Qe|Oed2z{QJOBU! zy-7qtRCwCdS3QUmK@@&-S_+YHk}6S)m9vZ&FHN{Cu}LduB{o*pHn!OmHX>SC*k~hG zVmw%q(BrqxToTDHAb$eK56yOK z0z$0<`5V`6$E$#`vMT2LXA5HIl=uyfv1a#3ufT94QUw;Gmg?&y`9~agZ5uXm?qKyc z-Q-}~w!f6Q<$nZv;O9Pj2X}Z6j{s-UY|D>bJ;ZHVa2jMdE=IU zo|hs67!HRVK``8`3KoF5UPjWBFp@Y_yVObW( zL*TzZIeh#5D{qiYdRo_gLgSNlQ~)A4k~L9LQaMPrM1LrL5JVCHD5#7l6Zv!O0|UJh zaRJDkOOgO|()AvQDF7lhA$7ZKJSpo#64|M8tOrpYcTua=e8JW3_t`2SarZ!eC~@>= ziCn{)Ww9s~Q0)?V4g{4mu$dzG%?#jjp&)`+t5tZtzRssrfJ#qxWKVwid_MjM$+yu6 zip3(d+kb7!;3hi6mh_oSM%a^I>?ZuPw+G|hUHCj0zz74rEtQ16)oMWrd734aCTn@L zBe3aoI{p!)QYqH$c13dH)r7L-D$zRGkv;hlpXj>)cj<{Luj*!f7leKjg4W5*jp-}7 zUKOt2`zfFOa|4jcf^@S0Sb$@u{|kUTcR5ef$9?`W`4>G9`XK5*c>u;RSGO)6;(vGw{1Mzcd(UZX6(wU4rmNa&K6PTWwLK4Md5#RUQUXqc=62td> z6^lhAF*!NelR(ec@z*FKm&*}`A^ZFL+^p5OnOL^~5;eymo6RylK29!|<7*W4bl#J| z!Ox#Gzkh${^VSwo6mfWX$ZKQR-Q8tpXNOv?hUa-?W@flx410TfL{UT-hK!Akr6SN1 zzV9oMe&zFd#bbOybxF6)=^=KWB$AYtZm2kx0Ew^VwCMLEvfF|44_#{X^*SB~{x1Ug ze7BGMS8A*A;;4y2@lS+6+T|sn;b*%S%hCk7FvP3kwT>-EeVn(K&7{&ECHN X@`t*kA8%~{00000NkvXXu0mjfr|)Iu diff --git a/Resources/Textures/Markers/jobs.rsi/musician.png b/Resources/Textures/Markers/jobs.rsi/musician.png index 2ef8ec312d53b1990b043e70ea58bb129dae6f78..7f82c6add76de851b4a78b086619f8347f3c550d 100644 GIT binary patch delta 799 zcmV+)1K|9_1+@l{BYyxHbVXQnQ*UN;cVTj606}DLVr3vnZDD6+Qe|Oed2z{QJOBU! z*GWV{RCwBA{Qv(y!$1Nih5-fx?f@2ilDF6NqwrNj3K;|h1i<{etyP}A3s6_6W^NG z$MFB*888Ni>Z3>he_lEW3hw`sl9K;{;&3)d9H{<3Og#vL_2V%ggo%yn6Ymp3vze{~C|d=R5NSRSN~YKc%-K<2-+xF*BXm)B8z2Xhc83P8R`7J~tp zzPBHqFj6H1V5u8dD8R(ga{TEki*o096_-I4v0sB%Y9H#g4oEZ8wA{Jvfz#ai6iR) zVVE9@8YJk3NQ$X}G0f-4g%r$T#8^yriwHT(A%CZIn4{>{Dh62&%Jal#x6yt9)f_;m zD5h%1gxDgMl5~K#HoQH*A6yiJn&gTKN^pf=zIe*E|W#<&1Bd15Le d5EuXmFaYwGr5g3xynp}z002ovPDHLkV1i%IZlVAH delta 684 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 N00>D%PDHLkV1mxaf%^ae delta 818 zcmV-21I_%U2FM1GBYy)ANklzO-K}B7{`BOLBX~))Ph92Sci#F22atYQ@3pq zmZ+O39g1l{s#65w!G!3Pure)r2tAg_;$p2JYO>d|2wp1ltvFDM_XY1D;(Ie(EF}ATYoK46()6L=iY|E_>mv? zRS=2w_z`47;CKsc0Oy_z0r31vKO0huM$|||ia_9eUA{X9xbSp{16u7oDk7&~U1|>R z-R%bm*JhkIMIdl=tG|ES+AQ{~3Kj|l$!4?K=wal;r_a3T{hosJ<24f3-$(C+ND75Q zK~{UR+nfR+nSVb{z_Kjq?CfOUof|)#eR=SR#l=PP`TU>h0?V?*_k92sy6tUe!M*SM zSe6y39F+*zwk?@V27p{HhiRHDblapShgj&gF-?wf~^c^(rJ6CsIU^*nEzoGSJt z5IlXoQNu98>y?$2UH4trC7n(yrJ`X3DwPTVK{!3nqo=0_fY#R5P%el-AQ$L0!k#ry zDwQaeN=k<6F*7rxthXnDo7vNx?P#O?<}GX4(=zs~_EeQhCCoiQS63J9?d49DifJ1ll5r>(7x;o)J*wB4%Oah&klwrw28(du=6nLs^u4yB#7;D5RQb$MAt wL@V+mBg$VyN=yd^26i<#I5?>7b*5tb8&jiDItoV5g8%>k07*qoM6N<$g3YUkCIA2c diff --git a/Resources/Textures/Markers/jobs.rsi/prisoner.png b/Resources/Textures/Markers/jobs.rsi/prisoner.png index 35383af8cb4b8fdf7e86a45af8deb5ef0ec3c6be..c4103ddb5fb533a541e77c590d0953fe39ca7ab4 100644 GIT binary patch delta 909 zcmV;819JSl2BHU$BYyxHbVXQnQ*UN;cVTj606}DLVr3vnZDD6+Qe|Oed2z{QJOBU# zL`g(JRCwC#S6@g|Q5gT-{vi}?`6q;;ZN_?PL0v0wqP2p+3MK|YD6$@c$R4r>iJ+&V zhtM9Bf}li*ASe=wpkZqcj9T7FO)46=8QF`v?kd5GINk4TyMNo=mYeRHFP)cjzdz^v ze&@U2`OY~4V+>2#mSKt8k`q`lmoaqjsz$aRIRm57$iG?IzY~;3y)4UF<7v!-32@L| zby+%=kvIui&^UdRijP39Mqsg^CrfXzIhes<5Mr@dT(L<6{JtUyd`o=_rfT#&d#r*B z=0jkSM`};{(0@}OQ&ukI8m~(d&iI4)8JpqXKVIL}^hy1q?SlUPe%8^^A&d`89PIbk zS$qz>V31M>xRh=8}U37wJzo6V+3579ZHtabuw6dD=;OP@JoR0QtQ!{`hK zl?aJwD~7=3gLYWE&S7%w6XeFd?8(h`Pz0uDfyNq&0C)r*JO|d7#FO&Cg)U~aRH343 zBb^QUoQ70rfT~mkl-3@~9f6|?IQbK4U5;a_^M9)ht061p_M#=CHNLxs8jDsXhsP8G zA}1k-btuIjZgp{oEyvq=a&5K#eX`L|JPFgs^|Njk2Ti9oI~y55MA zz$>Q}z-YYxRi-7f=(l15O`d!s2@?O`1^V1}u1S_A zB!6Ctbt9ncXS!%&F#H|SsVTmpTU{>xI`aGd@Or&yX=&lUZnqnKy}kSdEG;h=>Md&u zD#Zo;g7>4Ntg)#HwY9bI3=CvF!AK@O*~yRmb-9#=dgE`y+YvdZlf&Tke_uKG~00RK7E`!h*ecXQl00001KIqd2fPN5BYy(}Nkl_-;&_f`k_2h#gvZM(^uVM;;hMSnN98L{HQO4=vdN;33 z@9tFyzc9`@zrWw}(#Dqv`WHs1$H(z0T`>_(T$qi zEKK+BTyLkyl3hgqZm|~rLt6SZ&R)8}qB22lZIkJEmM##Dga)h0!Q@5MG@T_|*rhE6inEg64B$6`haw8h<#@D_{ zn2JEdhiN=d3n-MpT@=@QhLa~@Xml|7K@ta(nIhTF1c?~wKIbw z8EU)Nf_5xBbb48qQ4~cdYsm}(p!pe9!LSQP_jWy+`G15K`pB1{WN+8?;R*sZ!I<6m zh-z1|+!ymR!jS~L*Q@AI6!P-&NQp+(3M>ONs=lHEobMevpZxS4zDSjH%*-ImGB9AB z!0UUZ%d=4cl5f0$}E=<#@xu0&Gz!0(k6+S=OUf{a#1q5v;= k8y{_j3}A53)TT821Bt~&agM^K^8f$<07*qoM6N<$f(vShZU6uP diff --git a/Resources/Textures/Markers/jobs.rsi/psychologist.png b/Resources/Textures/Markers/jobs.rsi/psychologist.png index 3c6339791bd91d89c829433eee6db08f9574d263..31af5230d74fd649f02ca8acd57c85f4bb5477a7 100644 GIT binary patch delta 790 zcmV+x1L^$G1*`^;BYyxHbVXQnQ*UN;cVTj606}DLVr3vnZDD6+Qe|Oed2z{QJOBU! z&PhZ;RCwC#S50UWK@@&drBMuSN^3%LXi~Mkc}aqoKn)6>^kC47M|;qdsJRJ(CvT~s zClBpikccR`DY1})Vg(UAG^Cq~2#LgQG-@K~IB&AEne4{wrhnO(iw}nP=H!mzT)at92gi*Ow-IeEp7d+@pT} z#3C6P01S>GFbD?QwSN!H913%e`*1u)cJc&Bze%WfmqD3KhI+kTE}vNl82X1B70w%t z2BgzzVk%m9x&VWxQYkJ6gFy%cIsmp=|8JGcMocpZyMMO&>ym^2W(xCSZP!ze_D=qv z$FKt+f~%@Zh1_g5`9c6f7J<=D24M%lQ4!+f&1SQPJn8Z9g(PH=0<@FTG29>$c^AQ* z658waVjal{<>|e;(+tq-D|vEk z&WqP{cT#}CXBGCXp>%Ygzjt%~Eu!1B!Mc UL=Rb2p8x;=07*qoM6N<$f`c%7{r~^~ delta 697 zcmV;q0!IC;2G9kNBYy&yNkl_dv ziO3&d=|++A2N+myC|egMX8(aMSzw6TNNf}-wWVeW9UKrA#LEnSATKISGG4JV=LR6h$~`d zaBacMaeaD1kCzv;w}!AiUS7oh4q`!&inh0gSmZO8 z4(FUyRmGQ2A13DBef*63`+Kz8?ZuQN=bTK_B-1p>b=}Ao5K%bCIiLSlaL(x|Fvgx7 zpQ{K#E>=fG{eB-o5J(9Kf*|6T zNWkHG9ZRV@9JO|^Tl$;LfA@I&dACG3YVBYtb%(?C`hTAK1Q`#MWs@~*47p}oepkpZZI4UVcRy| zpPoR|b!fVdk@@4<*iuKP_{ps9AEX##luoCS&*uREuIq+2062~V+qP5VK8Xd4gE2tcmO)r?d*|AnZ-4Hoo4zF;c$|0dJ?H&? z@AuBR?>#~(h2^vaSY}I%HGvQUC(807WNUcdLl&dvyaYUrSHi}E^)v%F<|IParuCuu z!B4}S6q%imIZIMN*j6YzkDy2by{rv%#&j=cuWo zj(m1?GO$12e!|yxZsu`}^FnbUi5md~M-m8vV5`=y26e8Mc^qp^MzR0@;F)t^lMl&Nlsv?c!c}r5DyStkmQseT+nztwdH>=8V zcY~2W9|Zf$Y5mh{vLyK3qxIabr>QzUWau-&<7iXnU4Xp~ppQ@jU~?Ea8iHdyl2)V* z`O79KZnqx-88DKxfjxVJ!2q=-CD77h0Jqx>et*9oh5|#PQhg!;BO?*)S70kfN%1`I z@ELOCU@_fQls#wsE9U^*y6Yg)oQ1aH1r@-HNXNb2G3Ik~(j(^P%2D)-DBq+Df#V%> zGC2QVKg+q?oWzR#FIag$Che}s-ohfBU5Ifb(CeLyYEBUXVn4I3_;vpzj0FO$p|75` zf^sHhy33qSC)}vn$1ljwK2f7H5BYy+|NklJxEBSd_om3cPrq~SIltfM{LVSQdoTRYGL$l@(|^+7)FG7BkAG(GGE+Ft#cMzC%J~6i3di|=a*j+s%k#&c)9O+mK(*OMYAcPo%!Dk< z^!E00?czDrzI3i#S71e&Q>9$JH$JS#VXvan^bEgeH#zaFjr`7^tZ(G_`MVVgPj+-& zOI_Ed)6*iHW;?Ct8)@*=s{OwvS6Ld(lG;k^t_ivhVSi1l59yx;8a!{YzWImR-{7fb z<<&`qu?gaOJnA?D;c!?alS#^rMy`&;sCU=kuvw{h*KlEm#_P6nc{oayrIO3TQM_&|*Qd7u2nK^hA`#6HhXO<*5fKOkkYyPFuh)y; zXHy}(ZhvdB?ezj6%QAsLKr@7<49K!fJYL+~L?Xf0Gu8NgHePuBWBfiF6)z8vNF)G= z$KxvOQv*aI5g|#E8XQnp3NSl63&3B$4DIQU$Kyznq$vxBW+0c#DKG{oX5f?4j{$Hx zo$5Fx1IjpM-eEfM8m3YyQmK?CN2Sg?5a4X%34c!cUSwr0!`a4uF?{Df0C(pzG@q(b z$G!dO9eh3?0OQeq;jmXx@2+8f`61sv4S*tt%?dy=ndGC_%mCb9+yGNCI6|;&C>B76 zy%~qi%F0?si)#&MU^`EhrIPiH9Co{%$u%e6+$%7-=A^s3o7UD=e11P|ZEd_+_Zv5V z9DmvaeWBfS;6XgJZjVR%1wcpN6@zjsb}JMLsrH3-6ED^7FtT(SfDimLJXkgH)x^$! z#yNBgI{L2cne1}8R9lv1rlzLU_O0kUYGAF>{Yj<-mSvexC}dFVQdJTFpcbdyMXD6( zdL09MQob9eR1n<&%8O}tKuMBtxm?^@_%w`gIPK=5FoaGT1i+&$L2q;nfX=S2lK&O=)s0w82q8o!ofZpo zbK*=LLJ1r?X%J`X5DRm2B9l%FA%wUQi)sEM(zFF@nGA!2gKE3^{ehyfIE44z&mZvu gKTS;NS(B=N0oF#RgR6DIumAu607*qoM6N<$f`+61LI3~& diff --git a/Resources/Textures/Markers/jobs.rsi/rd.png b/Resources/Textures/Markers/jobs.rsi/rd.png index bfcd188b59fb06c35e00d3817b851c4e68d3729f..0074397c711dff7d1def3e38de5c037c4447566f 100644 GIT binary patch delta 894 zcmV-^1A+XO2$TnqBYyxHbVXQnQ*UN;cVTj606}DLVr3vnZDD6+Qe|Oed2z{QJOBU# zHc3Q5RCwCNS4~J%Q4~H`N&<)8Xlf9WKQy6>7NQt7!&K8Ms33IFqK)oibm2s_$fXlX z_-2u7+e8!?Eh?BzgAR%*SwxbOp;Kg$$~03771nLOJ9Ec*Z-1WSIP=U89_OBO&wc0I zbM86sKE^qx-9!QHGIrg8J((uwhI|^{*4jl@t5uA7O72(;ppi%yPn2Rfl!lKb=TyVI7Xfl|m13xx~tg=yKoK>A89(t0b zkk35}^4QLq(SLeV4&lujPQRmTV*Km%0}Yk(9jgLw^t7f`UD?<`rTZ(z9E`_!mP-U!rcRist|UfBNBP9$E9&v| z(GhA+%HPvCb*tCucvC$&91f;CwC1FsU%f5fKW*w9u5Q8J#a~N z(%wY&K*0l;haU7za{w=^r84p`uLv;!+M=EyPV0iE%Ap7SY@OKBfeKZjSy~n^edrh_ z)i*$PyIsr`(mp}KLymdqK_Ba~?QEMq$fpE$BzZ|sQM-l*g`Px0p3%mZWjHoACUWbe zZq`p52Y(Ur^J=}I@&E$RtMDmYrX{aF@O(Td9wQ*^y}i8} zVay*#;t`Q&!0B{qA_cq~RJpafhRSLx@NF=s43z`LgqO;lO9X>KO+*0bK_5<=QU&Pq zg-Q`c7UnfO-7Er94^HImz|nS(`1l}{7|WeXV}E|XKg}t*29I2ma~bMeF}?+O08qEv zohH+_;;qUsr%S2a@yyH&>7(*rZ^d5g zDyML)GM2uriFwG%i;JivRw=WgCE`1sg77AHzi^Is!fjv6vGZ(X=KL8As-hK-EUZ#^ zWp{zUr1YL6u^HmjmezW&3PR(Zd68Rg_i1reJIvI zErq!X)yX=gb~s;$dzc16R>7xm_avHH=r&=0x`&Bu6k&8ILw6ZQMpM=prL9+1qt0dZ zPcliorr#d2+?m;$KbyYnyxjAh@89qH&Ua2u;Qua$bSD;`yMH2L`uwf#wAV>_Vr*lh z(zlqp)&jIFdbsL6EO@y}|Gh}M!OT*g$gts2=4?s-(!A)R`I&ENE zdmo~pg&xs*Hh-In=1vS`u(25dprW}`@82_k7J7smi{5@%_zfSu`3v)fHvwopn~fVw z$`DBb$g(W1i&g+;>}G<&Ac5X-xKl=;cbs4_$c)_#z;)4zEXzql97tyKw)S>ZRi%^= zC$V74&!OLW6;9ly-+7h%{CslJfDo#x($?M%AnbN~!hbiB5CA|`Ri-?iogH_|;Ap(* ziQ{&WU0oo{vN&H;!<5H^qA0q3ad9!KoVXp|1{6hM%H!dDO-)j+NcaY(yG>ETd@}Hk(Z!?{GK_ilQ*>^(I;xNWuj!mrK{9Q4pfGxR_Uqi+QKHnNJ3y zxnO{w*nb`+E|-hEyu5!0;Qp!y>vI-XHZ&T`tzu>}YX4z;oQl(@sjRF7pg@vnp$CA* za;xx<-{AQy6YkYeLV%>gFe}qYR;Cev_r2#hT2cbQ*w`2ak_1BVG4I8VUD?o*S$g+^ zq_Ny8^0PBBAIQMB8sg=uCcbkN>EXC0uaRrd#eYQzHx^F49?cbojYB{*MZZwsr*}B~ z)O~h!!Hr3up|RX5VtPjvqH{>%LTxR6zn`}*USyO}ef%lR9J7Y`)Ds1`T&8f>XHNeH zwo6Axhma(R*Q%?5XmpH>j8IiorMslRt(0TdaNNARKJ%_Okn*qL_VDs<(~}Lme@arB z5Pu*L2p~xks;cU?lD|$q?e)gl_XGf7c6K)I>vTE|fS&ErDK3%*a5|laOBY@dZ&V-V z;ldxd+`j>^=KGeDr4lb4dX~{S56t^7+>fQmTql z2KfHRg&ns0bL-rnORp+U8enK}PyqC`*Lw3}_TPt$Jcz!BUxR{oKOCg)5~8lYKJCA1 zPn2tYeL@H!mY0^qamNS*Ao|0H4;cDE zddPMF*ith)46*-c2?xq&L{aqUEaf494S+2BczGX&IKQsbe}8^{e#VaH?C zB?=7_r&%s|^ytxlIXOAThiA@$E&KcF2g9>-*T6K04-!{(wqvB313;GN=jZ+(uOWD`|GO* zjA)6LI=KL3IUBDC!>`Y8!2JH;Y`C0kOEs7V$%E`fcLc>D0J9vN*nkdrasLXK-6pHf zQ1$pGm@T2G!+@*?<_JO|z(lOiVF1JiS;oc11?GcjWPi(HYGBbtwL}Q=)!$#=@u~sI z!=i{Pxd1)h|Ni_6_aUFS5||C5VZMjSgVYln3Isy{=4)7-!uTKyCb6(0EXSdaatHjx zUBWT5bCacy=xlhtBM(%%F}%L_gyF;ed;bk9CSh2@%*Kf#c57bWe*r}$22mv$P~AYC z+K^vZ5PwK25fuU;%R%Zvj;2Z!fXaC`er`|*z zRKy5M)gWKPEW^eIB|>C9gbE^(>jLBg=jX>)4D9@3C}jnybphFpQc$onGBFXI-KgpS zSe%1=3rh#1{Q|l<09SC68x15k%dr))#1^|GJAVL}pTR}(!TVnr-o1GP&rdcsHemYN zjT;PF8X92skt0XoIZsGLgwbA+hp3{Ms3^E`<;wrS;9#)Dva+(smccCtiG$=p>OktL z(j>b*AJR8m^56qjMNUpmjQjTO!zve}AOJ3qR1@*{4FLiS0PO9 delta 858 zcmV-g1Eu_;2Jr@vB!2;OQb$4nuFf3k0009kNkl~)SwXm|g zNo*P@jROHgD89OeJ?7fR|3EH1`w(cz!Sq&~s|Yb6A(ukHsxLWIHxbnrV+2ho^q^ZH zin6k6yfm9u*>-vuW-O_xc2= zW$M^klq3LijwF8jwMPct0G+VQFbelPf4c(^BO2fNk3(NutxK zN-zxdynoy6T1k>%+eXRFFF}$d1M4iy$g)fmsG8^P8(YAuA0N_s(WZNNB)qT4dA6o#RFB;QvtNg-p$;dzVoHib82!Jnc+<&yfFwE`hIF7BK9^TP=ENe7{(cBh7 z@`hokkLCN2rYUh855&w9FxG8o+cvgslcuTuKQ4>}SeEs#H&L^}^tgSHfYZcS0*1%$ z@cL8*{8zol?SsO*-dFSfiz=_{hhgl!U9IXFu)MqsKzRPV6?ZxUU}tAX`+j--df|`L zkyE%=sR$v2h&vszx4SF0t5un+a diff --git a/Resources/Textures/Markers/jobs.rsi/researchassistant.png b/Resources/Textures/Markers/jobs.rsi/researchassistant.png new file mode 100644 index 0000000000000000000000000000000000000000..50a5a75e411602f4a48dcd9457bc9de28ed70fe6 GIT binary patch literal 800 zcmV+*1K<3KP)=+TqGgoNaxtwdUuV8FCu48f|q z^#>K}xNq!kW;dJccC$4XA1pKP&6|C1-p@C?gi;Elq%jyVjog9pL5q#$MI9fWn+HJ< z*qm~?BMRXtNm9>#+~e2*X7t=lkBk}$XO|~Br8ld?N5G8Gn7mf#k$cW0smJ3XvMm1< zoQeTFD-Y?w=kAmQrgg^2Rb7hqo+u8mO?_P*(L>}egi!;R4F5n4`w^}WF;#Zqsr~}h6@Jf=5;^HmMh zzB|wlV(mijP@m;y(CiehZQ(%U!6Jj=Qu7OZ+}hF<6Nv;H#d@7Yrly!&X-RG0QLmR= z2p(oo9KJq3d-6gEEHmu)`*p@t<0!{<)I)vOB7pR8Lo!uLCX=L4D44EYn-ti! eY!!h&0t^6L`(TLqb)!lE00007hmNq68JK3W61Su}CV2trioL zCP+h4)FdUK1sV67IO*ia=BHb8@xkny_hx3lZ)V=izGa+qs-w{w28L2+JuH} z^SD`6OMn3WTgjK+hAaH}wH6K?fAuI^RDUJ!M=ARh;N>23w_Y2gP-O&q7520{AfqNVk=QK0ST@OfB@RRb69BD zs#HRv>@Bz(zD0vWV|uNT+J`%-9pprdH``~+z+oC08lZf_RTGf22RLNbza*CW*^`BW zzTGEwi*`v?kO))Z6bxf(Gw9 zm**a$68R@tF~BifmBj!5f^|2OECF|BUqW zEUsdt zLf(nepW(6z$XWPiV*0F8V!5GJ$=D{EnDuA3r<~bCehV-F$A{3bZqpJl00000NkvXX Hu0mjfv#prs literal 0 HcmV?d00001 diff --git a/Resources/Textures/Markers/jobs.rsi/scientist.png b/Resources/Textures/Markers/jobs.rsi/scientist.png index ac4849ba6902cf35b3ae487c04d5ea5291afd422..6a9bd40eff783520ac7d077b607f04e7466950bc 100644 GIT binary patch delta 856 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 sgCtQr9=F(uM8b$cd@dIeYUQd@i5Q^8VP7erQs znp0Ow4+YVXFsrb-n`jzL#)+9YuLsRECdN#ZZND(gyx;G=-+%8r-}m0{JxK_`{|RsP zV^)%yF_9j;L6VXXf>}utp8~1^CcBqAmzCg|zuVR(3$bUKY;7yzOf30DN_iPWO{_mN0ML{t?3!!T-- zb82s!L<4~a1%K+0(shc(B0itbv6-gHt8BKNybe6=4#?;8Xpf)pOuNtLKmN=!?LOM$ zC*Mj5{cey?gLXv8xCD0!f zf2=;G$LHhK>kNYfVGPsc-8&!g;X$7Iw8t z`J(tjh!X{xL8{w=nx={6s@#Zw`8czp<6*RgGz?>wD6I5e5<_Azaj z@pwF_s(;E4+b@|fSNJ-;ak8+ks=%$W+ael$hdTuWUDpAK$Ky=fWjeb$n6}Hr<8c6V zU1#&yW~$T6qv5D4C0cI7!JXGUKPb}I=V$0`1zp$4X0uLGfb3}zQdO0W)E1*1?#s)C z1Rf1X#Z;%4`ErGCc3x7h95p1Zg|6!??C0THkbkL8FPx}wVNGaBb-r9-VL!*;`JAMl zo&(LGsw&I*jI^+yW4>Hz6&h%vz~-Sz(lniRbq!dSg)GaCy;=#Yet?Dj8~|Tkg}`5t z>)4eFy?#F*luDwzyZa1@D(2?q7#SHsRaFKC286e(i$bx8$J@Hnx9rjD_Y(?-2?5X7 z)_<^Vn`|cI_?WUu$ReTluAUSQI3v|&~+VERY|AQOioUs zkB%~Y?;f%&v$efVPgj?lut1ANm`Effqg28ul}IEKlAZ}WvS@BfrQeW`7y^j?X;NXzZ+IDR}H*i%4d_JET8yf>)Z*PyCogDxy%R!Q= zf2}AAp->2b_4Rd3({yzsaz!8<4mWfv6bhK8Dao=d0)aro*i0tlioic@l5hR-JU-3< O0000e#`qJBsEH7NnpjOxqA?!4NJ8SzMU8s$ z=VGFwQ4b!B5Kmq-B;M@7pAbyc81W~fMoVa_q*6;;D6KZMFn{hF+@%XhTe`$YhPUs{ zoBh6dGxKIEFvjpdMW0KsApMb4RXHZH_Ii7GCj*;30y4PMS%+{qqWCNpGagle$s{x* z;Ay+A20!IsB_$>f?(z5(zbFFa=b7D0s3o4ql4q2 z-#TY!2|}R|2Y*t5O(l!g0IxdoBrue=0V~&H%jRvg*-&%fC=SJqaEnIx{C)iS;DgJw z1nQX&Wu8z$uCphJ$K$wVh~d)CYUMe-e^yR`%jIJ3hi;+VW@l{&>o5{c!2jkG?(M08 zuA~SHZ^g%s;D#10|dUH!j5@%I|n1s?@#Y5;N+)% ziqm`vR<2mhF2gqz7&BlF=RtuKxZsMAR{M1izXO}K#nh_vyQLIE`{FmZ$I-O`{ zNfgf2aeqy=EIlKm*fvL>HHnO;pd=8)+gKb%qXEOo1os7lK@}+33W3p4ICKTt97CD~ z&E|13g_b}c%$CwALDQu@G5~2e@+@F13qoEQAaHtVU*Lxz5y+UX;T_;BQ=a;`a;BFF>aG4aEd3=njFL7 z!8i&{2CUeB81?nrIfyK+tClOzK79O$(U0 t!DQmU2h#0?bZg2n6rasSMDj;~0RYZ6-EHiT8pZ$s002ovPDHLkV1g1q>O%kk delta 980 zcmV;_11tQL2yO-~zF6owxgyEQgbVgnf)QwD(?VN4Ryc7du? zu)vLA(JZ=R%gR5ZS+%SDfgr;ljXz+lgc&Bx;M+xn zYnKXpOxsQ0&FG$U?>Wz$d+(Wn|GQl6EQ-hDBGB1c8|$a1{m0LK;BfB6z!*YWv$HJfRgl#Y&^ zhH|cWJT9WqsQ78SDCU3ozTp{-MnyXnaI^&%vMh@Sx9&3+v3YRoK9*(Gd|&!}jvyRu zK`xhbh2@ACvw!yScXjf7t;jw3CdTP0=XRBk_xAYNG~2ojjue(7qH?$;Du-KQa&l6H z<%r|bU&s+{DwPtMOora$w;TriHG98qP!35)D!b=ZX1t!3A)4NT zj|wH$PIS7u0`y12sH#e-RH`KfD3wY8D2l@F-T}iMt>5k|0UnNyiy5znRm~=HU;pUrSneT4)vU^@-w^}8wRd`a!|2yA;zmwBs|0uxYHzy6x{}kY_ zt=38Fy%vDd9}_58ynnCBpPhD6A9KgHk^iX z1`rGeYj1b(>Q#fUeq2AV6}8j}gTbJP#Z6)W93LN3C=?p}l}ZI!mI;O4{~c{_ZwpP+ zTDqbwO&S;&xb#-KuA^z1OOhnf-Q9g@O+MdRkN5-0KcK|DdMbU?qLpPH3;VRpjEv=;K(!R^vd+yubZGW2S^py_WJ@?#u&ikDA z+isvMO!VhvVxx5+@_hvnL%eGsss-@k+@T)H9S-To z%CUTtgqtO9IV-HIf7+^@1Is{KW_AQQ5g(UYbATp8e3cDg`@$U?9qKMYQ)`Iadfwh` zUNbY7Ycv`b2!90Rfk{T7=I#IkXb*KIVtQTPpvgr=VkItKvti}pECo#_6OI)w=hB0QCC8rGeG1N1d({{4neA&suM`M&SdOY8Go{W9UkF_4~aPwJbuF&teZax zfe)>r4LEKLD(=_Ae`*U#Ya&arx5KH=86a}soD$JLQk)}5gN<|&nkPHemw+CcBkw=V znrnbDNe*I|W~4yUXP9IIvWq5&UIQ=~4E$W|f{3wEsSu=x3QPh?4;Qj0Kh>&0tJPxd zEd%nUOn*O-Hk`9lT8i;NO7;|7YVZJ^K!#mD`N%FkT?@b8uRsJ6J zd(CvZp~dY(iO0<=Y*!=_!29ql@;8=;uIb(Dl|G%62~+e))TiRb&AaMsLaKE@k2jSc zG5q6Ayory;wF5=84<)P;HWM@>1QI#fQ_!lE;rGBNQSWUYH|pH)(f+MdU}NidELl2C zV1LVpc9`^W@xFLIi?Cswf zwF7m&pM#r$*{QLD#5g?x4c-nhMo2o1)4ZwyNc9ZvmHz`A+&Yufn-huSSzCl1=`>FB zWGBi`@*{s$mVh2gZ>dR{j4c0K*qm>>*%YprhPbiG2sFP62EkO>19YKKny*(kLoPqw v2X|AugrfzL1o3+HLuH(>FBcKXZvh4Xmqg+WG&rSW00000NkvXXu0mjf_sRW~ delta 1252 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 JPDHLkV1he{#ZCYK delta 1175 zcmV;I1Zexc2dfE?B!3BTNLh0L01m_e01m_fl`9S#000DCNklBW!8|9>CF;m0z~x640f@LfmvBh3`x}`Y?%?vghrx}#fx1S zi5K+3#gI%%YX(bP6yqd@K$%G8LRx`Bce*}a)VJ%QADrS6|9?r7zVCCM=lQ?S*Lx29 z&(Lx;soXHzp3lqD*(0U%48>7 z$uP~j_FS3l8Gn8r&HXEVHKX+UI}&HN+L-jtTePh}l)jo#nmr8wGx?CJ83u@Uy`Ts(0FfKcTRbQHSKL$SoKqtL}E`|AK) zJaL7vUpMGyLq-D1h;r_{a6TdPIm2`my0Dd6=qPmIbA|z!n!bzk!g&LUuwTzgAaDDI z{XqVEwtuob^iT}j-aOtq(wA`l#4Ax2u37oBa+;N~Cy4}CSRJXu>2>hxCx?l}bgHYX zIexqWEwG30e*6XiWp91<@f2lpNjZ z>mFy9rY4($+wIn#tvhJg>v47&ob5D@O|_xIXP>$$Dk?(Pb;F+3YQ<)=vAMaKi+?#_ zhZ@NFG69m`j?C!i6agUZDWlOS(P$J%y+I!vfv?8K1mMjxXDBNxOYCoKYyc1p2KoH@ zbpUB;YkNE|rwYSELn0!w5(vnhsVTAB?NU`$B>+`bRbsc><<8WUtONogA~HNQWcuU8 p6jPVWmDb>;OP924GBdXS0qkKnk`Tu{B!U0{002ovPDHLkV1g(_M`Zv2 diff --git a/Resources/Textures/Markers/jobs.rsi/serviceworker.png b/Resources/Textures/Markers/jobs.rsi/serviceworker.png new file mode 100644 index 0000000000000000000000000000000000000000..b10b5ae46cf41714c60fc72fb7f785e1e3807cb7 GIT binary patch literal 861 zcmV-j1ETziP)8!PmX zwrWc*p4tk5q=pEd6ltp`4H6Gt(8KTth*EEt4b1c?`qHPk{Vh^vT2LPJap5-=9o zXe6nPJa?wub+a3r&l1pq$IP2IvomjYX5M>@a}NCk1N0gC?tpQ>#q^W=b@PddvjJNloz^>KqEk7rFRJ(-+I=^tyU{5l}ft| z#}vTJwJsg_{)c3v)9^reqZnsnmw@MV|9><8?8=?qYs^UNNqPk&%&xe3VB$41lghw_AqE zWRkEpyAcY7f=*tRll8jl1DQ+)u6vw>+lfFky_OwVoIXSN?zM}s`S2cB=Y%=}>VJ-M zD6iJIL8_xnM96+MbZsq&87 z?d<%x1+VG7`30$s4L-N90Mac85-TgZCm7C=kLxIh@;$kfrlY%W!&pviDCG0`SR#>V nxOQXAMkP8C*#B+#TYv!oF)v#)3^Rbl00000NkvXXu0mjf!vu@H literal 0 HcmV?d00001 diff --git a/Resources/Textures/Markers/jobs.rsi/technicalassistant.png b/Resources/Textures/Markers/jobs.rsi/technicalassistant.png new file mode 100644 index 0000000000000000000000000000000000000000..b3156bfe01969d5528cb175b2f0fd8e88ecaefcf GIT binary patch literal 952 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 diff --git a/Resources/Textures/Markers/jobs.rsi/zookeeper.png b/Resources/Textures/Markers/jobs.rsi/zookeeper.png index 12eb1144235b7c31ce50d15b71f65842875411e7..689697366268bd6a99c47b2132106e938e58a120 100644 GIT binary patch delta 910 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 Z{|0NE)2)_VO4tAZ002ovPDHLkV1iA04$%Mr From 46d189084499a0e390bd5877aabbf6167ec6d81e Mon Sep 17 00:00:00 2001 From: Nemanja <98561806+EmoGarbage404@users.noreply.github.com> Date: Mon, 9 Oct 2023 23:32:34 -0400 Subject: [PATCH 044/127] Fix fast kudzu (#20875) --- .../Spreader/SpreaderGridComponent.cs | 6 ++---- Content.Server/Spreader/SpreaderSystem.cs | 20 ++++--------------- 2 files changed, 6 insertions(+), 20 deletions(-) diff --git a/Content.Server/Spreader/SpreaderGridComponent.cs b/Content.Server/Spreader/SpreaderGridComponent.cs index 102678a251c..401b7d49165 100644 --- a/Content.Server/Spreader/SpreaderGridComponent.cs +++ b/Content.Server/Spreader/SpreaderGridComponent.cs @@ -1,10 +1,8 @@ -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom; - namespace Content.Server.Spreader; [RegisterComponent] public sealed partial class SpreaderGridComponent : Component { - [DataField("nextUpdate", customTypeSerializer:typeof(TimeOffsetSerializer))] - public TimeSpan NextUpdate = TimeSpan.Zero; + [DataField] + public float UpdateAccumulator = SpreaderSystem.SpreadCooldownSeconds; } diff --git a/Content.Server/Spreader/SpreaderSystem.cs b/Content.Server/Spreader/SpreaderSystem.cs index 4cd575cbd4a..d61cf303d6b 100644 --- a/Content.Server/Spreader/SpreaderSystem.cs +++ b/Content.Server/Spreader/SpreaderSystem.cs @@ -9,7 +9,6 @@ using Robust.Shared.Map.Components; using Robust.Shared.Prototypes; using Robust.Shared.Random; -using Robust.Shared.Timing; using Robust.Shared.Utility; namespace Content.Server.Spreader; @@ -19,13 +18,10 @@ namespace Content.Server.Spreader; ///

public sealed class SpreaderSystem : EntitySystem { - [Dependency] private readonly IGameTiming _timing = default!; [Dependency] private readonly IMapManager _mapManager = default!; [Dependency] private readonly IPrototypeManager _prototype = default!; [Dependency] private readonly IRobustRandom _robustRandom = default!; - private static readonly TimeSpan SpreadCooldown = TimeSpan.FromSeconds(SpreadCooldownSeconds); - /// /// Cached maximum number of updates per spreader prototype. This is applied per-grid. /// @@ -36,7 +32,7 @@ public sealed class SpreaderSystem : EntitySystem ///
private Dictionary> _gridUpdates = new(); - private const float SpreadCooldownSeconds = 1; + public const float SpreadCooldownSeconds = 1; [ValidatePrototypeId] private const string IgnoredTag = "SpreaderIgnore"; @@ -47,8 +43,6 @@ public override void Initialize() SubscribeLocalEvent(OnAirtightChanged); SubscribeLocalEvent(OnGridInit); - SubscribeLocalEvent(OnGridUnpaused); - SubscribeLocalEvent(OnTerminating); SetupPrototypes(); _prototype.PrototypesReloaded += OnPrototypeReload; @@ -87,11 +81,6 @@ private void OnAirtightChanged(ref AirtightChanged ev) } } - private void OnGridUnpaused(EntityUid uid, SpreaderGridComponent component, ref EntityUnpausedEvent args) - { - component.NextUpdate += args.PausedTime; - } - private void OnGridInit(GridInitializeEvent ev) { EnsureComp(ev.EntityUid); @@ -111,19 +100,18 @@ private void OnTerminating(EntityUid uid, EdgeSpreaderComponent component, ref E /// public override void Update(float frameTime) { - var curTime = _timing.CurTime; - // Check which grids are valid for spreading var spreadGrids = EntityQueryEnumerator(); _gridUpdates.Clear(); while (spreadGrids.MoveNext(out var uid, out var grid)) { - if (grid.NextUpdate > curTime) + grid.UpdateAccumulator -= frameTime; + if (grid.UpdateAccumulator > 0) continue; _gridUpdates[uid] = _prototypeUpdates.ShallowClone(); - grid.NextUpdate += SpreadCooldown; + grid.UpdateAccumulator += SpreadCooldownSeconds; } if (_gridUpdates.Count == 0) From 80e7f125576755cb24d35046703f134ca25b4f08 Mon Sep 17 00:00:00 2001 From: PJBot Date: Mon, 9 Oct 2023 23:33:38 -0400 Subject: [PATCH 045/127] Automatic changelog update --- Resources/Changelog/Changelog.yml | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 908c31cf7b5..5578b105368 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,9 +1,4 @@ Entries: -- author: hord-brayden - changes: - - {message: Added Syringe Support for Chemical Analysis Goggles, type: Fix} - id: 4480 - time: '2023-08-07T22:46:05.0000000+00:00' - author: deltanedas changes: - {message: Uplink codes no longer contain sharp notes., type: Remove} @@ -2952,3 +2947,9 @@ Entries: section., type: Add} id: 4979 time: '2023-10-09T23:42:53.0000000+00:00' +- author: EmoGarbage404 + changes: + - {message: 'Fixed kudzu, foam, smoke, and puddles spreading at extremely high rates.', + type: Fix} + id: 4980 + time: '2023-10-10T03:32:34.0000000+00:00' From 2c8a97fe023ec4ddc14b00ef072597a611a6a0d3 Mon Sep 17 00:00:00 2001 From: Nemanja <98561806+EmoGarbage404@users.noreply.github.com> Date: Mon, 9 Oct 2023 23:34:41 -0400 Subject: [PATCH 046/127] Revert "Revert "Reenable kudzu."" (#20876) --- .../Botany/Systems/MutationSystem.cs | 7 +++--- Resources/Prototypes/GameRules/events.yml | 24 +++++++++---------- 2 files changed, 15 insertions(+), 16 deletions(-) diff --git a/Content.Server/Botany/Systems/MutationSystem.cs b/Content.Server/Botany/Systems/MutationSystem.cs index 94a450ebeff..672139fbca2 100644 --- a/Content.Server/Botany/Systems/MutationSystem.cs +++ b/Content.Server/Botany/Systems/MutationSystem.cs @@ -37,7 +37,7 @@ public void MutateSeed(ref SeedData seed, float severity) } // Add up everything in the bits column and put the number here. - const int totalbits = 265; + const int totalbits = 270; // Tolerances (55) MutateFloat(ref seed.NutrientConsumption , 0.05f, 1.2f, 5, totalbits, severity); @@ -69,8 +69,7 @@ public void MutateSeed(ref SeedData seed, float severity) MutateBool(ref seed.Sentient , true , 10, totalbits, severity); MutateBool(ref seed.Ligneous , true , 10, totalbits, severity); MutateBool(ref seed.Bioluminescent, true , 10, totalbits, severity); - // Kudzu disabled until superkudzu bug is fixed - // MutateBool(ref seed.TurnIntoKudzu , true , 10, totalbits, severity); + MutateBool(ref seed.TurnIntoKudzu , true , 10, totalbits, severity); MutateBool(ref seed.CanScream , true , 10, totalbits, severity); seed.BioluminescentColor = RandomColor(seed.BioluminescentColor, 10, totalbits, severity); @@ -119,7 +118,7 @@ public SeedData Cross(SeedData a, SeedData b) CrossBool(ref result.Sentient, a.Sentient); CrossBool(ref result.Ligneous, a.Ligneous); CrossBool(ref result.Bioluminescent, a.Bioluminescent); - // CrossBool(ref result.TurnIntoKudzu, a.TurnIntoKudzu); + CrossBool(ref result.TurnIntoKudzu, a.TurnIntoKudzu); CrossBool(ref result.CanScream, a.CanScream); CrossGasses(ref result.ExudeGasses, a.ExudeGasses); diff --git a/Resources/Prototypes/GameRules/events.yml b/Resources/Prototypes/GameRules/events.yml index 927aea0973f..e15d65b5089 100644 --- a/Resources/Prototypes/GameRules/events.yml +++ b/Resources/Prototypes/GameRules/events.yml @@ -132,18 +132,18 @@ startDelay: 20 - type: GasLeakRule -#- type: entity -# id: KudzuGrowth -# parent: BaseGameRule -# noSpawn: true -# components: -# - type: StationEvent -# earliestStart: 15 -# minimumPlayers: 15 -# weight: 5 -# startDelay: 50 -# duration: 240 -# - type: KudzuGrowthRule +- type: entity + id: KudzuGrowth + parent: BaseGameRule + noSpawn: true + components: + - type: StationEvent + earliestStart: 15 + minimumPlayers: 15 + weight: 5 + startDelay: 50 + duration: 240 + - type: KudzuGrowthRule - type: entity id: MeteorSwarm From c35a018cad95f967e26a269e22b16a6d0eb92737 Mon Sep 17 00:00:00 2001 From: PJBot Date: Mon, 9 Oct 2023 23:35:45 -0400 Subject: [PATCH 047/127] Automatic changelog update --- Resources/Changelog/Changelog.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 5578b105368..f755401597e 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,9 +1,4 @@ Entries: -- author: deltanedas - changes: - - {message: Uplink codes no longer contain sharp notes., type: Remove} - id: 4481 - time: '2023-08-08T00:16:49.0000000+00:00' - author: TotallyLemon changes: - {message: 'Nanotrasen''s R&D department have improved the RPED''s design, allowing @@ -2953,3 +2948,8 @@ Entries: type: Fix} id: 4980 time: '2023-10-10T03:32:34.0000000+00:00' +- author: EmoGarbage404 + changes: + - {message: Reenabled Kudzu (again) (for real this time), type: Add} + id: 4981 + time: '2023-10-10T03:34:41.0000000+00:00' From 6f8c2b7e52d47678f54b3dc9f3ae13829bbd62ec Mon Sep 17 00:00:00 2001 From: Slava0135 <40753025+Slava0135@users.noreply.github.com> Date: Tue, 10 Oct 2023 09:32:10 +0300 Subject: [PATCH 048/127] Use conditions to store progress for Ninja objectives (#20254) * TryGetObjectiveComp * helper function to get objective * store N of jacked doors in condition * store called in threat bool in condition * store techs in steal research condition * fix access * remove unused transform system * use popup from shared system * fix formatting * condition => obj everywhere * i fogror to remove downloaded nodes from role * change signature * use query * View Variables * spider charge detonated => condition --- .../Ninja/Systems/NinjaGlovesSystem.cs | 10 ++---- .../Ninja/Systems/SpaceNinjaSystem.cs | 36 +++++++------------ .../Ninja/Systems/SpiderChargeSystem.cs | 5 +-- .../Components/DoorjackConditionComponent.cs | 5 ++- .../SpiderChargeConditionComponent.cs | 5 ++- .../StealResearchConditionComponent.cs | 5 ++- .../Components/TerrorConditionComponent.cs | 8 ++++- .../Systems/NinjaConditionsSystem.cs | 31 +++++----------- Content.Server/Roles/NinjaRoleComponent.cs | 24 ------------- Content.Shared/Mind/SharedMindSystem.cs | 27 ++++++++++++++ .../Ninja/Systems/SharedSpaceNinjaSystem.cs | 8 ++--- 11 files changed, 76 insertions(+), 88 deletions(-) diff --git a/Content.Server/Ninja/Systems/NinjaGlovesSystem.cs b/Content.Server/Ninja/Systems/NinjaGlovesSystem.cs index 119aaa74347..d84a7287751 100644 --- a/Content.Server/Ninja/Systems/NinjaGlovesSystem.cs +++ b/Content.Server/Ninja/Systems/NinjaGlovesSystem.cs @@ -1,16 +1,10 @@ using Content.Server.Communications; -using Content.Server.DoAfter; using Content.Server.Mind; using Content.Server.Ninja.Events; -using Content.Server.Power.Components; -using Content.Server.Roles; +using Content.Server.Objectives.Components; using Content.Shared.Communications; -using Content.Shared.DoAfter; -using Content.Shared.Interaction.Components; -using Content.Shared.Interaction.Events; using Content.Shared.Ninja.Components; using Content.Shared.Ninja.Systems; -using Content.Shared.Popups; using Content.Shared.Research.Components; using Content.Shared.Toggleable; @@ -94,7 +88,7 @@ private void EnableGloves(EntityUid uid, NinjaGlovesComponent comp, EntityUid us EnsureComp(user); // prevent calling in multiple threats by toggling gloves after - if (_mind.TryGetRole(user, out var role) && !role.CalledInThreat) + if (_mind.TryGetObjectiveComp(user, out var obj) && !obj.CalledInThreat) { var hacker = EnsureComp(user); var rule = _ninja.NinjaRule(user); diff --git a/Content.Server/Ninja/Systems/SpaceNinjaSystem.cs b/Content.Server/Ninja/Systems/SpaceNinjaSystem.cs index 0cc3aea2662..8f19850c70c 100644 --- a/Content.Server/Ninja/Systems/SpaceNinjaSystem.cs +++ b/Content.Server/Ninja/Systems/SpaceNinjaSystem.cs @@ -1,12 +1,8 @@ using Content.Server.Administration.Commands; using Content.Server.Communications; using Content.Server.Chat.Managers; -using Content.Server.StationEvents.Components; using Content.Server.GameTicking; -using Content.Server.GameTicking.Rules; using Content.Server.GameTicking.Rules.Components; -using Content.Server.Ghost.Roles.Events; -using Content.Server.Objectives; using Content.Server.Power.Components; using Content.Server.Power.EntitySystems; using Content.Server.PowerCell; @@ -23,16 +19,12 @@ using Content.Shared.Ninja.Components; using Content.Shared.Ninja.Systems; using Content.Shared.Popups; -using Content.Shared.Roles; -using Content.Shared.PowerCell.Components; using Content.Shared.Rounding; using Robust.Shared.Audio; -using Robust.Shared.GameObjects; -using Robust.Shared.Physics.Components; using Robust.Shared.Player; using Robust.Shared.Random; using System.Diagnostics.CodeAnalysis; -using System.Linq; +using Content.Server.Objectives.Components; namespace Content.Server.Ninja.Systems; @@ -57,8 +49,6 @@ public sealed class SpaceNinjaSystem : SharedSpaceNinjaSystem [Dependency] private readonly RoleSystem _role = default!; [Dependency] private readonly SharedAudioSystem _audio = default!; [Dependency] private readonly SharedMindSystem _mind = default!; - [Dependency] private readonly SharedPopupSystem _popup = default!; - [Dependency] private readonly SharedTransformSystem _transform = default!; [Dependency] private readonly StealthClothingSystem _stealthClothing = default!; public override void Initialize() @@ -85,12 +75,12 @@ public override void Update(float frameTime) ///
private int Download(EntityUid uid, List ids) { - if (!_mind.TryGetRole(uid, out var role)) + if (!_mind.TryGetObjectiveComp(uid, out var obj)) return 0; - var oldCount = role.DownloadedNodes.Count; - role.DownloadedNodes.UnionWith(ids); - var newCount = role.DownloadedNodes.Count; + var oldCount = obj.DownloadedNodes.Count; + obj.DownloadedNodes.UnionWith(ids); + var newCount = obj.DownloadedNodes.Count; return newCount - oldCount; } @@ -124,7 +114,7 @@ public void SetSuitPowerAlert(EntityUid uid, SpaceNinjaComponent? comp = null) if (GetNinjaBattery(uid, out _, out var battery)) { - var severity = ContentHelpers.RoundToLevels(MathF.Max(0f, battery.CurrentCharge), battery.MaxCharge, 8); + var severity = ContentHelpers.RoundToLevels(MathF.Max(0f, battery.CurrentCharge), battery.MaxCharge, 8); _alerts.ShowAlert(uid, AlertType.SuitPower, (short) severity); } else @@ -205,7 +195,7 @@ private void UpdateNinja(EntityUid uid, SpaceNinjaComponent ninja, float frameTi if (ninja.Suit == null) return; - float wattage = _suit.SuitWattage(ninja.Suit.Value); + float wattage = Suit.SuitWattage(ninja.Suit.Value); SetSuitPowerAlert(uid, ninja); if (!TryUseCharge(uid, wattage * frameTime)) @@ -225,11 +215,11 @@ private void OnDoorjack(EntityUid uid, SpaceNinjaComponent comp, ref EmaggedSome return; // this popup is serverside since door emag logic is serverside (power funnies) - _popup.PopupEntity(Loc.GetString("ninja-doorjack-success", ("target", Identity.Entity(args.Target, EntityManager))), uid, uid, PopupType.Medium); + Popup.PopupEntity(Loc.GetString("ninja-doorjack-success", ("target", Identity.Entity(args.Target, EntityManager))), uid, uid, PopupType.Medium); // handle greentext - if (_mind.TryGetRole(uid, out var role)) - role.DoorsJacked++; + if (_mind.TryGetObjectiveComp(uid, out var obj)) + obj.DoorsJacked++; } /// @@ -242,14 +232,14 @@ private void OnResearchStolen(EntityUid uid, SpaceNinjaComponent comp, ref Resea ? Loc.GetString("ninja-research-steal-fail") : Loc.GetString("ninja-research-steal-success", ("count", gained), ("server", args.Target)); - _popup.PopupEntity(str, uid, uid, PopupType.Medium); + Popup.PopupEntity(str, uid, uid, PopupType.Medium); } private void OnThreatCalledIn(EntityUid uid, SpaceNinjaComponent comp, ref ThreatCalledInEvent args) { - if (_mind.TryGetRole(uid, out var role)) + if (_mind.TryGetObjectiveComp(uid, out var obj)) { - role.CalledInThreat = true; + obj.CalledInThreat = true; } } } diff --git a/Content.Server/Ninja/Systems/SpiderChargeSystem.cs b/Content.Server/Ninja/Systems/SpiderChargeSystem.cs index 3ffc2a8ff35..6f3c3b3f9df 100644 --- a/Content.Server/Ninja/Systems/SpiderChargeSystem.cs +++ b/Content.Server/Ninja/Systems/SpiderChargeSystem.cs @@ -1,5 +1,6 @@ using Content.Server.Explosion.EntitySystems; using Content.Server.Mind; +using Content.Server.Objectives.Components; using Content.Server.Popups; using Content.Server.Roles; using Content.Server.Sticky.Events; @@ -69,10 +70,10 @@ private void OnStuck(EntityUid uid, SpiderChargeComponent comp, EntityStuckEvent /// private void OnExplode(EntityUid uid, SpiderChargeComponent comp, TriggerEvent args) { - if (comp.Planter == null || !_mind.TryGetRole(comp.Planter.Value, out var role)) + if (comp.Planter == null || !_mind.TryGetObjectiveComp(comp.Planter.Value, out var obj)) return; // assumes the target was destroyed, that the charge wasn't moved somehow - role.SpiderChargeDetonated = true; + obj.SpiderChargeDetonated = true; } } diff --git a/Content.Server/Objectives/Components/DoorjackConditionComponent.cs b/Content.Server/Objectives/Components/DoorjackConditionComponent.cs index 714a70d8b97..470680ae6d7 100644 --- a/Content.Server/Objectives/Components/DoorjackConditionComponent.cs +++ b/Content.Server/Objectives/Components/DoorjackConditionComponent.cs @@ -1,4 +1,5 @@ using Content.Server.Objectives.Systems; +using Content.Shared.Ninja.Systems; namespace Content.Server.Objectives.Components; @@ -6,7 +7,9 @@ namespace Content.Server.Objectives.Components; /// Objective condition that requires the player to be a ninja and have doorjacked at least a random number of airlocks. /// Requires to function. ///
-[RegisterComponent, Access(typeof(NinjaConditionsSystem))] +[RegisterComponent, Access(typeof(NinjaConditionsSystem), typeof(SharedSpaceNinjaSystem))] public sealed partial class DoorjackConditionComponent : Component { + [DataField("doorsJacked"), ViewVariables(VVAccess.ReadWrite)] + public int DoorsJacked; } diff --git a/Content.Server/Objectives/Components/SpiderChargeConditionComponent.cs b/Content.Server/Objectives/Components/SpiderChargeConditionComponent.cs index 4fbe8572cdd..1c6f22ed57c 100644 --- a/Content.Server/Objectives/Components/SpiderChargeConditionComponent.cs +++ b/Content.Server/Objectives/Components/SpiderChargeConditionComponent.cs @@ -1,3 +1,4 @@ +using Content.Server.Ninja.Systems; using Content.Server.Objectives.Systems; namespace Content.Server.Objectives.Components; @@ -5,7 +6,9 @@ namespace Content.Server.Objectives.Components; /// /// Requires that the player is a ninja and blew up their spider charge at its target location. /// -[RegisterComponent, Access(typeof(NinjaConditionsSystem))] +[RegisterComponent, Access(typeof(NinjaConditionsSystem), typeof(SpiderChargeSystem))] public sealed partial class SpiderChargeConditionComponent : Component { + [DataField("spiderChargeDetonated"), ViewVariables(VVAccess.ReadWrite)] + public bool SpiderChargeDetonated; } diff --git a/Content.Server/Objectives/Components/StealResearchConditionComponent.cs b/Content.Server/Objectives/Components/StealResearchConditionComponent.cs index 736a2e74b66..26710ed7cc7 100644 --- a/Content.Server/Objectives/Components/StealResearchConditionComponent.cs +++ b/Content.Server/Objectives/Components/StealResearchConditionComponent.cs @@ -1,4 +1,5 @@ using Content.Server.Objectives.Systems; +using Content.Shared.Ninja.Systems; namespace Content.Server.Objectives.Components; @@ -6,7 +7,9 @@ namespace Content.Server.Objectives.Components; /// Objective condition that requires the player to be a ninja and have stolen at least a random number of technologies. /// Requires to function. ///
-[RegisterComponent, Access(typeof(NinjaConditionsSystem))] +[RegisterComponent, Access(typeof(NinjaConditionsSystem), typeof(SharedSpaceNinjaSystem))] public sealed partial class StealResearchConditionComponent : Component { + [DataField("downloadedNodes"), ViewVariables(VVAccess.ReadWrite)] + public HashSet DownloadedNodes = new(); } diff --git a/Content.Server/Objectives/Components/TerrorConditionComponent.cs b/Content.Server/Objectives/Components/TerrorConditionComponent.cs index c94e3b424d0..acd3218ad4d 100644 --- a/Content.Server/Objectives/Components/TerrorConditionComponent.cs +++ b/Content.Server/Objectives/Components/TerrorConditionComponent.cs @@ -1,11 +1,17 @@ using Content.Server.Objectives.Systems; +using Content.Shared.Ninja.Systems; namespace Content.Server.Objectives.Components; /// /// Requires that the player is a ninja and has called in a threat. /// -[RegisterComponent, Access(typeof(NinjaConditionsSystem))] +[RegisterComponent, Access(typeof(NinjaConditionsSystem), typeof(SharedSpaceNinjaSystem))] public sealed partial class TerrorConditionComponent : Component { + /// + /// Whether the comms console has been hacked + /// + [DataField("calledInThreat"), ViewVariables(VVAccess.ReadWrite)] + public bool CalledInThreat; } diff --git a/Content.Server/Objectives/Systems/NinjaConditionsSystem.cs b/Content.Server/Objectives/Systems/NinjaConditionsSystem.cs index 8e03ef201dd..eaf97e97e01 100644 --- a/Content.Server/Objectives/Systems/NinjaConditionsSystem.cs +++ b/Content.Server/Objectives/Systems/NinjaConditionsSystem.cs @@ -2,7 +2,6 @@ using Content.Server.Objectives.Components; using Content.Server.Warps; using Content.Shared.Objectives.Components; -using Robust.Shared.GameObjects; namespace Content.Server.Objectives.Systems; @@ -31,22 +30,16 @@ public override void Initialize() private void OnDoorjackGetProgress(EntityUid uid, DoorjackConditionComponent comp, ref ObjectiveGetProgressEvent args) { - args.Progress = DoorjackProgress(args.MindId, _number.GetTarget(uid)); + args.Progress = DoorjackProgress(comp, _number.GetTarget(uid)); } - private float DoorjackProgress(EntityUid mindId, int target) + private float DoorjackProgress(DoorjackConditionComponent comp, int target) { // prevent divide-by-zero if (target == 0) return 1f; - if (!TryComp(mindId, out var role)) - return 0f; - - if (role.DoorsJacked >= target) - return 1f; - - return (float) role.DoorsJacked / (float) target; + return MathF.Min(comp.DoorsJacked / (float) target, 1f); } // spider charge @@ -58,7 +51,7 @@ private void OnSpiderChargeAfterAssign(EntityUid uid, SpiderChargeConditionCompo private void OnSpiderChargeGetProgress(EntityUid uid, SpiderChargeConditionComponent comp, ref ObjectiveGetProgressEvent args) { - args.Progress = TryComp(args.MindId, out var role) && role.SpiderChargeDetonated ? 1f : 0f; + args.Progress = comp.SpiderChargeDetonated ? 1f : 0f; } private string SpiderChargeTitle(EntityUid mindId) @@ -79,28 +72,20 @@ private string SpiderChargeTitle(EntityUid mindId) private void OnStealResearchGetProgress(EntityUid uid, StealResearchConditionComponent comp, ref ObjectiveGetProgressEvent args) { - args.Progress = StealResearchProgress(args.MindId, _number.GetTarget(uid)); + args.Progress = StealResearchProgress(comp, _number.GetTarget(uid)); } - private float StealResearchProgress(EntityUid mindId, int target) + private float StealResearchProgress(StealResearchConditionComponent comp, int target) { // prevent divide-by-zero if (target == 0) return 1f; - if (!TryComp(mindId, out var role)) - return 0f; - - if (role.DownloadedNodes.Count >= target) - return 1f; - - return (float) role.DownloadedNodes.Count / (float) target; + return MathF.Min(comp.DownloadedNodes.Count / (float) target, 1f); } - // terror - private void OnTerrorGetProgress(EntityUid uid, TerrorConditionComponent comp, ref ObjectiveGetProgressEvent args) { - args.Progress = TryComp(args.MindId, out var role) && role.CalledInThreat ? 1f : 0f; + args.Progress = comp.CalledInThreat ? 1f : 0f; } } diff --git a/Content.Server/Roles/NinjaRoleComponent.cs b/Content.Server/Roles/NinjaRoleComponent.cs index aa9e1cfa328..dcc55d0fb43 100644 --- a/Content.Server/Roles/NinjaRoleComponent.cs +++ b/Content.Server/Roles/NinjaRoleComponent.cs @@ -8,33 +8,9 @@ namespace Content.Server.Roles; [RegisterComponent] public sealed partial class NinjaRoleComponent : AntagonistRoleComponent { - /// - /// Number of doors that have been doorjacked, used for objective - /// - [DataField("doorsJacked")] - public int DoorsJacked; - - /// - /// Research nodes that have been downloaded, used for objective - /// - [DataField("downloadedNodes")] - public HashSet DownloadedNodes = new(); - /// /// Warp point that the spider charge has to target /// [DataField("spiderChargeTarget")] public EntityUid? SpiderChargeTarget; - - /// - /// Whether the spider charge has been detonated on the target, used for objective - /// - [DataField("spiderChargeDetonated")] - public bool SpiderChargeDetonated; - - /// - /// Whether the comms console has been hacked, used for objective - /// - [DataField("calledInThreat")] - public bool CalledInThreat; } diff --git a/Content.Shared/Mind/SharedMindSystem.cs b/Content.Shared/Mind/SharedMindSystem.cs index b7cd30e9621..be11d8a2ad4 100644 --- a/Content.Shared/Mind/SharedMindSystem.cs +++ b/Content.Shared/Mind/SharedMindSystem.cs @@ -292,6 +292,33 @@ public bool TryRemoveObjective(EntityUid mindId, MindComponent mind, int index) return true; } + public bool TryGetObjectiveComp(EntityUid uid, [NotNullWhen(true)] out T? objective) where T : Component + { + if (TryGetMind(uid, out var mindId, out var mind) && TryGetObjectiveComp(mindId, out objective, mind)) + { + return true; + } + objective = default; + return false; + } + + public bool TryGetObjectiveComp(EntityUid mindId, [NotNullWhen(true)] out T? objective, MindComponent? mind = null) where T : Component + { + if (Resolve(mindId, ref mind)) + { + var query = GetEntityQuery(); + foreach (var uid in mind.AllObjectives) + { + if (query.TryGetComponent(uid, out objective)) + { + return true; + } + } + } + objective = default; + return false; + } + public bool TryGetSession(EntityUid? mindId, [NotNullWhen(true)] out ICommonSession? session) { session = null; diff --git a/Content.Shared/Ninja/Systems/SharedSpaceNinjaSystem.cs b/Content.Shared/Ninja/Systems/SharedSpaceNinjaSystem.cs index d8ff07c27aa..fbcb4efe484 100644 --- a/Content.Shared/Ninja/Systems/SharedSpaceNinjaSystem.cs +++ b/Content.Shared/Ninja/Systems/SharedSpaceNinjaSystem.cs @@ -11,8 +11,8 @@ namespace Content.Shared.Ninja.Systems; ///
public abstract class SharedSpaceNinjaSystem : EntitySystem { - [Dependency] protected readonly SharedNinjaSuitSystem _suit = default!; - [Dependency] protected readonly SharedPopupSystem _popup = default!; + [Dependency] protected readonly SharedNinjaSuitSystem Suit = default!; + [Dependency] protected readonly SharedPopupSystem Popup = default!; public override void Initialize() { @@ -74,7 +74,7 @@ private void OnNinjaAttacked(EntityUid uid, SpaceNinjaComponent comp, AttackedEv { if (comp.Suit != null && TryComp(comp.Suit, out var stealthClothing) && stealthClothing.Enabled) { - _suit.RevealNinja(comp.Suit.Value, uid, null, stealthClothing); + Suit.RevealNinja(comp.Suit.Value, uid, null, stealthClothing); } } @@ -83,7 +83,7 @@ private void OnNinjaAttacked(EntityUid uid, SpaceNinjaComponent comp, AttackedEv ///
private void OnShotAttempted(EntityUid uid, SpaceNinjaComponent comp, ref ShotAttemptedEvent args) { - _popup.PopupClient(Loc.GetString("gun-disabled"), uid, uid); + Popup.PopupClient(Loc.GetString("gun-disabled"), uid, uid); args.Cancel(); } } From 764a0a15c1f96faf680900d4b9f5f74e152004fc Mon Sep 17 00:00:00 2001 From: GoodWheatley <109803540+GoodWheatley@users.noreply.github.com> Date: Tue, 10 Oct 2023 10:03:19 -0400 Subject: [PATCH 049/127] Fix species speeds (#20890) * Fix diona speed * Fix lizard speed --- Resources/Prototypes/Body/Parts/diona.yml | 6 ------ Resources/Prototypes/Body/Parts/reptilian.yml | 8 +------- 2 files changed, 1 insertion(+), 13 deletions(-) diff --git a/Resources/Prototypes/Body/Parts/diona.yml b/Resources/Prototypes/Body/Parts/diona.yml index 357cf7947b0..5257512aaab 100644 --- a/Resources/Prototypes/Body/Parts/diona.yml +++ b/Resources/Prototypes/Body/Parts/diona.yml @@ -62,9 +62,6 @@ components: - type: Sprite state: "l_leg" - - type: MovementBodyPart - walkSpeed : 1.5 - sprintSpeed : 3.5 - type: entity id: RightLegDiona @@ -76,9 +73,6 @@ - type: BodyPart partType: Leg symmetry: Right - - type: MovementBodyPart - walkSpeed : 1.5 - sprintSpeed : 3.5 - type: entity id: LeftFootDiona diff --git a/Resources/Prototypes/Body/Parts/reptilian.yml b/Resources/Prototypes/Body/Parts/reptilian.yml index 22ab7aeb525..a299636352a 100644 --- a/Resources/Prototypes/Body/Parts/reptilian.yml +++ b/Resources/Prototypes/Body/Parts/reptilian.yml @@ -90,9 +90,6 @@ - type: Sprite sprite: Mobs/Species/Reptilian/parts.rsi state: "l_leg" - - type: MovementBodyPart - walkSpeed : 2.7 - sprintSpeed : 4.5 - type: entity id: RightLegReptilian @@ -102,9 +99,6 @@ - type: Sprite sprite: Mobs/Species/Reptilian/parts.rsi state: "r_leg" - - type: MovementBodyPart - walkSpeed : 2.7 - sprintSpeed : 4.5 - type: entity id: LeftFootReptilian @@ -122,4 +116,4 @@ components: - type: Sprite sprite: Mobs/Species/Reptilian/parts.rsi - state: "r_foot" \ No newline at end of file + state: "r_foot" From 55f058f3d6e3fea17ac3325cc2c5d240983e9277 Mon Sep 17 00:00:00 2001 From: PJBot Date: Tue, 10 Oct 2023 10:04:24 -0400 Subject: [PATCH 050/127] Automatic changelog update --- Resources/Changelog/Changelog.yml | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index f755401597e..23e1073e792 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,10 +1,4 @@ Entries: -- author: TotallyLemon - changes: - - {message: 'Nanotrasen''s R&D department have improved the RPED''s design, allowing - it to quickly install parts into in-progress machine frames.', type: Add} - id: 4482 - time: '2023-08-08T00:26:25.0000000+00:00' - author: Doru991 changes: - {message: 'Due to Nanotrasen choosing a new seed supplier, most plants consume @@ -2953,3 +2947,8 @@ Entries: - {message: Reenabled Kudzu (again) (for real this time), type: Add} id: 4981 time: '2023-10-10T03:34:41.0000000+00:00' +- author: GoodWheatley + changes: + - {message: Dionas are actually the same speed as other species now., type: Fix} + id: 4982 + time: '2023-10-10T14:03:20.0000000+00:00' From 6abb55088c5f56adfa2df00d4be12f0113a85beb Mon Sep 17 00:00:00 2001 From: potato1234_x <79580518+potato1234x@users.noreply.github.com> Date: Wed, 11 Oct 2023 02:55:30 +1000 Subject: [PATCH 051/127] CuraDrobe + Misc Librarian Stuff (#19469) * sprites * stuff * jumpsuit sprites * jumpskirt sprites * fix 2 * CLOTHING FIX 2 IM LOSING MY MIND * contrast 2 * update 239 --- .../advertisements/vending/curadrobe.ftl | 2 ++ .../Advertisements/curadrobe.yml | 5 +++ .../VendingMachines/Inventories/curadrobe.yml | 14 ++++++++ .../Entities/Clothing/Eyes/glasses.yml | 16 +++++++++ .../Entities/Clothing/Uniforms/jumpskirts.yml | 22 +++++++++++++ .../Entities/Clothing/Uniforms/jumpsuits.yml | 13 +++++++- .../Service/vending_machine_restock.yml | 1 + .../Structures/Machines/vending_machines.yml | 26 +++++++++++++++ .../Roles/Jobs/Civilian/librarian.yml | 5 +-- .../jamjar.rsi/equipped-EYES-hamster.png | Bin 0 -> 7979 bytes .../Eyes/Glasses/jamjar.rsi/equipped-EYES.png | Bin 0 -> 292 bytes .../Clothing/Eyes/Glasses/jamjar.rsi/icon.png | Bin 0 -> 322 bytes .../Eyes/Glasses/jamjar.rsi/inhand-left.png | Bin 0 -> 189 bytes .../Eyes/Glasses/jamjar.rsi/inhand-right.png | Bin 0 -> 191 bytes .../Eyes/Glasses/jamjar.rsi/meta.json | 30 +++++++++++++++++ .../equipped-INNERCLOTHING-monkey.png | Bin 0 -> 7639 bytes .../curator.rsi/equipped-INNERCLOTHING.png | Bin 0 -> 597 bytes .../Uniforms/Jumpskirt/curator.rsi/icon.png | Bin 0 -> 362 bytes .../Jumpskirt/curator.rsi/inhand-left.png | Bin 0 -> 421 bytes .../Jumpskirt/curator.rsi/inhand-right.png | Bin 0 -> 429 bytes .../Uniforms/Jumpskirt/curator.rsi/meta.json | 30 +++++++++++++++++ .../equipped-INNERCLOTHING-monkey.png | Bin 0 -> 7642 bytes .../librarian.rsi/equipped-INNERCLOTHING.png | Bin 0 -> 606 bytes .../Uniforms/Jumpskirt/librarian.rsi/icon.png | Bin 0 -> 353 bytes .../Jumpskirt/librarian.rsi/inhand-left.png | Bin 0 -> 425 bytes .../Jumpskirt/librarian.rsi/inhand-right.png | Bin 0 -> 435 bytes .../Jumpskirt/librarian.rsi/meta.json | 30 +++++++++++++++++ .../equipped-INNERCLOTHING-monkey.png | Bin 0 -> 7693 bytes .../curator.rsi/equipped-INNERCLOTHING.png | Bin 0 -> 658 bytes .../Uniforms/Jumpsuit/curator.rsi/icon.png | Bin 0 -> 353 bytes .../Jumpsuit/curator.rsi/inhand-left.png | Bin 0 -> 421 bytes .../Jumpsuit/curator.rsi/inhand-right.png | Bin 0 -> 429 bytes .../Uniforms/Jumpsuit/curator.rsi/meta.json | 30 +++++++++++++++++ .../equipped-INNERCLOTHING-monkey.png | Bin 20477 -> 7693 bytes .../librarian.rsi/equipped-INNERCLOTHING.png | Bin 661 -> 675 bytes .../Uniforms/Jumpsuit/librarian.rsi/icon.png | Bin 469 -> 346 bytes .../Jumpsuit/librarian.rsi/inhand-left.png | Bin 497 -> 425 bytes .../Jumpsuit/librarian.rsi/inhand-right.png | Bin 559 -> 435 bytes .../Uniforms/Jumpsuit/librarian.rsi/meta.json | 2 +- .../VendingMachines/curadrobe.rsi/broken.png | Bin 0 -> 443 bytes .../VendingMachines/curadrobe.rsi/meta.json | 31 ++++++++++++++++++ .../curadrobe.rsi/normal-unshaded.png | Bin 0 -> 1971 bytes .../VendingMachines/curadrobe.rsi/off.png | Bin 0 -> 318 bytes .../VendingMachines/curadrobe.rsi/panel.png | Bin 0 -> 190 bytes 44 files changed, 251 insertions(+), 6 deletions(-) create mode 100644 Resources/Locale/en-US/advertisements/vending/curadrobe.ftl create mode 100644 Resources/Prototypes/Catalog/VendingMachines/Advertisements/curadrobe.yml create mode 100644 Resources/Prototypes/Catalog/VendingMachines/Inventories/curadrobe.yml create mode 100644 Resources/Textures/Clothing/Eyes/Glasses/jamjar.rsi/equipped-EYES-hamster.png create mode 100644 Resources/Textures/Clothing/Eyes/Glasses/jamjar.rsi/equipped-EYES.png create mode 100644 Resources/Textures/Clothing/Eyes/Glasses/jamjar.rsi/icon.png create mode 100644 Resources/Textures/Clothing/Eyes/Glasses/jamjar.rsi/inhand-left.png create mode 100644 Resources/Textures/Clothing/Eyes/Glasses/jamjar.rsi/inhand-right.png create mode 100644 Resources/Textures/Clothing/Eyes/Glasses/jamjar.rsi/meta.json create mode 100644 Resources/Textures/Clothing/Uniforms/Jumpskirt/curator.rsi/equipped-INNERCLOTHING-monkey.png create mode 100644 Resources/Textures/Clothing/Uniforms/Jumpskirt/curator.rsi/equipped-INNERCLOTHING.png create mode 100644 Resources/Textures/Clothing/Uniforms/Jumpskirt/curator.rsi/icon.png create mode 100644 Resources/Textures/Clothing/Uniforms/Jumpskirt/curator.rsi/inhand-left.png create mode 100644 Resources/Textures/Clothing/Uniforms/Jumpskirt/curator.rsi/inhand-right.png create mode 100644 Resources/Textures/Clothing/Uniforms/Jumpskirt/curator.rsi/meta.json create mode 100644 Resources/Textures/Clothing/Uniforms/Jumpskirt/librarian.rsi/equipped-INNERCLOTHING-monkey.png create mode 100644 Resources/Textures/Clothing/Uniforms/Jumpskirt/librarian.rsi/equipped-INNERCLOTHING.png create mode 100644 Resources/Textures/Clothing/Uniforms/Jumpskirt/librarian.rsi/icon.png create mode 100644 Resources/Textures/Clothing/Uniforms/Jumpskirt/librarian.rsi/inhand-left.png create mode 100644 Resources/Textures/Clothing/Uniforms/Jumpskirt/librarian.rsi/inhand-right.png create mode 100644 Resources/Textures/Clothing/Uniforms/Jumpskirt/librarian.rsi/meta.json create mode 100644 Resources/Textures/Clothing/Uniforms/Jumpsuit/curator.rsi/equipped-INNERCLOTHING-monkey.png create mode 100644 Resources/Textures/Clothing/Uniforms/Jumpsuit/curator.rsi/equipped-INNERCLOTHING.png create mode 100644 Resources/Textures/Clothing/Uniforms/Jumpsuit/curator.rsi/icon.png create mode 100644 Resources/Textures/Clothing/Uniforms/Jumpsuit/curator.rsi/inhand-left.png create mode 100644 Resources/Textures/Clothing/Uniforms/Jumpsuit/curator.rsi/inhand-right.png create mode 100644 Resources/Textures/Clothing/Uniforms/Jumpsuit/curator.rsi/meta.json create mode 100644 Resources/Textures/Structures/Machines/VendingMachines/curadrobe.rsi/broken.png create mode 100644 Resources/Textures/Structures/Machines/VendingMachines/curadrobe.rsi/meta.json create mode 100644 Resources/Textures/Structures/Machines/VendingMachines/curadrobe.rsi/normal-unshaded.png create mode 100644 Resources/Textures/Structures/Machines/VendingMachines/curadrobe.rsi/off.png create mode 100644 Resources/Textures/Structures/Machines/VendingMachines/curadrobe.rsi/panel.png diff --git a/Resources/Locale/en-US/advertisements/vending/curadrobe.ftl b/Resources/Locale/en-US/advertisements/vending/curadrobe.ftl new file mode 100644 index 00000000000..d7495746973 --- /dev/null +++ b/Resources/Locale/en-US/advertisements/vending/curadrobe.ftl @@ -0,0 +1,2 @@ +advertisement-curadrobe-1 = Glasses for your eyes and literature for your soul, CuraDrobe has it all! +advertisement-curadrobe-2 = Impress & enthrall your library guests with CuraDrobe's extended line of pens! diff --git a/Resources/Prototypes/Catalog/VendingMachines/Advertisements/curadrobe.yml b/Resources/Prototypes/Catalog/VendingMachines/Advertisements/curadrobe.yml new file mode 100644 index 00000000000..71cc1230b2a --- /dev/null +++ b/Resources/Prototypes/Catalog/VendingMachines/Advertisements/curadrobe.yml @@ -0,0 +1,5 @@ +- type: advertisementsPack + id: CuraDrobeAds + advertisements: + - advertisement-curadrobe-1 + - advertisement-curadrobe-2 diff --git a/Resources/Prototypes/Catalog/VendingMachines/Inventories/curadrobe.yml b/Resources/Prototypes/Catalog/VendingMachines/Inventories/curadrobe.yml new file mode 100644 index 00000000000..b083c62ed56 --- /dev/null +++ b/Resources/Prototypes/Catalog/VendingMachines/Inventories/curadrobe.yml @@ -0,0 +1,14 @@ +- type: vendingMachineInventory + id: CuraDrobeInventory + startingInventory: + BooksBag: 1 + HandLabeler: 2 + ClothingEyesGlasses: 2 + ClothingEyesGlassesJamjar: 2 + ClothingUniformJumpsuitCurator: 3 + ClothingUniformJumpskirtCurator: 3 + ClothingUniformJumpsuitLibrarian: 3 + ClothingUniformJumpskirtLibrarian: 3 + ClothingShoesBootsLaceup: 2 + ClothingHeadsetService: 2 + diff --git a/Resources/Prototypes/Entities/Clothing/Eyes/glasses.yml b/Resources/Prototypes/Entities/Clothing/Eyes/glasses.yml index c97290fdaaa..2323db881e8 100644 --- a/Resources/Prototypes/Entities/Clothing/Eyes/glasses.yml +++ b/Resources/Prototypes/Entities/Clothing/Eyes/glasses.yml @@ -80,6 +80,22 @@ - HamsterWearable - WhitelistChameleon +- type: entity + parent: ClothingEyesBase + id: ClothingEyesGlassesJamjar + name: jamjar glasses + description: Also known as Virginity Protectors. + components: + - type: Sprite + sprite: Clothing/Eyes/Glasses/jamjar.rsi + - type: Clothing + sprite: Clothing/Eyes/Glasses/jamjar.rsi + - type: VisionCorrection + - type: Tag + tags: + - HamsterWearable + - WhitelistChameleon + - type: entity parent: ClothingEyesBase id: ClothingEyesGlassesOutlawGlasses diff --git a/Resources/Prototypes/Entities/Clothing/Uniforms/jumpskirts.yml b/Resources/Prototypes/Entities/Clothing/Uniforms/jumpskirts.yml index bbfec42bea9..d0eeb5b64b9 100644 --- a/Resources/Prototypes/Entities/Clothing/Uniforms/jumpskirts.yml +++ b/Resources/Prototypes/Entities/Clothing/Uniforms/jumpskirts.yml @@ -537,6 +537,28 @@ - type: Clothing sprite: Clothing/Uniforms/Jumpskirt/Color/maroon.rsi +- type: entity + parent: ClothingUniformSkirtBase + id: ClothingUniformJumpskirtLibrarian + name: librarian jumpskirt + description: A cosy green jumper fit for a curator of books. + components: + - type: Sprite + sprite: Clothing/Uniforms/Jumpskirt/librarian.rsi + - type: Clothing + sprite: Clothing/Uniforms/Jumpskirt/librarian.rsi + +- type: entity + parent: ClothingUniformSkirtBase + id: ClothingUniformJumpskirtCurator + name: sensible skirt + description: It's sensible. Too sensible... + components: + - type: Sprite + sprite: Clothing/Uniforms/Jumpskirt/curator.rsi + - type: Clothing + sprite: Clothing/Uniforms/Jumpskirt/curator.rsi + - type: entity parent: ClothingUniformSkirtBase id: ClothingUniformJumpskirtPerformer diff --git a/Resources/Prototypes/Entities/Clothing/Uniforms/jumpsuits.yml b/Resources/Prototypes/Entities/Clothing/Uniforms/jumpsuits.yml index 8d3bee7b190..5e857141b85 100644 --- a/Resources/Prototypes/Entities/Clothing/Uniforms/jumpsuits.yml +++ b/Resources/Prototypes/Entities/Clothing/Uniforms/jumpsuits.yml @@ -767,6 +767,17 @@ - type: Clothing sprite: Clothing/Uniforms/Jumpsuit/librarian.rsi +- type: entity + parent: ClothingUniformBase + id: ClothingUniformJumpsuitCurator + name: sensible suit + description: It's sensible. Too sensible... + components: + - type: Sprite + sprite: Clothing/Uniforms/Jumpsuit/curator.rsi + - type: Clothing + sprite: Clothing/Uniforms/Jumpsuit/curator.rsi + - type: entity parent: ClothingUniformBase id: ClothingUniformJumpsuitLawyerRed @@ -1157,7 +1168,7 @@ - type: entity parent: ClothingUniformBase id: ClothingUniformJumpsuitCossack - name: Cossack suit + name: cossack suit description: the good old pants and brigantine. components: - type: Sprite 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 3324e7d2c31..6ada51176c9 100644 --- a/Resources/Prototypes/Entities/Objects/Specific/Service/vending_machine_restock.yml +++ b/Resources/Prototypes/Entities/Objects/Specific/Service/vending_machine_restock.yml @@ -135,6 +135,7 @@ - SecDrobeInventory - ViroDrobeInventory - WinterDrobeInventory + - CuraDrobeInventory - type: Sprite layers: - state: base diff --git a/Resources/Prototypes/Entities/Structures/Machines/vending_machines.yml b/Resources/Prototypes/Entities/Structures/Machines/vending_machines.yml index 3e8f6a9b6b1..8e06d23ee76 100644 --- a/Resources/Prototypes/Entities/Structures/Machines/vending_machines.yml +++ b/Resources/Prototypes/Entities/Structures/Machines/vending_machines.yml @@ -1614,6 +1614,32 @@ - type: AccessReader access: [["Chemistry"]] +- type: entity + parent: VendingMachine + id: VendingMachineCuraDrobe + name: CuraDrobe + description: A lowstock vendor only capable of vending clothing for curators and librarians. + components: + - type: VendingMachine + pack: CuraDrobeInventory + offState: off + brokenState: broken + normalState: normal-unshaded + - type: Advertise + pack: CuraDrobeAds + - type: Sprite + sprite: Structures/Machines/VendingMachines/curadrobe.rsi + layers: + - state: "off" + map: ["enum.VendingMachineVisualLayers.Base"] + - state: "off" + map: ["enum.VendingMachineVisualLayers.BaseUnshaded"] + shader: unshaded + - state: panel + map: ["enum.WiresVisualLayers.MaintenancePanel"] + - type: AccessReader + access: [["Service"]] + - type: entity parent: VendingMachine id: VendingMachineAtmosDrobe diff --git a/Resources/Prototypes/Roles/Jobs/Civilian/librarian.yml b/Resources/Prototypes/Roles/Jobs/Civilian/librarian.yml index 8a3e2adaa37..68d075f89fc 100644 --- a/Resources/Prototypes/Roles/Jobs/Civilian/librarian.yml +++ b/Resources/Prototypes/Roles/Jobs/Civilian/librarian.yml @@ -19,10 +19,7 @@ id: LibrarianPDA ears: ClothingHeadsetService pocket1: d10Dice - belt: BooksBag pocket2: HandLabeler # for making named bestsellers - inhand: - right hand: BriefcaseBrownFilled - innerclothingskirt: ClothingUniformJumpskirtColorLightBrown + innerclothingskirt: ClothingUniformJumpskirtLibrarian satchel: ClothingBackpackSatchelLibrarianFilled duffelbag: ClothingBackpackDuffelLibrarianFilled diff --git a/Resources/Textures/Clothing/Eyes/Glasses/jamjar.rsi/equipped-EYES-hamster.png b/Resources/Textures/Clothing/Eyes/Glasses/jamjar.rsi/equipped-EYES-hamster.png new file mode 100644 index 0000000000000000000000000000000000000000..1d7042d3df9158df1629cace61d8b46e5f8831ee GIT binary patch literal 7979 zcmd^EU5H#s74B?wSrY~pmhoR`dj)mZny#N)_f|DCy_uPwY({pnvy)jf5k%`&)t$Ly zrf=JQlj-C^*If`6L0MK1#Xnf|!H0-X3ZkwcxFGoAA3;<^9~4#$z9f=JJok6*OlIPw zGp@mH`tMeq^VO+yPMtcZ>iNZ!kB=RB`;l6$Ha35vvjo4#lFtK&;rlD!{nV@Qb7-*i z_)P86&)@l1czDC=^ulzl_MOiiy`kO+&+lG*VtMZ7&6}5gb^W;?{&ReM{PgM5$G>{@ z&CmS+I>*Mwe)`87@aGTL-jgsNjh9ZI0^YX?1Fr}SAH*L}MhcBdMD|Nf5}_0UW;PV)u4 z(3`bu;fafVd+OrJWqt9imZtGod+f;MumuPkHdgiF#(HK(nwyP!N)n%) zYD_01)>jr5>$6ec*7<~sG7wqJ{&wvHP+&|*J?I5H#a9X*+kS|Z4xPE6VoQ82q@6tLN``J)EzvWf#fh9JJ9{G z7l%=|p1>+UIu}nhK;mpF8@&>{JIM6~nrjYKuSq6wGPRV@=#s8?uD_m2V06>2+YQ@| z2S7_o+TL0eM}xI!59qRc+W?^Ag@tmAU1izWD2EutbLU|ixmI?i9xPwz+2)cRMCbb2 z&YcG_A1-Dyh?ne^Quo0QE+(7FvID|m(9}G6TNXx4q(jr%5)^B#ETs@R zTme=i)*v6lmv${Ck~soPJpwHAn1=%?k#%*D!3xbe(vGx(2F9h-9|6`;)Zjo_BpqsV z*nm+K5MLRJ9gDFu0xTCk5iZ5ZdX95&(t3s&<`V_5n&-N;pcCy0Pf;2uM(7CAN~5jC zE(P6M@8G1B*08__MBhq3hqZ(t-!m`=%4EPtF_|U~=fc&nHL+X?iniHwVa!N6SPy>SHi}%i?T@4}6$o8D{FN6^#l4Z_Z#wiU^Gi@!dd6 z!ITTz&MoXk&X5BaBLnarnS)ha3F0Dbak>pzqy!`q;2_{L5;G>jl-V#9upPrZ*$<&S zQtK6pWFCo$Jq_B|+@Qb*t+amWss6wwnf+9wNbQSyC(C?+JS`4dN+(56TPF#%g@v}QwGbrZ$vMJX?Y6)9 zX3!P(UEw#^Z1;AFc!rWv?aDuhf_PK)?er?-srxAoGQjO@Rpebf|1On1Q0GThHPh0y zN=QUG#0<}MFcR8uksK`|6 zqkiwt@NNPe6taeD79gnLIpTo>Wt~Gj1oeh1B$qhAP}bksUXlg4*Y|q58=Dvc7SK$> zexo5#C6JfFMkC;hdk*F{@Z2(WxPutC>oM7DzQ6ykH=lB07havGWYr*4%2){qX&Cqq zu`LOIWh^Z4D;U)=4nEI0kU)1&&+u**)&7c|I}UXJCyOfc#%hgI6ihqIp`z-`cGcs_ z_Meoh;N`a~fuNXy+lp2tS`|g;euLc(_N}FqL!11pe9tm;e+Pk?oE5NJ28!;s5Y2|z z1*RCPP<>}h$7Sg`nOx_zpo)cZE6uUma2|L|TZxqRtRzM0`nk07^eBc`lO*3cW3_ub z4b1W zGDvD_7Y-3pj-4I5u$|e9t=@A5Zac>1H4<+W!YJyd%+e-H1w(owyc z2R{4C&;IqHqgRf;^w7*Fet+bXH=bWTTzls5mG*;wy6@_XUwg~3Z@l>Dk44ofy`glX(f`u%tWsIx;Y9 z?C1WI$O_~u2Ka=y{{R1f-PPaC`+kawiiU@WyUqJ9*1Q)e$;-=o{NW!U$6wS z9u>FY1X=(=2iP4F`c88@sXV)IubOMZ*I!KmW?nxY`tOltU=RYLhADiLIp&MssGjs3 P=l}*!S3j3^P6O>_%)r2R7=#&*=dVZs3QqQPaSXBWe>>qIAG0EdOQCGx z)BpB6n6I2znS1H=xtEr9N`Y^@t8#8%%YiQCRe^HXX7gWqz-Ra1?k8Ek`2p2k{}Zm5QWQS;QC2yk++@Os_l=sFVGAAR$18#jo@A&=Q>)&qyDe!dlb6Mw<&;$UZU`T%e literal 0 HcmV?d00001 diff --git a/Resources/Textures/Clothing/Eyes/Glasses/jamjar.rsi/inhand-right.png b/Resources/Textures/Clothing/Eyes/Glasses/jamjar.rsi/inhand-right.png new file mode 100644 index 0000000000000000000000000000000000000000..b02a6b8528882e34c02cf6d49c3e873a49b63708 GIT binary patch literal 191 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=ZJsWUAr*7p-a5#8$bg6Sg3m?Q zIlRWWAIiLCARZRx!yHugw;tbAs;#pz}GF(a>?-z!hA?A3j+YA;AX&;@6+br#4T(ZZ0u(irUM@j$Q^q$t`@QmAdiFVv)n0HN(>Nd~v$M1ID!$vx z?b^OXv@%r%qEsmYnuG!(p`m6iTWHgrX2NyuH0$ zubp#n>`;QrNxt*WzW19q@6G(?&705nZ|PmJ?51U@RBA=v=HdYS-X8odT?F6X_|a!x zho3fYptmb^_~##Z4IUN`7fOXx>Zym9U!Y6ic|-r5gFW^wx8zo>`u6vJ_*i@UnKNf{ zcT6DC)%%HqpIg6v>#Q4qQ06{O*UO_7z z4PXQQ51O-?bVJ17k;@c<9@9gm{&crn<7v4=K@2NuTGcxQSyd(V!)byAIg7=th!GJD z2^$hgH$NHZE}ibIS++4y+|=w2o^qKH->(|k?8L-G$AsA7)`qi!uIpJ$vV1w~`KEsp*dSxeQnw4y9a;u`6EFU*NfHomR6#2M&hT5VTk< zR~@U3HY~7MmXGo>ulOFw3bAZ;#PwZo#GM5?em$)NaB-;=_tDapayjn8^Lxf&7)`IV zl=cR9Re5%Rd+u0`@t$!ob6qqV&mZ7ZPMw1~h{wvlW6z=+yqPvAUUy~@4c>&JjgSZN z?*tbZ-8D{qw>IdyqxohnCoFiixE zFc}nNLzE3cy$uTn#tDc}avDO(wH$j_gdid;ArTJ>#1J$?CP{>ZE2G;Tb!%V{&x@VeR?RJRiY^-qW^$pzxCa67 z;;=LqQWqUgG&LJXoxHF~>*~^Fu}2bht*cuokgkFvD>5z=bcJlvIF@%svPcLK z7=}U22bL1s(p4Sl0@s?pHQ^C_Dw>4IimnRtfaL<`nnD}aHeu;iu$EhrMW|*6PPm$| zTqJ@ifwi{WoM4oy1W}nwRI@Z&5au&)xy=<>mnafdYKOknbqyn3qq?k$s>Z1`58v8E zAfg7ol@yp|jpabG4L-3kmqn2g)tncsOb8Yg0@iBHd3$Bn0{3=Uuy9Qio6NEWL~X7k zOO|Y;>n03aF)@=giEDz~V%T9*l2(#rH9H>#+eE2k^i@2c0$KGH^MN4_7-C5#tTzt+ zrz*@AB580E== zr4RxuGwdb-Hlv%5)Evmc=x9PB7)Rhxl`)Mm*+RBz%g7QX8JQAzm1#hJf+%rarBMeh zU}ki**$Mc3SAu^V`PEjwGtm_Dc_T@x(wfJE^dXmt@`os?3b$7fZ)6|_WkF_@XTh$` z!MW2~BSS)+riOEA+~zjk5IUjW5`JQYS1z~PhbRrHminG+`xCUr3&XG(&Lsm00jH}a zkz36C1v=ZKDw;0q*v4>n zxU#(@B)GTtdRjUZ^1c94aN0dn>GO5H7f%H|tqKY+JnMX{*v$$Z$x*;pkS^O>E z-~Zd2PrR@r4>nV>BnibfCJ3QH1OJBG0{V-&Fv3q@B>TAfdCpZKx@&rb3t3b|g;PA0 zHKbC^5fmW^(o7Y2kDC%PRnwGh5{2vv5{LgUs^C1ckig9C6ne!wP|M2W{~p_gG?6@f zMkm>s=hWyp9;Q2+g1juK8Up=X?raLDOsG{Gi5VYN2j;p9%}}4>xF)pKtd!1LADCO^ zF0?ZNc1cI>LMsGe7cF3-t|HeLr+ggO1UiFaz5(S0I0rY9-#pX>FKLUB8gGVzYQgAO zqa>gb44oE4y^mHLKM#!8Fl0t^tP|Wigyr$Aa1+M!iY$vz zo0{1?UB2I`^UuU6TkX1TtVK{S1b$;_5OA5b9;V_mloHqN54CK@#4h97k_zj{h_^& ze(`SXR7k^QH?8yG> zCjT^koW7_Zxb6A_FE2g$%~el+|G~)+hg_V9N$e)5e+&cC|yzN5#C4S!p7YV~^$q#nQS zJdW-_qI2)dmgt_< zLl0=V#k+S-)<3)R@cpmj>!1AYuOEN+a2wj!v!!^r>r?mt3siy^p#T5? literal 0 HcmV?d00001 diff --git a/Resources/Textures/Clothing/Uniforms/Jumpskirt/curator.rsi/equipped-INNERCLOTHING.png b/Resources/Textures/Clothing/Uniforms/Jumpskirt/curator.rsi/equipped-INNERCLOTHING.png new file mode 100644 index 0000000000000000000000000000000000000000..f4943098c5e2507ff4d710453b277a80bf913c44 GIT binary patch literal 597 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!7>k44ofy`glX(f`u%tWsIx;Y9 z?C1WI$O_~e1o(uw7RkviUAe7YMdjVQcedW;?y(COYiQ&Z*XtTN#Ysw*%F9RkShrMW zFPz?$5$z4sRN|fV5l9J?1o;L3M+FQIlw&1p0tQ)gQkXb}e!I(mydtV!JA3iEfZs7~j`KG5`}>ugH8LSwOXJr!fr*orT#Qt`&uACOY{GDrf!D#3 z;os8ok6oJ4NB$n(zu3QPt*=U7Xj9Kb*&C%|=IM|5FMXAof2DlG%q51U3=29GN*y-o zGi3b!A(nXM$C8P9`CL-LatE$;S~ne2|M;ok&AL3lk9`Y1dcOSRkm)0FfVYJK%T0tMyvD^zZ9<-KEn%2M62{d;pz6LZZXwjWX( ba{s?myYY6HROfqOlrea^`njxgN@xNAFEjp_ literal 0 HcmV?d00001 diff --git a/Resources/Textures/Clothing/Uniforms/Jumpskirt/curator.rsi/icon.png b/Resources/Textures/Clothing/Uniforms/Jumpskirt/curator.rsi/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..0142dcbeeb895de4999d76905b94de6f38f630c1 GIT binary patch literal 362 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE3?yBabR7dyjKx9jP7LeL$-D$|SkfJR9T^xl z_H+M9WCik#1AIbUi{#{%uH3eI_3FhM8t>k{v-K`_k6oBoT(4{7)UKiuCn;GfFCXb+ zof+lbQklJQdKXaN@`ZoRfs|lLkYDhBG{B&`c4iV#lC!`gvY3H^?;r>>?wFYU7AUyb z)5S5w!vAgmYrbX$9yfd4xEmV3{`v3jzjbEP8QtGIQ@|K%(Gg>==&Smg)^>bP0l+XkK7afvo literal 0 HcmV?d00001 diff --git a/Resources/Textures/Clothing/Uniforms/Jumpskirt/curator.rsi/inhand-left.png b/Resources/Textures/Clothing/Uniforms/Jumpskirt/curator.rsi/inhand-left.png new file mode 100644 index 0000000000000000000000000000000000000000..a4ee3cd2212413f7433373f53270656a589bdc3e GIT binary patch literal 421 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!7>k44ofy`glX(f`u%tWsIx;Y9 z?C1WI$O_~e1o(uw21-aQUAb+shQ_;h?`*xxb&Z_dV;8oosMrb#c{-S6M0>YXW-pxH zWpAdHCNB@vbmwx3H;@u23Gxg6j|vzbD91_yu3r#+OXGq~T!D=Is;y5GSsuQu1^Sl3)78&qol`;+07-k44ofy`glX(f`u%tWsIx;Y9 z?C1WI$O_~e1o(uw21-aQUAb+shQ_;h?`*xxb&Z_dV;8oosMrb#rOC^CI+$ccd$&|( zFPz?GZ>9y*H2Vd+A&?R%3Gxg6j|vzbD91_y%|V_lkx&F-e~-QL!z zcOflxe{D0TkAPt#r_y<$3!67A;?`NW^2I672I)lC@T^^HV-=<=*C zJrkxvSMi9L;ESSq0U;%=@e#onS)agTe~DWM4f D0o|ie literal 0 HcmV?d00001 diff --git a/Resources/Textures/Clothing/Uniforms/Jumpskirt/curator.rsi/meta.json b/Resources/Textures/Clothing/Uniforms/Jumpskirt/curator.rsi/meta.json new file mode 100644 index 00000000000..0a48ac3e373 --- /dev/null +++ b/Resources/Textures/Clothing/Uniforms/Jumpskirt/curator.rsi/meta.json @@ -0,0 +1,30 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/47718914e47c6fbf23d6dc97f073a9daa11b23cb and modified by potato1234x (github) for ss14", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "icon" + }, + { + "name": "equipped-INNERCLOTHING", + "directions": 4 + }, + { + "name": "equipped-INNERCLOTHING-monkey", + "directions": 4 + }, + { + "name": "inhand-left", + "directions": 4 + }, + { + "name": "inhand-right", + "directions": 4 + } + ] +} diff --git a/Resources/Textures/Clothing/Uniforms/Jumpskirt/librarian.rsi/equipped-INNERCLOTHING-monkey.png b/Resources/Textures/Clothing/Uniforms/Jumpskirt/librarian.rsi/equipped-INNERCLOTHING-monkey.png new file mode 100644 index 0000000000000000000000000000000000000000..2462daf587c5c64b8494674bee55e9c2fee37239 GIT binary patch literal 7642 zcmeHMeQX>@6~8tKjgux2B4}tR*t83lj(GT}*+)&-V!?LVqOhEkLfnCesXQ|)Uv+14WC)M%XuU~{WO{K0al~ii+ z^5E~9)PoPLNTpU@aQg@Rf$oha^9s$>_AK69EtEhym1-C}F{jUPUn z7F@eEy;%-R$J3GU=#ii znlovkCgN{vP3M9hg@Nu~q1`KUL1|VI!>T4|Mzg4BnylR}5G*PgEM+8&h-Avxl!;LP zq@g=OXerx{*_ZFEcLz_c=^@`QnVHPk*jV$J)a;c9GooP_8B8*SAdo)c3Z)pkSgHF9JeR4`QbugX!O&`gHjCv-Bjw?m z1vbm@VP4=xzXGyiEL$4#e6KR(O#>ajp40)jxVt;hmnYFik{^FzFW+ zQ&LP(`y>`kj1v%{d5rTxUj3nGI5>wPog(MLYl9Lf&ec05eGr~y9#wa#3 z9j{!Ve%39}L7piU2U{`|jj>!jt;}|B*eioUJS(+i8Z|f2$$M-hn8~>!;}r-%B@Rn{ zA+^!LL{q(S*v*QadRv>JNFB0d=xyy{jJT-N+sMN3#Z-<(Ly~oDuvx$w+?E`RYslh;6~gLV6p^LbmPmmw9V%uC&4T(#97O=L&s3qA9>C|C$Sea3zD-t0@WEci9 z8(2yl+t3VTh+MDx)`CaysbmqNsD>ua0+x%M>ng2TTZg4rz*=t0Hlex`IN?gda*2qR z4AweIeS%S{5kwU(Q{C1bQJl@ZX8>+YPon5>32Pj2O;*Er=uA-%lMSxJ>QV`T zl^J%E0Grayr^_znV01Vk5sV{nsK%Jim|`PGa};DtvVtrbyvlSSKT(poq0y*=1~5}P z>T&}<-=5&#T7I>Oe=*S%^LZ^vD$#O<2kAp=I?5lSq$=EALA;iMn3M&XRh9+2HV5ZU zYK;sDb?O@K#c`Y2cthxfdPDfJAzr-HZXcr5q#Ej1JjWlSWu6;^&2T0eNC-GtEs5M< z=FidD6*@X=S4+%LIn@nB6j-5}Dr2NGTR|$2j3TR+sM%T+#hJPq(jqZPtb$}--WqAY zi!P35BO9W{L2hR=kr7eD)f*69)3GEu1X;w8k%nRS&~3;gbdH%OSq?KCCmPM=1w`t{ z*bHJKz87P{yy7S?&ybUV?Nzz!j)&<^XONc#RYRbkOPx*OlnJ$JGcn_%>cC8Qp(*MU99M_7>y^@J>jN{Z+=X@~ zz%J^@n`?z2?4kio)K%pA{DhC=nm|iX%r~LD0O#OZ@|%Ua;6-gQQtiz^P%Ri9sg(pY zg5i@9gYUXx^7UlJEtghIzMiZ&p?7D|^|QcuHAAK}$2!5SLs%Z)1UF$kt15~FwW+Di zljVEeDjy!myHFml1mvK~b&aVn8mMiVPA%~wR0|hI;<~C9iLe#!!r%#_6giouk8T(^boR^3<}dun`A_Zs?H>*< zyHK6C^5&(VyY^Uh_urPDzH7k`o`2@+PE}Odkp_i{K@FTzY-c4JME<3vF13lM$ z?Zmi0UcK*y^G)AxvV^^l{%+oe-fK^Pd;j6JUpjGIeR1pi&IT8v>pOb#kGFk({9igb B88!d_ literal 0 HcmV?d00001 diff --git a/Resources/Textures/Clothing/Uniforms/Jumpskirt/librarian.rsi/equipped-INNERCLOTHING.png b/Resources/Textures/Clothing/Uniforms/Jumpskirt/librarian.rsi/equipped-INNERCLOTHING.png new file mode 100644 index 0000000000000000000000000000000000000000..56b96469654a0c76c4926361836daaedd7c30d83 GIT binary patch literal 606 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!7>k44ofy`glX(f`u%tWsIx;Y9 z?C1WI$O_~e2l#}zGQ_cLTe_6HOzhpecjb1r3q9P$o0RJF@||>bKdkj<@MmJp;?m>=AP|>i?x|#zHvU7!~Ej&yNbF4-_LLy>_6UqwC+RovDt}-nmHA{ zL~Dh9@b&(W^SLa-P|tWkBlOE+q5JcW2+KWe*;LkWk@3N@dNgOd|DR~L*!burwMWOb9No@y%?X*7a`w>sC9h4-T`Au%bBSRo z!vi6|R}BgC83Mk2)V;H!aM?sXYu4VCA_p#Y$~ivv$&u^3Y8n~*M$qJ($SiiR`i7R*VAf0SAu i;N<~w+CH|N+uZjzKFA;-cKQ^%3DUx_B80bm{Pgg&ebxsLQ0C7x-Gynhq literal 0 HcmV?d00001 diff --git a/Resources/Textures/Clothing/Uniforms/Jumpskirt/librarian.rsi/inhand-left.png b/Resources/Textures/Clothing/Uniforms/Jumpskirt/librarian.rsi/inhand-left.png new file mode 100644 index 0000000000000000000000000000000000000000..9feaebdb55a104eaa0ec59dfdc73ffcf1cd1c044 GIT binary patch literal 425 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!7>k44ofy`glX(f`u%tWsIx;Y9 z?C1WI$O_~e2l#}zGQ_cLTe?)dN$K6Ycjb1r++|`;y1ENJ+!-=CKdkjX*{-8!VC3iH zwZBF+DJiL$#EUe4jvTI6A3pSEhbipA}VO(FIs z*QfF^O?cbT;#AS*aNJx&I6&mFcAQ@KCO$D0g@8!+^qot-_^nKtDLIAHVZ)kK&DTXj z4L%IpPpLlNmGWxAn&!IGE!;5&b{t?m^Oj}T&RnJocfuO8@+LEwZJ!g*I6L~>dj{QH x;f873xb?ua8CQw7biL#DErAPm?oGIDxBACd^?6_ZI{|&m;OXk;vd$@?2>`CitiS*O literal 0 HcmV?d00001 diff --git a/Resources/Textures/Clothing/Uniforms/Jumpskirt/librarian.rsi/inhand-right.png b/Resources/Textures/Clothing/Uniforms/Jumpskirt/librarian.rsi/inhand-right.png new file mode 100644 index 0000000000000000000000000000000000000000..6b8fccf1f47aa2e8242a03b3db30eee46060e119 GIT binary patch literal 435 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!7>k44ofy`glX(f`u%tWsIx;Y9 z?C1WI$O_~e2l#}zGQ_cLTe?)dN$K6Ycjb1r++|`;y1ENJ+!-=CKdkjX*{-8!VC3iH zwZBF+DJiL?DvlZM=8h3L_py-Y zpyKRsgJ+pMG4ubQnwI$Xw2|I~7n^+_urN)!yPW^r-nraz<PTCTck_Ye1ffAQi|r%tup zJcvl^vOAvIwrJ7Tq4iHa{$T%?Z(b_j0OGHD$9KZdT(5iOs*mEIMEk*4Uxqicipy7* z6N%ZM_Wv3Z-+5wQA~FA6r>EEJ&8^T)H{V1p*I-SRd=aD*iRPu1A~n}DFKMtor_ho* zec**u(y>}nw@W#kE4HzIXZhw5TeW#*kGXlhsadI|={b$f6&(=r%%jOlexOj+D=n!i zunzzG&0H#374g=$q%wYw$=+O7vdt~Aq|_uM6U$0c(VBQkQAFj7NrHKa!vZH@LPYSwACYwu^t#@ZTYTdz8ORC@ViaN&)4h}XA3QcaQkK;8><1pa}K_G$3Lj{jk zP@%jq0I9)bS=lT(MbB{yNgtLP?nbXA1r`TG$rmH+Lb>KI@Elj6MUHR6{?Mv|mKn(v zH~*sdr%pf}#3NajGzFim)j zFzMkXU66EMxe@a^#xaOMauh<&wH$jWL=X@bk$`)6qVuXQkvKw3ax?<04~u$qLKtz` z2*omW+b!j(mv-{Bk8#C9Uo$t-7|BJ`N^f%q+!7eX(n2#=uepv+)-^Z!GdWW*Ss4OQ zj>1w~NUgLl)>La8aMFB-+S;l~Lc1tvYHJ&xA*~r%k|mtUXfo+gn>l~kfneBaH9WPp zfJQ9WbS!Bvm$n=L9K$r9>7HC6>hmSreGRCIM>+CN%`hL@Kq-8mwqiq)GxI zgf}q^VluFl*p{YfNaLAW^Q{4o;8VdMM3Oayp9C!98B=9iwYCOJFMzeo5-mbi+jqi+ zgk=KZ4H2xhrP>6eR3V5;Or)x%+B`p*dCP1jOPWZLpin#Tt){6MX)4tuMNm{mtx5RS zCOi>T@U1ArEUPXDif!p^7YGq?(q5WFQ$ylnq|7lrV}Dbv2|#yq{S4 z$-KBG)czP<9L+|vpBDOf-X}Tnb zXYr4HfB$c9KGDJsJy=W0;v^K=7$bx#4g4E!^XV_*!Vo`(5%1%|=Q$UI=q~CJPGwOM z1y1o)QjtP2Lr{buNHrATJ!Xi+Pz*z|Nf@&8NF4sZsQmNHR01=xQ|Ni`Ky@pR|9fl~ z&_w+38J=Xvo>Rl)c#!UN_<5OMH3a%O*Vz3Ri4oq|x8lyhKaW!bGRw*5~ zJ}|M$U0`Pn?5vL5sa6PrF6zL9U4^dCj`%pL2{ik~d>zUQa1O2}ziFrop4Ap1Rp0db z)q;VI)slchFnl=P|E?*(PoMdbbuFFAa=WHDpY4q~qT@1m*Ena1+MT zvLp#mn;P3ZTE5Gvuz}vJ1Lg6uPY$wJ(-`}rj@s(+)M76JwP0byuB)n%2wLGT44xob z;YFPP6kX=A0^H!0;HvJsM}GHLxPt8J%w~Femz~^sv~Vc-sg9G6dLL~4+dW6WI`_71 z_doWf{J!gVT)*|L*M;BAU-3@c57sqq-PicQ)q7^I?cBb|8GdZ5-f9m!F=dBr_5cNL!b^Utif_sr=T+2MB%cn5#+LtDy*u}x=}Ue&ci+qf z-}`+lcjnS9J05>4bChpbcgf*96NegJn*P3bO~Y%apExm`U(&hqThlwXynbx|M|j=W z4!?2CoB7!*z0>4cb=Hid2Ohd~&#^haZ!Vwt?1$4D+h2V4^FLX%*}p^WY+sq(+q&+) Fe*tWBFfjlC literal 0 HcmV?d00001 diff --git a/Resources/Textures/Clothing/Uniforms/Jumpsuit/curator.rsi/equipped-INNERCLOTHING.png b/Resources/Textures/Clothing/Uniforms/Jumpsuit/curator.rsi/equipped-INNERCLOTHING.png new file mode 100644 index 0000000000000000000000000000000000000000..1112b8ad75da1640be2c326d24da0a40d6e8c6d0 GIT binary patch literal 658 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!7>k44ofy`glX(f`u%tWsIx;Y9 z?C1WI$O_~e2l#}z7RkviUAe7YMdjVQcedW;?y(COYiQ&Z*XtTN#Ysw*%F73PSYSNkEMXO$D8S^_9U7_N_^3ikdEK^0sk<$2aeXzO{y9>wut(f4M^}8>!Uf57(Yw{+ z3z|$eUX@?^m+izK9)Tx1mopDZlrb{CX891s{NnSQ8}-ME!&tt~Z@BZH?ZH`t#Iz>2 zIDh$1|B8*yZ&r&jZJZeX$@78xi9dh*d}f#?#{X%W@|oLV$288F4<5gfJ;3{n=YLw^ z%GoEH=6^3f;3VwXeRS!x(%7&08&5I5`~JJDUYdblQ?}vWLgt7SdI=A6XEoUVpU?QC zsr1J6b@Q3!0;Ileef_*)dkF&{Ln(tDuftdQq<+n4m;VpH-#!M`9a(>eEYi|TqEO9mE^ z@89Z#ZZMW;U0%H3Ua;orXND>F(lSG@a;h$fogG^0#G0`!Ld(QLpKk{v-K`_k6oBoT(4{7)UKiuCn;GfFCXb+ zoe}NbQklJQdRL&U8BlA*4Qej%VNXMsm#F#`kNeh_A~U=3CQ z3QqHMaSXBWf7>6;cUXak#oSOuv9t2d|4p$P@)25R8E-kBNRxC}VDq7wX~UY=yAH@m zi3wQjuRMNha+he?^SgG!3Q7-n*M95iVLHB17D)3rJ%}ubzwx!FN4M#OrqCI4AODA| zoZ`*b2vj)#&}!)}R=eZ%_{qL|wkvy_dK#Dv{aUA(WO*4k=4YIXJj?C&<3xPLXN4)B Zm~!6O27j*(NC&!*!PC{xWt~$(697NPieLZ$ literal 0 HcmV?d00001 diff --git a/Resources/Textures/Clothing/Uniforms/Jumpsuit/curator.rsi/inhand-left.png b/Resources/Textures/Clothing/Uniforms/Jumpsuit/curator.rsi/inhand-left.png new file mode 100644 index 0000000000000000000000000000000000000000..a4ee3cd2212413f7433373f53270656a589bdc3e GIT binary patch literal 421 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I3?%1nZ+ru!7>k44ofy`glX(f`u%tWsIx;Y9 z?C1WI$O_~e1o(uw21-aQUAb+shQ_;h?`*xxb&Z_dV;8oosMrb#c{-S6M0>YXW-pxH zWpAdHCNB@vbmwx3H;@u23Gxg6j|vzbD91_yu3r#+OXGq~T!D=Is;y5GSsuQu1^Sl3)78&qol`;+07-k44ofy`glX(f`u%tWsIx;Y9 z?C1WI$O_~e1o(uw21-aQUAb+shQ_;h?`*xxb&Z_dV;8oosMrb#rOC^CI+$ccd$&|( zFPz?GZ>9y*H2Vd+A&?R%3Gxg6j|vzbD91_y%|V_lkx&F-e~-QL!z zcOflxe{D0TkAPt#r_y<$3!67A;?`NW^2I672I)lC@T^^HV-=<=*C zJrkxvSMi9L;ESSq0U;%=@e#onS)agTe~DWM4f D0o|ie literal 0 HcmV?d00001 diff --git a/Resources/Textures/Clothing/Uniforms/Jumpsuit/curator.rsi/meta.json b/Resources/Textures/Clothing/Uniforms/Jumpsuit/curator.rsi/meta.json new file mode 100644 index 00000000000..0a48ac3e373 --- /dev/null +++ b/Resources/Textures/Clothing/Uniforms/Jumpsuit/curator.rsi/meta.json @@ -0,0 +1,30 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/47718914e47c6fbf23d6dc97f073a9daa11b23cb and modified by potato1234x (github) for ss14", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "icon" + }, + { + "name": "equipped-INNERCLOTHING", + "directions": 4 + }, + { + "name": "equipped-INNERCLOTHING-monkey", + "directions": 4 + }, + { + "name": "inhand-left", + "directions": 4 + }, + { + "name": "inhand-right", + "directions": 4 + } + ] +} diff --git a/Resources/Textures/Clothing/Uniforms/Jumpsuit/librarian.rsi/equipped-INNERCLOTHING-monkey.png b/Resources/Textures/Clothing/Uniforms/Jumpsuit/librarian.rsi/equipped-INNERCLOTHING-monkey.png index 066cdfe77df77d13c7902ca854c584a0825d330a..7f424f1d8829494abe553cc8f1a324bb201358be 100644 GIT binary patch delta 2256 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 Xx!M9Kr2^t500000NkvXXu0mjfsHi1s delta 623 zcmZ3?I+b;TVSP@3Pl)TRt%E~(z8EpC)9J_d|YB^bgM2$E6xWvG~pi&a#7tHX#{y#zRbxB+a0|Vo7PZ!6K zh}O5$0{ags2((1%s$OlsrBr1a=K1sg|Br09p6E?nIKBFl-d(NG^zX?Uo!vpvIUn;B zHyz#~yl~f>@6`{hRIOuQ%f73;JEP%M0?)(anza|-NN$1SYf@i4*wG?J|+FrQ@*TbKOn6y>7>&cZ1b2!i#g&;ibL!5 z=Mv`XYCj}DYzkFudCyRD`pER=ngsdfnMu2MFw{sYOcr6#J)-_)+6(oGeADM>ED+zQ zWXrte+AZUIG7oar2i8UB+L<-!INxd6*;P;bi8pFXaqh!c}5^>aBUP z%Jt0Q_g{3k-FQ^X#G5H0^7poTlN4Lsfq;!0yYHCzU)X-5(bj&^0&PjjEVdQwC)Dcq zMKBm7x)?XOZB=KV!D1j7Ao)(g%wN;QKmUVMds@SdUABFat;sTeiWw&o87}yGDOGLS z_DsPqMIvElt98U3Lx&=^<~s);&C`9DH&yEHS zPkFBbqy$TX{DS|Z0S48z^)r)zvYZ7Tk;M!QeEUI|(SkJ?q-C#Xg45B_Eh4ag@F&?f$uN_a9b`r>sAMEUyJH9h?btAA_f> KpUXO@geCwQbaK+s#X(muXz0)!38cym z#hOqD;Zg{py%Hw-o8J5TJomf@L_|bHh)_wos3cuo*Ine0Be$%nTr{P{A!;HfD&B7Pz^Werfb;AYu3ugO0P@8qynArd33Rvrriqu21RlS3 z(Cz*pkyydO+7tG&9T29D?FnKca0}Ya9vs^ko4YgLcuklJ$2R_i1(@xyl62QMK4F;( zpYq0Bf8WN5`hPqg{Sbc6CxzgjaCp%ug_IUYwtCOSc{%}mAJ~BR^^=@FggfVDdFHCm zYifC5_g4Izm*6d!!mI=qVj$Pbz%ms$wgJaBP|JhYmZ>1u$}H9Z0F(v=Sf&EYRB(A! z%xfqN!Y!C4NGS!SbS@(i5fT5FUqzp*h8QE>3;+NC07*qoM6N<$g3Hv-7ytkO diff --git a/Resources/Textures/Clothing/Uniforms/Jumpsuit/librarian.rsi/inhand-left.png b/Resources/Textures/Clothing/Uniforms/Jumpsuit/librarian.rsi/inhand-left.png index 48053d29482bd32d1a8c266f0d9ca8e484adc18d..9feaebdb55a104eaa0ec59dfdc73ffcf1cd1c044 100644 GIT binary patch delta 410 zcmey!ypnl>WIZzj1H;_yjcNS%G}x0G|+7 zhB%gOOP7i_DZP95uH4R+yG+bUS9hU@J3}VthqeAE+jaB|jQo7O_SdK;B_&l$ zVzmtdQi3Hxe!>6I0E6n<`k6^USlH9QW)e53*Icmh?c2)bzRbU7 zozv*4X?ZNowWoi%j|0=JTYAQqm%W_BskO+%#6E4+auti)7n?%tP3o^tL_t(|obB1MO2beX z1>h4Y(y6pi2#8ZN>f{qBI4bBCm)6CHaB;|+bju`yyLNRE9GqeVitn z3T<3*k7~XykpKW73KIap{mJos390S1($S!fC`{1U`dE2vHqf>+4Pr9xYj5{2u@jJWe)s$HXi(38vm(%|>sQ!L z4LX4?Qqi8!jejkz^&HfJ#=2tx2%mtX_cKIcg6#(vQJ7%=ZFlt{-Prm!v}Nln5)GhQ zt>R+y6ae6U9%|1M33LhZcR&yX@O@w82}uX4A{syt1oP|Ra40rYDo_>umtaP(*RxdD zMU@dK5fKp)5fKp)5gAONBP^vFTMMCrw6wpQ%am=6{aeQ!9NgSm+3#oFVxC#Xo`6|< z3;=CsTA3GVkIf4}xIH#600o^oUbGon3*kE6=o28(9vdBiM0;#>0DyjbY;*u@kBLav Y7j`1f&FHbBp8x;=07*qoM6N<$f?&DSod5s; diff --git a/Resources/Textures/Clothing/Uniforms/Jumpsuit/librarian.rsi/inhand-right.png b/Resources/Textures/Clothing/Uniforms/Jumpsuit/librarian.rsi/inhand-right.png index b026a2421e9ef8dab15374db3256ffcca29a7110..6b8fccf1f47aa2e8242a03b3db30eee46060e119 100644 GIT binary patch delta 420 zcmZ3_vYB~;WIZzj1H;_yjcNS%G}x0G|+7 zhB%gOOP7i_DZP95uH4R+yG+bUS9hU@J3}VthqeAE+jaB|jQo7O_SdK;B_&l$ zVzmtdQi3Hxe!>6I0E6n<`k6^USOT9bE;)bNKcLSUJYD@<);T3K0RTUXu~Gm4 delta 545 zcmV++0^a?z1Fr;-8Gi-<0063Kaozv`00DDSM?wIu&K&6g00HSqL_t(|obB2@OT$nU z2H-a$B`(E6AyCAj8Fg}XQE;rNTU}Zge}s!e7k@{$PNKML7Y7%?!6~L-DW!oxOO|30 z;-INl8*h?+nUwdL(%gQWd(P<{dI}H`5fKp)5fKp)0HB<8QGd?5{~gA}0`{=vcT=n6 zT}@9z)6>3du}zFmTz-2H`6d7WEYkr1+#T)@-!yZ!9M6qIC|V`|9phI*WJMcIKsoDL zrUO)MWzcV;xb=*eC%9TA?{?d(uuKP;TyIwUn21=klKz>9LBA<|&7U10I=TJ%xZ7SG zC%)P7DcbpE1Am&HMo`g~NA6T@Mfzbu>oMV9G<)QE(hexJj$xS&)*gzmOb0u!o70SO zdaAY}EsSJcngCT*ahf^;02JT$CJAwFq82Ui3@{7>wOTC^Z4X2*nlu51VGOT3oz8@z z%}~{4;l9@i{O)@qbwHtYoScz)NRbkts%j!f<}zcQ0ZAK~%LJbR j0&(&Ra2onbM9KF7V%^Q{WWyQ200000NkvXXu0mjfj=l08 diff --git a/Resources/Textures/Clothing/Uniforms/Jumpsuit/librarian.rsi/meta.json b/Resources/Textures/Clothing/Uniforms/Jumpsuit/librarian.rsi/meta.json index 2e1a43d61a0..0a48ac3e373 100644 --- a/Resources/Textures/Clothing/Uniforms/Jumpsuit/librarian.rsi/meta.json +++ b/Resources/Textures/Clothing/Uniforms/Jumpsuit/librarian.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Based on blacksuit from paradisestation at commit https://github.com/ParadiseSS13/Paradise/commit/4daf5d1a1b45fc3fcc4fd9703222159e6c1f38c8, modified by Peptide, monkey made by brainfood1183 (github) for ss14", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/47718914e47c6fbf23d6dc97f073a9daa11b23cb and modified by potato1234x (github) for ss14", "size": { "x": 32, "y": 32 diff --git a/Resources/Textures/Structures/Machines/VendingMachines/curadrobe.rsi/broken.png b/Resources/Textures/Structures/Machines/VendingMachines/curadrobe.rsi/broken.png new file mode 100644 index 0000000000000000000000000000000000000000..dc955af7f898563df382fcf283997636432cecb9 GIT binary patch literal 443 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE3?yBabR7dyjKx9jP7LeL$-D$|SkfJR9T^xl z_H+M9WCijq1AIbUEew?=bXGN0=LEY4ES%MypAji6D&p;8YHy)gm=!&5dPjh#)w_4^ zt}K@+4&qEqNN{s=n>uwWPlB zSEK+1-*~z>hFJJdop_tC*?`Ac@#!SB+X;XEA3vANzG&@t1MYyOGBWD2eM=fwO*vIA z!dayCJ1!<}gk`A0M&XEyKR+9e%l$0|1ESjn5N_ljHnoRwOuIhMGx zFjb!kc(;gOvT)*of|VjKt}x!NyX@BZU6t$2ZQtMjB|EelR!#ZzeRL7CAE#egtA~caOW<+k*p?<1aWm0TT!O+1vf@Sh>4B_Le`j zOh!b@i8M_FH5`qgpln98(n-a%@ozva%`ks6|1+~0|D$h@JHi=vZg2Pd_IaM~eV_0B z-W8Votgz4tp$LM6we&hGAQ z;X(TXe>idYjpLa;k9sq+$6$K$=#MS6jqB;wSKILZFKz_)ANqFH-EArKp4QX5Tc>9& zpVU11$dUYGD>LGfQtq@{ZaNzeUs}9{inyQ9-dEqy)!8y`PQ;|rBOv@vXhUasWXz(N zv$qci*H2#Kig+-iLOst6mYpr*P5P+LDY?HSu;mB3>t9%!WZe<@@Ym8M+)Tq zd3Do``mhRnRpxbd|I7BexVGcetmus94gaj|8G9fSdwfy-?~c8xxT>%;E}>%O>U{@C zK50*V@LSiqYj<9c(k|Wn=*<1|NtwTrCui;urM%QJe znZEGk^Y-;g?yp0-8fWd-j_4?8`#5`Vf5)Pe$=lDSJ+*G$`N`Y)f4&w!+dOCgxfD4% zdSS=WUFEq8AK%OCn|x7pqf* z%7Tv<kPm0#l|>1dfbYnJl{v1W{dGt*TB`iISb57=|H8HKA7H5P^GYT{2sPyF8JDB0d=t z@NkmgmIcv;DzdCqtdxxyjAJlBr`v2EQg?ZLK0rr^8rDrvDw1$Im8iXFkDO5j$-Y>g zi}n=Nx&cuDJYuE9fs88Pk|X_eo*Ux2DR0p%g{jQ=f5clu=H5R@OTs*9_r|RD(K)p3-V7bAiJZu%< zG2bLt#=7hP9$Hv0gD~Mad!kFEZCakz<9s5Wh-+*#jk8uxhifSf&;W{M5=q9-_lP#R znw7v*JIoFy0n5Xi1RCq}EzXauE(3}wBs`rY{4qt8)}W>gi8O{1!}3TbltVc@w`AgZ zHVop19p=GC;bp^40Y{MMZ$8RssDS|&G(dvwY4QgHO|Z3f<(Q@x6=&W4`FQAla%8Zj z`~87|LxnL>6}6V6*wIALiN1xa`x-`^&kGDIdne?l&NI{ELvlM}IybJ~HY2|0Tv|*^ z{pB57w_oVp5Rr_$*mCgFxn-kbr+l;SN>b@pNl4^~)??`p&xI8}4g641m{68>Z!WUx z$r^d9I^g^6tv5WPmWgWK7BOEAIMu(&mU>b0z51q{zypC&M?5hC0*J>iz?;0=WhN literal 0 HcmV?d00001 diff --git a/Resources/Textures/Structures/Machines/VendingMachines/curadrobe.rsi/off.png b/Resources/Textures/Structures/Machines/VendingMachines/curadrobe.rsi/off.png new file mode 100644 index 0000000000000000000000000000000000000000..06e2276e4e03a59894713e831687c2141fd115d0 GIT binary patch literal 318 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE3?yBabR7dyjKx9jP7LeL$-D$|SkfJR9T^xl z_H+M9WCikd1AIbUEew?=bXGN0=PaDnou3gYEGpvdV*2jgyDQ6Oii0?V-2)O665QO} zrcRv-)KNcq&NLv!UlQaO{2v7{T)8u2AyA65z$3Dlfr0NZ2s0kfUy%aR=IP=XV&VUG zq9<2_0gtQolEB-ye#?hjEjYX2!MWCcA*RZ|EJCmYYOLsV@&sUPdhH0;G?Y|JR?9@uGM}aqoEelepc}lrlyVxEmPDd tX}wWjHQ};L-Tr1K!H{1ou10%VGAJ#Q>HhjVBo^ot22WQ%mvv4FO#tPxc2fWV literal 0 HcmV?d00001 diff --git a/Resources/Textures/Structures/Machines/VendingMachines/curadrobe.rsi/panel.png b/Resources/Textures/Structures/Machines/VendingMachines/curadrobe.rsi/panel.png new file mode 100644 index 0000000000000000000000000000000000000000..0032751ff4ffedd3d0ecc00eaf4e0ab459929e9f GIT binary patch literal 190 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=ffJR!TD@E@bvU_NvA($#wnr(!Xc+! zxY-SW0LU@E^H5*bg578Khv|+_lg$sW*?jCvdBeJOdWZj3DYB`nt4B%rOPnz=`)6-p h#&6~hvQUMA!DX(Lkd@zrT|fshc)I$ztaD0e0svz&KxzO0 literal 0 HcmV?d00001 From 57e1d642acd3f14e995cef8f832f3a5b7cf08a87 Mon Sep 17 00:00:00 2001 From: PJBot Date: Tue, 10 Oct 2023 12:56:34 -0400 Subject: [PATCH 052/127] Automatic changelog update --- Resources/Changelog/Changelog.yml | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 23e1073e792..a7b487bd90a 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,11 +1,4 @@ Entries: -- author: Doru991 - changes: - - {message: 'Due to Nanotrasen choosing a new seed supplier, most plants consume - nutrients much faster.', type: Tweak} - - {message: Composting produce into trays actually works now., type: Fix} - id: 4483 - time: '2023-08-08T00:29:59.0000000+00:00' - author: Ilya246 changes: - {message: Fix radiator transfer rate in high-pressure environments., type: Fix} @@ -2952,3 +2945,11 @@ Entries: - {message: Dionas are actually the same speed as other species now., type: Fix} id: 4982 time: '2023-10-10T14:03:20.0000000+00:00' +- author: Potato1234_x + changes: + - {message: Added the CuraDrobe., type: Add} + - {message: Added the sensible suit and skirt., type: Add} + - {message: Fixed the librarian not having their own jumpskirt., type: Fix} + - {message: Resprited the librarian jumpsuit., type: Tweak} + id: 4983 + time: '2023-10-10T16:55:31.0000000+00:00' From b4d734d7c576616f04ba8ee2fdb26109de07c7d3 Mon Sep 17 00:00:00 2001 From: Whisper <121047731+QuietlyWhisper@users.noreply.github.com> Date: Tue, 10 Oct 2023 14:02:46 -0400 Subject: [PATCH 053/127] organs edible to lizards, and make their food contents uncooked proteins (#20882) * organs edible to lizards, and make their food contents uncooked proteins * npc mobs avoid eating brains for player QOL --- Resources/Prototypes/Body/Organs/Animal/animal.yml | 9 ++++++--- Resources/Prototypes/Body/Organs/arachnid.yml | 9 ++++++--- Resources/Prototypes/Body/Organs/diona.yml | 6 +++--- Resources/Prototypes/Body/Organs/dwarf.yml | 2 +- Resources/Prototypes/Body/Organs/human.yml | 13 ++++++++++--- Resources/Prototypes/Body/Organs/moth.yml | 2 +- Resources/Prototypes/Body/Organs/rat.yml | 2 +- Resources/Prototypes/Body/Organs/reptilian.yml | 2 +- Resources/Prototypes/Body/Organs/slime.yml | 4 ++-- 9 files changed, 31 insertions(+), 18 deletions(-) diff --git a/Resources/Prototypes/Body/Organs/Animal/animal.yml b/Resources/Prototypes/Body/Organs/Animal/animal.yml index db7793210b5..083d596152a 100644 --- a/Resources/Prototypes/Body/Organs/Animal/animal.yml +++ b/Resources/Prototypes/Body/Organs/Animal/animal.yml @@ -14,11 +14,14 @@ food: maxVol: 5 reagents: - - ReagentId: Nutriment + - ReagentId: UncookedAnimalProteins Quantity: 5 - type: FlavorProfile flavors: - chicken # everything kinda tastes like chicken + - type: Tag + tags: + - Meat - type: entity @@ -49,7 +52,7 @@ food: maxVol: 5 reagents: - - ReagentId: Nutriment + - ReagentId: UncookedAnimalProteins Quantity: 5 - type: entity @@ -68,7 +71,7 @@ food: maxVol: 5 reagents: - - ReagentId: Nutriment + - ReagentId: UncookedAnimalProteins Quantity: 5 - type: Stomach - type: Metabolizer diff --git a/Resources/Prototypes/Body/Organs/arachnid.yml b/Resources/Prototypes/Body/Organs/arachnid.yml index 3ec991af865..b4eb11b623b 100644 --- a/Resources/Prototypes/Body/Organs/arachnid.yml +++ b/Resources/Prototypes/Body/Organs/arachnid.yml @@ -19,8 +19,11 @@ food: maxVol: 5 reagents: - - ReagentId: Nutriment + - ReagentId: UncookedAnimalProteins Quantity: 5 + - type: Tag + tags: + - Meat - type: entity id: OrganArachnidStomach @@ -40,7 +43,7 @@ food: maxVol: 5 reagents: - - ReagentId: Nutriment + - ReagentId: UncookedAnimalProteins Quantity: 5 - type: Metabolizer updateFrequency: 1.5 @@ -77,7 +80,7 @@ food: maxVol: 5 reagents: - - ReagentId: Nutriment + - ReagentId: UncookedAnimalProteins Quantity: 5 - type: entity diff --git a/Resources/Prototypes/Body/Organs/diona.yml b/Resources/Prototypes/Body/Organs/diona.yml index 482ec42927b..282bb224d81 100644 --- a/Resources/Prototypes/Body/Organs/diona.yml +++ b/Resources/Prototypes/Body/Organs/diona.yml @@ -19,7 +19,7 @@ food: maxVol: 5 reagents: - - ReagentId: Nutriment + - ReagentId: UncookedAnimalProteins Quantity: 5 - type: FlavorProfile flavors: @@ -46,7 +46,7 @@ food: maxVol: 5 reagents: - - ReagentId: Nutriment + - ReagentId: UncookedAnimalProteins Quantity: 5 - type: Brain - type: InputMover @@ -87,7 +87,7 @@ food: maxVol: 5 reagents: - - ReagentId: Nutriment + - ReagentId: UncookedAnimalProteins Quantity: 5 - type: Stomach - type: Metabolizer diff --git a/Resources/Prototypes/Body/Organs/dwarf.yml b/Resources/Prototypes/Body/Organs/dwarf.yml index afe2c66b26b..8da0cb1666f 100644 --- a/Resources/Prototypes/Body/Organs/dwarf.yml +++ b/Resources/Prototypes/Body/Organs/dwarf.yml @@ -29,7 +29,7 @@ food: maxVol: 5 reagents: - - ReagentId: Nutriment + - ReagentId: UncookedAnimalProteins Quantity: 5 - type: Stomach - type: Metabolizer diff --git a/Resources/Prototypes/Body/Organs/human.yml b/Resources/Prototypes/Body/Organs/human.yml index 1ece318f1d9..6abf168a9e7 100644 --- a/Resources/Prototypes/Body/Organs/human.yml +++ b/Resources/Prototypes/Body/Organs/human.yml @@ -18,11 +18,14 @@ food: maxVol: 5 reagents: - - ReagentId: Nutriment + - ReagentId: UncookedAnimalProteins Quantity: 5 - type: FlavorProfile flavors: - people + - type: Tag + tags: + - Meat - type: entity id: OrganHumanBrain @@ -39,6 +42,10 @@ - type: InputMover - type: Examiner - type: BlockMovement + - type: BadFood + - type: Tag + tags: + - Meat - type: entity id: OrganHumanEyes @@ -111,7 +118,7 @@ food: maxVol: 5 reagents: - - ReagentId: Nutriment + - ReagentId: UncookedAnimalProteins Quantity: 5 - type: entity @@ -148,7 +155,7 @@ food: maxVol: 5 reagents: - - ReagentId: Nutriment + - ReagentId: UncookedAnimalProteins Quantity: 5 - type: Stomach # The stomach metabolizes stuff like foods and drinks. diff --git a/Resources/Prototypes/Body/Organs/moth.yml b/Resources/Prototypes/Body/Organs/moth.yml index a19c6a4ee33..55fb517c552 100644 --- a/Resources/Prototypes/Body/Organs/moth.yml +++ b/Resources/Prototypes/Body/Organs/moth.yml @@ -14,7 +14,7 @@ food: maxVol: 5 reagents: - - ReagentId: Nutriment + - ReagentId: UncookedAnimalProteins Quantity: 5 - type: Metabolizer maxReagents: 3 diff --git a/Resources/Prototypes/Body/Organs/rat.yml b/Resources/Prototypes/Body/Organs/rat.yml index fb93012d97b..9d1352c72f5 100644 --- a/Resources/Prototypes/Body/Organs/rat.yml +++ b/Resources/Prototypes/Body/Organs/rat.yml @@ -18,7 +18,7 @@ food: maxVol: 5 reagents: - - ReagentId: Nutriment + - ReagentId: UncookedAnimalProteins Quantity: 5 - type: Sprite state: stomach diff --git a/Resources/Prototypes/Body/Organs/reptilian.yml b/Resources/Prototypes/Body/Organs/reptilian.yml index 83139f3eca0..b2233a92070 100644 --- a/Resources/Prototypes/Body/Organs/reptilian.yml +++ b/Resources/Prototypes/Body/Organs/reptilian.yml @@ -16,5 +16,5 @@ food: maxVol: 5 reagents: - - ReagentId: Nutriment + - ReagentId: UncookedAnimalProteins Quantity: 5 diff --git a/Resources/Prototypes/Body/Organs/slime.yml b/Resources/Prototypes/Body/Organs/slime.yml index e6ce18b335d..a532c1223a3 100644 --- a/Resources/Prototypes/Body/Organs/slime.yml +++ b/Resources/Prototypes/Body/Organs/slime.yml @@ -27,7 +27,7 @@ food: maxVol: 5 reagents: - - ReagentId: Nutriment + - ReagentId: UncookedAnimalProteins Quantity: 5 @@ -63,5 +63,5 @@ food: maxVol: 5 reagents: - - ReagentId: Nutriment + - ReagentId: UncookedAnimalProteins Quantity: 5 From 660ee13b8995cdd4cfa8c61d6ceecf78f7e2029e Mon Sep 17 00:00:00 2001 From: PJBot Date: Tue, 10 Oct 2023 14:03:53 -0400 Subject: [PATCH 054/127] Automatic changelog update --- Resources/Changelog/Changelog.yml | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index a7b487bd90a..5f9db50390b 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,9 +1,4 @@ Entries: -- author: Ilya246 - changes: - - {message: Fix radiator transfer rate in high-pressure environments., type: Fix} - id: 4484 - time: '2023-08-08T08:16:23.0000000+00:00' - author: chromiumboy changes: - {message: Access readers can now be programmed using the access configurator., @@ -2953,3 +2948,10 @@ Entries: - {message: Resprited the librarian jumpsuit., type: Tweak} id: 4983 time: '2023-10-10T16:55:31.0000000+00:00' +- author: Whisper + changes: + - {message: Lizards can eat organs again!, type: Fix} + - {message: Organs now contain uncooked proteins instead of edible nutriment. Animals + will be able to consume this., type: Tweak} + id: 4984 + time: '2023-10-10T18:02:47.0000000+00:00' From 83062e39b041fdad8d936f0acc681e6c6eecb6c5 Mon Sep 17 00:00:00 2001 From: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com> Date: Wed, 11 Oct 2023 08:33:04 +1100 Subject: [PATCH 055/127] Fix shuttle planet FTL overlapping markers (#20887) --- Content.Server/Parallax/BiomeSystem.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Content.Server/Parallax/BiomeSystem.cs b/Content.Server/Parallax/BiomeSystem.cs index d54293f5683..ab66a48b979 100644 --- a/Content.Server/Parallax/BiomeSystem.cs +++ b/Content.Server/Parallax/BiomeSystem.cs @@ -553,6 +553,9 @@ private void LoadChunk( foreach (var node in nodes) { + if (modified.Contains(node)) + continue; + // Need to ensure the tile under it has loaded for anchoring. if (TryGetBiomeTile(node, component.Layers, component.Noise, grid, out var tile)) { From 8e77faf71ec2e8b67ed3dfb896fafb4574919106 Mon Sep 17 00:00:00 2001 From: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com> Date: Wed, 11 Oct 2023 08:33:17 +1100 Subject: [PATCH 056/127] Fix salvage faction non-determinism (#20886) --- Content.Shared/Salvage/SharedSalvageSystem.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/Content.Shared/Salvage/SharedSalvageSystem.cs b/Content.Shared/Salvage/SharedSalvageSystem.cs index 918b18f8dfd..e5124ab4d03 100644 --- a/Content.Shared/Salvage/SharedSalvageSystem.cs +++ b/Content.Shared/Salvage/SharedSalvageSystem.cs @@ -48,6 +48,7 @@ public SalvageMission GetMission(SalvageDifficultyPrototype difficulty, int seed var air = GetBiomeMod(biome.ID, rand, ref modifierBudget); var dungeon = GetBiomeMod(biome.ID, rand, ref modifierBudget); var factionProtos = _proto.EnumeratePrototypes().ToList(); + factionProtos.Sort((x, y) => string.Compare(x.ID, y.ID, StringComparison.Ordinal)); var faction = factionProtos[rand.Next(factionProtos.Count)]; var mods = new List(); From 1b90732e33bb32763380a77d03d058a05087153a Mon Sep 17 00:00:00 2001 From: PJBot Date: Tue, 10 Oct 2023 17:34:21 -0400 Subject: [PATCH 057/127] Automatic changelog update --- Resources/Changelog/Changelog.yml | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 5f9db50390b..811836b71bc 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,16 +1,4 @@ Entries: -- author: chromiumboy - changes: - - {message: Access readers can now be programmed using the access configurator., - type: Add} - id: 4485 - time: '2023-08-08T18:30:46.0000000+00:00' -- author: Slava0135 - changes: - - {message: Stun batons and bolas can now be thrown to deal stamina damage. Stun - batons no longer show the damage effect when stunning., type: Fix} - id: 4486 - time: '2023-08-08T20:19:31.0000000+00:00' - author: PJB3005 changes: - {message: Better nuke sprite from /vg/., type: Tweak} @@ -2955,3 +2943,15 @@ Entries: will be able to consume this., type: Tweak} id: 4984 time: '2023-10-10T18:02:47.0000000+00:00' +- author: metalgearsloth + changes: + - {message: Fix shuttles sometimes clipping planet marker entities such as ore., + type: Fix} + id: 4985 + time: '2023-10-10T21:33:04.0000000+00:00' +- author: metalgearsloth + changes: + - {message: Fix expedition faction sometimes not aligning with the mission faction., + type: Fix} + id: 4986 + time: '2023-10-10T21:33:18.0000000+00:00' From 425e49bbc857c7a4c4a0025a8e71e6589a946d88 Mon Sep 17 00:00:00 2001 From: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com> Date: Wed, 11 Oct 2023 08:35:50 +1100 Subject: [PATCH 058/127] Fix salvage mission biome seed (#20885) --- Content.Server/Parallax/BiomeSystem.cs | 3 +++ Content.Shared/Parallax/Biomes/BiomeComponent.cs | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/Content.Server/Parallax/BiomeSystem.cs b/Content.Server/Parallax/BiomeSystem.cs index ab66a48b979..a9d78afa865 100644 --- a/Content.Server/Parallax/BiomeSystem.cs +++ b/Content.Server/Parallax/BiomeSystem.cs @@ -107,6 +107,9 @@ private void OnBiomeStartup(EntityUid uid, BiomeComponent component, ComponentSt private void OnBiomeMapInit(EntityUid uid, BiomeComponent component, MapInitEvent args) { + if (component.Seed != -1) + return; + SetSeed(component, _random.Next()); } diff --git a/Content.Shared/Parallax/Biomes/BiomeComponent.cs b/Content.Shared/Parallax/Biomes/BiomeComponent.cs index 7e373db6e01..0fe21821728 100644 --- a/Content.Shared/Parallax/Biomes/BiomeComponent.cs +++ b/Content.Shared/Parallax/Biomes/BiomeComponent.cs @@ -15,7 +15,7 @@ public sealed partial class BiomeComponent : Component [ViewVariables(VVAccess.ReadWrite), DataField("seed")] [AutoNetworkedField] - public int Seed; + public int Seed = -1; /// /// The underlying entity, decal, and tile layers for the biome. From 6f2f0b492fef81d5967573f3a59f967b82674c50 Mon Sep 17 00:00:00 2001 From: Emisse <99158783+Emisse@users.noreply.github.com> Date: Tue, 10 Oct 2023 16:46:47 -0600 Subject: [PATCH 059/127] Bagel Update (#20896) * bagel update * bagel update --- Resources/Maps/bagel.yml | 588 ++++++++++++++++++++++++--------------- 1 file changed, 357 insertions(+), 231 deletions(-) diff --git a/Resources/Maps/bagel.yml b/Resources/Maps/bagel.yml index f9f593407d4..72ee490cc13 100644 --- a/Resources/Maps/bagel.yml +++ b/Resources/Maps/bagel.yml @@ -6413,7 +6413,8 @@ entities: -2,-2: 0: 65535 -2,-1: - 0: 61439 + 0: 61407 + 1: 32 2,-3: 0: 63280 2,-2: @@ -6567,7 +6568,8 @@ entities: -5,-1: 0: 65535 -5,0: - 0: 65535 + 0: 65279 + 1: 256 -5,1: 0: 65535 -5,2: @@ -6587,7 +6589,8 @@ entities: 1,-5: 0: 3311 2,-8: - 0: 65535 + 2: 1 + 0: 65534 2,-5: 0: 65535 3,-8: @@ -6638,19 +6641,19 @@ entities: 0: 65535 5,-8: 0: 32767 - 1: 32768 + 3: 32768 5,-7: 0: 65399 - 1: 136 + 3: 136 5,-6: 0: 65535 5,-5: 0: 65535 6,-8: 0: 36863 - 1: 28672 + 3: 28672 6,-7: - 1: 119 + 3: 119 0: 65416 6,-6: 0: 65535 @@ -6679,7 +6682,8 @@ entities: 6,-2: 0: 65535 7,-4: - 0: 65535 + 0: 65503 + 1: 32 7,-3: 0: 65535 7,-2: @@ -7251,7 +7255,8 @@ entities: 4,-12: 0: 65535 -12,1: - 0: 65535 + 0: 32767 + 1: 32768 -12,2: 0: 65535 -10,3: @@ -7534,10 +7539,10 @@ entities: 0: 34944 -7,-13: 0: 2184 - 2: 9984 + 4: 9984 -6,-13: 0: 36232 - 2: 512 + 4: 512 -5,-13: 0: 36744 -2,-20: @@ -7574,7 +7579,7 @@ entities: 0: 65535 -8,11: 0: 64719 - 2: 816 + 4: 816 -7,8: 0: 65535 -7,9: @@ -7594,7 +7599,8 @@ entities: 2,4: 0: 65535 3,4: - 0: 65535 + 0: 65519 + 1: 16 3,5: 0: 61439 0,-21: @@ -7607,15 +7613,15 @@ entities: 0: 65535 -12,10: 0: 62451 - 2: 3072 - 3: 12 + 4: 3072 + 5: 12 -11,10: - 2: 256 + 4: 256 0: 65278 - 3: 1 + 5: 1 -11,11: 0: 52478 - 2: 1 + 4: 1 -10,10: 0: 65535 -10,8: @@ -7632,7 +7638,7 @@ entities: 0: 65535 -9,11: 0: 63359 - 2: 2176 + 4: 2176 -8,12: 0: 48063 -7,12: @@ -7802,7 +7808,8 @@ entities: 9,3: 0: 65535 10,3: - 0: 65535 + 0: 32767 + 6: 32768 11,3: 0: 65535 13,2: @@ -7834,7 +7841,7 @@ entities: -1,11: 0: 65535 -5,12: - 2: 30515 + 4: 30515 0: 35020 -5,13: 0: 65535 @@ -7852,7 +7859,7 @@ entities: 0: 65535 -4,12: 0: 17 - 2: 65518 + 4: 65518 -4,13: 0: 65535 -4,14: @@ -7860,7 +7867,7 @@ entities: -4,15: 0: 61951 -3,12: - 2: 13107 + 4: 13107 0: 52428 -3,13: 0: 65535 @@ -7892,13 +7899,13 @@ entities: 0: 65535 -7,14: 0: 8191 - 2: 57344 + 4: 57344 -7,15: - 2: 238 + 4: 238 0: 65297 -6,12: 0: 4369 - 2: 61166 + 4: 61166 -6,13: 0: 65535 -6,14: @@ -8185,7 +8192,7 @@ entities: 0: 65535 -7,-12: 0: 44544 - 2: 34 + 4: 34 -6,-10: 0: 39144 13,-14: @@ -8211,7 +8218,7 @@ entities: 17,-8: 0: 29457 17,-7: - 3: 1 + 5: 1 0: 4990 17,-6: 0: 4593 @@ -8339,14 +8346,14 @@ entities: 0: 35771 -12,8: 0: 62451 - 4: 12 - 5: 3072 + 7: 12 + 8: 3072 -12,9: 0: 62451 - 2: 3084 + 4: 3084 -12,11: 0: 8947 - 2: 12 + 4: 12 -12,12: 0: 8751 -12,13: @@ -8540,11 +8547,11 @@ entities: -13,7: 0: 39327 -11,8: - 4: 1 + 7: 1 0: 65278 - 5: 256 + 8: 256 -11,9: - 2: 257 + 4: 257 0: 65278 1,12: 0: 63897 @@ -8566,8 +8573,8 @@ entities: 0: 65497 -13,12: 0: 53199 - 5: 48 - 4: 12288 + 8: 48 + 7: 12288 -13,13: 0: 61727 -18,4: @@ -9060,8 +9067,8 @@ entities: 0: 255 -14,12: 0: 32639 - 5: 128 - 4: 32768 + 8: 128 + 7: 32768 -14,13: 0: 31 -17,12: @@ -9077,9 +9084,9 @@ entities: -3,-20: 0: 28672 -8,-13: - 2: 3840 + 4: 3840 -9,-13: - 2: 3584 + 4: 3584 uniqueMixes: - volume: 2500 temperature: 293.15 @@ -9096,6 +9103,36 @@ entities: - 0 - 0 - 0 + - volume: 2500 + temperature: 293.14996 + moles: + - 20.078888 + - 75.53487 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - volume: 2500 + temperature: 293.15 + moles: + - 21.596506 + - 81.243996 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 - volume: 2500 temperature: 235 moles: @@ -9141,6 +9178,21 @@ entities: - 0 - 0 - 0 + - volume: 2500 + temperature: 293.15 + moles: + - 21.806608 + - 82.03439 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 - volume: 2500 temperature: 293.15 moles: @@ -13977,6 +14029,23 @@ entities: - pos: 5.5,23.5 parent: 60 type: Transform +- proto: AmePart + entities: + - uid: 16550 + components: + - pos: 8.452343,23.559658 + parent: 60 + type: Transform + - uid: 17676 + components: + - pos: 8.561718,23.497158 + parent: 60 + type: Transform + - uid: 18546 + components: + - pos: 8.671093,23.403408 + parent: 60 + type: Transform - proto: AnalysisComputerCircuitboard entities: - uid: 9455 @@ -57815,15 +57884,6 @@ entities: - pos: 31.52947,14.40356 parent: 60 type: Transform - - uid: 17299 - components: - - flags: InContainer - type: MetaData - - parent: 16058 - type: Transform - - canCollide: False - type: Physics - - type: InsideEntityStorage - proto: ClothingBackpackSatchelLeather entities: - uid: 4702 @@ -57854,17 +57914,6 @@ entities: - pos: 19.497345,-45.396423 parent: 60 type: Transform -- proto: ClothingBeltMercWebbing - entities: - - uid: 18546 - components: - - flags: InContainer - type: MetaData - - parent: 16058 - type: Transform - - canCollide: False - type: Physics - - type: InsideEntityStorage - proto: ClothingBeltMilitaryWebbing entities: - uid: 9121 @@ -57947,17 +57996,6 @@ entities: - pos: 14.470102,-43.56056 parent: 60 type: Transform -- proto: ClothingEyesGlassesMercenary - entities: - - uid: 17676 - components: - - flags: InContainer - type: MetaData - - parent: 16058 - type: Transform - - canCollide: False - type: Physics - - type: InsideEntityStorage - proto: ClothingEyesGlassesSunglasses entities: - uid: 2252 @@ -58107,17 +58145,6 @@ entities: - pos: 35.520084,-27.379148 parent: 60 type: Transform -- proto: ClothingHandsGlovesMercFingerless - entities: - - uid: 17674 - components: - - flags: InContainer - type: MetaData - - parent: 16058 - type: Transform - - canCollide: False - type: Physics - - type: InsideEntityStorage - proto: ClothingHandsGlovesNitrile entities: - uid: 4119 @@ -58153,17 +58180,6 @@ entities: - pos: -56.55667,-23.491457 parent: 60 type: Transform -- proto: ClothingHeadBandMerc - entities: - - uid: 17463 - components: - - flags: InContainer - type: MetaData - - parent: 16058 - type: Transform - - canCollide: False - type: Physics - - type: InsideEntityStorage - proto: ClothingHeadBandRed entities: - uid: 1405 @@ -58216,17 +58232,6 @@ entities: - pos: -38.320274,19.65635 parent: 60 type: Transform -- proto: ClothingHeadHatBeretMerc - entities: - - uid: 19043 - components: - - flags: InContainer - type: MetaData - - parent: 16058 - type: Transform - - canCollide: False - type: Physics - - type: InsideEntityStorage - proto: ClothingHeadHatBowlerHat entities: - uid: 8020 @@ -58514,17 +58519,6 @@ entities: - pos: 29.516983,-1.2031906 parent: 60 type: Transform -- proto: ClothingHeadHelmetMerc - entities: - - uid: 19162 - components: - - flags: InContainer - type: MetaData - - parent: 16058 - type: Transform - - canCollide: False - type: Physics - - type: InsideEntityStorage - proto: ClothingHeadHelmetRiot entities: - uid: 1866 @@ -58689,17 +58683,6 @@ entities: - pos: 46.643196,3.6000824 parent: 60 type: Transform -- proto: ClothingMaskGasMerc - entities: - - uid: 19163 - components: - - flags: InContainer - type: MetaData - - parent: 16058 - type: Transform - - canCollide: False - type: Physics - - type: InsideEntityStorage - proto: ClothingMaskNeckGaiter entities: - uid: 927 @@ -58766,6 +58749,13 @@ entities: - pos: -47.5,-26.5 parent: 60 type: Transform +- proto: ClothingNeckCloakTrans + entities: + - uid: 7082 + components: + - pos: -40.498245,-36.02266 + parent: 60 + type: Transform - proto: ClothingNeckHeadphones entities: - uid: 7861 @@ -58799,6 +58789,83 @@ entities: - pos: -11.221505,22.789167 parent: 60 type: Transform +- proto: ClothingNeckMantleCap + entities: + - uid: 16678 + components: + - flags: InContainer + type: MetaData + - parent: 1964 + type: Transform + - canCollide: False + type: Physics + - type: InsideEntityStorage +- proto: ClothingNeckMantleCE + entities: + - uid: 17299 + components: + - flags: InContainer + type: MetaData + - parent: 15403 + type: Transform + - canCollide: False + type: Physics + - type: InsideEntityStorage +- proto: ClothingNeckMantleCMO + entities: + - uid: 17463 + components: + - flags: InContainer + type: MetaData + - parent: 7044 + type: Transform + - canCollide: False + type: Physics + - type: InsideEntityStorage +- proto: ClothingNeckMantleHOP + entities: + - uid: 5207 + components: + - flags: InContainer + type: MetaData + - parent: 6235 + type: Transform + - canCollide: False + type: Physics + - type: InsideEntityStorage +- proto: ClothingNeckMantleHOS + entities: + - uid: 17672 + components: + - flags: InContainer + type: MetaData + - parent: 5933 + type: Transform + - canCollide: False + type: Physics + - type: InsideEntityStorage +- proto: ClothingNeckMantleQM + entities: + - uid: 16058 + components: + - flags: InContainer + type: MetaData + - parent: 13099 + type: Transform + - canCollide: False + type: Physics + - type: InsideEntityStorage +- proto: ClothingNeckMantleRD + entities: + - uid: 17673 + components: + - flags: InContainer + type: MetaData + - parent: 8197 + type: Transform + - canCollide: False + type: Physics + - type: InsideEntityStorage - proto: ClothingNeckNonBinaryPin entities: - uid: 13569 @@ -59053,17 +59120,6 @@ entities: - canCollide: False type: Physics - type: InsideEntityStorage -- proto: ClothingOuterHardsuitSalvage - entities: - - uid: 5207 - components: - - flags: InContainer - type: MetaData - - parent: 13099 - type: Transform - - canCollide: False - type: Physics - - type: InsideEntityStorage - proto: ClothingOuterHardsuitSyndicate entities: - uid: 8071 @@ -59122,17 +59178,6 @@ entities: - pos: 59.42158,-46.288704 parent: 60 type: Transform -- proto: ClothingOuterVestWebMerc - entities: - - uid: 17672 - components: - - flags: InContainer - type: MetaData - - parent: 16058 - type: Transform - - canCollide: False - type: Physics - - type: InsideEntityStorage - proto: ClothingShoesBootsJack entities: - uid: 846 @@ -59169,17 +59214,6 @@ entities: - pos: -22.454462,29.447395 parent: 60 type: Transform -- proto: ClothingShoesBootsMercFilled - entities: - - uid: 17673 - components: - - flags: InContainer - type: MetaData - - parent: 16058 - type: Transform - - canCollide: False - type: Physics - - type: InsideEntityStorage - proto: ClothingShoesBootsWork entities: - uid: 23663 @@ -59376,17 +59410,6 @@ entities: - pos: 37.53859,15.558934 parent: 60 type: Transform -- proto: ClothingUniformJumpsuitMercenary - entities: - - uid: 16678 - components: - - flags: InContainer - type: MetaData - - parent: 16058 - type: Transform - - canCollide: False - type: Physics - - type: InsideEntityStorage - proto: ClothingUniformJumpsuitOperative entities: - uid: 8069 @@ -60594,11 +60617,6 @@ entities: type: Transform - proto: CrateEngineeringAMEJar entities: - - uid: 7082 - components: - - pos: -3.5,33.5 - parent: 60 - type: Transform - uid: 16061 components: - pos: 6.5,23.5 @@ -61301,54 +61319,6 @@ entities: - pos: -4.5,-28.5 parent: 60 type: Transform -- proto: CrateWeaponSecure - entities: - - uid: 16058 - components: - - name: mercenary's stash - type: MetaData - - pos: 56.5,-17.5 - parent: 60 - type: Transform - - air: - volume: 200 - immutable: False - temperature: 293.14957 - moles: - - 1.8856695 - - 7.0937095 - - 0 - - 0 - - 0 - - 0 - - 0 - - 0 - - 0 - - 0 - - 0 - - 0 - type: EntityStorage - - containers: - entity_storage: !type:Container - showEnts: False - occludes: True - ents: - - 18546 - - 17676 - - 17674 - - 17673 - - 17672 - - 17463 - - 17299 - - 16678 - - 19043 - - 19162 - - 19163 - paper_label: !type:ContainerSlot - showEnts: False - occludes: True - ent: null - type: ContainerContainer - proto: CrayonBox entities: - uid: 6700 @@ -106478,6 +106448,35 @@ entities: - pos: -6.5,-2.5 parent: 60 type: Transform + - air: + volume: 200 + immutable: False + temperature: 293.1496 + moles: + - 1.7459903 + - 6.568249 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + type: EntityStorage + - containers: + entity_storage: !type:Container + showEnts: False + occludes: True + ents: + - 16678 + paper_label: !type:ContainerSlot + showEnts: False + occludes: True + ent: null + type: ContainerContainer - proto: LockerChemistryFilled entities: - uid: 2529 @@ -106533,6 +106532,35 @@ entities: - pos: 12.5,17.5 parent: 60 type: Transform + - air: + volume: 200 + immutable: False + temperature: 293.1496 + moles: + - 1.7459903 + - 6.568249 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + type: EntityStorage + - containers: + entity_storage: !type:Container + showEnts: False + occludes: True + ents: + - 17299 + paper_label: !type:ContainerSlot + showEnts: False + occludes: True + ent: null + type: ContainerContainer - proto: LockerChiefMedicalOfficerFilledHardsuit entities: - uid: 7044 @@ -106540,6 +106568,35 @@ entities: - pos: 29.5,-14.5 parent: 60 type: Transform + - air: + volume: 200 + immutable: False + temperature: 293.1496 + moles: + - 1.7459903 + - 6.568249 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + type: EntityStorage + - containers: + entity_storage: !type:Container + showEnts: False + occludes: True + ents: + - 17463 + paper_label: !type:ContainerSlot + showEnts: False + occludes: True + ent: null + type: ContainerContainer - proto: LockerDetectiveFilled entities: - uid: 7640 @@ -107079,8 +107136,8 @@ entities: immutable: False temperature: 293.1496 moles: - - 1.6495836 - - 6.2055764 + - 1.877957 + - 7.0646954 - 0 - 0 - 0 @@ -107097,6 +107154,7 @@ entities: showEnts: False occludes: True ents: + - 5207 - 4641 paper_label: !type:ContainerSlot showEnts: False @@ -107110,6 +107168,35 @@ entities: - pos: -19.5,2.5 parent: 60 type: Transform + - air: + volume: 200 + immutable: False + temperature: 293.1496 + moles: + - 1.7459903 + - 6.568249 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + type: EntityStorage + - containers: + entity_storage: !type:Container + showEnts: False + occludes: True + ents: + - 17672 + paper_label: !type:ContainerSlot + showEnts: False + occludes: True + ent: null + type: ContainerContainer - proto: LockerMedicalFilled entities: - uid: 241 @@ -107168,8 +107255,8 @@ entities: immutable: False temperature: 293.1496 moles: - - 1.877957 - - 7.0646954 + - 1.8962268 + - 7.133425 - 0 - 0 - 0 @@ -107186,7 +107273,7 @@ entities: showEnts: False occludes: True ents: - - 5207 + - 16058 paper_label: !type:ContainerSlot showEnts: False occludes: True @@ -107199,6 +107286,35 @@ entities: - pos: -44.5,7.5 parent: 60 type: Transform + - air: + volume: 200 + immutable: False + temperature: 293.1496 + moles: + - 1.7459903 + - 6.568249 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + type: EntityStorage + - containers: + entity_storage: !type:Container + showEnts: False + occludes: True + ents: + - 17673 + paper_label: !type:ContainerSlot + showEnts: False + occludes: True + ent: null + type: ContainerContainer - proto: LockerSalvageSpecialistFilled entities: - uid: 215 @@ -107853,7 +107969,7 @@ entities: entities: - uid: 7003 components: - - pos: 44.487556,-48.458042 + - pos: 56.487034,-17.432411 parent: 60 type: Transform - proto: MaterialReclaimer @@ -115167,6 +115283,11 @@ entities: - pos: -20.5,5.5 parent: 60 type: Transform + - uid: 19043 + components: + - pos: 8.5,23.5 + parent: 60 + type: Transform - uid: 19131 components: - pos: 20.5,19.5 @@ -124427,7 +124548,7 @@ entities: - pos: 0.5,47.5 parent: 60 type: Transform - - uid: 16550 + - uid: 19162 components: - pos: -5.5,33.5 parent: 60 @@ -124599,6 +124720,11 @@ entities: - pos: 4.5,34.5 parent: 60 type: Transform + - uid: 17674 + components: + - pos: -3.5,33.5 + parent: 60 + type: Transform - uid: 17946 components: - name: GravGenSMES From ab75941bc0b6ef154a267235dcd477836557312a Mon Sep 17 00:00:00 2001 From: Emisse <99158783+Emisse@users.noreply.github.com> Date: Tue, 10 Oct 2023 16:46:54 -0600 Subject: [PATCH 060/127] box update (#20897) --- Resources/Maps/box.yml | 219 +++++++++++++++++++++++++++++------------ 1 file changed, 155 insertions(+), 64 deletions(-) diff --git a/Resources/Maps/box.yml b/Resources/Maps/box.yml index ecf1095cba4..9a31f100920 100644 --- a/Resources/Maps/box.yml +++ b/Resources/Maps/box.yml @@ -6000,7 +6000,8 @@ entities: -8,-8: 0: 65535 -8,-7: - 0: 65535 + 0: 61439 + 1: 4096 -8,-6: 0: 65535 -8,-5: @@ -6082,7 +6083,8 @@ entities: 2,-7: 0: 65535 2,-6: - 0: 65535 + 0: 65519 + 1: 16 2,-5: 0: 65535 3,-8: @@ -6104,7 +6106,8 @@ entities: -3,-8: 0: 65535 -3,-7: - 0: 65535 + 2: 1 + 0: 65534 -3,-6: 0: 65535 -3,-5: @@ -6271,21 +6274,21 @@ entities: 0: 65535 6,-12: 0: 16179 - 1: 204 - 2: 49152 + 3: 204 + 4: 49152 6,-11: 0: 65331 - 2: 204 + 4: 204 6,-10: 0: 65535 6,-9: 0: 65535 7,-12: - 1: 17 + 3: 17 0: 61422 - 2: 4096 + 4: 4096 7,-11: - 2: 17 + 4: 17 0: 65518 7,-10: 0: 65535 @@ -6541,7 +6544,7 @@ entities: 0: 52462 8,0: 0: 65527 - 3: 8 + 5: 8 8,1: 0: 65295 8,2: @@ -6549,7 +6552,7 @@ entities: 8,3: 0: 65535 9,0: - 3: 15 + 5: 15 0: 65520 9,1: 0: 65487 @@ -6558,7 +6561,7 @@ entities: 9,3: 0: 32767 10,0: - 3: 1 + 5: 1 0: 65534 10,1: 0: 65535 @@ -6902,7 +6905,7 @@ entities: 0: 65535 8,-1: 0: 30591 - 3: 34944 + 5: 34944 9,-4: 0: 65535 9,-3: @@ -6911,7 +6914,7 @@ entities: 0: 65535 9,-1: 0: 15 - 3: 65520 + 5: 65520 10,-4: 0: 65535 10,-3: @@ -6920,7 +6923,7 @@ entities: 0: 65535 10,-1: 0: 61167 - 3: 4368 + 5: 4368 11,-4: 0: 65535 11,-3: @@ -7221,10 +7224,10 @@ entities: 0: 65535 3,-14: 0: 16383 - 2: 49152 + 4: 49152 3,-13: 0: 65331 - 2: 204 + 4: 204 8,-12: 0: 65535 8,-11: @@ -7393,7 +7396,7 @@ entities: 0: 65535 20,-5: 0: 29431 - 2: 8 + 4: 8 21,-8: 0: 65535 21,-7: @@ -7582,7 +7585,7 @@ entities: 0: 65535 13,-13: 0: 65501 - 2: 34 + 4: 34 14,-16: 0: 65535 14,-15: @@ -7641,16 +7644,16 @@ entities: 0: 65535 21,-4: 0: 13104 - 2: 52416 + 4: 52416 21,-3: 0: 12595 - 2: 204 + 4: 204 21,-2: 0: 13105 - 2: 52416 + 4: 52416 21,-1: 0: 51 - 2: 204 + 4: 204 16,-19: 0: 63244 16,-18: @@ -7751,7 +7754,7 @@ entities: 0: 65535 4,-17: 0: 34959 - 4: 30576 + 6: 30576 5,-20: 0: 62813 5,-19: @@ -7780,9 +7783,9 @@ entities: 0: 65535 4,-14: 0: 61439 - 2: 4096 + 4: 4096 4,-13: - 2: 17 + 4: 17 0: 65518 5,-16: 0: 65535 @@ -7796,26 +7799,26 @@ entities: 0: 65518 6,-15: 0: 16383 - 2: 49152 + 4: 49152 6,-14: 0: 16179 - 2: 49356 + 4: 49356 6,-13: 0: 16179 - 2: 204 - 1: 49152 + 4: 204 + 3: 49152 7,-16: 0: 39305 7,-15: 0: 61433 - 2: 4096 + 4: 4096 7,-14: - 2: 4113 + 4: 4113 0: 61422 7,-13: - 2: 17 + 4: 17 0: 61422 - 1: 4096 + 3: 4096 -4,-20: 0: 65504 -4,-19: @@ -7958,7 +7961,7 @@ entities: 0: 65535 3,-17: 0: 34959 - 5: 30576 + 7: 30576 0,-24: 0: 65416 0,-23: @@ -8451,6 +8454,36 @@ entities: - 0 - 0 - 0 + - volume: 2500 + temperature: 293.14996 + moles: + - 20.078888 + - 75.53487 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - volume: 2500 + temperature: 293.15 + moles: + - 24.680622 + - 92.84615 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 - volume: 2500 temperature: 293.15 moles: @@ -13886,6 +13919,23 @@ entities: - pos: -9.5,-72.5 parent: 8364 type: Transform +- proto: AmePart + entities: + - uid: 27762 + components: + - pos: -12.607154,-72.37925 + parent: 8364 + type: Transform + - uid: 27763 + components: + - pos: -12.466529,-72.50425 + parent: 8364 + type: Transform + - uid: 27764 + components: + - pos: -12.294654,-72.62925 + parent: 8364 + type: Transform - proto: AmplifierSubspaceStockPart entities: - uid: 16364 @@ -13897,7 +13947,7 @@ entities: entities: - uid: 16368 components: - - pos: -8.99259,-39.184814 + - pos: -8.826363,-39.400078 parent: 8364 type: Transform - proto: AnomalyScanner @@ -50529,6 +50579,11 @@ entities: - pos: -32.5,20.5 parent: 8364 type: Transform + - uid: 13323 + components: + - pos: -36.5,20.5 + parent: 8364 + type: Transform - uid: 13328 components: - pos: -39.5,20.5 @@ -56828,26 +56883,11 @@ entities: - pos: 65.5,16.5 parent: 8364 type: Transform - - uid: 13323 - components: - - pos: -33.5,20.5 - parent: 8364 - type: Transform - uid: 13324 components: - pos: -34.5,20.5 parent: 8364 type: Transform - - uid: 13325 - components: - - pos: -35.5,20.5 - parent: 8364 - type: Transform - - uid: 13326 - components: - - pos: -36.5,20.5 - parent: 8364 - type: Transform - uid: 13327 components: - pos: -37.5,20.5 @@ -70775,6 +70815,11 @@ entities: - 0 - 0 type: EntityStorage + - uid: 13325 + components: + - pos: -4.5,-33.5 + parent: 8364 + type: Transform - uid: 26622 components: - pos: 7.5,-59.5 @@ -71740,7 +71785,7 @@ entities: entities: - uid: 16349 components: - - pos: -9.94314,-39.65799 + - pos: -10.591988,-38.696953 parent: 8364 type: Transform - proto: d10Dice @@ -81805,7 +81850,7 @@ entities: entities: - uid: 16354 components: - - pos: -8.945715,-39.591064 + - pos: -10.388863,-38.431328 parent: 8364 type: Transform - proto: FireAlarm @@ -122455,6 +122500,24 @@ entities: - pos: 8.5,-22.5 parent: 8364 type: Transform + - air: + volume: 200 + immutable: False + temperature: 293.1496 + moles: + - 1.7459903 + - 6.568249 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + type: EntityStorage - proto: LockerChemistryFilled entities: - uid: 18772 @@ -123084,8 +123147,8 @@ entities: immutable: False temperature: 293.1496 moles: - - 5.001885 - - 18.816614 + - 2.146141 + - 8.073578 - 0 - 0 - 0 @@ -123273,6 +123336,24 @@ entities: - pos: -31.5,-24.5 parent: 8364 type: Transform + - air: + volume: 200 + immutable: False + temperature: 293.1496 + moles: + - 1.7459903 + - 6.568249 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + type: EntityStorage - proto: LockerResearchDirectorFilledHardsuit entities: - uid: 15814 @@ -124073,7 +124154,7 @@ entities: entities: - uid: 16355 components: - - pos: -8.245951,-39.650208 + - pos: -10.435738,-39.009453 parent: 8364 type: Transform - proto: MedicalBed @@ -124242,12 +124323,12 @@ entities: entities: - uid: 16356 components: - - pos: -8.652201,-39.009583 + - pos: -10.498238,-39.353203 parent: 8364 type: Transform - uid: 16357 components: - - pos: -8.807449,-39.33577 + - pos: -10.310738,-39.540703 parent: 8364 type: Transform - uid: 21185 @@ -132247,6 +132328,11 @@ entities: - pos: -13.5,-37.5 parent: 8364 type: Transform + - uid: 16113 + components: + - pos: -12.5,-72.5 + parent: 8364 + type: Transform - uid: 16396 components: - pos: 7.5,-46.5 @@ -142070,6 +142156,11 @@ entities: - pos: -50.5,23.5 parent: 8364 type: Transform + - uid: 13326 + components: + - pos: -3.5,-33.5 + parent: 8364 + type: Transform - uid: 15809 components: - name: Telecomms SMES @@ -142110,6 +142201,11 @@ entities: - pos: 34.5,-91.5 parent: 8364 type: Transform + - uid: 27765 + components: + - pos: -9.5,-64.5 + parent: 8364 + type: Transform - proto: SMESMachineCircuitboard entities: - uid: 12457 @@ -147134,11 +147230,6 @@ entities: - pos: -28.5,-55.5 parent: 8364 type: Transform - - uid: 16113 - components: - - pos: -4.5,-33.5 - parent: 8364 - type: Transform - uid: 16114 components: - pos: -5.5,-33.5 @@ -150071,7 +150162,7 @@ entities: entities: - uid: 16366 components: - - pos: -9.281598,-39.498627 + - pos: -8.560738,-38.931328 parent: 8364 type: Transform - proto: TrashBag From edbfef22d6913361e09cc45b44995940ea3cae63 Mon Sep 17 00:00:00 2001 From: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com> Date: Wed, 11 Oct 2023 10:41:11 +1100 Subject: [PATCH 061/127] Climbing refactor (#20516) --- .../DragDropHelper.cs | 2 +- .../DragDropSystem.cs | 13 +- .../Movement/Systems/ClimbSystem.cs | 33 -- .../Systems/Actions/ActionUIController.cs | 2 +- .../Tests/Climbing/ClimbingTest.cs | 4 +- Content.Server/Climbing/ClimbSystem.cs | 476 ----------------- Content.Server/Interaction/DragDropSystem.cs | 8 + .../Interaction/InteractionSystem.cs | 41 -- .../BiomassReclaimerSystem.cs | 4 +- Content.Server/Medical/CryoPodSystem.cs | 2 +- .../Medical/MedicalScannerSystem.cs | 2 +- .../NPC/Pathfinding/PathfindingSystem.Grid.cs | 1 + .../NPC/Systems/NPCSteeringSystem.Context.cs | 1 + .../Systems/NPCSteeringSystem.Obstacles.cs | 4 +- .../NPC/Systems/NPCSteeringSystem.cs | 5 +- .../ActionBlocker/ActionBlockerSystem.cs | 2 +- Content.Shared/Climbing/ClimbingComponent.cs | 27 - .../{ => Components}/BonkableComponent.cs | 4 +- .../{ => Components}/ClimbableComponent.cs | 9 +- .../Climbing/Components/ClimbingComponent.cs | 36 ++ .../Components/GlassTableComponent.cs | 4 +- .../Climbing/Events/ClimbedOnEvent.cs | 7 + .../Climbing/Events/EndClimbEvent.cs | 5 +- .../Climbing/Events/StartClimbEvent.cs | 7 + Content.Shared/Climbing/SharedClimbSystem.cs | 34 -- .../Climbing/{ => Systems}/BonkSystem.cs | 17 +- .../Climbing/Systems/ClimbSystem.cs | 486 ++++++++++++++++++ Content.Shared/DoAfter/SharedDoAfterSystem.cs | 14 +- .../DragDrop/SharedDragDropSystem.cs | 47 +- .../Interaction/SharedInteractionSystem.cs | 1 + 30 files changed, 637 insertions(+), 661 deletions(-) rename Content.Client/{DragDrop => Interaction}/DragDropHelper.cs (99%) rename Content.Client/{DragDrop => Interaction}/DragDropSystem.cs (97%) delete mode 100644 Content.Client/Movement/Systems/ClimbSystem.cs delete mode 100644 Content.Server/Climbing/ClimbSystem.cs create mode 100644 Content.Server/Interaction/DragDropSystem.cs delete mode 100644 Content.Shared/Climbing/ClimbingComponent.cs rename Content.Shared/Climbing/{ => Components}/BonkableComponent.cs (90%) rename Content.Shared/Climbing/{ => Components}/ClimbableComponent.cs (84%) create mode 100644 Content.Shared/Climbing/Components/ClimbingComponent.cs rename {Content.Server => Content.Shared}/Climbing/Components/GlassTableComponent.cs (90%) create mode 100644 Content.Shared/Climbing/Events/ClimbedOnEvent.cs create mode 100644 Content.Shared/Climbing/Events/StartClimbEvent.cs delete mode 100644 Content.Shared/Climbing/SharedClimbSystem.cs rename Content.Shared/Climbing/{ => Systems}/BonkSystem.cs (88%) create mode 100644 Content.Shared/Climbing/Systems/ClimbSystem.cs diff --git a/Content.Client/DragDrop/DragDropHelper.cs b/Content.Client/Interaction/DragDropHelper.cs similarity index 99% rename from Content.Client/DragDrop/DragDropHelper.cs rename to Content.Client/Interaction/DragDropHelper.cs index d8286ee7054..ce5e08207c2 100644 --- a/Content.Client/DragDrop/DragDropHelper.cs +++ b/Content.Client/Interaction/DragDropHelper.cs @@ -1,7 +1,7 @@ using Robust.Client.Input; using Robust.Shared.Map; -namespace Content.Client.DragDrop; +namespace Content.Client.Interaction; /// /// Helper for implementing drag and drop interactions. diff --git a/Content.Client/DragDrop/DragDropSystem.cs b/Content.Client/Interaction/DragDropSystem.cs similarity index 97% rename from Content.Client/DragDrop/DragDropSystem.cs rename to Content.Client/Interaction/DragDropSystem.cs index a8c1a06686e..66571a9d27f 100644 --- a/Content.Client/DragDrop/DragDropSystem.cs +++ b/Content.Client/Interaction/DragDropSystem.cs @@ -1,3 +1,4 @@ +using System.Numerics; using Content.Client.CombatMode; using Content.Client.Gameplay; using Content.Client.Outline; @@ -7,7 +8,6 @@ using Content.Shared.Interaction; using Content.Shared.Interaction.Events; using Content.Shared.Popups; -using JetBrains.Annotations; using Robust.Client.GameObjects; using Robust.Client.Graphics; using Robust.Client.Input; @@ -20,15 +20,13 @@ using Robust.Shared.Player; using Robust.Shared.Prototypes; using Robust.Shared.Utility; -using System.Numerics; using DrawDepth = Content.Shared.DrawDepth.DrawDepth; -namespace Content.Client.DragDrop; +namespace Content.Client.Interaction; /// /// Handles clientside drag and drop logic /// -[UsedImplicitly] public sealed class DragDropSystem : SharedDragDropSystem { [Dependency] private readonly IStateManager _stateManager = default!; @@ -45,8 +43,6 @@ public sealed class DragDropSystem : SharedDragDropSystem [Dependency] private readonly EntityLookupSystem _lookup = default!; [Dependency] private readonly SharedPopupSystem _popup = default!; - private ISawmill _sawmill = default!; - // how often to recheck possible targets (prevents calling expensive // check logic each update) private const float TargetRecheckInterval = 0.25f; @@ -110,7 +106,6 @@ public sealed class DragDropSystem : SharedDragDropSystem public override void Initialize() { base.Initialize(); - _sawmill = Logger.GetSawmill("drag_drop"); UpdatesOutsidePrediction = true; UpdatesAfter.Add(typeof(SharedEyeSystem)); @@ -263,7 +258,7 @@ private void StartDrag() return; } - _sawmill.Warning($"Unable to display drag shadow for {ToPrettyString(_draggedEntity.Value)} because it has no sprite component."); + Log.Warning($"Unable to display drag shadow for {ToPrettyString(_draggedEntity.Value)} because it has no sprite component."); } private bool UpdateDrag(float frameTime) @@ -392,7 +387,7 @@ private bool OnUseMouseUp(in PointerInputCmdHandler.PointerInputCmdArgs args) } // tell the server about the drop attempt - RaiseNetworkEvent(new DragDropRequestEvent(GetNetEntity(_draggedEntity.Value), GetNetEntity(entity))); + RaisePredictiveEvent(new DragDropRequestEvent(GetNetEntity(_draggedEntity.Value), GetNetEntity(entity))); EndDrag(); return true; } diff --git a/Content.Client/Movement/Systems/ClimbSystem.cs b/Content.Client/Movement/Systems/ClimbSystem.cs deleted file mode 100644 index 003b478b30d..00000000000 --- a/Content.Client/Movement/Systems/ClimbSystem.cs +++ /dev/null @@ -1,33 +0,0 @@ -using Content.Client.Interactable; -using Content.Shared.Climbing; -using Content.Shared.DragDrop; - -namespace Content.Client.Movement.Systems; - -public sealed class ClimbSystem : SharedClimbSystem -{ - [Dependency] private readonly InteractionSystem _interactionSystem = default!; - - public override void Initialize() - { - base.Initialize(); - SubscribeLocalEvent(OnCanDragDropOn); - } - - protected override void OnCanDragDropOn(EntityUid uid, ClimbableComponent component, ref CanDropTargetEvent args) - { - base.OnCanDragDropOn(uid, component, ref args); - - if (!args.CanDrop) - return; - - var user = args.User; - var target = uid; - var dragged = args.Dragged; - bool Ignored(EntityUid entity) => entity == target || entity == user || entity == dragged; - - args.CanDrop = _interactionSystem.InRangeUnobstructed(user, target, component.Range, predicate: Ignored) - && _interactionSystem.InRangeUnobstructed(user, dragged, component.Range, predicate: Ignored); - args.Handled = true; - } -} diff --git a/Content.Client/UserInterface/Systems/Actions/ActionUIController.cs b/Content.Client/UserInterface/Systems/Actions/ActionUIController.cs index bb83e370fe4..b2ff36d05c3 100644 --- a/Content.Client/UserInterface/Systems/Actions/ActionUIController.cs +++ b/Content.Client/UserInterface/Systems/Actions/ActionUIController.cs @@ -3,9 +3,9 @@ using System.Runtime.InteropServices; using Content.Client.Actions; using Content.Client.Construction; -using Content.Client.DragDrop; using Content.Client.Gameplay; using Content.Client.Hands; +using Content.Client.Interaction; using Content.Client.Outline; using Content.Client.UserInterface.Controls; using Content.Client.UserInterface.Systems.Actions.Controls; diff --git a/Content.IntegrationTests/Tests/Climbing/ClimbingTest.cs b/Content.IntegrationTests/Tests/Climbing/ClimbingTest.cs index f6bcc6e1291..d8d3086520e 100644 --- a/Content.IntegrationTests/Tests/Climbing/ClimbingTest.cs +++ b/Content.IntegrationTests/Tests/Climbing/ClimbingTest.cs @@ -1,8 +1,8 @@ #nullable enable using Content.IntegrationTests.Tests.Interaction; -using Content.Server.Climbing; -using Content.Shared.Climbing; using Robust.Shared.Maths; +using ClimbingComponent = Content.Shared.Climbing.Components.ClimbingComponent; +using ClimbSystem = Content.Shared.Climbing.Systems.ClimbSystem; namespace Content.IntegrationTests.Tests.Climbing; diff --git a/Content.Server/Climbing/ClimbSystem.cs b/Content.Server/Climbing/ClimbSystem.cs deleted file mode 100644 index e9d25f361f2..00000000000 --- a/Content.Server/Climbing/ClimbSystem.cs +++ /dev/null @@ -1,476 +0,0 @@ -using System.Numerics; -using Content.Server.Body.Systems; -using Content.Server.Climbing.Components; -using Content.Server.Interaction; -using Content.Server.Popups; -using Content.Server.Stunnable; -using Content.Shared.ActionBlocker; -using Content.Shared.Body.Components; -using Content.Shared.Body.Part; -using Content.Shared.Buckle.Components; -using Content.Shared.Climbing; -using Content.Shared.Climbing.Events; -using Content.Shared.Damage; -using Content.Shared.DoAfter; -using Content.Shared.DragDrop; -using Content.Shared.GameTicking; -using Content.Shared.Hands.Components; -using Content.Shared.IdentityManagement; -using Content.Shared.Physics; -using Content.Shared.Popups; -using Content.Shared.Verbs; -using JetBrains.Annotations; -using Robust.Server.GameObjects; -using Robust.Shared.Physics; -using Robust.Shared.Physics.Collision.Shapes; -using Robust.Shared.Physics.Components; -using Robust.Shared.Physics.Dynamics; -using Robust.Shared.Physics.Events; -using Robust.Shared.Physics.Systems; -using Robust.Shared.Player; - -namespace Content.Server.Climbing; - -[UsedImplicitly] -public sealed class ClimbSystem : SharedClimbSystem -{ - [Dependency] private readonly ActionBlockerSystem _actionBlockerSystem = default!; - [Dependency] private readonly AudioSystem _audio = default!; - [Dependency] private readonly BodySystem _bodySystem = default!; - [Dependency] private readonly DamageableSystem _damageableSystem = default!; - [Dependency] private readonly SharedDoAfterSystem _doAfterSystem = default!; - [Dependency] private readonly FixtureSystem _fixtureSystem = default!; - [Dependency] private readonly PopupSystem _popupSystem = default!; - [Dependency] private readonly InteractionSystem _interactionSystem = default!; - [Dependency] private readonly StunSystem _stunSystem = default!; - [Dependency] private readonly SharedPhysicsSystem _physics = default!; - - private const string ClimbingFixtureName = "climb"; - private const int ClimbingCollisionGroup = (int) (CollisionGroup.TableLayer | CollisionGroup.LowImpassable); - - private readonly Dictionary> _fixtureRemoveQueue = new(); - - public override void Initialize() - { - base.Initialize(); - - SubscribeLocalEvent(Reset); - SubscribeLocalEvent>(AddClimbableVerb); - SubscribeLocalEvent(OnClimbableDragDrop); - - SubscribeLocalEvent(OnDoAfter); - SubscribeLocalEvent(OnClimbEndCollide); - SubscribeLocalEvent(OnBuckleChange); - - SubscribeLocalEvent(OnGlassClimbed); - } - - protected override void OnCanDragDropOn(EntityUid uid, ClimbableComponent component, ref CanDropTargetEvent args) - { - base.OnCanDragDropOn(uid, component, ref args); - - if (!args.CanDrop) - return; - - string reason; - var canVault = args.User == args.Dragged - ? CanVault(component, args.User, uid, out reason) - : CanVault(component, args.User, args.Dragged, uid, out reason); - - if (!canVault) - _popupSystem.PopupEntity(reason, args.User, args.User); - - args.CanDrop = canVault; - args.Handled = true; - } - - private void AddClimbableVerb(EntityUid uid, ClimbableComponent component, GetVerbsEvent args) - { - if (!args.CanAccess || !args.CanInteract || !_actionBlockerSystem.CanMove(args.User)) - return; - - if (!TryComp(args.User, out ClimbingComponent? climbingComponent) || climbingComponent.IsClimbing) - return; - - // TODO VERBS ICON add a climbing icon? - args.Verbs.Add(new AlternativeVerb - { - Act = () => TryClimb(args.User, args.User, args.Target, out _, component), - Text = Loc.GetString("comp-climbable-verb-climb") - }); - } - - private void OnClimbableDragDrop(EntityUid uid, ClimbableComponent component, ref DragDropTargetEvent args) - { - // definitely a better way to check if two entities are equal - // but don't have computer access and i have to do this without syntax - if (args.Handled || args.User != args.Dragged && !HasComp(args.User)) - return; - TryClimb(args.User, args.Dragged, uid, out _, component); - } - - public bool TryClimb(EntityUid user, - EntityUid entityToMove, - EntityUid climbable, - out DoAfterId? id, - ClimbableComponent? comp = null, - ClimbingComponent? climbing = null) - { - id = null; - - if (!Resolve(climbable, ref comp) || !Resolve(entityToMove, ref climbing)) - return false; - - // Note, IsClimbing does not mean a DoAfter is active, it means the target has already finished a DoAfter and - // is currently on top of something.. - if (climbing.IsClimbing) - return true; - - var args = new DoAfterArgs(EntityManager, user, comp.ClimbDelay, new ClimbDoAfterEvent(), entityToMove, target: climbable, used: entityToMove) - { - BreakOnTargetMove = true, - BreakOnUserMove = true, - BreakOnDamage = true - }; - - _audio.PlayPvs(comp.StartClimbSound, climbable); - _doAfterSystem.TryStartDoAfter(args, out id); - return true; - } - - private void OnDoAfter(EntityUid uid, ClimbingComponent component, ClimbDoAfterEvent args) - { - if (args.Handled || args.Cancelled || args.Args.Target == null || args.Args.Used == null) - return; - - Climb(uid, args.Args.User, args.Args.Used.Value, args.Args.Target.Value, climbing: component); - - args.Handled = true; - } - - private void Climb(EntityUid uid, EntityUid user, EntityUid instigator, EntityUid climbable, bool silent = false, ClimbingComponent? climbing = null, - PhysicsComponent? physics = null, FixturesComponent? fixtures = null, ClimbableComponent? comp = null) - { - if (!Resolve(uid, ref climbing, ref physics, ref fixtures, false)) - return; - - if (!Resolve(climbable, ref comp)) - return; - - if (!ReplaceFixtures(climbing, fixtures)) - return; - - climbing.IsClimbing = true; - Dirty(climbing); - - _audio.PlayPvs(comp.FinishClimbSound, climbable); - MoveEntityToward(uid, climbable, physics, climbing); - // we may potentially need additional logic since we're forcing a player onto a climbable - // there's also the cases where the user might collide with the person they are forcing onto the climbable that i haven't accounted for - - RaiseLocalEvent(uid, new StartClimbEvent(climbable), false); - RaiseLocalEvent(climbable, new ClimbedOnEvent(uid, user), false); - - if (silent) - return; - if (user == uid) - { - var othersMessage = Loc.GetString("comp-climbable-user-climbs-other", ("user", Identity.Entity(uid, EntityManager)), - ("climbable", climbable)); - uid.PopupMessageOtherClients(othersMessage); - - var selfMessage = Loc.GetString("comp-climbable-user-climbs", ("climbable", climbable)); - uid.PopupMessage(selfMessage); - } - else - { - var othersMessage = Loc.GetString("comp-climbable-user-climbs-force-other", ("user", Identity.Entity(user, EntityManager)), - ("moved-user", Identity.Entity(uid, EntityManager)), ("climbable", climbable)); - user.PopupMessageOtherClients(othersMessage); - - var selfMessage = Loc.GetString("comp-climbable-user-climbs-force", ("moved-user", Identity.Entity(uid, EntityManager)), - ("climbable", climbable)); - user.PopupMessage(selfMessage); - } - } - - /// - /// Replaces the current fixtures with non-climbing collidable versions so that climb end can be detected - /// - /// Returns whether adding the new fixtures was successful - private bool ReplaceFixtures(ClimbingComponent climbingComp, FixturesComponent fixturesComp) - { - var uid = climbingComp.Owner; - - // Swap fixtures - foreach (var (name, fixture) in fixturesComp.Fixtures) - { - if (climbingComp.DisabledFixtureMasks.ContainsKey(name) - || fixture.Hard == false - || (fixture.CollisionMask & ClimbingCollisionGroup) == 0) - continue; - - climbingComp.DisabledFixtureMasks.Add(name, fixture.CollisionMask & ClimbingCollisionGroup); - _physics.SetCollisionMask(uid, name, fixture, fixture.CollisionMask & ~ClimbingCollisionGroup, fixturesComp); - } - - if (!_fixtureSystem.TryCreateFixture( - uid, - new PhysShapeCircle(0.35f), - ClimbingFixtureName, - collisionLayer: (int) CollisionGroup.None, - collisionMask: ClimbingCollisionGroup, - hard: false, - manager: fixturesComp)) - { - return false; - } - - return true; - } - - private void OnClimbEndCollide(EntityUid uid, ClimbingComponent component, ref EndCollideEvent args) - { - if (args.OurFixtureId != ClimbingFixtureName - || !component.IsClimbing - || component.OwnerIsTransitioning) - return; - - foreach (var fixture in args.OurFixture.Contacts.Keys) - { - if (fixture == args.OtherFixture) - continue; - // If still colliding with a climbable, do not stop climbing - if (HasComp(args.OtherEntity)) - return; - } - - StopClimb(uid, component); - } - - private void StopClimb(EntityUid uid, ClimbingComponent? climbing = null, FixturesComponent? fixtures = null) - { - if (!Resolve(uid, ref climbing, ref fixtures, false)) - return; - - foreach (var (name, fixtureMask) in climbing.DisabledFixtureMasks) - { - if (!fixtures.Fixtures.TryGetValue(name, out var fixture)) - { - continue; - } - - _physics.SetCollisionMask(uid, name, fixture, fixture.CollisionMask | fixtureMask, fixtures); - } - climbing.DisabledFixtureMasks.Clear(); - - if (!_fixtureRemoveQueue.TryGetValue(uid, out var removeQueue)) - { - removeQueue = new Dictionary(); - _fixtureRemoveQueue.Add(uid, removeQueue); - } - - if (fixtures.Fixtures.TryGetValue(ClimbingFixtureName, out var climbingFixture)) - removeQueue.Add(ClimbingFixtureName, climbingFixture); - - climbing.IsClimbing = false; - climbing.OwnerIsTransitioning = false; - var ev = new EndClimbEvent(); - RaiseLocalEvent(uid, ref ev); - Dirty(climbing); - } - - /// - /// Checks if the user can vault the target - /// - /// The component of the entity that is being vaulted - /// The entity that wants to vault - /// The object that is being vaulted - /// The reason why it cant be dropped - /// - public bool CanVault(ClimbableComponent component, EntityUid user, EntityUid target, out string reason) - { - if (!_actionBlockerSystem.CanInteract(user, target)) - { - reason = Loc.GetString("comp-climbable-cant-interact"); - return false; - } - - if (!HasComp(user) - || !TryComp(user, out BodyComponent? body) - || !_bodySystem.BodyHasPartType(user, BodyPartType.Leg, body) - || !_bodySystem.BodyHasPartType(user, BodyPartType.Foot, body)) - { - reason = Loc.GetString("comp-climbable-cant-climb"); - return false; - } - - if (!_interactionSystem.InRangeUnobstructed(user, target, component.Range)) - { - reason = Loc.GetString("comp-climbable-cant-reach"); - return false; - } - - reason = string.Empty; - return true; - } - - /// - /// Checks if the user can vault the dragged entity onto the the target - /// - /// The climbable component of the object being vaulted onto - /// The user that wants to vault the entity - /// The entity that is being vaulted - /// The object that is being vaulted onto - /// The reason why it cant be dropped - /// - public bool CanVault(ClimbableComponent component, EntityUid user, EntityUid dragged, EntityUid target, - out string reason) - { - if (!_actionBlockerSystem.CanInteract(user, dragged) || !_actionBlockerSystem.CanInteract(user, target)) - { - reason = Loc.GetString("comp-climbable-cant-interact"); - return false; - } - - if (!HasComp(dragged)) - { - reason = Loc.GetString("comp-climbable-cant-climb"); - return false; - } - - bool Ignored(EntityUid entity) => entity == target || entity == user || entity == dragged; - - if (!_interactionSystem.InRangeUnobstructed(user, target, component.Range, predicate: Ignored) - || !_interactionSystem.InRangeUnobstructed(user, dragged, component.Range, predicate: Ignored)) - { - reason = Loc.GetString("comp-climbable-cant-reach"); - return false; - } - - reason = string.Empty; - return true; - } - - public void ForciblySetClimbing(EntityUid uid, EntityUid climbable, ClimbingComponent? component = null) - { - Climb(uid, uid, uid, climbable, true, component); - } - - private void OnBuckleChange(EntityUid uid, ClimbingComponent component, ref BuckleChangeEvent args) - { - if (!args.Buckling) - return; - StopClimb(uid, component); - } - - private void OnGlassClimbed(EntityUid uid, GlassTableComponent component, ClimbedOnEvent args) - { - if (TryComp(args.Climber, out var physics) && physics.Mass <= component.MassLimit) - return; - - _damageableSystem.TryChangeDamage(args.Climber, component.ClimberDamage, origin: args.Climber); - _damageableSystem.TryChangeDamage(uid, component.TableDamage, origin: args.Climber); - _stunSystem.TryParalyze(args.Climber, TimeSpan.FromSeconds(component.StunTime), true); - - // Not shown to the user, since they already get a 'you climb on the glass table' popup - _popupSystem.PopupEntity( - Loc.GetString("glass-table-shattered-others", ("table", uid), ("climber", Identity.Entity(args.Climber, EntityManager))), args.Climber, - Filter.PvsExcept(args.Climber), true); - } - - /// - /// Moves the entity toward the target climbed entity - /// - public void MoveEntityToward(EntityUid uid, EntityUid target, PhysicsComponent? physics = null, ClimbingComponent? climbing = null) - { - if (!Resolve(uid, ref physics, ref climbing, false)) - return; - - var from = Transform(uid).WorldPosition; - var to = Transform(target).WorldPosition; - var (x, y) = (to - from).Normalized(); - - if (MathF.Abs(x) < 0.6f) // user climbed mostly vertically so lets make it a clean straight line - to = new Vector2(from.X, to.Y); - else if (MathF.Abs(y) < 0.6f) // user climbed mostly horizontally so lets make it a clean straight line - to = new Vector2(to.X, from.Y); - - var velocity = (to - from).Length(); - - if (velocity <= 0.0f) - return; - - // Since there are bodies with different masses: - // mass * 10 seems enough to move entity - // instead of launching cats like rockets against the walls with constant impulse value. - _physics.ApplyLinearImpulse(uid, (to - from).Normalized() * velocity * physics.Mass * 10, body: physics); - _physics.SetBodyType(uid, BodyType.Dynamic, body: physics); - climbing.OwnerIsTransitioning = true; - _actionBlockerSystem.UpdateCanMove(uid); - - // Transition back to KinematicController after BufferTime - climbing.Owner.SpawnTimer((int) (ClimbingComponent.BufferTime * 1000), () => - { - if (climbing.Deleted) - return; - - _physics.SetBodyType(uid, BodyType.KinematicController); - climbing.OwnerIsTransitioning = false; - _actionBlockerSystem.UpdateCanMove(uid); - }); - } - - public override void Update(float frameTime) - { - foreach (var (uid, fixtures) in _fixtureRemoveQueue) - { - if (!TryComp(uid, out var physicsComp) - || !TryComp(uid, out var fixturesComp)) - { - continue; - } - - foreach (var fixture in fixtures) - { - _fixtureSystem.DestroyFixture(uid, fixture.Key, fixture.Value, body: physicsComp, manager: fixturesComp); - } - } - - _fixtureRemoveQueue.Clear(); - } - - private void Reset(RoundRestartCleanupEvent ev) - { - _fixtureRemoveQueue.Clear(); - } - -} - -/// -/// Raised on an entity when it is climbed on. -/// -public sealed class ClimbedOnEvent : EntityEventArgs -{ - public EntityUid Climber; - public EntityUid Instigator; - - public ClimbedOnEvent(EntityUid climber, EntityUid instigator) - { - Climber = climber; - Instigator = instigator; - } -} - -/// -/// Raised on an entity when it successfully climbs on something. -/// -public sealed class StartClimbEvent : EntityEventArgs -{ - public EntityUid Climbable; - - public StartClimbEvent(EntityUid climbable) - { - Climbable = climbable; - } -} diff --git a/Content.Server/Interaction/DragDropSystem.cs b/Content.Server/Interaction/DragDropSystem.cs new file mode 100644 index 00000000000..9a4c26e3f95 --- /dev/null +++ b/Content.Server/Interaction/DragDropSystem.cs @@ -0,0 +1,8 @@ +using Content.Shared.DragDrop; + +namespace Content.Server.Interaction; + +public sealed class DragDropSystem : SharedDragDropSystem +{ + +} diff --git a/Content.Server/Interaction/InteractionSystem.cs b/Content.Server/Interaction/InteractionSystem.cs index c39c086960d..a612b738400 100644 --- a/Content.Server/Interaction/InteractionSystem.cs +++ b/Content.Server/Interaction/InteractionSystem.cs @@ -32,8 +32,6 @@ public override void Initialize() { base.Initialize(); - SubscribeNetworkEvent(HandleDragDropRequestEvent); - SubscribeLocalEvent(HandleUserInterfaceRangeCheck); } @@ -58,45 +56,6 @@ public override bool CanAccessViaStorage(EntityUid user, EntityUid target) return _uiSystem.SessionHasOpenUi(container.Owner, StorageComponent.StorageUiKey.Key, actor.PlayerSession); } - #region Drag drop - - private void HandleDragDropRequestEvent(DragDropRequestEvent msg, EntitySessionEventArgs args) - { - var dragged = GetEntity(msg.Dragged); - var target = GetEntity(msg.Target); - - if (Deleted(dragged) || Deleted(target)) - return; - - var user = args.SenderSession.AttachedEntity; - - if (user == null || !_actionBlockerSystem.CanInteract(user.Value, target)) - return; - - // must be in range of both the target and the object they are drag / dropping - // Client also does this check but ya know we gotta validate it. - if (!InRangeUnobstructed(user.Value, dragged, popup: true) - || !InRangeUnobstructed(user.Value, target, popup: true)) - { - return; - } - - var dragArgs = new DragDropDraggedEvent(user.Value, target); - - // trigger dragdrops on the dropped entity - RaiseLocalEvent(dragged, ref dragArgs); - - if (dragArgs.Handled) - return; - - var dropArgs = new DragDropTargetEvent(user.Value, dragged); - - // trigger dragdrops on the target entity (what you are dropping onto) - RaiseLocalEvent(GetEntity(msg.Target), ref dropArgs); - } - - #endregion - private void HandleUserInterfaceRangeCheck(ref BoundUserInterfaceCheckRangeEvent ev) { if (ev.Player.AttachedEntity is not { } user) diff --git a/Content.Server/Medical/BiomassReclaimer/BiomassReclaimerSystem.cs b/Content.Server/Medical/BiomassReclaimer/BiomassReclaimerSystem.cs index 40637c5362b..45f8d2ed983 100644 --- a/Content.Server/Medical/BiomassReclaimer/BiomassReclaimerSystem.cs +++ b/Content.Server/Medical/BiomassReclaimer/BiomassReclaimerSystem.cs @@ -1,6 +1,5 @@ using System.Numerics; using Content.Server.Body.Components; -using Content.Server.Climbing; using Content.Server.Construction; using Content.Server.Fluids.EntitySystems; using Content.Server.Materials; @@ -9,6 +8,7 @@ using Content.Shared.Audio; using Content.Shared.CCVar; using Content.Shared.Chemistry.Components; +using Content.Shared.Climbing.Events; using Content.Shared.Construction.Components; using Content.Shared.Database; using Content.Shared.DoAfter; @@ -160,7 +160,7 @@ private void OnAfterInteractUsing(EntityUid uid, BiomassReclaimerComponent compo }); } - private void OnClimbedOn(EntityUid uid, BiomassReclaimerComponent component, ClimbedOnEvent args) + private void OnClimbedOn(EntityUid uid, BiomassReclaimerComponent component, ref ClimbedOnEvent args) { if (!CanGib(uid, args.Climber, component)) { diff --git a/Content.Server/Medical/CryoPodSystem.cs b/Content.Server/Medical/CryoPodSystem.cs index ddd29d26a2c..98f8e305b63 100644 --- a/Content.Server/Medical/CryoPodSystem.cs +++ b/Content.Server/Medical/CryoPodSystem.cs @@ -7,7 +7,6 @@ using Content.Server.Body.Systems; using Content.Server.Chemistry.Components.SolutionManager; using Content.Server.Chemistry.EntitySystems; -using Content.Server.Climbing; using Content.Server.Medical.Components; using Content.Server.NodeContainer; using Content.Server.NodeContainer.EntitySystems; @@ -32,6 +31,7 @@ using Robust.Server.GameObjects; using Robust.Shared.Timing; using Content.Server.Temperature.Components; +using Content.Shared.Climbing.Systems; namespace Content.Server.Medical; diff --git a/Content.Server/Medical/MedicalScannerSystem.cs b/Content.Server/Medical/MedicalScannerSystem.cs index 57ca815cb7b..d4694e8fb8d 100644 --- a/Content.Server/Medical/MedicalScannerSystem.cs +++ b/Content.Server/Medical/MedicalScannerSystem.cs @@ -1,4 +1,3 @@ -using Content.Server.Climbing; using Content.Server.Cloning; using Content.Server.Medical.Components; using Content.Shared.Destructible; @@ -13,6 +12,7 @@ using Content.Shared.DeviceLinking.Events; using Content.Server.Power.EntitySystems; using Content.Shared.Body.Components; +using Content.Shared.Climbing.Systems; using Content.Shared.Mobs.Components; using Content.Shared.Mobs.Systems; using Robust.Server.Containers; diff --git a/Content.Server/NPC/Pathfinding/PathfindingSystem.Grid.cs b/Content.Server/NPC/Pathfinding/PathfindingSystem.Grid.cs index 95d267f7d73..72d6606c910 100644 --- a/Content.Server/NPC/Pathfinding/PathfindingSystem.Grid.cs +++ b/Content.Server/NPC/Pathfinding/PathfindingSystem.Grid.cs @@ -18,6 +18,7 @@ using Robust.Shared.Physics.Events; using Robust.Shared.Timing; using Robust.Shared.Utility; +using ClimbableComponent = Content.Shared.Climbing.Components.ClimbableComponent; namespace Content.Server.NPC.Pathfinding; diff --git a/Content.Server/NPC/Systems/NPCSteeringSystem.Context.cs b/Content.Server/NPC/Systems/NPCSteeringSystem.Context.cs index 920db537dfe..6507f24edf6 100644 --- a/Content.Server/NPC/Systems/NPCSteeringSystem.Context.cs +++ b/Content.Server/NPC/Systems/NPCSteeringSystem.Context.cs @@ -10,6 +10,7 @@ using Content.Shared.Physics; using Robust.Shared.Map; using Robust.Shared.Physics.Components; +using ClimbingComponent = Content.Shared.Climbing.Components.ClimbingComponent; namespace Content.Server.NPC.Systems; diff --git a/Content.Server/NPC/Systems/NPCSteeringSystem.Obstacles.cs b/Content.Server/NPC/Systems/NPCSteeringSystem.Obstacles.cs index 87deec9ea9d..70d1e89bc4f 100644 --- a/Content.Server/NPC/Systems/NPCSteeringSystem.Obstacles.cs +++ b/Content.Server/NPC/Systems/NPCSteeringSystem.Obstacles.cs @@ -9,6 +9,8 @@ using Robust.Shared.Physics; using Robust.Shared.Physics.Components; using Robust.Shared.Utility; +using ClimbableComponent = Content.Shared.Climbing.Components.ClimbableComponent; +using ClimbingComponent = Content.Shared.Climbing.Components.ClimbingComponent; namespace Content.Server.NPC.Systems; @@ -132,7 +134,7 @@ private SteeringObstacleStatus TryHandleFlags(EntityUid uid, NPCSteeringComponen { return SteeringObstacleStatus.Completed; } - else if (climbing.OwnerIsTransitioning) + else if (climbing.NextTransition != null) { return SteeringObstacleStatus.Continuing; } diff --git a/Content.Server/NPC/Systems/NPCSteeringSystem.cs b/Content.Server/NPC/Systems/NPCSteeringSystem.cs index 0fa28f6af79..61b43df6f00 100644 --- a/Content.Server/NPC/Systems/NPCSteeringSystem.cs +++ b/Content.Server/NPC/Systems/NPCSteeringSystem.cs @@ -1,21 +1,19 @@ -using System.Linq; using System.Numerics; using System.Threading; using System.Threading.Tasks; using Content.Server.Administration.Managers; -using Content.Server.Climbing; using Content.Server.DoAfter; using Content.Server.Doors.Systems; using Content.Server.NPC.Components; using Content.Server.NPC.Events; using Content.Server.NPC.Pathfinding; using Content.Shared.CCVar; +using Content.Shared.Climbing.Systems; using Content.Shared.CombatMode; using Content.Shared.Interaction; using Content.Shared.Movement.Components; using Content.Shared.Movement.Systems; using Content.Shared.NPC; -using Content.Shared.NPC; using Content.Shared.NPC.Events; using Content.Shared.Physics; using Content.Shared.Weapons.Melee; @@ -28,7 +26,6 @@ using Robust.Shared.Player; using Robust.Shared.Players; using Robust.Shared.Random; -using Robust.Shared.Threading; using Robust.Shared.Timing; using Robust.Shared.Utility; using Content.Shared.Prying.Systems; diff --git a/Content.Shared/ActionBlocker/ActionBlockerSystem.cs b/Content.Shared/ActionBlocker/ActionBlockerSystem.cs index 93aa5dd9099..d2b12a4b292 100644 --- a/Content.Shared/ActionBlocker/ActionBlockerSystem.cs +++ b/Content.Shared/ActionBlocker/ActionBlockerSystem.cs @@ -47,7 +47,7 @@ public bool UpdateCanMove(EntityUid uid, InputMoverComponent? component = null) RaiseLocalEvent(uid, ev); if (component.CanMove == ev.Cancelled) - Dirty(component); + Dirty(uid, component); component.CanMove = !ev.Cancelled; return !ev.Cancelled; diff --git a/Content.Shared/Climbing/ClimbingComponent.cs b/Content.Shared/Climbing/ClimbingComponent.cs deleted file mode 100644 index cd443af6aad..00000000000 --- a/Content.Shared/Climbing/ClimbingComponent.cs +++ /dev/null @@ -1,27 +0,0 @@ -using Robust.Shared.GameStates; - -namespace Content.Shared.Climbing; - -[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] -public sealed partial class ClimbingComponent : Component -{ - /// - /// Whether the owner is climbing on a climbable entity. - /// - [ViewVariables, AutoNetworkedField] - public bool IsClimbing { get; set; } - - /// - /// Whether the owner is being moved onto the climbed entity. - /// - [ViewVariables, AutoNetworkedField] - public bool OwnerIsTransitioning { get; set; } - - /// - /// We'll launch the mob onto the table and give them at least this amount of time to be on it. - /// - public const float BufferTime = 0.3f; - - [ViewVariables] - public Dictionary DisabledFixtureMasks { get; } = new(); -} diff --git a/Content.Shared/Climbing/BonkableComponent.cs b/Content.Shared/Climbing/Components/BonkableComponent.cs similarity index 90% rename from Content.Shared/Climbing/BonkableComponent.cs rename to Content.Shared/Climbing/Components/BonkableComponent.cs index afffe1ff991..cc85e1c5626 100644 --- a/Content.Shared/Climbing/BonkableComponent.cs +++ b/Content.Shared/Climbing/Components/BonkableComponent.cs @@ -2,13 +2,13 @@ using Robust.Shared.Audio; using Robust.Shared.GameStates; -namespace Content.Shared.Climbing; +namespace Content.Shared.Climbing.Components; /// /// Makes entity do damage and stun entities with ClumsyComponent /// upon DragDrop or Climb interactions. /// -[RegisterComponent, NetworkedComponent, Access(typeof(BonkSystem))] +[RegisterComponent, NetworkedComponent, Access(typeof(Systems.BonkSystem))] public sealed partial class BonkableComponent : Component { /// diff --git a/Content.Shared/Climbing/ClimbableComponent.cs b/Content.Shared/Climbing/Components/ClimbableComponent.cs similarity index 84% rename from Content.Shared/Climbing/ClimbableComponent.cs rename to Content.Shared/Climbing/Components/ClimbableComponent.cs index 7ad289348ab..1a924e5c305 100644 --- a/Content.Shared/Climbing/ClimbableComponent.cs +++ b/Content.Shared/Climbing/Components/ClimbableComponent.cs @@ -1,11 +1,12 @@ -using Content.Shared.CCVar; -using Content.Shared.Damage; using Content.Shared.Interaction; using Robust.Shared.Audio; using Robust.Shared.GameStates; -namespace Content.Shared.Climbing +namespace Content.Shared.Climbing.Components { + /// + /// Indicates this entity can be vaulted on top of. + /// [RegisterComponent, NetworkedComponent] public sealed partial class ClimbableComponent : Component { @@ -18,7 +19,7 @@ public sealed partial class ClimbableComponent : Component /// The time it takes to climb onto the entity. /// [DataField("delay")] - public float ClimbDelay = 0.8f; + public float ClimbDelay = 1.5f; /// /// Sound to be played when a climb is started. diff --git a/Content.Shared/Climbing/Components/ClimbingComponent.cs b/Content.Shared/Climbing/Components/ClimbingComponent.cs new file mode 100644 index 00000000000..9738c0cee9b --- /dev/null +++ b/Content.Shared/Climbing/Components/ClimbingComponent.cs @@ -0,0 +1,36 @@ +using System.Numerics; +using Robust.Shared.GameStates; +using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom; + +namespace Content.Shared.Climbing.Components; + +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +public sealed partial class ClimbingComponent : Component +{ + /// + /// Whether the owner is climbing on a climbable entity. + /// + [AutoNetworkedField, DataField] + public bool IsClimbing; + + /// + /// Whether the owner is being moved onto the climbed entity. + /// + [AutoNetworkedField, DataField(customTypeSerializer:typeof(TimeOffsetSerializer))] + public TimeSpan? NextTransition; + + /// + /// Direction to move when transition. + /// + [AutoNetworkedField, DataField] + public Vector2 Direction; + + /// + /// How fast the entity is moved when climbing. + /// + [DataField] + public float TransitionRate = 5f; + + [AutoNetworkedField, DataField] + public Dictionary DisabledFixtureMasks = new(); +} diff --git a/Content.Server/Climbing/Components/GlassTableComponent.cs b/Content.Shared/Climbing/Components/GlassTableComponent.cs similarity index 90% rename from Content.Server/Climbing/Components/GlassTableComponent.cs rename to Content.Shared/Climbing/Components/GlassTableComponent.cs index 009fba91f44..d191793adf4 100644 --- a/Content.Server/Climbing/Components/GlassTableComponent.cs +++ b/Content.Shared/Climbing/Components/GlassTableComponent.cs @@ -1,13 +1,13 @@ using Content.Shared.Damage; -namespace Content.Server.Climbing.Components; +namespace Content.Shared.Climbing.Components; /// /// Glass tables shatter and stun you when climbed on. /// This is a really entity-specific behavior, so opted to make it /// not very generalized with regards to naming. /// -[RegisterComponent, Access(typeof(ClimbSystem))] +[RegisterComponent, Access(typeof(Systems.ClimbSystem))] public sealed partial class GlassTableComponent : Component { /// diff --git a/Content.Shared/Climbing/Events/ClimbedOnEvent.cs b/Content.Shared/Climbing/Events/ClimbedOnEvent.cs new file mode 100644 index 00000000000..8b0484d5d68 --- /dev/null +++ b/Content.Shared/Climbing/Events/ClimbedOnEvent.cs @@ -0,0 +1,7 @@ +namespace Content.Shared.Climbing.Events; + +/// +/// Raised on an entity when it is climbed on. +/// +[ByRefEvent] +public readonly record struct ClimbedOnEvent(EntityUid Climber, EntityUid Instigator); diff --git a/Content.Shared/Climbing/Events/EndClimbEvent.cs b/Content.Shared/Climbing/Events/EndClimbEvent.cs index 12eaac236d7..6963cabf301 100644 --- a/Content.Shared/Climbing/Events/EndClimbEvent.cs +++ b/Content.Shared/Climbing/Events/EndClimbEvent.cs @@ -4,7 +4,4 @@ namespace Content.Shared.Climbing.Events; /// Raised on an entity when it ends climbing. /// [ByRefEvent] -public readonly record struct EndClimbEvent -{ - -} +public readonly record struct EndClimbEvent; diff --git a/Content.Shared/Climbing/Events/StartClimbEvent.cs b/Content.Shared/Climbing/Events/StartClimbEvent.cs new file mode 100644 index 00000000000..3563a39bb82 --- /dev/null +++ b/Content.Shared/Climbing/Events/StartClimbEvent.cs @@ -0,0 +1,7 @@ +namespace Content.Shared.Climbing.Events; + +/// +/// Raised on an entity when it successfully climbs on something. +/// +[ByRefEvent] +public readonly record struct StartClimbEvent(EntityUid Climbable); diff --git a/Content.Shared/Climbing/SharedClimbSystem.cs b/Content.Shared/Climbing/SharedClimbSystem.cs deleted file mode 100644 index 12b84bbb7ea..00000000000 --- a/Content.Shared/Climbing/SharedClimbSystem.cs +++ /dev/null @@ -1,34 +0,0 @@ -using Content.Shared.DoAfter; -using Content.Shared.DragDrop; -using Content.Shared.Movement.Events; -using Robust.Shared.Serialization; - -namespace Content.Shared.Climbing; - -public abstract partial class SharedClimbSystem : EntitySystem -{ - public override void Initialize() - { - base.Initialize(); - SubscribeLocalEvent(HandleMoveAttempt); - } - - private static void HandleMoveAttempt(EntityUid uid, ClimbingComponent component, UpdateCanMoveEvent args) - { - if (component.LifeStage > ComponentLifeStage.Running) - return; - - if (component.OwnerIsTransitioning) - args.Cancel(); - } - - protected virtual void OnCanDragDropOn(EntityUid uid, ClimbableComponent component, ref CanDropTargetEvent args) - { - args.CanDrop = HasComp(args.Dragged); - } - - [Serializable, NetSerializable] - protected sealed partial class ClimbDoAfterEvent : SimpleDoAfterEvent - { - } -} diff --git a/Content.Shared/Climbing/BonkSystem.cs b/Content.Shared/Climbing/Systems/BonkSystem.cs similarity index 88% rename from Content.Shared/Climbing/BonkSystem.cs rename to Content.Shared/Climbing/Systems/BonkSystem.cs index eda392fa31f..6ded524b19d 100644 --- a/Content.Shared/Climbing/BonkSystem.cs +++ b/Content.Shared/Climbing/Systems/BonkSystem.cs @@ -1,17 +1,18 @@ -using Content.Shared.Interaction; -using Content.Shared.Stunnable; using Content.Shared.CCVar; +using Content.Shared.Climbing.Components; using Content.Shared.Damage; using Content.Shared.DoAfter; using Content.Shared.DragDrop; -using Robust.Shared.Configuration; -using Content.Shared.Popups; using Content.Shared.IdentityManagement; +using Content.Shared.Interaction; using Content.Shared.Interaction.Components; +using Content.Shared.Popups; +using Content.Shared.Stunnable; +using Robust.Shared.Configuration; using Robust.Shared.Player; using Robust.Shared.Serialization; -namespace Content.Shared.Climbing; +namespace Content.Shared.Climbing.Systems; public sealed partial class BonkSystem : EntitySystem { @@ -30,7 +31,7 @@ public override void Initialize() SubscribeLocalEvent(OnBonkDoAfter); } - private void OnBonkDoAfter(EntityUid uid, BonkableComponent component, BonkDoAfterEvent args) + private void OnBonkDoAfter(EntityUid uid, Components.BonkableComponent component, BonkDoAfterEvent args) { if (args.Handled || args.Cancelled || args.Args.Target == null) return; @@ -41,7 +42,7 @@ private void OnBonkDoAfter(EntityUid uid, BonkableComponent component, BonkDoAft } - public bool TryBonk(EntityUid user, EntityUid bonkableUid, BonkableComponent? bonkableComponent = null) + public bool TryBonk(EntityUid user, EntityUid bonkableUid, Components.BonkableComponent? bonkableComponent = null) { if (!Resolve(bonkableUid, ref bonkableComponent, false)) return false; @@ -71,7 +72,7 @@ public bool TryBonk(EntityUid user, EntityUid bonkableUid, BonkableComponent? bo } - private void OnDragDrop(EntityUid uid, BonkableComponent component, ref DragDropTargetEvent args) + private void OnDragDrop(EntityUid uid, Components.BonkableComponent component, ref DragDropTargetEvent args) { if (args.Handled || !HasComp(args.Dragged)) return; diff --git a/Content.Shared/Climbing/Systems/ClimbSystem.cs b/Content.Shared/Climbing/Systems/ClimbSystem.cs new file mode 100644 index 00000000000..4e25fa4ac0d --- /dev/null +++ b/Content.Shared/Climbing/Systems/ClimbSystem.cs @@ -0,0 +1,486 @@ +using System.Numerics; +using Content.Shared.ActionBlocker; +using Content.Shared.Body.Components; +using Content.Shared.Body.Part; +using Content.Shared.Body.Systems; +using Content.Shared.Buckle.Components; +using Content.Shared.Climbing.Components; +using Content.Shared.Climbing.Events; +using Content.Shared.Damage; +using Content.Shared.DoAfter; +using Content.Shared.DragDrop; +using Content.Shared.Hands.Components; +using Content.Shared.IdentityManagement; +using Content.Shared.Interaction; +using Content.Shared.Movement.Events; +using Content.Shared.Movement.Systems; +using Content.Shared.Physics; +using Content.Shared.Popups; +using Content.Shared.Stunnable; +using Content.Shared.Verbs; +using Robust.Shared.Physics; +using Robust.Shared.Physics.Collision.Shapes; +using Robust.Shared.Physics.Components; +using Robust.Shared.Physics.Controllers; +using Robust.Shared.Physics.Events; +using Robust.Shared.Physics.Systems; +using Robust.Shared.Player; +using Robust.Shared.Serialization; +using Robust.Shared.Timing; + +namespace Content.Shared.Climbing.Systems; + +public sealed partial class ClimbSystem : VirtualController +{ + [Dependency] private readonly IGameTiming _timing = default!; + [Dependency] private readonly ActionBlockerSystem _actionBlockerSystem = default!; + [Dependency] private readonly DamageableSystem _damageableSystem = default!; + [Dependency] private readonly FixtureSystem _fixtureSystem = default!; + [Dependency] private readonly SharedAudioSystem _audio = default!; + [Dependency] private readonly SharedBodySystem _bodySystem = default!; + [Dependency] private readonly SharedDoAfterSystem _doAfterSystem = default!; + [Dependency] private readonly SharedInteractionSystem _interactionSystem = default!; + [Dependency] private readonly SharedPopupSystem _popupSystem = default!; + [Dependency] private readonly SharedPhysicsSystem _physics = default!; + [Dependency] private readonly SharedStunSystem _stunSystem = default!; + [Dependency] private readonly SharedTransformSystem _xformSystem = default!; + + private const string ClimbingFixtureName = "climb"; + private const int ClimbingCollisionGroup = (int) (CollisionGroup.TableLayer | CollisionGroup.LowImpassable); + + private EntityQuery _fixturesQuery; + private EntityQuery _xformQuery; + + public override void Initialize() + { + base.Initialize(); + + _fixturesQuery = GetEntityQuery(); + _xformQuery = GetEntityQuery(); + + SubscribeLocalEvent(OnMoveAttempt); + SubscribeLocalEvent(OnParentChange); + SubscribeLocalEvent(OnDoAfter); + SubscribeLocalEvent(OnClimbEndCollide); + SubscribeLocalEvent(OnBuckleChange); + SubscribeLocalEvent(OnClimbableUnpaused); + + SubscribeLocalEvent(OnCanDragDropOn); + SubscribeLocalEvent>(AddClimbableVerb); + SubscribeLocalEvent(OnClimbableDragDrop); + + SubscribeLocalEvent(OnGlassClimbed); + } + + private void OnClimbableUnpaused(EntityUid uid, ClimbingComponent component, ref EntityUnpausedEvent args) + { + if (component.NextTransition == null) + return; + + component.NextTransition = component.NextTransition.Value + args.PausedTime; + Dirty(uid, component); + } + + public override void UpdateBeforeSolve(bool prediction, float frameTime) + { + base.UpdateBeforeSolve(prediction, frameTime); + + var query = EntityQueryEnumerator(); + var curTime = _timing.CurTime; + + // Move anything still climb in the specified direction. + while (query.MoveNext(out var uid, out var comp)) + { + if (comp.NextTransition == null) + continue; + + if (comp.NextTransition < curTime) + { + FinishTransition(uid, comp); + continue; + } + + var xform = _xformQuery.GetComponent(uid); + _xformSystem.SetLocalPositionNoLerp(uid, xform.LocalPosition + comp.Direction * frameTime, xform); + } + } + + private void FinishTransition(EntityUid uid, ClimbingComponent comp) + { + // TODO: Validate climb here + comp.NextTransition = null; + _actionBlockerSystem.UpdateCanMove(uid); + Dirty(uid, comp); + + // Stop if necessary. + if (!_fixturesQuery.TryGetComponent(uid, out var fixtures) || + !IsClimbing(uid, fixtures)) + { + StopClimb(uid, comp); + return; + } + } + + /// + /// Returns true if entity currently has a valid vault. + /// + private bool IsClimbing(EntityUid uid, FixturesComponent? fixturesComp = null) + { + if (!_fixturesQuery.Resolve(uid, ref fixturesComp) || !fixturesComp.Fixtures.TryGetValue(ClimbingFixtureName, out var climbFixture)) + return false; + + foreach (var contact in climbFixture.Contacts.Values) + { + var other = uid == contact.EntityA ? contact.EntityB : contact.EntityA; + + if (HasComp(other)) + { + return true; + } + } + + return false; + } + + private void OnMoveAttempt(EntityUid uid, ClimbingComponent component, UpdateCanMoveEvent args) + { + // Can't move when transition. + if (component.NextTransition != null) + args.Cancel(); + } + + private void OnParentChange(EntityUid uid, ClimbingComponent component, ref EntParentChangedMessage args) + { + if (component.NextTransition != null) + { + StopClimb(uid, component); + } + } + + private void OnCanDragDropOn(EntityUid uid, ClimbableComponent component, ref CanDropTargetEvent args) + { + if (args.Handled) + return; + + var canVault = args.User == args.Dragged + ? CanVault(component, args.User, uid, out _) + : CanVault(component, args.User, args.Dragged, uid, out _); + + args.CanDrop = canVault; + args.Handled = true; + } + + private void AddClimbableVerb(EntityUid uid, ClimbableComponent component, GetVerbsEvent args) + { + if (!args.CanAccess || !args.CanInteract || !_actionBlockerSystem.CanMove(args.User)) + return; + + if (!TryComp(args.User, out ClimbingComponent? climbingComponent) || climbingComponent.IsClimbing) + return; + + // TODO VERBS ICON add a climbing icon? + args.Verbs.Add(new AlternativeVerb + { + Act = () => TryClimb(args.User, args.User, args.Target, out _, component), + Text = Loc.GetString("comp-climbable-verb-climb") + }); + } + + private void OnClimbableDragDrop(EntityUid uid, ClimbableComponent component, ref DragDropTargetEvent args) + { + // definitely a better way to check if two entities are equal + // but don't have computer access and i have to do this without syntax + if (args.Handled || args.User != args.Dragged && !HasComp(args.User)) + return; + + TryClimb(args.User, args.Dragged, uid, out _, component); + } + + public bool TryClimb( + EntityUid user, + EntityUid entityToMove, + EntityUid climbable, + out DoAfterId? id, + ClimbableComponent? comp = null, + ClimbingComponent? climbing = null) + { + id = null; + + if (!Resolve(climbable, ref comp) || !Resolve(entityToMove, ref climbing)) + return false; + + // Note, IsClimbing does not mean a DoAfter is active, it means the target has already finished a DoAfter and + // is currently on top of something.. + if (climbing.IsClimbing) + return true; + + var args = new DoAfterArgs(EntityManager, user, comp.ClimbDelay, new ClimbDoAfterEvent(), + entityToMove, + target: climbable, + used: entityToMove) + { + BreakOnTargetMove = true, + BreakOnUserMove = true, + BreakOnDamage = true + }; + + _audio.PlayPredicted(comp.StartClimbSound, climbable, user); + return _doAfterSystem.TryStartDoAfter(args, out id); + } + + private void OnDoAfter(EntityUid uid, ClimbingComponent component, ClimbDoAfterEvent args) + { + if (args.Handled || args.Cancelled || args.Args.Target == null || args.Args.Used == null) + return; + + Climb(uid, args.Args.User, args.Args.Target.Value, climbing: component); + args.Handled = true; + } + + private void Climb(EntityUid uid, EntityUid user, EntityUid climbable, bool silent = false, ClimbingComponent? climbing = null, + PhysicsComponent? physics = null, FixturesComponent? fixtures = null, ClimbableComponent? comp = null) + { + if (!Resolve(uid, ref climbing, ref physics, ref fixtures, false)) + return; + + if (!Resolve(climbable, ref comp)) + return; + + if (!ReplaceFixtures(uid, climbing, fixtures)) + return; + + var xform = _xformQuery.GetComponent(uid); + var (worldPos, worldRot) = _xformSystem.GetWorldPositionRotation(xform); + var worldDirection = _xformSystem.GetWorldPosition(climbable) - worldPos; + var distance = worldDirection.Length(); + var parentRot = (worldRot - xform.LocalRotation); + // Need direction relative to climber's parent. + var localDirection = (-parentRot).RotateVec(worldDirection); + + climbing.IsClimbing = true; + var climbDuration = TimeSpan.FromSeconds(distance / climbing.TransitionRate); + climbing.NextTransition = _timing.CurTime + climbDuration; + + climbing.Direction = localDirection.Normalized() * climbing.TransitionRate; + Dirty(uid, climbing); + + _audio.PlayPredicted(comp.FinishClimbSound, climbable, user); + _actionBlockerSystem.UpdateCanMove(uid); + + var startEv = new StartClimbEvent(climbable); + var climbedEv = new ClimbedOnEvent(uid, user); + RaiseLocalEvent(uid, ref startEv); + RaiseLocalEvent(climbable, ref climbedEv); + + if (silent) + return; + + string selfMessage; + string othersMessage; + + if (user == uid) + { + othersMessage = Loc.GetString("comp-climbable-user-climbs-other", + ("user", Identity.Entity(uid, EntityManager)), + ("climbable", climbable)); + + selfMessage = Loc.GetString("comp-climbable-user-climbs", ("climbable", climbable)); + } + else + { + othersMessage = Loc.GetString("comp-climbable-user-climbs-force-other", + ("user", Identity.Entity(user, EntityManager)), + ("moved-user", Identity.Entity(uid, EntityManager)), ("climbable", climbable)); + + selfMessage = Loc.GetString("comp-climbable-user-climbs-force", ("moved-user", Identity.Entity(uid, EntityManager)), + ("climbable", climbable)); + } + + _popupSystem.PopupEntity(othersMessage, uid, Filter.PvsExcept(user, entityManager: EntityManager), true); + _popupSystem.PopupClient(selfMessage, uid, user); + } + + /// + /// Replaces the current fixtures with non-climbing collidable versions so that climb end can be detected + /// + /// Returns whether adding the new fixtures was successful + private bool ReplaceFixtures(EntityUid uid, ClimbingComponent climbingComp, FixturesComponent fixturesComp) + { + // Swap fixtures + foreach (var (name, fixture) in fixturesComp.Fixtures) + { + if (climbingComp.DisabledFixtureMasks.ContainsKey(name) + || fixture.Hard == false + || (fixture.CollisionMask & ClimbingCollisionGroup) == 0) + { + continue; + } + + climbingComp.DisabledFixtureMasks.Add(name, fixture.CollisionMask & ClimbingCollisionGroup); + _physics.SetCollisionMask(uid, name, fixture, fixture.CollisionMask & ~ClimbingCollisionGroup, fixturesComp); + } + + if (!_fixtureSystem.TryCreateFixture( + uid, + new PhysShapeCircle(0.35f), + ClimbingFixtureName, + collisionLayer: (int) CollisionGroup.None, + collisionMask: ClimbingCollisionGroup, + hard: false, + manager: fixturesComp)) + { + return false; + } + + return true; + } + + private void OnClimbEndCollide(EntityUid uid, ClimbingComponent component, ref EndCollideEvent args) + { + if (args.OurFixtureId != ClimbingFixtureName + || !component.IsClimbing + || component.NextTransition != null) + { + return; + } + + foreach (var fixture in args.OurFixture.Contacts.Keys) + { + if (fixture == args.OtherFixture) + continue; + + // If still colliding with a climbable, do not stop climbing + if (HasComp(args.OtherEntity)) + return; + } + + StopClimb(uid, component); + } + + private void StopClimb(EntityUid uid, ClimbingComponent? climbing = null, FixturesComponent? fixtures = null) + { + if (!Resolve(uid, ref climbing, ref fixtures, false)) + return; + + foreach (var (name, fixtureMask) in climbing.DisabledFixtureMasks) + { + if (!fixtures.Fixtures.TryGetValue(name, out var fixture)) + { + continue; + } + + _physics.SetCollisionMask(uid, name, fixture, fixture.CollisionMask | fixtureMask, fixtures); + } + + climbing.DisabledFixtureMasks.Clear(); + _fixtureSystem.DestroyFixture(uid, ClimbingFixtureName, manager: fixtures); + climbing.IsClimbing = false; + climbing.NextTransition = null; + var ev = new EndClimbEvent(); + RaiseLocalEvent(uid, ref ev); + Dirty(uid, climbing); + } + + /// + /// Checks if the user can vault the target + /// + /// The component of the entity that is being vaulted + /// The entity that wants to vault + /// The object that is being vaulted + /// The reason why it cant be dropped + public bool CanVault(ClimbableComponent component, EntityUid user, EntityUid target, out string reason) + { + if (!_actionBlockerSystem.CanInteract(user, target)) + { + reason = Loc.GetString("comp-climbable-cant-interact"); + return false; + } + + if (!HasComp(user) + || !TryComp(user, out BodyComponent? body) + || !_bodySystem.BodyHasPartType(user, BodyPartType.Leg, body) + || !_bodySystem.BodyHasPartType(user, BodyPartType.Foot, body)) + { + reason = Loc.GetString("comp-climbable-cant-climb"); + return false; + } + + if (!_interactionSystem.InRangeUnobstructed(user, target, component.Range)) + { + reason = Loc.GetString("comp-climbable-cant-reach"); + return false; + } + + reason = string.Empty; + return true; + } + + /// + /// Checks if the user can vault the dragged entity onto the the target + /// + /// The climbable component of the object being vaulted onto + /// The user that wants to vault the entity + /// The entity that is being vaulted + /// The object that is being vaulted onto + /// The reason why it cant be dropped + /// + public bool CanVault(ClimbableComponent component, EntityUid user, EntityUid dragged, EntityUid target, + out string reason) + { + if (!_actionBlockerSystem.CanInteract(user, dragged) || !_actionBlockerSystem.CanInteract(user, target)) + { + reason = Loc.GetString("comp-climbable-cant-interact"); + return false; + } + + if (!HasComp(dragged)) + { + reason = Loc.GetString("comp-climbable-cant-climb"); + return false; + } + + bool Ignored(EntityUid entity) => entity == target || entity == user || entity == dragged; + + if (!_interactionSystem.InRangeUnobstructed(user, target, component.Range, predicate: Ignored) + || !_interactionSystem.InRangeUnobstructed(user, dragged, component.Range, predicate: Ignored)) + { + reason = Loc.GetString("comp-climbable-cant-reach"); + return false; + } + + reason = string.Empty; + return true; + } + + public void ForciblySetClimbing(EntityUid uid, EntityUid climbable, ClimbingComponent? component = null) + { + Climb(uid, uid, climbable, true, component); + } + + private void OnBuckleChange(EntityUid uid, ClimbingComponent component, ref BuckleChangeEvent args) + { + if (!args.Buckling) + return; + StopClimb(uid, component); + } + + private void OnGlassClimbed(EntityUid uid, GlassTableComponent component, ref ClimbedOnEvent args) + { + if (TryComp(args.Climber, out var physics) && physics.Mass <= component.MassLimit) + return; + + _damageableSystem.TryChangeDamage(args.Climber, component.ClimberDamage, origin: args.Climber); + _damageableSystem.TryChangeDamage(uid, component.TableDamage, origin: args.Climber); + _stunSystem.TryParalyze(args.Climber, TimeSpan.FromSeconds(component.StunTime), true); + + // Not shown to the user, since they already get a 'you climb on the glass table' popup + _popupSystem.PopupEntity( + Loc.GetString("glass-table-shattered-others", ("table", uid), ("climber", Identity.Entity(args.Climber, EntityManager))), args.Climber, + Filter.PvsExcept(args.Climber), true); + } + + [Serializable, NetSerializable] + private sealed partial class ClimbDoAfterEvent : SimpleDoAfterEvent + { + } +} diff --git a/Content.Shared/DoAfter/SharedDoAfterSystem.cs b/Content.Shared/DoAfter/SharedDoAfterSystem.cs index 691d9a47582..382ecb5a9a5 100644 --- a/Content.Shared/DoAfter/SharedDoAfterSystem.cs +++ b/Content.Shared/DoAfter/SharedDoAfterSystem.cs @@ -43,7 +43,7 @@ private void OnUnpaused(EntityUid uid, DoAfterComponent component, ref EntityUnp doAfter.CancelledTime = doAfter.CancelledTime.Value + args.PausedTime; } - Dirty(component); + Dirty(uid, component); } private void OnStateChanged(EntityUid uid, DoAfterComponent component, MobStateChangedEvent args) @@ -55,7 +55,7 @@ private void OnStateChanged(EntityUid uid, DoAfterComponent component, MobStateC { InternalCancel(doAfter, component); } - Dirty(component); + Dirty(uid, component); } /// @@ -63,10 +63,12 @@ private void OnStateChanged(EntityUid uid, DoAfterComponent component, MobStateC /// private void OnDamage(EntityUid uid, DoAfterComponent component, DamageChangedEvent args) { - if (!args.InterruptsDoAfters || !args.DamageIncreased || args.DamageDelta == null) + // If we're applying state then let the server state handle the do_after prediction. + // This is to avoid scenarios where a do_after is erroneously cancelled on the final tick. + if (!args.InterruptsDoAfters || !args.DamageIncreased || args.DamageDelta == null || GameTiming.ApplyingState) return; - var delta = args.DamageDelta?.Total; + var delta = args.DamageDelta.GetTotal(); var dirty = false; foreach (var doAfter in component.DoAfters.Values) @@ -79,7 +81,7 @@ private void OnDamage(EntityUid uid, DoAfterComponent component, DamageChangedEv } if (dirty) - Dirty(component); + Dirty(uid, component); } private void RaiseDoAfterEvents(DoAfter doAfter, DoAfterComponent component) @@ -254,7 +256,7 @@ public bool TryStartDoAfter(DoAfterArgs args, [NotNullWhen(true)] out DoAfterId? comp.DoAfters.Add(doAfter.Index, doAfter); EnsureComp(args.User); - Dirty(comp); + Dirty(args.User, comp); args.Event.DoAfter = doAfter; return true; } diff --git a/Content.Shared/DragDrop/SharedDragDropSystem.cs b/Content.Shared/DragDrop/SharedDragDropSystem.cs index 7f1f6c23f73..24c79015d82 100644 --- a/Content.Shared/DragDrop/SharedDragDropSystem.cs +++ b/Content.Shared/DragDrop/SharedDragDropSystem.cs @@ -1,6 +1,51 @@ -namespace Content.Shared.DragDrop; +using Content.Shared.ActionBlocker; +using Content.Shared.Interaction; + +namespace Content.Shared.DragDrop; public abstract class SharedDragDropSystem : EntitySystem { + [Dependency] private readonly ActionBlockerSystem _actionBlockerSystem = default!; + [Dependency] private readonly SharedInteractionSystem _interaction = default!; + + public override void Initialize() + { + base.Initialize(); + SubscribeAllEvent(OnDragDropRequestEvent); + } + + private void OnDragDropRequestEvent(DragDropRequestEvent msg, EntitySessionEventArgs args) + { + var dragged = GetEntity(msg.Dragged); + var target = GetEntity(msg.Target); + + if (Deleted(dragged) || Deleted(target)) + return; + + var user = args.SenderSession.AttachedEntity; + + if (user == null || !_actionBlockerSystem.CanInteract(user.Value, target)) + return; + + // must be in range of both the target and the object they are drag / dropping + // Client also does this check but ya know we gotta validate it. + if (!_interaction.InRangeUnobstructed(user.Value, dragged, popup: true) + || !_interaction.InRangeUnobstructed(user.Value, target, popup: true)) + { + return; + } + + var dragArgs = new DragDropDraggedEvent(user.Value, target); + + // trigger dragdrops on the dropped entity + RaiseLocalEvent(dragged, ref dragArgs); + + if (dragArgs.Handled) + return; + + var dropArgs = new DragDropTargetEvent(user.Value, dragged); + // trigger dragdrops on the target entity (what you are dropping onto) + RaiseLocalEvent(GetEntity(msg.Target), ref dropArgs); + } } diff --git a/Content.Shared/Interaction/SharedInteractionSystem.cs b/Content.Shared/Interaction/SharedInteractionSystem.cs index d79a892c711..4a9a43ca2c2 100644 --- a/Content.Shared/Interaction/SharedInteractionSystem.cs +++ b/Content.Shared/Interaction/SharedInteractionSystem.cs @@ -6,6 +6,7 @@ using Content.Shared.Administration.Managers; using Content.Shared.CombatMode; using Content.Shared.Database; +using Content.Shared.DragDrop; using Content.Shared.Hands; using Content.Shared.Hands.Components; using Content.Shared.Input; From 969fd334dc9afcc79ba7f64d9f382047d950b035 Mon Sep 17 00:00:00 2001 From: PJBot Date: Tue, 10 Oct 2023 19:42:16 -0400 Subject: [PATCH 062/127] Automatic changelog update --- Resources/Changelog/Changelog.yml | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 811836b71bc..d0a8f897c5d 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,9 +1,4 @@ Entries: -- author: PJB3005 - changes: - - {message: Better nuke sprite from /vg/., type: Tweak} - id: 4487 - time: '2023-08-08T21:55:41.0000000+00:00' - author: Nairodian changes: - {message: Changed random maintenance loot spawns to be more diverse., type: Tweak} @@ -2955,3 +2950,10 @@ Entries: type: Fix} id: 4986 time: '2023-10-10T21:33:18.0000000+00:00' +- author: metalgearsloth + changes: + - {message: Vaulting tables is now predicted., type: Fix} + - {message: Fix buckle sound not playing., type: Fix} + - {message: Buckling is now predicted., type: Fix} + id: 4987 + time: '2023-10-10T23:41:12.0000000+00:00' From 088832a29582f634cbacc049c853acad1ea2e775 Mon Sep 17 00:00:00 2001 From: Leon Friedrich <60421075+ElectroJr@users.noreply.github.com> Date: Wed, 11 Oct 2023 13:27:14 +1100 Subject: [PATCH 063/127] Update engine to v166.0.0 (#20899) --- RobustToolbox | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RobustToolbox b/RobustToolbox index a8ddd837c84..7095a58685f 160000 --- a/RobustToolbox +++ b/RobustToolbox @@ -1 +1 @@ -Subproject commit a8ddd837c847f7cd8e71ae4926418a992b6ff4a3 +Subproject commit 7095a58685f60707b38edfc4689b658a5bd21a92 From 6db534ef86765e12b56ac0880158d3d0a0ba226b Mon Sep 17 00:00:00 2001 From: deltanedas <39013340+deltanedas@users.noreply.github.com> Date: Wed, 11 Oct 2023 03:55:53 +0100 Subject: [PATCH 064/127] uncloak ninja after attacking (#20892) * raise MeleeAttackEvent on the user after swinging * add disable bool to RevealNinja * uncloak ninja after attacking --------- Co-authored-by: deltanedas <@deltanedas:kde.org> --- .../Ninja/Systems/SharedNinjaSuitSystem.cs | 5 ++++- .../Ninja/Systems/SharedSpaceNinjaSystem.cs | 15 ++++++++++++++- .../Weapons/Melee/Events/MeleeAttackEvent.cs | 7 +++++++ .../Weapons/Melee/SharedMeleeWeaponSystem.cs | 3 +++ 4 files changed, 28 insertions(+), 2 deletions(-) create mode 100644 Content.Shared/Weapons/Melee/Events/MeleeAttackEvent.cs diff --git a/Content.Shared/Ninja/Systems/SharedNinjaSuitSystem.cs b/Content.Shared/Ninja/Systems/SharedNinjaSuitSystem.cs index 6bcd3432a91..473e29cc943 100644 --- a/Content.Shared/Ninja/Systems/SharedNinjaSuitSystem.cs +++ b/Content.Shared/Ninja/Systems/SharedNinjaSuitSystem.cs @@ -96,7 +96,7 @@ protected virtual void NinjaEquippedSuit(EntityUid uid, NinjaSuitComponent comp, /// /// Force uncloaks the user and disables suit abilities. /// - public void RevealNinja(EntityUid uid, EntityUid user, NinjaSuitComponent? comp = null, StealthClothingComponent? stealthClothing = null) + public void RevealNinja(EntityUid uid, EntityUid user, bool disable = true, NinjaSuitComponent? comp = null, StealthClothingComponent? stealthClothing = null) { if (!Resolve(uid, ref comp, ref stealthClothing)) return; @@ -104,6 +104,9 @@ public void RevealNinja(EntityUid uid, EntityUid user, NinjaSuitComponent? comp if (!StealthClothing.SetEnabled(uid, user, false, stealthClothing)) return; + if (!disable) + return; + // previously cloaked, disable abilities for a short time _audio.PlayPredicted(comp.RevealSound, uid, user); // all abilities check for a usedelay on the ninja diff --git a/Content.Shared/Ninja/Systems/SharedSpaceNinjaSystem.cs b/Content.Shared/Ninja/Systems/SharedSpaceNinjaSystem.cs index fbcb4efe484..522f29fe420 100644 --- a/Content.Shared/Ninja/Systems/SharedSpaceNinjaSystem.cs +++ b/Content.Shared/Ninja/Systems/SharedSpaceNinjaSystem.cs @@ -19,6 +19,7 @@ public override void Initialize() base.Initialize(); SubscribeLocalEvent(OnNinjaAttacked); + SubscribeLocalEvent(OnNinjaAttack); SubscribeLocalEvent(OnShotAttempted); } @@ -74,7 +75,19 @@ private void OnNinjaAttacked(EntityUid uid, SpaceNinjaComponent comp, AttackedEv { if (comp.Suit != null && TryComp(comp.Suit, out var stealthClothing) && stealthClothing.Enabled) { - Suit.RevealNinja(comp.Suit.Value, uid, null, stealthClothing); + Suit.RevealNinja(comp.Suit.Value, uid, true, null, stealthClothing); + } + } + + /// + /// Handle revealing ninja if cloaked when attacking. + /// Only reveals, there is no cooldown. + /// + private void OnNinjaAttack(EntityUid uid, SpaceNinjaComponent comp, ref MeleeAttackEvent args) + { + if (comp.Suit != null && TryComp(comp.Suit, out var stealthClothing) && stealthClothing.Enabled) + { + Suit.RevealNinja(comp.Suit.Value, uid, false, null, stealthClothing); } } diff --git a/Content.Shared/Weapons/Melee/Events/MeleeAttackEvent.cs b/Content.Shared/Weapons/Melee/Events/MeleeAttackEvent.cs new file mode 100644 index 00000000000..9530b0e6552 --- /dev/null +++ b/Content.Shared/Weapons/Melee/Events/MeleeAttackEvent.cs @@ -0,0 +1,7 @@ +namespace Content.Shared.Weapons.Melee.Events; + +/// +/// Event raised on the user after attacking with a melee weapon, regardless of whether it hit anything. +/// +[ByRefEvent] +public record struct MeleeAttackEvent(EntityUid Weapon); diff --git a/Content.Shared/Weapons/Melee/SharedMeleeWeaponSystem.cs b/Content.Shared/Weapons/Melee/SharedMeleeWeaponSystem.cs index ebe1a21e679..4259706ba86 100644 --- a/Content.Shared/Weapons/Melee/SharedMeleeWeaponSystem.cs +++ b/Content.Shared/Weapons/Melee/SharedMeleeWeaponSystem.cs @@ -426,6 +426,9 @@ private bool AttemptAttack(EntityUid user, EntityUid weaponUid, MeleeWeaponCompo DoLungeAnimation(user, weapon.Angle, GetCoordinates(attack.Coordinates).ToMap(EntityManager, TransformSystem), weapon.Range, animation); } + var attackEv = new MeleeAttackEvent(weaponUid); + RaiseLocalEvent(user, ref attackEv); + weapon.Attacking = true; return true; } From ef233cf0fecf5c618d6b91acfeee03eb119ad501 Mon Sep 17 00:00:00 2001 From: PJBot Date: Tue, 10 Oct 2023 22:56:57 -0400 Subject: [PATCH 065/127] Automatic changelog update --- Resources/Changelog/Changelog.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index d0a8f897c5d..6ab83496c3f 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,9 +1,4 @@ Entries: -- author: Nairodian - changes: - - {message: Changed random maintenance loot spawns to be more diverse., type: Tweak} - id: 4488 - time: '2023-08-09T00:47:35.0000000+00:00' - author: Whisper changes: - {message: Temporarily disable the Wheelchair Bound trait until its vehicle code @@ -2957,3 +2952,8 @@ Entries: - {message: Buckling is now predicted., type: Fix} id: 4987 time: '2023-10-10T23:41:12.0000000+00:00' +- author: deltanedas + changes: + - {message: Ninja uncloak after attacking with melee weapons., type: Tweak} + id: 4988 + time: '2023-10-11T02:55:54.0000000+00:00' From 9bcf67753a62cfd36762c761cd3584b041bc2df7 Mon Sep 17 00:00:00 2001 From: DrSmugleaf Date: Tue, 10 Oct 2023 20:06:24 -0700 Subject: [PATCH 066/127] Replace string data fields with LocId where relevant (#20883) --- .../SolutionContainerVisualsComponent.cs | 39 ++++++++----------- .../SolutionContainerVisualsSystem.cs | 2 +- .../Tests/VendingMachineRestockTest.cs | 15 ++++--- .../Components/SolutionSpikerComponent.cs | 12 +++--- .../CommunicationsConsoleComponent.cs | 25 ++++++------ .../CommunicationsConsoleSystem.cs | 14 +++---- .../Forensics/Components/FiberComponent.cs | 6 +-- Content.Server/Nuke/NukeLabelComponent.cs | 4 +- Content.Server/Nuke/NukeLabelSystem.cs | 2 +- .../NukeOps/WarDeclaratorComponent.cs | 18 ++++----- Content.Server/NukeOps/WarDeclaratorSystem.cs | 4 +- .../Nutrition/Components/FoodComponent.cs | 8 ++-- .../Nutrition/Components/OpenableComponent.cs | 4 +- .../Nutrition/EntitySystems/CreamPieSystem.cs | 4 +- .../Nutrition/EntitySystems/FoodSystem.cs | 10 ++--- .../Components/CargoGiftsRuleComponent.cs | 26 ++++++------- .../StationEvents/Events/CargoGiftsRule.cs | 3 +- .../Storage/Components/PickRandomComponent.cs | 10 ++--- .../Components/TabletopGameComponent.cs | 11 +++--- .../UserInterface/ActivatableUIComponent.cs | 19 +++++---- Content.Server/Wires/WiresComponent.cs | 10 ++--- .../Bed/Sleep/SleepEmitSoundComponent.cs | 10 ++--- .../CartridgeLoader/CartridgeComponent.cs | 2 +- .../Reaction/ReactionMixerComponent.cs | 6 +-- .../PartAssemblyConstructionGraphStep.cs | 9 ++--- .../Examine/ExamineSystemShared.Group.cs | 8 ++-- .../Examine/GroupExamineComponent.cs | 34 ++++++++-------- .../Implants/Components/RattleComponent.cs | 12 +++--- Content.Shared/Materials/MaterialPrototype.cs | 21 +++++----- .../AnimalHusbandry/ReproductiveComponent.cs | 33 ++++++++-------- .../Mobs/Cyborgs/base_borg_chassis.yml | 2 +- .../Entities/Mobs/Player/admin_ghost.yml | 2 +- .../Instruments/instruments_structures.yml | 4 +- .../Entities/Objects/Specific/Mech/mechs.yml | 4 +- .../Entities/Structures/Dispensers/booze.yml | 4 +- .../Entities/Structures/Dispensers/chem.yml | 4 +- .../Entities/Structures/Dispensers/soda.yml | 4 +- .../Structures/Doors/Airlocks/access.yml | 10 ++--- .../Doors/Airlocks/base_structureairlocks.yml | 6 +-- .../Structures/Doors/Airlocks/highsec.yml | 6 +-- .../Structures/Doors/Airlocks/shuttle.yml | 2 +- .../Structures/Doors/Firelocks/firelock.yml | 4 +- .../Doors/Windoors/base_structurewindoors.yml | 4 +- .../Structures/Machines/Computers/arcades.yml | 8 ++-- .../Structures/Machines/Medical/cryo_pod.yml | 4 +- .../Structures/Machines/anomaly_equipment.yml | 12 +++--- .../Entities/Structures/Machines/bombs.yml | 4 +- .../Structures/Machines/chem_master.yml | 4 +- .../Structures/Machines/cloning_machine.yml | 4 +- .../Structures/Machines/fatextractor.yml | 4 +- .../Structures/Machines/gravity_generator.yml | 4 +- .../Entities/Structures/Machines/lathe.yml | 8 ++-- .../Machines/material_reclaimer.yml | 4 +- .../Structures/Machines/medical_scanner.yml | 4 +- .../Entities/Structures/Machines/research.yml | 2 +- .../Structures/Machines/telecomms.yml | 4 +- .../Structures/Machines/vending_machines.yml | 4 +- .../Structures/Piping/Atmospherics/unary.yml | 4 +- .../Power/Generation/PA/control_box.yml | 4 +- .../Power/Generation/portable_generator.yml | 4 +- .../Entities/Structures/Power/apc.yml | 4 +- .../Entities/Structures/Power/chargers.yml | 2 +- .../Entities/Structures/Power/smes.yml | 4 +- .../Entities/Structures/Power/substation.yml | 4 +- .../Structures/Wallmounts/air_alarm.yml | 4 +- .../Structures/Wallmounts/fire_alarm.yml | 4 +- .../Structures/Wallmounts/intercom.yml | 4 +- .../Wallmounts/surveillance_camera.yml | 2 +- .../Entities/Structures/hydro_tray.yml | 4 +- 69 files changed, 265 insertions(+), 286 deletions(-) diff --git a/Content.Client/Chemistry/Visualizers/SolutionContainerVisualsComponent.cs b/Content.Client/Chemistry/Visualizers/SolutionContainerVisualsComponent.cs index 5fd44fe2853..5b8ae937665 100644 --- a/Content.Client/Chemistry/Visualizers/SolutionContainerVisualsComponent.cs +++ b/Content.Client/Chemistry/Visualizers/SolutionContainerVisualsComponent.cs @@ -1,11 +1,4 @@ -using System; using Content.Shared.Chemistry; -using JetBrains.Annotations; -using Robust.Client.GameObjects; -using Robust.Shared.GameObjects; -using Robust.Shared.IoC; -using Robust.Shared.Maths; -using Robust.Shared.Serialization.Manager.Attributes; using Robust.Shared.Utility; namespace Content.Client.Chemistry.Visualizers @@ -13,40 +6,40 @@ namespace Content.Client.Chemistry.Visualizers [RegisterComponent] public sealed partial class SolutionContainerVisualsComponent : Component { - [DataField("maxFillLevels")] + [DataField] public int MaxFillLevels = 0; - [DataField("fillBaseName")] + [DataField] public string? FillBaseName = null; - [DataField("layer")] - public SolutionContainerLayers FillLayer = SolutionContainerLayers.Fill; - [DataField("baseLayer")] + [DataField] + public SolutionContainerLayers Layer = SolutionContainerLayers.Fill; + [DataField] public SolutionContainerLayers BaseLayer = SolutionContainerLayers.Base; - [DataField("overlayLayer")] + [DataField] public SolutionContainerLayers OverlayLayer = SolutionContainerLayers.Overlay; - [DataField("changeColor")] + [DataField] public bool ChangeColor = true; - [DataField("emptySpriteName")] + [DataField] public string? EmptySpriteName = null; - [DataField("emptySpriteColor")] + [DataField] public Color EmptySpriteColor = Color.White; - [DataField("metamorphic")] + [DataField] public bool Metamorphic = false; - [DataField("metamorphicDefaultSprite")] + [DataField] public SpriteSpecifier? MetamorphicDefaultSprite; - [DataField("metamorphicNameFull")] - public string MetamorphicNameFull = "transformable-container-component-glass"; + [DataField] + public LocId MetamorphicNameFull = "transformable-container-component-glass"; /// /// Which solution of the SolutionContainerManagerComponent to represent. /// If not set, will work as default. /// - [DataField("solutionName")] + [DataField] public string? SolutionName; - [DataField("initialName")] + [DataField] public string InitialName = string.Empty; - [DataField("initialDescription")] + [DataField] public string InitialDescription = string.Empty; } } diff --git a/Content.Client/Chemistry/Visualizers/SolutionContainerVisualsSystem.cs b/Content.Client/Chemistry/Visualizers/SolutionContainerVisualsSystem.cs index 7c518b4a617..44a24595bac 100644 --- a/Content.Client/Chemistry/Visualizers/SolutionContainerVisualsSystem.cs +++ b/Content.Client/Chemistry/Visualizers/SolutionContainerVisualsSystem.cs @@ -41,7 +41,7 @@ protected override void OnAppearanceChange(EntityUid uid, SolutionContainerVisua if (args.Sprite == null) return; - if (!args.Sprite.LayerMapTryGet(component.FillLayer, out var fillLayer)) + if (!args.Sprite.LayerMapTryGet(component.Layer, out var fillLayer)) return; // Currently some solution methods such as overflowing will try to update appearance with a diff --git a/Content.IntegrationTests/Tests/VendingMachineRestockTest.cs b/Content.IntegrationTests/Tests/VendingMachineRestockTest.cs index 7e1de7d0c88..49fee976317 100644 --- a/Content.IntegrationTests/Tests/VendingMachineRestockTest.cs +++ b/Content.IntegrationTests/Tests/VendingMachineRestockTest.cs @@ -1,18 +1,17 @@ #nullable enable using System.Collections.Generic; -using Robust.Shared.GameObjects; -using Robust.Shared.Map; -using Robust.Shared.Prototypes; -using Content.Server.Storage.Components; using Content.Server.VendingMachines; +using Content.Server.Wires; using Content.Shared.Cargo.Prototypes; using Content.Shared.Damage; using Content.Shared.Damage.Prototypes; -using Content.Shared.VendingMachines; -using Content.Shared.Wires; -using Content.Server.Wires; using Content.Shared.Prototypes; using Content.Shared.Storage.Components; +using Content.Shared.VendingMachines; +using Content.Shared.Wires; +using Robust.Shared.GameObjects; +using Robust.Shared.Map; +using Robust.Shared.Prototypes; namespace Content.IntegrationTests.Tests { @@ -96,7 +95,7 @@ public sealed class VendingMachineRestockTest : EntitySystem name: Test Ramen components: - type: Wires - LayoutId: Vending + layoutId: Vending - type: VendingMachine pack: TestInventory - type: Sprite diff --git a/Content.Server/Chemistry/Components/SolutionSpikerComponent.cs b/Content.Server/Chemistry/Components/SolutionSpikerComponent.cs index 63b6ebefcc6..1fad6c9a3e8 100644 --- a/Content.Server/Chemistry/Components/SolutionSpikerComponent.cs +++ b/Content.Server/Chemistry/Components/SolutionSpikerComponent.cs @@ -7,24 +7,24 @@ public sealed partial class SolutionSpikerComponent : Component /// The source solution to take the reagents from in order /// to spike the other solution container. /// - [DataField("sourceSolution")] + [DataField] public string SourceSolution { get; private set; } = string.Empty; /// /// If spiking with this entity should ignore empty containers or not. /// - [DataField("ignoreEmpty")] + [DataField] public bool IgnoreEmpty { get; private set; } /// /// What should pop up when spiking with this entity. /// - [DataField("popup")] - public string Popup { get; private set; } = "spike-solution-generic"; + [DataField] + public LocId Popup { get; private set; } = "spike-solution-generic"; /// /// What should pop up when spiking fails because the container was empty. /// - [DataField("popupEmpty")] - public string PopupEmpty { get; private set; } = "spike-solution-empty-generic"; + [DataField] + public LocId PopupEmpty { get; private set; } = "spike-solution-empty-generic"; } diff --git a/Content.Server/Communications/CommunicationsConsoleComponent.cs b/Content.Server/Communications/CommunicationsConsoleComponent.cs index e7b5f20cf39..82a4a945397 100644 --- a/Content.Server/Communications/CommunicationsConsoleComponent.cs +++ b/Content.Server/Communications/CommunicationsConsoleComponent.cs @@ -1,6 +1,5 @@ using Content.Server.UserInterface; using Content.Shared.Communications; -using Robust.Server.GameObjects; using Robust.Shared.Audio; namespace Content.Server.Communications @@ -21,41 +20,41 @@ public sealed partial class CommunicationsConsoleComponent : SharedCommunication /// If a Fluent ID isn't found, just uses the raw string /// [ViewVariables(VVAccess.ReadWrite)] - [DataField("title", required: true)] - public string AnnouncementDisplayName = "comms-console-announcement-title-station"; + [DataField(required: true)] + public LocId Title = "comms-console-announcement-title-station"; /// /// Announcement color /// [ViewVariables(VVAccess.ReadWrite)] - [DataField("color")] - public Color AnnouncementColor = Color.Gold; + [DataField] + public Color Color = Color.Gold; /// /// Time in seconds between announcement delays on a per-console basis /// [ViewVariables(VVAccess.ReadWrite)] - [DataField("delay")] - public int DelayBetweenAnnouncements = 90; + [DataField] + public int Delay = 90; /// /// Can call or recall the shuttle /// [ViewVariables(VVAccess.ReadWrite)] - [DataField("canShuttle")] - public bool CanCallShuttle = true; + [DataField] + public bool CanShuttle = true; /// /// Announce on all grids (for nukies) /// - [DataField("global")] - public bool AnnounceGlobal = false; + [DataField] + public bool Global = false; /// /// Announce sound file path /// - [DataField("sound")] - public SoundSpecifier AnnouncementSound = new SoundPathSpecifier("/Audio/Announcements/announce.ogg"); + [DataField] + public SoundSpecifier Sound = new SoundPathSpecifier("/Audio/Announcements/announce.ogg"); public PlayerBoundUserInterface? UserInterface => Owner.GetUIOrNull(CommunicationsConsoleUiKey.Key); } diff --git a/Content.Server/Communications/CommunicationsConsoleSystem.cs b/Content.Server/Communications/CommunicationsConsoleSystem.cs index b7ad536816a..e2a96335d01 100644 --- a/Content.Server/Communications/CommunicationsConsoleSystem.cs +++ b/Content.Server/Communications/CommunicationsConsoleSystem.cs @@ -188,7 +188,7 @@ private bool CanCallOrRecall(CommunicationsConsoleComponent comp) // Calling shuttle checks if (_roundEndSystem.ExpectedCountdownEnd is null) - return comp.CanCallShuttle; + return comp.CanShuttle; // Recalling shuttle checks var recallThreshold = _cfg.GetCVar(CCVars.EmergencyRecallTurningPoint); @@ -256,27 +256,27 @@ private void OnAnnounceMessage(EntityUid uid, CommunicationsConsoleComponent com } } - comp.AnnouncementCooldownRemaining = comp.DelayBetweenAnnouncements; + comp.AnnouncementCooldownRemaining = comp.Delay; UpdateCommsConsoleInterface(uid, comp); var ev = new CommunicationConsoleAnnouncementEvent(uid, comp, msg, message.Session.AttachedEntity); RaiseLocalEvent(ref ev); // allow admemes with vv - Loc.TryGetString(comp.AnnouncementDisplayName, out var title); - title ??= comp.AnnouncementDisplayName; + Loc.TryGetString(comp.Title, out var title); + title ??= comp.Title; msg += "\n" + Loc.GetString("comms-console-announcement-sent-by") + " " + author; - if (comp.AnnounceGlobal) + if (comp.Global) { - _chatSystem.DispatchGlobalAnnouncement(msg, title, announcementSound: comp.AnnouncementSound, colorOverride: comp.AnnouncementColor); + _chatSystem.DispatchGlobalAnnouncement(msg, title, announcementSound: comp.Sound, colorOverride: comp.Color); if (message.Session.AttachedEntity != null) _adminLogger.Add(LogType.Chat, LogImpact.Low, $"{ToPrettyString(message.Session.AttachedEntity.Value):player} has sent the following global announcement: {msg}"); return; } - _chatSystem.DispatchStationAnnouncement(uid, msg, title, colorOverride: comp.AnnouncementColor); + _chatSystem.DispatchStationAnnouncement(uid, msg, title, colorOverride: comp.Color); if (message.Session.AttachedEntity != null) _adminLogger.Add(LogType.Chat, LogImpact.Low, $"{ToPrettyString(message.Session.AttachedEntity.Value):player} has sent the following station announcement: {msg}"); diff --git a/Content.Server/Forensics/Components/FiberComponent.cs b/Content.Server/Forensics/Components/FiberComponent.cs index 766ad979b66..2086c958702 100644 --- a/Content.Server/Forensics/Components/FiberComponent.cs +++ b/Content.Server/Forensics/Components/FiberComponent.cs @@ -7,10 +7,10 @@ namespace Content.Server.Forensics [RegisterComponent] public sealed partial class FiberComponent : Component { - [DataField("fiberMaterial")] - public string FiberMaterial = "fibers-synthetic"; + [DataField] + public LocId FiberMaterial = "fibers-synthetic"; - [DataField("fiberColor")] + [DataField] public string? FiberColor; } } diff --git a/Content.Server/Nuke/NukeLabelComponent.cs b/Content.Server/Nuke/NukeLabelComponent.cs index a8e4786888c..aea54e95dae 100644 --- a/Content.Server/Nuke/NukeLabelComponent.cs +++ b/Content.Server/Nuke/NukeLabelComponent.cs @@ -9,6 +9,6 @@ namespace Content.Server.Nuke; [RegisterComponent] public sealed partial class NukeLabelComponent : Component { - [DataField("prefix")] public string NukeLabel = "nuke-label-nanotrasen"; - [DataField("serialLength")] public int SerialLength = 6; + [DataField] public LocId Prefix = "nuke-label-nanotrasen"; + [DataField] public int SerialLength = 6; } diff --git a/Content.Server/Nuke/NukeLabelSystem.cs b/Content.Server/Nuke/NukeLabelSystem.cs index b9416ee2792..39f0b1ca770 100644 --- a/Content.Server/Nuke/NukeLabelSystem.cs +++ b/Content.Server/Nuke/NukeLabelSystem.cs @@ -16,7 +16,7 @@ public override void Initialize() private void OnMapInit(EntityUid uid, NukeLabelComponent nuke, MapInitEvent args) { - var label = Loc.GetString(nuke.NukeLabel, ("serial", _nuke.GenerateRandomNumberString(nuke.SerialLength))); + var label = Loc.GetString(nuke.Prefix, ("serial", _nuke.GenerateRandomNumberString(nuke.SerialLength))); var meta = MetaData(uid); _metaData.SetEntityName(uid, $"{meta.EntityName} ({label})", meta); } diff --git a/Content.Server/NukeOps/WarDeclaratorComponent.cs b/Content.Server/NukeOps/WarDeclaratorComponent.cs index 1a1f9116c60..15279ee13ca 100644 --- a/Content.Server/NukeOps/WarDeclaratorComponent.cs +++ b/Content.Server/NukeOps/WarDeclaratorComponent.cs @@ -12,37 +12,37 @@ public sealed partial class WarDeclaratorComponent : Component /// Custom war declaration message. If empty, use default. /// [ViewVariables(VVAccess.ReadWrite)] - [DataField("message")] + [DataField] public string Message; /// /// Permission to customize message text /// [ViewVariables(VVAccess.ReadWrite)] - [DataField("allowEditingMessage")] + [DataField] public bool AllowEditingMessage = true; [ViewVariables(VVAccess.ReadWrite)] - [DataField("maxMessageLength")] + [DataField] public int MaxMessageLength = 512; /// /// War declarement text color /// [ViewVariables(VVAccess.ReadWrite)] - [DataField("color")] - public Color DeclarementColor = Color.Red; + [DataField] + public Color Color = Color.Red; /// /// War declarement sound file path /// - [DataField("sound")] - public SoundSpecifier DeclarementSound = new SoundPathSpecifier("/Audio/Announcements/war.ogg"); + [DataField] + public SoundSpecifier Sound = new SoundPathSpecifier("/Audio/Announcements/war.ogg"); /// /// Fluent ID for the declarement title /// [ViewVariables(VVAccess.ReadWrite)] - [DataField("title")] - public string DeclarementTitle = "comms-console-announcement-title-nukie"; + [DataField] + public LocId Title = "comms-console-announcement-title-nukie"; } diff --git a/Content.Server/NukeOps/WarDeclaratorSystem.cs b/Content.Server/NukeOps/WarDeclaratorSystem.cs index 2df2cb34832..dcf6c28d434 100644 --- a/Content.Server/NukeOps/WarDeclaratorSystem.cs +++ b/Content.Server/NukeOps/WarDeclaratorSystem.cs @@ -76,9 +76,9 @@ private void OnActivated(EntityUid uid, WarDeclaratorComponent component, WarDec { message = Loc.GetString("war-declarator-default-message"); } - var title = Loc.GetString(component.DeclarementTitle); + var title = Loc.GetString(component.Title); - _nukeopsRuleSystem.DeclareWar(args.Session.AttachedEntity.Value, message, title, component.DeclarementSound, component.DeclarementColor); + _nukeopsRuleSystem.DeclareWar(args.Session.AttachedEntity.Value, message, title, component.Sound, component.Color); if (args.Session.AttachedEntity != null) _adminLogger.Add(LogType.Chat, LogImpact.Low, $"{ToPrettyString(args.Session.AttachedEntity.Value):player} has declared war with this text: {message}"); diff --git a/Content.Server/Nutrition/Components/FoodComponent.cs b/Content.Server/Nutrition/Components/FoodComponent.cs index 0f696d36946..af743521321 100644 --- a/Content.Server/Nutrition/Components/FoodComponent.cs +++ b/Content.Server/Nutrition/Components/FoodComponent.cs @@ -1,10 +1,8 @@ using Content.Server.Body.Components; -using Content.Server.Chemistry.EntitySystems; using Content.Server.Nutrition.EntitySystems; using Content.Shared.FixedPoint; using Robust.Shared.Audio; using Robust.Shared.Prototypes; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; namespace Content.Server.Nutrition.Components; @@ -17,8 +15,8 @@ public sealed partial class FoodComponent : Component [DataField] public SoundSpecifier UseSound = new SoundPathSpecifier("/Audio/Items/eatfood.ogg"); - [DataField("trash")] - public EntProtoId? TrashPrototype; + [DataField] + public EntProtoId? Trash; [DataField] public FixedPoint2? TransferAmount = FixedPoint2.New(5); @@ -55,7 +53,7 @@ public sealed partial class FoodComponent : Component /// The localization identifier for the eat message. Needs a "food" entity argument passed to it. ///
[DataField] - public string EatMessage = "food-nom"; + public LocId EatMessage = "food-nom"; /// /// How long it takes to eat the food personally. diff --git a/Content.Server/Nutrition/Components/OpenableComponent.cs b/Content.Server/Nutrition/Components/OpenableComponent.cs index 5164ed21ec5..63efd520962 100644 --- a/Content.Server/Nutrition/Components/OpenableComponent.cs +++ b/Content.Server/Nutrition/Components/OpenableComponent.cs @@ -28,7 +28,7 @@ public sealed partial class OpenableComponent : Component /// Text shown when examining and its open. /// [DataField, ViewVariables(VVAccess.ReadWrite)] - public string ExamineText = "drink-component-on-examine-is-opened"; + public LocId ExamineText = "drink-component-on-examine-is-opened"; /// /// The locale id for the popup shown when IsClosed is called and closed. Needs a "owner" entity argument passed to it. @@ -36,7 +36,7 @@ public sealed partial class OpenableComponent : Component /// It's still generic enough that you should change it if you make openable non-drinks, i.e. unwrap it first, peel it first. /// [DataField, ViewVariables(VVAccess.ReadWrite)] - public string ClosedPopup = "drink-component-try-use-drink-not-open"; + public LocId ClosedPopup = "drink-component-try-use-drink-not-open"; /// /// Sound played when opening. diff --git a/Content.Server/Nutrition/EntitySystems/CreamPieSystem.cs b/Content.Server/Nutrition/EntitySystems/CreamPieSystem.cs index 9af2397720a..ee0e18e998f 100644 --- a/Content.Server/Nutrition/EntitySystems/CreamPieSystem.cs +++ b/Content.Server/Nutrition/EntitySystems/CreamPieSystem.cs @@ -45,9 +45,9 @@ protected override void SplattedCreamPie(EntityUid uid, CreamPieComponent creamP { _puddle.TrySpillAt(uid, solution, out _, false); } - if (!string.IsNullOrEmpty(foodComp.TrashPrototype)) + if (!string.IsNullOrEmpty(foodComp.Trash)) { - EntityManager.SpawnEntity(foodComp.TrashPrototype, Transform(uid).Coordinates); + EntityManager.SpawnEntity(foodComp.Trash, Transform(uid).Coordinates); } } ActivatePayload(uid); diff --git a/Content.Server/Nutrition/EntitySystems/FoodSystem.cs b/Content.Server/Nutrition/EntitySystems/FoodSystem.cs index af037187408..6213b4e9c62 100644 --- a/Content.Server/Nutrition/EntitySystems/FoodSystem.cs +++ b/Content.Server/Nutrition/EntitySystems/FoodSystem.cs @@ -1,4 +1,3 @@ -using System.Linq; using Content.Server.Body.Components; using Content.Server.Body.Systems; using Content.Server.Chemistry.EntitySystems; @@ -22,13 +21,12 @@ using Content.Shared.Inventory; using Content.Shared.Mobs.Systems; using Content.Shared.Nutrition; -using Content.Shared.Verbs; using Content.Shared.Stacks; +using Content.Shared.Storage; +using Content.Shared.Verbs; using Robust.Shared.Audio; using Robust.Shared.Player; using Robust.Shared.Utility; -using Content.Shared.Tag; -using Content.Shared.Storage; namespace Content.Server.Nutrition.EntitySystems; @@ -309,7 +307,7 @@ private void OnDoAfter(EntityUid uid, FoodComponent component, ConsumeDoAfterEve if (ev.Cancelled) return; - if (string.IsNullOrEmpty(component.TrashPrototype)) + if (string.IsNullOrEmpty(component.Trash)) QueueDel(uid); else DeleteAndSpawnTrash(component, uid, args.User); @@ -319,7 +317,7 @@ public void DeleteAndSpawnTrash(FoodComponent component, EntityUid food, EntityU { //We're empty. Become trash. var position = Transform(food).MapPosition; - var finisher = Spawn(component.TrashPrototype, position); + var finisher = Spawn(component.Trash, position); // If the user is holding the item if (user != null && _hands.IsHolding(user.Value, food, out var hand)) diff --git a/Content.Server/StationEvents/Components/CargoGiftsRuleComponent.cs b/Content.Server/StationEvents/Components/CargoGiftsRuleComponent.cs index 895afc6a9f6..ab5d722a737 100644 --- a/Content.Server/StationEvents/Components/CargoGiftsRuleComponent.cs +++ b/Content.Server/StationEvents/Components/CargoGiftsRuleComponent.cs @@ -1,8 +1,6 @@ using Content.Server.StationEvents.Events; using Content.Shared.Cargo.Prototypes; using Robust.Shared.Prototypes; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.Dictionary; namespace Content.Server.StationEvents.Components; @@ -15,43 +13,43 @@ public sealed partial class CargoGiftsRuleComponent : Component /// /// The base announcement string (which then incorporates the strings below) /// - [DataField("announce"), ViewVariables(VVAccess.ReadWrite)] - public string Announce = "cargo-gifts-event-announcement"; + [DataField, ViewVariables(VVAccess.ReadWrite)] + public LocId Announce = "cargo-gifts-event-announcement"; /// /// What is being sent /// - [DataField("description"), ViewVariables(VVAccess.ReadWrite)] - public string Description = "cargo-gift-default-description"; + [DataField, ViewVariables(VVAccess.ReadWrite)] + public LocId Description = "cargo-gift-default-description"; /// /// Sender of the gifts /// - [DataField("sender"), ViewVariables(VVAccess.ReadWrite)] - public string Sender = "cargo-gift-default-sender"; + [DataField, ViewVariables(VVAccess.ReadWrite)] + public LocId Sender = "cargo-gift-default-sender"; /// /// Destination of the gifts (who they get sent to on the station) /// - [DataField("dest"), ViewVariables(VVAccess.ReadWrite)] - public string Dest = "cargo-gift-default-dest"; + [DataField, ViewVariables(VVAccess.ReadWrite)] + public LocId Dest = "cargo-gift-default-dest"; /// /// Cargo that you would like gifted to the station, with the quantity for each /// Use Ids from cargoProduct Prototypes /// - [DataField("gifts", required: true, customTypeSerializer:typeof(PrototypeIdDictionarySerializer)), ViewVariables(VVAccess.ReadWrite)] - public Dictionary Gifts = new(); + [DataField(required: true), ViewVariables(VVAccess.ReadWrite)] + public Dictionary, int> Gifts = new(); /// /// How much space (minimum) you want to leave in the order database for supply to actually do their work /// - [DataField("orderSpaceToLeave"), ViewVariables(VVAccess.ReadWrite)] + [DataField, ViewVariables(VVAccess.ReadWrite)] public int OrderSpaceToLeave = 5; /// /// Time until we consider next lot of gifts (if supply is overflowing with orders) /// - [DataField("timeUntilNextGifts"), ViewVariables(VVAccess.ReadWrite)] + [DataField, ViewVariables(VVAccess.ReadWrite)] public float TimeUntilNextGifts = 10.0f; } diff --git a/Content.Server/StationEvents/Events/CargoGiftsRule.cs b/Content.Server/StationEvents/Events/CargoGiftsRule.cs index 51fafd6cb30..f0f9586ad33 100644 --- a/Content.Server/StationEvents/Events/CargoGiftsRule.cs +++ b/Content.Server/StationEvents/Events/CargoGiftsRule.cs @@ -4,7 +4,6 @@ using Content.Server.GameTicking; using Content.Server.GameTicking.Rules.Components; using Content.Server.StationEvents.Components; -using Content.Shared.Cargo.Prototypes; using Robust.Shared.Prototypes; namespace Content.Server.StationEvents.Events; @@ -56,7 +55,7 @@ protected override void ActiveTick(EntityUid uid, CargoGiftsRuleComponent compon var (productId, qty) = component.Gifts.First(); component.Gifts.Remove(productId); - var product = _prototypeManager.Index(productId); + var product = _prototypeManager.Index(productId); if (!_cargoSystem.AddAndApproveOrder( station!.Value, diff --git a/Content.Server/Storage/Components/PickRandomComponent.cs b/Content.Server/Storage/Components/PickRandomComponent.cs index ae48ce2e214..00c79b9ea4f 100644 --- a/Content.Server/Storage/Components/PickRandomComponent.cs +++ b/Content.Server/Storage/Components/PickRandomComponent.cs @@ -14,18 +14,18 @@ public sealed partial class PickRandomComponent : Component /// /// Whitelist for potential picked items. /// - [DataField("whitelist"), ViewVariables(VVAccess.ReadWrite)] + [DataField, ViewVariables(VVAccess.ReadWrite)] public EntityWhitelist? Whitelist; /// /// Locale id for the pick verb text. /// - [DataField("verbText"), ViewVariables(VVAccess.ReadWrite)] - public string VerbText = "comp-pick-random-verb-text"; + [DataField, ViewVariables(VVAccess.ReadWrite)] + public LocId VerbText = "comp-pick-random-verb-text"; /// /// Locale id for the empty storage message. /// - [DataField("emptyText"), ViewVariables(VVAccess.ReadWrite)] - public string EmptyText = "comp-pick-random-empty"; + [DataField, ViewVariables(VVAccess.ReadWrite)] + public LocId EmptyText = "comp-pick-random-empty"; } diff --git a/Content.Server/Tabletop/Components/TabletopGameComponent.cs b/Content.Server/Tabletop/Components/TabletopGameComponent.cs index 0196eec196b..da7a09b2131 100644 --- a/Content.Server/Tabletop/Components/TabletopGameComponent.cs +++ b/Content.Server/Tabletop/Components/TabletopGameComponent.cs @@ -1,5 +1,4 @@ using System.Numerics; -using Vector2 = System.Numerics.Vector2; namespace Content.Server.Tabletop.Components { @@ -12,25 +11,25 @@ public sealed partial class TabletopGameComponent : Component /// /// The localized name of the board. Shown in the UI. /// - [DataField("boardName")] - public string BoardName { get; private set; } = "tabletop-default-board-name"; + [DataField] + public LocId BoardName { get; private set; } = "tabletop-default-board-name"; /// /// The type of method used to set up a tabletop. /// - [DataField("setup", required: true)] + [DataField(required: true)] public TabletopSetup Setup { get; private set; } = new TabletopChessSetup(); /// /// The size of the viewport being opened. Must match the board dimensions otherwise you'll get the space parallax (unless that's what you want). /// - [DataField("size")] + [DataField] public Vector2i Size { get; private set; } = (300, 300); /// /// The zoom of the viewport camera. /// - [DataField("cameraZoom")] + [DataField] public Vector2 CameraZoom { get; private set; } = Vector2.One; /// diff --git a/Content.Server/UserInterface/ActivatableUIComponent.cs b/Content.Server/UserInterface/ActivatableUIComponent.cs index fe9ae850c84..ff605c81190 100644 --- a/Content.Server/UserInterface/ActivatableUIComponent.cs +++ b/Content.Server/UserInterface/ActivatableUIComponent.cs @@ -1,4 +1,3 @@ -using Robust.Server.GameObjects; using Robust.Server.Player; using Robust.Shared.Reflection; using Robust.Shared.Serialization; @@ -15,21 +14,21 @@ public sealed partial class ActivatableUIComponent : Component, [ViewVariables] public PlayerBoundUserInterface? UserInterface => (Key != null) ? Owner.GetUIOrNull(Key) : null; [ViewVariables(VVAccess.ReadWrite)] - [DataField("inHandsOnly")] + [DataField] public bool InHandsOnly { get; set; } = false; - [DataField("singleUser")] + [DataField] public bool SingleUser { get; set; } = false; [ViewVariables(VVAccess.ReadWrite)] - [DataField("adminOnly")] + [DataField] public bool AdminOnly { get; set; } = false; [DataField("key", required: true)] private string _keyRaw = default!; - [DataField("verbText")] - public string VerbText = "ui-verb-toggle-open"; + [DataField] + public LocId VerbText = "ui-verb-toggle-open"; /// /// Whether you need a hand to operate this UI. The hand does not need to be free, you just need to have one. @@ -39,28 +38,28 @@ public sealed partial class ActivatableUIComponent : Component, /// more generic interaction / configuration that might not require hands. /// [ViewVariables(VVAccess.ReadWrite)] - [DataField("requireHands")] + [DataField] public bool RequireHands = true; /// /// Whether you can activate this ui with activateinhand or not /// [ViewVariables(VVAccess.ReadWrite)] - [DataField("rightClickOnly")] + [DataField] public bool rightClickOnly = false; /// /// Whether spectators (non-admin ghosts) should be allowed to view this UI. /// [ViewVariables(VVAccess.ReadWrite)] - [DataField("allowSpectator")] + [DataField] public bool AllowSpectator = true; /// /// Whether the UI should close when the item is deselected due to a hand swap or drop /// [ViewVariables(VVAccess.ReadWrite)] - [DataField("closeOnHandDeselect")] + [DataField] public bool CloseOnHandDeselect = true; /// diff --git a/Content.Server/Wires/WiresComponent.cs b/Content.Server/Wires/WiresComponent.cs index 9283e1e18f2..526b73a300d 100644 --- a/Content.Server/Wires/WiresComponent.cs +++ b/Content.Server/Wires/WiresComponent.cs @@ -8,13 +8,13 @@ public sealed partial class WiresComponent : Component /// /// The name of this entity's internal board. /// - [DataField("BoardName")] - public string BoardName { get; set; } = "wires-board-name-default"; + [DataField] + public LocId BoardName { get; set; } = "wires-board-name-default"; /// /// The layout ID of this entity's wires. /// - [DataField("LayoutId", required: true)] + [DataField(required: true)] public string LayoutId { get; set; } = default!; /// @@ -47,7 +47,7 @@ public sealed partial class WiresComponent : Component /// If this should follow the layout saved the first time the layout dictated by the /// layout ID is generated, or if a new wire order should be generated every time. /// - [DataField("alwaysRandomize")] + [DataField] public bool AlwaysRandomize { get; private set; } /// @@ -64,6 +64,6 @@ public sealed partial class WiresComponent : Component [ViewVariables] public Dictionary StateData { get; } = new(); - [DataField("pulseSound")] + [DataField] public SoundSpecifier PulseSound = new SoundPathSpecifier("/Audio/Effects/multitool_pulse.ogg"); } diff --git a/Content.Shared/Bed/Sleep/SleepEmitSoundComponent.cs b/Content.Shared/Bed/Sleep/SleepEmitSoundComponent.cs index e1918eac262..6313f633f21 100644 --- a/Content.Shared/Bed/Sleep/SleepEmitSoundComponent.cs +++ b/Content.Shared/Bed/Sleep/SleepEmitSoundComponent.cs @@ -8,24 +8,24 @@ public sealed partial class SleepEmitSoundComponent : Component /// /// Sound to play when sleeping /// - [DataField("snore"), ViewVariables(VVAccess.ReadWrite)] + [DataField, ViewVariables(VVAccess.ReadWrite)] public SoundSpecifier Snore = new SoundCollectionSpecifier("Snores", AudioParams.Default.WithVariation(0.2f)); /// /// Interval between snore attempts in seconds /// - [DataField("interval"), ViewVariables(VVAccess.ReadWrite)] + [DataField, ViewVariables(VVAccess.ReadWrite)] public float Interval = 5f; /// /// Chance for snore attempt to succeed /// - [DataField("chance"), ViewVariables(VVAccess.ReadWrite)] + [DataField, ViewVariables(VVAccess.ReadWrite)] public float Chance = 0.33f; /// /// Popup for snore (e.g. Zzz...) /// - [DataField("popUp"), ViewVariables(VVAccess.ReadWrite)] - public string PopUp = "sleep-onomatopoeia"; + [DataField, ViewVariables(VVAccess.ReadWrite)] + public LocId PopUp = "sleep-onomatopoeia"; } diff --git a/Content.Shared/CartridgeLoader/CartridgeComponent.cs b/Content.Shared/CartridgeLoader/CartridgeComponent.cs index ba7e6fe2d58..56debb48f4f 100644 --- a/Content.Shared/CartridgeLoader/CartridgeComponent.cs +++ b/Content.Shared/CartridgeLoader/CartridgeComponent.cs @@ -11,7 +11,7 @@ namespace Content.Shared.CartridgeLoader; public sealed partial class CartridgeComponent : Component { [DataField(required: true)] - public string ProgramName = "default-program-name"; + public LocId ProgramName = "default-program-name"; [DataField] public SpriteSpecifier? Icon; diff --git a/Content.Shared/Chemistry/Reaction/ReactionMixerComponent.cs b/Content.Shared/Chemistry/Reaction/ReactionMixerComponent.cs index 849fffcf5e3..69697239533 100644 --- a/Content.Shared/Chemistry/Reaction/ReactionMixerComponent.cs +++ b/Content.Shared/Chemistry/Reaction/ReactionMixerComponent.cs @@ -9,15 +9,15 @@ public sealed partial class ReactionMixerComponent : Component /// A list of IDs for categories of reactions that can be mixed (i.e. HOLY for a bible, DRINK for a spoon) /// [ViewVariables] - [DataField("reactionTypes")] + [DataField] public List ReactionTypes = default!; /// /// A string which identifies the string to be sent when successfully mixing a solution /// [ViewVariables] - [DataField("mixMessage")] - public string MixMessage = "default-mixing-success"; + [DataField] + public LocId MixMessage = "default-mixing-success"; } [ByRefEvent] diff --git a/Content.Shared/Construction/Steps/PartAssemblyConstructionGraphStep.cs b/Content.Shared/Construction/Steps/PartAssemblyConstructionGraphStep.cs index 9119587a6b2..f22fc459a71 100644 --- a/Content.Shared/Construction/Steps/PartAssemblyConstructionGraphStep.cs +++ b/Content.Shared/Construction/Steps/PartAssemblyConstructionGraphStep.cs @@ -1,6 +1,5 @@ using Content.Shared.Construction.Components; using Content.Shared.Examine; -using JetBrains.Annotations; namespace Content.Shared.Construction.Steps; @@ -10,14 +9,14 @@ public sealed partial class PartAssemblyConstructionGraphStep : ConstructionGrap /// /// A valid ID on 's dictionary of strings to part lists. /// - [DataField("assemblyId")] + [DataField] public string AssemblyId = string.Empty; /// - /// A localization string used for + /// A localization string used when examining and for the guidebook. /// - [DataField("guideString")] - public string GuideString = "construction-guide-condition-part-assembly"; + [DataField] + public LocId GuideString = "construction-guide-condition-part-assembly"; public bool Condition(EntityUid uid, IEntityManager entityManager) { diff --git a/Content.Shared/Examine/ExamineSystemShared.Group.cs b/Content.Shared/Examine/ExamineSystemShared.Group.cs index 4b050da2f4b..bd284f321c8 100644 --- a/Content.Shared/Examine/ExamineSystemShared.Group.cs +++ b/Content.Shared/Examine/ExamineSystemShared.Group.cs @@ -1,5 +1,5 @@ -using Robust.Shared.Utility; using Content.Shared.Verbs; +using Robust.Shared.Utility; namespace Content.Shared.Examine { @@ -23,7 +23,7 @@ public override void Initialize() /// private void OnGroupExamineVerb(EntityUid uid, GroupExamineComponent component, GetVerbsEvent args) { - foreach (var group in component.ExamineGroups) + foreach (var group in component.Group) { if (!EntityHasComponent(uid, group.Components)) continue; @@ -116,7 +116,7 @@ public void AddDetailedExamineVerb(GetVerbsEvent verbsEvent, Compon // Make sure we have the component name as a string var componentName = _componentFactory.GetComponentName(component.GetType()); - foreach (var examineGroup in groupExamine.ExamineGroups) + foreach (var examineGroup in groupExamine.Group) { // If any of the examine groups list of components contain this componentname if (examineGroup.Components.Contains(componentName)) @@ -124,7 +124,7 @@ public void AddDetailedExamineVerb(GetVerbsEvent verbsEvent, Compon foreach (var entry in examineGroup.Entries) { // If any of the entries already are from your component, dont do anything else - no doubles! - if (entry.ComponentName == componentName) + if (entry.Component == componentName) return; } diff --git a/Content.Shared/Examine/GroupExamineComponent.cs b/Content.Shared/Examine/GroupExamineComponent.cs index a61971a2c5f..f91fd4c4de8 100644 --- a/Content.Shared/Examine/GroupExamineComponent.cs +++ b/Content.Shared/Examine/GroupExamineComponent.cs @@ -12,8 +12,8 @@ public sealed partial class GroupExamineComponent : Component /// /// A list of ExamineGroups. /// - [DataField("group")] - public List ExamineGroups = new() + [DataField] + public List Group = new() { // TODO Remove hardcoded component names. new ExamineGroup() @@ -33,14 +33,14 @@ public sealed partial class ExamineGroup /// /// The title of the Examine Group. Localized string that gets added to the examine tooltip. /// - [DataField("title")] + [DataField] [ViewVariables(VVAccess.ReadWrite)] public string? Title; /// /// A list of ExamineEntries, containing which component it belongs to, which priority it has, and what FormattedMessage it holds. /// - [DataField("entries")] + [DataField] public List Entries = new(); // TODO custom type serializer, or just make this work via some other automatic grouping process that doesn't @@ -48,25 +48,25 @@ public sealed partial class ExamineGroup /// /// A list of all components this ExamineGroup encompasses. /// - [DataField("components")] + [DataField] public List Components = new(); /// /// The icon path for the Examine Group. /// - [DataField("icon")] + [DataField] public SpriteSpecifier Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/examine-star.png")); /// /// The text shown in the context verb menu. /// - [DataField("contextText")] - public string ContextText = "verb-examine-group-other"; + [DataField] + public LocId ContextText = "verb-examine-group-other"; /// /// Details shown when hovering over the button. /// - [DataField("hoverMessage")] + [DataField] public string HoverMessage = string.Empty; } @@ -79,25 +79,25 @@ public sealed partial class ExamineEntry /// /// Which component does this entry relate to? /// - [DataField("component", required: true)] - public string ComponentName; + [DataField(required: true)] + public string Component; /// /// What priority has this entry - entries are sorted high to low. /// - [DataField("priority")] + [DataField] public float Priority = 0f; /// /// The FormattedMessage of this entry. /// - [DataField("message", required: true)] + [DataField(required: true)] public FormattedMessage Message; - /// Should be set to _componentFactory.GetComponentName(component.GetType()) to properly function. - public ExamineEntry(string componentName, float priority, FormattedMessage message) + /// Should be set to _componentFactory.GetComponentName(component.GetType()) to properly function. + public ExamineEntry(string component, float priority, FormattedMessage message) { - ComponentName = componentName; + Component = component; Priority = priority; Message = message; } @@ -106,7 +106,7 @@ private ExamineEntry() { // parameterless ctor is required for data-definition serialization Message = default!; - ComponentName = default!; + Component = default!; } } diff --git a/Content.Shared/Implants/Components/RattleComponent.cs b/Content.Shared/Implants/Components/RattleComponent.cs index e8b98e462f9..ab1ccdb069d 100644 --- a/Content.Shared/Implants/Components/RattleComponent.cs +++ b/Content.Shared/Implants/Components/RattleComponent.cs @@ -1,6 +1,6 @@ using Content.Shared.Radio; using Robust.Shared.GameStates; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; +using Robust.Shared.Prototypes; namespace Content.Shared.Implants.Components; @@ -8,14 +8,14 @@ namespace Content.Shared.Implants.Components; public sealed partial class RattleComponent : Component { // The radio channel the message will be sent to - [DataField("radioChannel", customTypeSerializer: typeof(PrototypeIdSerializer))] - public string RadioChannel = "Syndicate"; + [DataField] + public ProtoId RadioChannel = "Syndicate"; // The message that the implant will send when crit - [DataField("critMessage")] - public string CritMessage = "deathrattle-implant-critical-message"; + [DataField] + public LocId CritMessage = "deathrattle-implant-critical-message"; // The message that the implant will send when dead [DataField("deathMessage")] - public string DeathMessage = "deathrattle-implant-dead-message"; + public LocId DeathMessage = "deathrattle-implant-dead-message"; } diff --git a/Content.Shared/Materials/MaterialPrototype.cs b/Content.Shared/Materials/MaterialPrototype.cs index 7eb4dfd9a43..cf1159947be 100644 --- a/Content.Shared/Materials/MaterialPrototype.cs +++ b/Content.Shared/Materials/MaterialPrototype.cs @@ -1,7 +1,6 @@ using Robust.Shared.Prototypes; -using Robust.Shared.Utility; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.Array; +using Robust.Shared.Utility; namespace Content.Shared.Materials { @@ -17,7 +16,7 @@ public sealed class MaterialPrototype : IPrototype, IInheritingPrototype public string[]? Parents { get; } [ViewVariables] - [AbstractDataFieldAttribute] + [AbstractDataField] public bool Abstract { get; } = false; [ViewVariables] @@ -29,10 +28,10 @@ public sealed class MaterialPrototype : IPrototype, IInheritingPrototype /// between the material and physical entities you can carry, /// include which stack we should spawn by default. /// - [DataField("stackEntity", customTypeSerializer:typeof(PrototypeIdSerializer))] - public string? StackEntity; + [DataField] + public ProtoId? StackEntity; - [DataField("name")] + [DataField] public string Name = string.Empty; /// @@ -40,22 +39,22 @@ public sealed class MaterialPrototype : IPrototype, IInheritingPrototype /// Lathe recipe tooltips and material storage display use this to let you change a material to sound nicer. /// For example, 5 bars of gold is better than 5 sheets of gold. /// - [DataField("unit")] - public string Unit = "materials-unit-sheet"; + [DataField] + public LocId Unit = "materials-unit-sheet"; - [DataField("color")] + [DataField] public Color Color { get; private set; } = Color.Gray; /// /// An icon used to represent the material in graphic interfaces. /// - [DataField("icon")] + [DataField] public SpriteSpecifier Icon { get; private set; } = SpriteSpecifier.Invalid; /// /// The price per cm3. /// - [DataField("price", required: true)] + [DataField(required: true)] public double Price = 0; } } diff --git a/Content.Shared/Nutrition/AnimalHusbandry/ReproductiveComponent.cs b/Content.Shared/Nutrition/AnimalHusbandry/ReproductiveComponent.cs index c3f1fc69f50..ea9edcb5076 100644 --- a/Content.Shared/Nutrition/AnimalHusbandry/ReproductiveComponent.cs +++ b/Content.Shared/Nutrition/AnimalHusbandry/ReproductiveComponent.cs @@ -1,5 +1,4 @@ -using Content.Shared.Nutrition.Components; -using Content.Shared.Storage; +using Content.Shared.Storage; using Content.Shared.Whitelist; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom; @@ -16,93 +15,93 @@ public sealed partial class ReproductiveComponent : Component /// /// The next time when breeding will be attempted. /// - [DataField("nextBreedAttempt", customTypeSerializer: typeof(TimeOffsetSerializer)), ViewVariables(VVAccess.ReadWrite)] + [DataField(customTypeSerializer: typeof(TimeOffsetSerializer)), ViewVariables(VVAccess.ReadWrite)] public TimeSpan NextBreedAttempt; /// /// Minimum length between each attempt to breed. /// - [DataField("minBreedAttemptInterval"), ViewVariables(VVAccess.ReadWrite)] + [DataField, ViewVariables(VVAccess.ReadWrite)] public TimeSpan MinBreedAttemptInterval = TimeSpan.FromSeconds(45); /// /// Maximum length between each attempt to breed. /// - [DataField("maxBreedAttemptInterval"), ViewVariables(VVAccess.ReadWrite)] + [DataField, ViewVariables(VVAccess.ReadWrite)] public TimeSpan MaxBreedAttemptInterval = TimeSpan.FromSeconds(60); /// /// How close to a partner an entity must be in order to breed. /// Unrealistically long. /// - [DataField("breedRange"), ViewVariables(VVAccess.ReadWrite)] + [DataField, ViewVariables(VVAccess.ReadWrite)] public float BreedRange = 3f; /// /// How many other entities with this component are allowed in range before we stop. /// - [DataField("capacity"), ViewVariables(VVAccess.ReadWrite)] + [DataField, ViewVariables(VVAccess.ReadWrite)] public int Capacity = 6; /// /// The chance that, on a given attempt, /// for each valid partner, the entity will breed. /// - [DataField("breedChance"), ViewVariables(VVAccess.ReadWrite)] + [DataField, ViewVariables(VVAccess.ReadWrite)] public float BreedChance = 0.15f; /// /// Entity prototypes for what type of /// offspring can be produced by this entity. /// - [DataField("offspring", required: true)] + [DataField(required: true)] public List Offspring = default!; /// /// Whether or not this entity has bred successfully /// and will produce offspring imminently /// - [DataField("gestating")] + [DataField] public bool Gestating; /// /// When gestation will end. /// Null if is false /// - [DataField("gestationEndTime"), ViewVariables(VVAccess.ReadWrite)] + [DataField, ViewVariables(VVAccess.ReadWrite)] public TimeSpan? GestationEndTime; /// /// How long it takes the entity after breeding /// to produce offspring /// - [DataField("gestationDuration"), ViewVariables(VVAccess.ReadWrite)] + [DataField, ViewVariables(VVAccess.ReadWrite)] public TimeSpan GestationDuration = TimeSpan.FromMinutes(1.5); /// /// How much hunger is consumed when an entity /// gives birth. A balancing tool to require feeding. /// - [DataField("hungerPerBirth"), ViewVariables(VVAccess.ReadWrite)] + [DataField, ViewVariables(VVAccess.ReadWrite)] public float HungerPerBirth = 75f; /// /// Popup shown when an entity gives birth. /// Configurable for things like laying eggs. /// - [DataField("birthPopup"), ViewVariables(VVAccess.ReadWrite)] - public string BirthPopup = "reproductive-birth-popup"; + [DataField, ViewVariables(VVAccess.ReadWrite)] + public LocId BirthPopup = "reproductive-birth-popup"; /// /// Whether or not the offspring should be made into "infants". /// - [DataField("makeOffspringInfant"), ViewVariables(VVAccess.ReadWrite)] + [DataField, ViewVariables(VVAccess.ReadWrite)] public bool MakeOffspringInfant = true; /// /// An entity whitelist for what entities /// can be this one's partner. /// - [DataField("partnerWhitelist", required: true)] + [DataField(required: true)] public EntityWhitelist PartnerWhitelist = default!; } diff --git a/Resources/Prototypes/Entities/Mobs/Cyborgs/base_borg_chassis.yml b/Resources/Prototypes/Entities/Mobs/Cyborgs/base_borg_chassis.yml index 8139994c503..126e5338495 100644 --- a/Resources/Prototypes/Entities/Mobs/Cyborgs/base_borg_chassis.yml +++ b/Resources/Prototypes/Entities/Mobs/Cyborgs/base_borg_chassis.yml @@ -94,7 +94,7 @@ - type: WiresPanel - type: ActivatableUIRequiresPanel - type: Wires - LayoutId: Borg + layoutId: Borg - type: NameIdentifier group: Silicon - type: ContainerContainer diff --git a/Resources/Prototypes/Entities/Mobs/Player/admin_ghost.yml b/Resources/Prototypes/Entities/Mobs/Player/admin_ghost.yml index c07d62946e7..3f5a7af8d3c 100644 --- a/Resources/Prototypes/Entities/Mobs/Player/admin_ghost.yml +++ b/Resources/Prototypes/Entities/Mobs/Player/admin_ghost.yml @@ -61,7 +61,7 @@ toggleAction: ActionAGhostShowStationRecords - type: SolarControlConsole # look ma i AM the computer! - type: CommunicationsConsole - title: communicationsconsole-announcement-title-centcom + title: comms-console-announcement-title-centcom color: "#228b22" - type: RadarConsole - type: CargoOrderConsole diff --git a/Resources/Prototypes/Entities/Objects/Fun/Instruments/instruments_structures.yml b/Resources/Prototypes/Entities/Objects/Fun/Instruments/instruments_structures.yml index 6dcd4ad683d..ad4d2eac8a5 100644 --- a/Resources/Prototypes/Entities/Objects/Fun/Instruments/instruments_structures.yml +++ b/Resources/Prototypes/Entities/Objects/Fun/Instruments/instruments_structures.yml @@ -164,8 +164,8 @@ - type: WiresVisuals - type: WiresPanel - type: Wires - BoardName: wires-board-name-dawinstrument - LayoutId: DawInstrument + boardName: wires-board-name-dawinstrument + layoutId: DawInstrument - type: Machine board: DawInstrumentMachineCircuitboard - type: Instrument diff --git a/Resources/Prototypes/Entities/Objects/Specific/Mech/mechs.yml b/Resources/Prototypes/Entities/Objects/Specific/Mech/mechs.yml index 725dee61d37..5eab64e73ac 100644 --- a/Resources/Prototypes/Entities/Objects/Specific/Mech/mechs.yml +++ b/Resources/Prototypes/Entities/Objects/Specific/Mech/mechs.yml @@ -54,8 +54,8 @@ - type: Clickable - type: WiresPanel - type: Wires #we just want the panel - BoardName: wires-board-name-mech - LayoutId: Mech + boardName: wires-board-name-mech + layoutId: Mech - type: Fixtures fixtures: fix1: diff --git a/Resources/Prototypes/Entities/Structures/Dispensers/booze.yml b/Resources/Prototypes/Entities/Structures/Dispensers/booze.yml index f6364f6323b..f64bc4ce018 100644 --- a/Resources/Prototypes/Entities/Structures/Dispensers/booze.yml +++ b/Resources/Prototypes/Entities/Structures/Dispensers/booze.yml @@ -17,8 +17,8 @@ - type: Machine board: BoozeDispenserMachineCircuitboard - type: Wires - BoardName: wires-board-name-booze - LayoutId: BoozeDispenser + boardName: wires-board-name-booze + layoutId: BoozeDispenser - type: GuideHelp guides: - Bartender diff --git a/Resources/Prototypes/Entities/Structures/Dispensers/chem.yml b/Resources/Prototypes/Entities/Structures/Dispensers/chem.yml index ba02da325e0..fd39cf2a5ec 100644 --- a/Resources/Prototypes/Entities/Structures/Dispensers/chem.yml +++ b/Resources/Prototypes/Entities/Structures/Dispensers/chem.yml @@ -26,8 +26,8 @@ - type: Machine board: ChemDispenserMachineCircuitboard - type: Wires - BoardName: wires-board-name-chemdispenser - LayoutId: ChemDispenser + boardName: wires-board-name-chemdispenser + layoutId: ChemDispenser - type: UpgradePowerDraw powerDrawMultiplier: 0.75 scaling: Exponential diff --git a/Resources/Prototypes/Entities/Structures/Dispensers/soda.yml b/Resources/Prototypes/Entities/Structures/Dispensers/soda.yml index 3cd8e4dbcb0..4322d56947a 100644 --- a/Resources/Prototypes/Entities/Structures/Dispensers/soda.yml +++ b/Resources/Prototypes/Entities/Structures/Dispensers/soda.yml @@ -17,8 +17,8 @@ - type: Machine board: SodaDispenserMachineCircuitboard - type: Wires - BoardName: wires-board-name-soda - LayoutId: SodaDispenser + boardName: wires-board-name-soda + layoutId: SodaDispenser - type: GuideHelp guides: - Bartender diff --git a/Resources/Prototypes/Entities/Structures/Doors/Airlocks/access.yml b/Resources/Prototypes/Entities/Structures/Doors/Airlocks/access.yml index 7dea7bfb53a..0cc5d90a1e1 100644 --- a/Resources/Prototypes/Entities/Structures/Doors/Airlocks/access.yml +++ b/Resources/Prototypes/Entities/Structures/Doors/Airlocks/access.yml @@ -207,7 +207,7 @@ - type: AccessReader access: [["Command"]] - type: Wires - LayoutId: AirlockCommand + layoutId: AirlockCommand - type: entity parent: AirlockCommand @@ -273,7 +273,7 @@ - type: AccessReader access: [["Security"]] - type: Wires - LayoutId: AirlockSecurity + layoutId: AirlockSecurity - type: entity parent: AirlockSecurity @@ -283,7 +283,7 @@ - type: AccessReader access: [["Detective"]] - type: Wires - LayoutId: AirlockSecurity + layoutId: AirlockSecurity - type: entity parent: AirlockSecurity @@ -293,7 +293,7 @@ - type: AccessReader access: [["Brig"]] - type: Wires - LayoutId: AirlockSecurity + layoutId: AirlockSecurity - type: entity parent: AirlockSecurity @@ -303,7 +303,7 @@ - type: AccessReader access: [["Armory"]] - type: Wires - LayoutId: AirlockArmory + layoutId: AirlockArmory - type: entity parent: AirlockSecurity diff --git a/Resources/Prototypes/Entities/Structures/Doors/Airlocks/base_structureairlocks.yml b/Resources/Prototypes/Entities/Structures/Doors/Airlocks/base_structureairlocks.yml index 51d3cfdda09..35f2e4d05fb 100644 --- a/Resources/Prototypes/Entities/Structures/Doors/Airlocks/base_structureairlocks.yml +++ b/Resources/Prototypes/Entities/Structures/Doors/Airlocks/base_structureairlocks.yml @@ -76,8 +76,8 @@ - type: WiresPanel - type: WiresPanelSecurity - type: Wires - BoardName: wires-board-name-airlock - LayoutId: Airlock + boardName: wires-board-name-airlock + layoutId: Airlock - type: DoorSignalControl - type: DeviceNetwork deviceNetId: Wireless @@ -134,7 +134,7 @@ price: 150 - type: Tag tags: - - Airlock + - Airlock # This tag is used to nagivate the Airlock construction graph. It's needed because the construction graph is shared between Airlock, AirlockGlass, and HighSecDoor placement: mode: SnapgridCenter diff --git a/Resources/Prototypes/Entities/Structures/Doors/Airlocks/highsec.yml b/Resources/Prototypes/Entities/Structures/Doors/Airlocks/highsec.yml index c653d2d0100..b560e8cd10f 100644 --- a/Resources/Prototypes/Entities/Structures/Doors/Airlocks/highsec.yml +++ b/Resources/Prototypes/Entities/Structures/Doors/Airlocks/highsec.yml @@ -70,8 +70,8 @@ - type: WiresPanelSecurity securityLevel: maxSecurity - type: Wires - BoardName: wires-board-name-highsec - LayoutId: HighSec + boardName: wires-board-name-highsec + layoutId: HighSec alwaysRandomize: true - type: UserInterface interfaces: @@ -100,4 +100,4 @@ - type: Tag tags: - HighSecDoor - # This tag is used to nagivate the Airlock construction graph. It's needed because this construction graph is shared between Airlock, AirlockGlass, and HighSecDoor \ No newline at end of file + # This tag is used to nagivate the Airlock construction graph. It's needed because this construction graph is shared between Airlock, AirlockGlass, and HighSecDoor diff --git a/Resources/Prototypes/Entities/Structures/Doors/Airlocks/shuttle.yml b/Resources/Prototypes/Entities/Structures/Doors/Airlocks/shuttle.yml index e6459f484a9..aa14d74838a 100644 --- a/Resources/Prototypes/Entities/Structures/Doors/Airlocks/shuttle.yml +++ b/Resources/Prototypes/Entities/Structures/Doors/Airlocks/shuttle.yml @@ -43,7 +43,7 @@ - state: panel_open map: ["enum.WiresVisualLayers.MaintenancePanel"] - type: Wires - LayoutId: Docking + layoutId: Docking - type: Door bumpOpen: false closeTimeTwo: 0.4 diff --git a/Resources/Prototypes/Entities/Structures/Doors/Firelocks/firelock.yml b/Resources/Prototypes/Entities/Structures/Doors/Firelocks/firelock.yml index e12daa537fc..dccc76e96c1 100644 --- a/Resources/Prototypes/Entities/Structures/Doors/Firelocks/firelock.yml +++ b/Resources/Prototypes/Entities/Structures/Doors/Firelocks/firelock.yml @@ -84,8 +84,8 @@ - type: WiresVisuals - type: WiresPanel - type: Wires - BoardName: wires-board-name-firelock - LayoutId: Firelock + boardName: wires-board-name-firelock + layoutId: Firelock - type: UserInterface interfaces: - key: enum.WiresUiKey.Key diff --git a/Resources/Prototypes/Entities/Structures/Doors/Windoors/base_structurewindoors.yml b/Resources/Prototypes/Entities/Structures/Doors/Windoors/base_structurewindoors.yml index 6a973c5015e..cdaba14d528 100644 --- a/Resources/Prototypes/Entities/Structures/Doors/Windoors/base_structurewindoors.yml +++ b/Resources/Prototypes/Entities/Structures/Doors/Windoors/base_structurewindoors.yml @@ -118,8 +118,8 @@ usesApcPower: true - type: WiresPanel - type: Wires - BoardName: wires-board-name-windoor - LayoutId: Airlock + boardName: wires-board-name-windoor + layoutId: Airlock - type: UserInterface interfaces: - key: enum.WiresUiKey.Key diff --git a/Resources/Prototypes/Entities/Structures/Machines/Computers/arcades.yml b/Resources/Prototypes/Entities/Structures/Machines/Computers/arcades.yml index b3463f12449..ab2bdb2c5d8 100644 --- a/Resources/Prototypes/Entities/Structures/Machines/Computers/arcades.yml +++ b/Resources/Prototypes/Entities/Structures/Machines/Computers/arcades.yml @@ -87,8 +87,8 @@ - PlushieHampter - type: WiresPanel - type: Wires - LayoutId: Arcade - BoardName: wires-board-name-arcade + layoutId: Arcade + boardName: wires-board-name-arcade - type: ActivatableUI key: enum.SpaceVillainArcadeUiKey.Key - type: ActivatableUIRequiresPower @@ -129,8 +129,8 @@ - type: ActivatableUIRequiresPower - type: WiresPanel - type: Wires - LayoutId: Arcade - BoardName: wires-board-name-arcade + layoutId: Arcade + boardName: wires-board-name-arcade - type: UserInterface interfaces: - key: enum.BlockGameUiKey.Key diff --git a/Resources/Prototypes/Entities/Structures/Machines/Medical/cryo_pod.yml b/Resources/Prototypes/Entities/Structures/Machines/Medical/cryo_pod.yml index e7ae4d2394e..2184ee73ea6 100644 --- a/Resources/Prototypes/Entities/Structures/Machines/Medical/cryo_pod.yml +++ b/Resources/Prototypes/Entities/Structures/Machines/Medical/cryo_pod.yml @@ -51,8 +51,8 @@ - type: WiresVisuals - type: WiresPanel - type: Wires - BoardName: wires-board-name-cryopod - LayoutId: CryoPod + boardName: wires-board-name-cryopod + layoutId: CryoPod - type: Damageable damageContainer: Inorganic damageModifierSet: Metallic diff --git a/Resources/Prototypes/Entities/Structures/Machines/anomaly_equipment.yml b/Resources/Prototypes/Entities/Structures/Machines/anomaly_equipment.yml index 596b2f77070..dc2b5c66781 100644 --- a/Resources/Prototypes/Entities/Structures/Machines/anomaly_equipment.yml +++ b/Resources/Prototypes/Entities/Structures/Machines/anomaly_equipment.yml @@ -38,8 +38,8 @@ - type: Appearance - type: WiresPanel - type: Wires - BoardName: wires-board-name-vessel - LayoutId: Vessel + boardName: wires-board-name-vessel + layoutId: Vessel - type: AmbientSound enabled: false range: 3 @@ -175,8 +175,8 @@ - type: WiresPanel - type: WiresVisuals - type: Wires - BoardName: wires-board-name-ape - LayoutId: Ape + boardName: wires-board-name-ape + layoutId: Ape - type: GenericVisualizer visuals: enum.PowerDeviceVisuals.Powered: @@ -264,8 +264,8 @@ doAfterDelay: 5 - type: WiresPanel - type: Wires - BoardName: wires-board-name-anomalygenerator - LayoutId: AnomalyGenerator + boardName: wires-board-name-anomalygenerator + layoutId: AnomalyGenerator - type: Destructible thresholds: - trigger: diff --git a/Resources/Prototypes/Entities/Structures/Machines/bombs.yml b/Resources/Prototypes/Entities/Structures/Machines/bombs.yml index 9bd5070b73b..580253f1189 100644 --- a/Resources/Prototypes/Entities/Structures/Machines/bombs.yml +++ b/Resources/Prototypes/Entities/Structures/Machines/bombs.yml @@ -13,7 +13,7 @@ - key: enum.WiresUiKey.Key type: WiresBoundUserInterface - type: Wires - LayoutId: Defusable + layoutId: Defusable alwaysRandomize: true - type: Defusable - type: Rotatable @@ -56,7 +56,7 @@ description: A bomb for dummies, manual not included. components: - type: Wires - LayoutId: Defusable + layoutId: Defusable alwaysRandomize: true - type: Sprite sprite: Structures/Machines/bomb.rsi diff --git a/Resources/Prototypes/Entities/Structures/Machines/chem_master.yml b/Resources/Prototypes/Entities/Structures/Machines/chem_master.yml index 8c006572ed0..e215a70f4c0 100644 --- a/Resources/Prototypes/Entities/Structures/Machines/chem_master.yml +++ b/Resources/Prototypes/Entities/Structures/Machines/chem_master.yml @@ -61,8 +61,8 @@ # Machine / Construction stuff - type: WiresPanel - type: Wires - BoardName: wires-board-name-chemmaster - LayoutId: chem_master + boardName: wires-board-name-chemmaster + layoutId: chem_master - type: Machine board: ChemMasterMachineCircuitboard - type: ContainerContainer diff --git a/Resources/Prototypes/Entities/Structures/Machines/cloning_machine.yml b/Resources/Prototypes/Entities/Structures/Machines/cloning_machine.yml index 6b3992b0d89..0cc9f71e55a 100644 --- a/Resources/Prototypes/Entities/Structures/Machines/cloning_machine.yml +++ b/Resources/Prototypes/Entities/Structures/Machines/cloning_machine.yml @@ -61,8 +61,8 @@ - Biomass - type: WiresPanel - type: Wires - BoardName: wires-board-name-cloningpod - LayoutId: CloningPod + boardName: wires-board-name-cloningpod + layoutId: CloningPod - type: ApcPowerReceiver powerLoad: 200 #Receives most of its power from the console - type: Appearance diff --git a/Resources/Prototypes/Entities/Structures/Machines/fatextractor.yml b/Resources/Prototypes/Entities/Structures/Machines/fatextractor.yml index 01b6f82e85b..d574b286c45 100644 --- a/Resources/Prototypes/Entities/Structures/Machines/fatextractor.yml +++ b/Resources/Prototypes/Entities/Structures/Machines/fatextractor.yml @@ -96,8 +96,8 @@ board: FatExtractorMachineCircuitboard - type: WiresPanel - type: Wires - BoardName: wires-board-name-fatextractor - LayoutId: FatExtractor + boardName: wires-board-name-fatextractor + layoutId: FatExtractor - type: Appearance - type: Speech speechVerb: Robotic diff --git a/Resources/Prototypes/Entities/Structures/Machines/gravity_generator.yml b/Resources/Prototypes/Entities/Structures/Machines/gravity_generator.yml index 7e2709ae95d..657c597b148 100644 --- a/Resources/Prototypes/Entities/Structures/Machines/gravity_generator.yml +++ b/Resources/Prototypes/Entities/Structures/Machines/gravity_generator.yml @@ -121,8 +121,8 @@ max: 1 - type: WiresPanel - type: Wires - BoardName: wires-board-name-minigravitygenerator - LayoutId: MiniGravityGenerator + boardName: wires-board-name-minigravitygenerator + layoutId: MiniGravityGenerator - type: Machine board: MiniGravityGeneratorCircuitboard - type: ApcPowerReceiver diff --git a/Resources/Prototypes/Entities/Structures/Machines/lathe.yml b/Resources/Prototypes/Entities/Structures/Machines/lathe.yml index a406b8e0c01..b1ea5f9e3d1 100644 --- a/Resources/Prototypes/Entities/Structures/Machines/lathe.yml +++ b/Resources/Prototypes/Entities/Structures/Machines/lathe.yml @@ -31,8 +31,8 @@ acts: ["Destruction"] - type: WiresPanel - type: Wires - BoardName: wires-board-name-autolathe - LayoutId: Autolathe + boardName: wires-board-name-autolathe + layoutId: Autolathe - type: ActivatableUI key: enum.LatheUiKey.Key - type: ActivatableUIRequiresPower @@ -187,8 +187,8 @@ - type: Machine board: ProtolatheMachineCircuitboard - type: Wires - BoardName: wires-board-name-protolathe - LayoutId: Protolathe + boardName: wires-board-name-protolathe + layoutId: Protolathe - type: MaterialStorage whitelist: tags: diff --git a/Resources/Prototypes/Entities/Structures/Machines/material_reclaimer.yml b/Resources/Prototypes/Entities/Structures/Machines/material_reclaimer.yml index bb8f6d200b7..b7886b7ca59 100644 --- a/Resources/Prototypes/Entities/Structures/Machines/material_reclaimer.yml +++ b/Resources/Prototypes/Entities/Structures/Machines/material_reclaimer.yml @@ -59,8 +59,8 @@ board: MaterialReclaimerMachineCircuitboard - type: WiresPanel - type: Wires - BoardName: wires-board-name-reclaimer - LayoutId: Reclaimer + boardName: wires-board-name-reclaimer + layoutId: Reclaimer - type: MaterialReclaimer whitelist: components: diff --git a/Resources/Prototypes/Entities/Structures/Machines/medical_scanner.yml b/Resources/Prototypes/Entities/Structures/Machines/medical_scanner.yml index 7a86fdf11ae..c8d233f04cc 100644 --- a/Resources/Prototypes/Entities/Structures/Machines/medical_scanner.yml +++ b/Resources/Prototypes/Entities/Structures/Machines/medical_scanner.yml @@ -78,8 +78,8 @@ board: MedicalScannerMachineCircuitboard - type: WiresPanel - type: Wires - BoardName: wires-board-name-medicalscanner - LayoutId: MedicalScanner + boardName: wires-board-name-medicalscanner + layoutId: MedicalScanner - type: Appearance - type: Climbable - type: ApcPowerReceiver diff --git a/Resources/Prototypes/Entities/Structures/Machines/research.yml b/Resources/Prototypes/Entities/Structures/Machines/research.yml index ef9b63ca73e..d042e9d1046 100644 --- a/Resources/Prototypes/Entities/Structures/Machines/research.yml +++ b/Resources/Prototypes/Entities/Structures/Machines/research.yml @@ -24,7 +24,7 @@ - type: ExtensionCableReceiver - type: WiresPanel - type: Wires - LayoutId: rndserver + layoutId: rndserver - type: WiresVisuals - type: Machine board: ResearchAndDevelopmentServerMachineCircuitboard diff --git a/Resources/Prototypes/Entities/Structures/Machines/telecomms.yml b/Resources/Prototypes/Entities/Structures/Machines/telecomms.yml index 1c03d011485..0f84f200bb0 100644 --- a/Resources/Prototypes/Entities/Structures/Machines/telecomms.yml +++ b/Resources/Prototypes/Entities/Structures/Machines/telecomms.yml @@ -49,8 +49,8 @@ board: TelecomServerCircuitboard - type: WiresPanel - type: Wires - BoardName: wires-board-name-telecomserver - LayoutId: TelecomServer + boardName: wires-board-name-telecomserver + layoutId: TelecomServer - type: Transform anchored: true - type: Pullable diff --git a/Resources/Prototypes/Entities/Structures/Machines/vending_machines.yml b/Resources/Prototypes/Entities/Structures/Machines/vending_machines.yml index 8e06d23ee76..839ae47ef56 100644 --- a/Resources/Prototypes/Entities/Structures/Machines/vending_machines.yml +++ b/Resources/Prototypes/Entities/Structures/Machines/vending_machines.yml @@ -64,8 +64,8 @@ type: WiresBoundUserInterface - type: WiresPanel - type: Wires - BoardName: wires-board-name-vendingmachine - LayoutId: Vending + boardName: wires-board-name-vendingmachine + layoutId: Vending - type: Anchorable - type: TypingIndicator proto: robot diff --git a/Resources/Prototypes/Entities/Structures/Piping/Atmospherics/unary.yml b/Resources/Prototypes/Entities/Structures/Piping/Atmospherics/unary.yml index c4282a2d4df..e9d1c4a30d0 100644 --- a/Resources/Prototypes/Entities/Structures/Piping/Atmospherics/unary.yml +++ b/Resources/Prototypes/Entities/Structures/Piping/Atmospherics/unary.yml @@ -241,8 +241,8 @@ key: enum.ThermomachineUiKey.Key - type: WiresPanel - type: Wires - BoardName: wires-board-name-thermomachine - LayoutId: Thermomachine + boardName: wires-board-name-thermomachine + layoutId: Thermomachine - type: WiresVisuals - type: NodeContainer nodes: diff --git a/Resources/Prototypes/Entities/Structures/Power/Generation/PA/control_box.yml b/Resources/Prototypes/Entities/Structures/Power/Generation/PA/control_box.yml index 5da747571a1..ca0cebffecd 100644 --- a/Resources/Prototypes/Entities/Structures/Power/Generation/PA/control_box.yml +++ b/Resources/Prototypes/Entities/Structures/Power/Generation/PA/control_box.yml @@ -23,8 +23,8 @@ type: WiresBoundUserInterface - type: WiresPanel - type: Wires - BoardName: wires-board-name-pa - LayoutId: ParticleAccelerator + boardName: wires-board-name-pa + layoutId: ParticleAccelerator # Unfinished diff --git a/Resources/Prototypes/Entities/Structures/Power/Generation/portable_generator.yml b/Resources/Prototypes/Entities/Structures/Power/Generation/portable_generator.yml index 0fe35f3464e..261b9a344c4 100644 --- a/Resources/Prototypes/Entities/Structures/Power/Generation/portable_generator.yml +++ b/Resources/Prototypes/Entities/Structures/Power/Generation/portable_generator.yml @@ -43,8 +43,8 @@ # Construction, interaction - type: WiresPanel - type: Wires - BoardName: wires-board-name-generator - LayoutId: Generator + boardName: wires-board-name-generator + layoutId: Generator - type: UserInterface interfaces: - key: enum.GeneratorComponentUiKey.Key diff --git a/Resources/Prototypes/Entities/Structures/Power/apc.yml b/Resources/Prototypes/Entities/Structures/Power/apc.yml index defe6d0cd4a..35a8f0f7049 100644 --- a/Resources/Prototypes/Entities/Structures/Power/apc.yml +++ b/Resources/Prototypes/Entities/Structures/Power/apc.yml @@ -91,8 +91,8 @@ - type: WallMount - type: WiresPanel - type: Wires - BoardName: wires-board-name-apc - LayoutId: APC + boardName: wires-board-name-apc + layoutId: APC - type: WiresVisuals - type: Damageable damageContainer: Inorganic diff --git a/Resources/Prototypes/Entities/Structures/Power/chargers.yml b/Resources/Prototypes/Entities/Structures/Power/chargers.yml index 8967f60e203..520b293cb5d 100644 --- a/Resources/Prototypes/Entities/Structures/Power/chargers.yml +++ b/Resources/Prototypes/Entities/Structures/Power/chargers.yml @@ -213,7 +213,7 @@ - machine_board - entity_storage - type: Wires - LayoutId: borgcharger + layoutId: borgcharger - type: WiresPanel - type: WiresVisuals - type: Machine diff --git a/Resources/Prototypes/Entities/Structures/Power/smes.yml b/Resources/Prototypes/Entities/Structures/Power/smes.yml index 08ddbe4b2a6..68d72f64f89 100644 --- a/Resources/Prototypes/Entities/Structures/Power/smes.yml +++ b/Resources/Prototypes/Entities/Structures/Power/smes.yml @@ -63,8 +63,8 @@ castShadows: false - type: WiresPanel - type: Wires - BoardName: wires-board-name-smes - LayoutId: SMES + boardName: wires-board-name-smes + layoutId: SMES - type: Machine board: SMESMachineCircuitboard - type: StationInfiniteBatteryTarget diff --git a/Resources/Prototypes/Entities/Structures/Power/substation.yml b/Resources/Prototypes/Entities/Structures/Power/substation.yml index d160ea8365f..6e3ef2f7f1a 100644 --- a/Resources/Prototypes/Entities/Structures/Power/substation.yml +++ b/Resources/Prototypes/Entities/Structures/Power/substation.yml @@ -87,8 +87,8 @@ totalIntensity: 200 - type: WiresPanel - type: Wires - BoardName: wires-board-name-substation - LayoutId: Substation + boardName: wires-board-name-substation + layoutId: Substation - type: Machine board: SubstationMachineCircuitboard - type: StationInfiniteBatteryTarget diff --git a/Resources/Prototypes/Entities/Structures/Wallmounts/air_alarm.yml b/Resources/Prototypes/Entities/Structures/Wallmounts/air_alarm.yml index 6d23dab829c..3e91daaa390 100644 --- a/Resources/Prototypes/Entities/Structures/Wallmounts/air_alarm.yml +++ b/Resources/Prototypes/Entities/Structures/Wallmounts/air_alarm.yml @@ -59,8 +59,8 @@ type: WiresBoundUserInterface - type: WiresPanel - type: Wires - BoardName: wires-board-name-airalarm - LayoutId: AirAlarm + boardName: wires-board-name-airalarm + layoutId: AirAlarm - type: AccessReader access: [["Atmospherics"]] - type: ContainerFill diff --git a/Resources/Prototypes/Entities/Structures/Wallmounts/fire_alarm.yml b/Resources/Prototypes/Entities/Structures/Wallmounts/fire_alarm.yml index da866d98231..7e0635edc82 100644 --- a/Resources/Prototypes/Entities/Structures/Wallmounts/fire_alarm.yml +++ b/Resources/Prototypes/Entities/Structures/Wallmounts/fire_alarm.yml @@ -66,8 +66,8 @@ type: WiresBoundUserInterface - type: WiresPanel - type: Wires - BoardName: wires-board-name-firealarm - LayoutId: FireAlarm + boardName: wires-board-name-firealarm + layoutId: FireAlarm - type: Sprite sprite: Structures/Wallmounts/air_monitors.rsi layers: diff --git a/Resources/Prototypes/Entities/Structures/Wallmounts/intercom.yml b/Resources/Prototypes/Entities/Structures/Wallmounts/intercom.yml index 59409f41325..c8cdcfd40aa 100644 --- a/Resources/Prototypes/Entities/Structures/Wallmounts/intercom.yml +++ b/Resources/Prototypes/Entities/Structures/Wallmounts/intercom.yml @@ -50,8 +50,8 @@ anchored: true - type: WiresPanel - type: Wires - BoardName: wires-board-name-intercom - LayoutId: Intercom + boardName: wires-board-name-intercom + layoutId: Intercom - type: ActivatableUIRequiresPower - type: ActivatableUI key: enum.IntercomUiKey.Key diff --git a/Resources/Prototypes/Entities/Structures/Wallmounts/surveillance_camera.yml b/Resources/Prototypes/Entities/Structures/Wallmounts/surveillance_camera.yml index fcdf92dab5c..8679d595e31 100644 --- a/Resources/Prototypes/Entities/Structures/Wallmounts/surveillance_camera.yml +++ b/Resources/Prototypes/Entities/Structures/Wallmounts/surveillance_camera.yml @@ -23,7 +23,7 @@ - type: WiresPanel - type: Wires alwaysRandomize: true - LayoutId: SurveillanceCamera + layoutId: SurveillanceCamera - type: Damageable damageContainer: Inorganic damageModifierSet: Metallic diff --git a/Resources/Prototypes/Entities/Structures/hydro_tray.yml b/Resources/Prototypes/Entities/Structures/hydro_tray.yml index 944ff6ebff5..f2b8feaa395 100644 --- a/Resources/Prototypes/Entities/Structures/hydro_tray.yml +++ b/Resources/Prototypes/Entities/Structures/hydro_tray.yml @@ -79,8 +79,8 @@ board: HydroponicsTrayMachineCircuitboard - type: WiresPanel - type: Wires - BoardName: wires-board-name-hydroponicstray - LayoutId: HydroponicsTray + boardName: wires-board-name-hydroponicstray + layoutId: HydroponicsTray - type: AmbientSound volume: -9 range: 5 From d99d85500cdfe84798872090a101fe0b19d9a13d Mon Sep 17 00:00:00 2001 From: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com> Date: Wed, 11 Oct 2023 14:07:21 +1100 Subject: [PATCH 067/127] Fix shuttle throwing (#20884) The original PR had a lot of strange and unperformant code. --- .../Systems/ShuttleSystem.FasterThanLight.cs | 37 +++++++++---------- .../Shuttles/Systems/ShuttleSystem.cs | 3 +- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/Content.Server/Shuttles/Systems/ShuttleSystem.FasterThanLight.cs b/Content.Server/Shuttles/Systems/ShuttleSystem.FasterThanLight.cs index e9895e89aaa..49e1b1cb84d 100644 --- a/Content.Server/Shuttles/Systems/ShuttleSystem.FasterThanLight.cs +++ b/Content.Server/Shuttles/Systems/ShuttleSystem.FasterThanLight.cs @@ -479,17 +479,20 @@ private void DoTheDinosaur(TransformComponent xform) // Get enumeration exceptions from people dropping things if we just paralyze as we go var toKnock = new ValueList(); KnockOverKids(xform, ref toKnock); + TryComp(xform.GridUid, out var grid); if (TryComp(xform.GridUid, out var shuttleBody)) { - foreach (var child in toKnock) { - if (!_statusQuery.TryGetComponent(child, out var status)) continue; + if (!_statusQuery.TryGetComponent(child, out var status)) + continue; + _stuns.TryParalyze(child, _hyperspaceKnockdownTime, true, status); // If the guy we knocked down is on a spaced tile, throw them too - TossIfSpaced(shuttleBody, child); + if (grid != null) + TossIfSpaced(grid, shuttleBody, child); } } } @@ -510,25 +513,23 @@ private void KnockOverKids(TransformComponent xform, ref ValueList to /// /// Throws people who are standing on a spaced tile, tries to throw them towards a neighbouring space tile /// - private void TossIfSpaced(PhysicsComponent shuttleBody, EntityUid tossed) + private void TossIfSpaced(MapGridComponent shuttleGrid, PhysicsComponent shuttleBody, EntityUid tossed) { - - if (!_xformQuery.TryGetComponent(tossed, out var childXform)) + if (!_xformQuery.TryGetComponent(tossed, out var childXform) ) return; - if (!_physicsQuery.TryGetComponent(tossed, out var phys)) + // only toss if its on lattice/space + var tile = shuttleGrid.GetTileRef(childXform.Coordinates); + + if (!tile.IsSpace(_tileDefManager)) return; - // only toss if its on lattice/space - var tile = childXform.Coordinates.GetTileRef(EntityManager, _mapManager); + var throwDirection = childXform.LocalPosition - shuttleBody.LocalCenter; - if (tile != null && tile.Value.IsSpace() && _mapManager.TryGetGrid(tile.Value.GridUid, out var grid)) - { - Vector2 direction = -Vector2.UnitY; + if (throwDirection == Vector2.Zero) + return; - var foo = childXform.LocalPosition - shuttleBody.LocalCenter; - _throwing.TryThrow(tossed, foo.Normalized() * 10.0f, 50.0f); - } + _throwing.TryThrow(tossed, throwDirection.Normalized() * 10.0f, 50.0f); } /// @@ -694,10 +695,8 @@ private void Smimsh(EntityUid uid, FixturesComponent? manager = null, MapGridCom return; // Flatten anything not parented to a grid. - var xformQuery = GetEntityQuery(); - var transform = _physics.GetPhysicsTransform(uid, xform, xformQuery); + var transform = _physics.GetPhysicsTransform(uid, xform, _xformQuery); var aabbs = new List(manager.Fixtures.Count); - var mobQuery = GetEntityQuery(); var immune = new HashSet(); foreach (var fixture in manager.Fixtures.Values) @@ -717,7 +716,7 @@ private void Smimsh(EntityUid uid, FixturesComponent? manager = null, MapGridCom continue; } - if (mobQuery.TryGetComponent(ent, out var mob)) + if (_bodyQuery.TryGetComponent(ent, out var mob)) { var gibs = _bobby.GibBody(ent, body: mob); immune.UnionWith(gibs); diff --git a/Content.Server/Shuttles/Systems/ShuttleSystem.cs b/Content.Server/Shuttles/Systems/ShuttleSystem.cs index cc93858948d..41e4cbc2be9 100644 --- a/Content.Server/Shuttles/Systems/ShuttleSystem.cs +++ b/Content.Server/Shuttles/Systems/ShuttleSystem.cs @@ -22,8 +22,10 @@ namespace Content.Server.Shuttles.Systems; [UsedImplicitly] public sealed partial class ShuttleSystem : SharedShuttleSystem { + [Dependency] private readonly IConfigurationManager _cfg = default!; [Dependency] private readonly IMapManager _mapManager = default!; [Dependency] private readonly IRobustRandom _random = default!; + [Dependency] private readonly ITileDefinitionManager _tileDefManager = default!; [Dependency] private readonly BodySystem _bobby = default!; [Dependency] private readonly DockingSystem _dockSystem = default!; [Dependency] private readonly DoorSystem _doors = default!; @@ -40,7 +42,6 @@ public sealed partial class ShuttleSystem : SharedShuttleSystem [Dependency] private readonly ThrowingSystem _throwing = default!; [Dependency] private readonly ThrusterSystem _thruster = default!; [Dependency] private readonly UserInterfaceSystem _uiSystem = default!; - [Dependency] private readonly IConfigurationManager _cfg = default!; private ISawmill _sawmill = default!; From ac2f914706eb7ac453c59b08c235d15b3babdaec Mon Sep 17 00:00:00 2001 From: gus Date: Tue, 10 Oct 2023 23:09:26 -0400 Subject: [PATCH 068/127] crabs look for food (#20874) Co-authored-by: gus --- Resources/Prototypes/Entities/Mobs/NPCs/animals.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml b/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml index 7af84db8e58..a79a0e0a99b 100644 --- a/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml +++ b/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml @@ -528,6 +528,9 @@ - type: Tag tags: - VimPilot + - type: HTN + rootTask: + task: RuminantCompound - type: entity name: goat From 106d7f9fdae964cd4e2b0bc29456182db21545e7 Mon Sep 17 00:00:00 2001 From: PJBot Date: Tue, 10 Oct 2023 23:10:30 -0400 Subject: [PATCH 069/127] Automatic changelog update --- Resources/Changelog/Changelog.yml | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 6ab83496c3f..2163dadf69a 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,10 +1,4 @@ Entries: -- author: Whisper - changes: - - {message: Temporarily disable the Wheelchair Bound trait until its vehicle code - is fixed., type: Tweak} - id: 4489 - time: '2023-08-09T03:10:47.0000000+00:00' - author: Doru991 changes: - {message: Space cats' EVA suits are now functional! Oxygen not included., type: Tweak} @@ -2957,3 +2951,8 @@ Entries: - {message: Ninja uncloak after attacking with melee weapons., type: Tweak} id: 4988 time: '2023-10-11T02:55:54.0000000+00:00' +- author: gusxyz + changes: + - {message: Crabs will seek out food to eat now., type: Add} + id: 4989 + time: '2023-10-11T03:09:26.0000000+00:00' From bf6827f1e9ed147acfec13df3aeef396618a14a0 Mon Sep 17 00:00:00 2001 From: Vasilis Date: Wed, 11 Oct 2023 05:11:46 +0200 Subject: [PATCH 070/127] Hopefully??? (#20865) --- Content.Server/Anomaly/Effects/ElectricityAnomalySystem.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Content.Server/Anomaly/Effects/ElectricityAnomalySystem.cs b/Content.Server/Anomaly/Effects/ElectricityAnomalySystem.cs index 0302c62f008..688218d6ca1 100644 --- a/Content.Server/Anomaly/Effects/ElectricityAnomalySystem.cs +++ b/Content.Server/Anomaly/Effects/ElectricityAnomalySystem.cs @@ -48,7 +48,7 @@ private void OnSupercritical(EntityUid uid, ElectricityAnomalyComponent componen if (mobQuery.HasComponent(ent)) validEnts.Add(ent); - if (_random.Prob(0.2f) && poweredQuery.HasComponent(ent)) + if (_random.Prob(0.01f) && poweredQuery.HasComponent(ent)) validEnts.Add(ent); } From 33d8cd49fa39f3b2487744bbf918dd08b0602ca3 Mon Sep 17 00:00:00 2001 From: PJBot Date: Tue, 10 Oct 2023 23:12:55 -0400 Subject: [PATCH 071/127] Automatic changelog update --- Resources/Changelog/Changelog.yml | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 2163dadf69a..b8d6356b598 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,9 +1,4 @@ Entries: -- author: Doru991 - changes: - - {message: Space cats' EVA suits are now functional! Oxygen not included., type: Tweak} - id: 4490 - time: '2023-08-09T03:35:15.0000000+00:00' - author: Flareguy changes: - {message: 'The overhead perspective, hueshifted-looking rocks now use sprites @@ -2956,3 +2951,9 @@ Entries: - {message: Crabs will seek out food to eat now., type: Add} id: 4989 time: '2023-10-11T03:09:26.0000000+00:00' +- author: Vasilis + changes: + - {message: Potentially fix (or hopefully at least reduce) electrical anomaly lagging + everyone on supercrit., type: Fix} + id: 4990 + time: '2023-10-11T03:11:46.0000000+00:00' From d2665b6bba567da8b8941aab52946c9d57b2de42 Mon Sep 17 00:00:00 2001 From: deltanedas <39013340+deltanedas@users.noreply.github.com> Date: Wed, 11 Oct 2023 04:17:44 +0100 Subject: [PATCH 072/127] glue only mutes if drank (#20627) * glue only mutes if drunk * glue mutes and fixes bleeding on touch * no mute on touch --------- Co-authored-by: deltanedas <@deltanedas:kde.org> --- Resources/Prototypes/Reagents/cleaning.yml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Resources/Prototypes/Reagents/cleaning.yml b/Resources/Prototypes/Reagents/cleaning.yml index a24d8e60ff9..c1f8c2b352a 100644 --- a/Resources/Prototypes/Reagents/cleaning.yml +++ b/Resources/Prototypes/Reagents/cleaning.yml @@ -67,6 +67,13 @@ viscosity: 0.5 tileReactions: - !type:SpillTileReaction + reactiveEffects: + Acidic: + methods: [ Touch ] + effects: + # pva glue? no, antibiotic glue for sealing wounds + - !type:ModifyBleedAmount + amount: -1.5 metabolisms: Narcotic: effects: @@ -76,6 +83,8 @@ type: Add time: 5 refresh: false + Drink: + effects: - !type:GenericStatusEffect key: Muted component: Muted From c7d1fb80b5513f427783167c201628435f9a9f7e Mon Sep 17 00:00:00 2001 From: ShadowCommander <10494922+ShadowCommander@users.noreply.github.com> Date: Tue, 10 Oct 2023 20:43:48 -0700 Subject: [PATCH 073/127] Add a command to hide replay UI (#19956) --- .../Ghost/GhostToggleSelfVisibility.cs | 30 ++++++++++++++++ .../Replay/ContentReplayPlaybackManager.cs | 2 ++ .../ReplayToggleScreenshotModeCommand.cs | 35 +++++++++++++++++++ .../Replay/UI/ReplaySpectateEntityState.cs | 8 +++-- 4 files changed, 73 insertions(+), 2 deletions(-) create mode 100644 Content.Client/Ghost/GhostToggleSelfVisibility.cs create mode 100644 Content.Client/Replay/ReplayToggleScreenshotModeCommand.cs diff --git a/Content.Client/Ghost/GhostToggleSelfVisibility.cs b/Content.Client/Ghost/GhostToggleSelfVisibility.cs new file mode 100644 index 00000000000..321bd9d32a4 --- /dev/null +++ b/Content.Client/Ghost/GhostToggleSelfVisibility.cs @@ -0,0 +1,30 @@ +using Content.Shared.Ghost; +using Robust.Client.GameObjects; +using Robust.Shared.Console; + +namespace Content.Client.Ghost; + +public sealed class GhostToggleSelfVisibility : IConsoleCommand +{ + public string Command => "toggleselfghost"; + public string Description => "Toggles seeing your own ghost."; + public string Help => "toggleselfghost"; + public void Execute(IConsoleShell shell, string argStr, string[] args) + { + var attachedEntity = shell.Player?.AttachedEntity; + if (!attachedEntity.HasValue) + return; + + var entityManager = IoCManager.Resolve(); + if (!entityManager.HasComponent(attachedEntity)) + { + shell.WriteError("Entity must be a ghost."); + return; + } + + if (!entityManager.TryGetComponent(attachedEntity, out SpriteComponent? spriteComponent)) + return; + + spriteComponent.Visible = !spriteComponent.Visible; + } +} diff --git a/Content.Client/Replay/ContentReplayPlaybackManager.cs b/Content.Client/Replay/ContentReplayPlaybackManager.cs index a96752383a5..cbb51172552 100644 --- a/Content.Client/Replay/ContentReplayPlaybackManager.cs +++ b/Content.Client/Replay/ContentReplayPlaybackManager.cs @@ -46,6 +46,8 @@ public sealed class ContentReplayPlaybackManager /// public Type? DefaultState; + public bool IsScreenshotMode = false; + private bool _initialized; public void Initialize() diff --git a/Content.Client/Replay/ReplayToggleScreenshotModeCommand.cs b/Content.Client/Replay/ReplayToggleScreenshotModeCommand.cs new file mode 100644 index 00000000000..40b1a135d44 --- /dev/null +++ b/Content.Client/Replay/ReplayToggleScreenshotModeCommand.cs @@ -0,0 +1,35 @@ +using Content.Client.UserInterface.Systems.Chat; +using Content.Shared.Chat; +using Robust.Client.Replays.Commands; +using Robust.Client.Replays.UI; +using Robust.Client.UserInterface; +using Robust.Shared.Console; + +namespace Content.Client.Replay; + +public sealed class ReplayToggleScreenshotModeCommand : BaseReplayCommand +{ + [Dependency] private readonly IUserInterfaceManager _userInterfaceManager = default!; + [Dependency] private readonly ContentReplayPlaybackManager _replayManager = default!; + + public override string Command => "replay_toggle_screenshot_mode"; + + public override void Execute(IConsoleShell shell, string argStr, string[] args) + { + var screen = _userInterfaceManager.ActiveScreen; + if (screen == null) + return; + + _replayManager.IsScreenshotMode = !_replayManager.IsScreenshotMode; + + var showReplayWidget = _replayManager.IsScreenshotMode; + screen.ShowWidget(showReplayWidget); + + foreach (var chatBox in _userInterfaceManager.GetUIController().Chats) + { + chatBox.ChatInput.Visible = !showReplayWidget; + if (!showReplayWidget) + chatBox.ChatInput.ChannelSelector.Select(ChatSelectChannel.Local); + } + } +} diff --git a/Content.Client/Replay/UI/ReplaySpectateEntityState.cs b/Content.Client/Replay/UI/ReplaySpectateEntityState.cs index f36c366dae4..c64201bc036 100644 --- a/Content.Client/Replay/UI/ReplaySpectateEntityState.cs +++ b/Content.Client/Replay/UI/ReplaySpectateEntityState.cs @@ -12,6 +12,8 @@ namespace Content.Client.Replay.UI; [Virtual] public class ReplaySpectateEntityState : GameplayState { + [Dependency] private readonly ContentReplayPlaybackManager _replayManager = default!; + protected override void Startup() { base.Startup(); @@ -21,11 +23,13 @@ protected override void Startup() return; screen.ShowWidget(false); - SetAnchorAndMarginPreset(screen.GetOrAddWidget(), LayoutPreset.TopLeft, margin: 10); + var replayWidget = screen.GetOrAddWidget(); + SetAnchorAndMarginPreset(replayWidget, LayoutPreset.TopLeft, margin: 10); + replayWidget.Visible = !_replayManager.IsScreenshotMode; foreach (var chatbox in UserInterfaceManager.GetUIController().Chats) { - chatbox.ChatInput.Visible = false; + chatbox.ChatInput.Visible = _replayManager.IsScreenshotMode; } } From f789de2cd3dd5259fa4677e09521cf076b0645ea Mon Sep 17 00:00:00 2001 From: PJBot Date: Tue, 10 Oct 2023 23:44:51 -0400 Subject: [PATCH 074/127] Automatic changelog update --- Resources/Changelog/Changelog.yml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index b8d6356b598..d9502b721c3 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,12 +1,4 @@ Entries: -- author: Flareguy - changes: - - {message: 'The overhead perspective, hueshifted-looking rocks now use sprites - from SS13 that match the perspective of all other walls.', type: Tweak} - - {message: Added ironrock for mappers to use. It is easily identifiable by its - bright red colors and garish appearance., type: Add} - id: 4491 - time: '2023-08-09T04:00:27.0000000+00:00' - author: Lank changes: - {message: What Moths consider to be made of cloth should now be more accurate., @@ -2957,3 +2949,11 @@ Entries: everyone on supercrit., type: Fix} id: 4990 time: '2023-10-11T03:11:46.0000000+00:00' +- author: ShadowCommander + changes: + - {message: 'Added toggleselfghost command, which toggles being able to see your + own ghost.', type: Add} + - {message: 'Added replay_toggle_screenshot_mode command, which toggles the HUD + in replay mode to look similar to ingame.', type: Add} + id: 4991 + time: '2023-10-11T03:43:48.0000000+00:00' From 440a578047539e0cd5659894e137ebf4336bd42b Mon Sep 17 00:00:00 2001 From: Leon Friedrich <60421075+ElectroJr@users.noreply.github.com> Date: Wed, 11 Oct 2023 14:45:05 +1100 Subject: [PATCH 075/127] Add mind entities to PVS overrides (#20847) --- Content.Server/GameTicking/GameTicker.Player.cs | 8 +++++++- Content.Server/Mind/MindSystem.cs | 6 ++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/Content.Server/GameTicking/GameTicker.Player.cs b/Content.Server/GameTicking/GameTicker.Player.cs index f6402589b2e..3aef1bbe785 100644 --- a/Content.Server/GameTicking/GameTicker.Player.cs +++ b/Content.Server/GameTicking/GameTicker.Player.cs @@ -29,8 +29,11 @@ private async void PlayerStatusChanged(object? sender, SessionStatusEventArgs ar if (_mind.TryGetMind(session.UserId, out var mindId, out var mind)) { - if (args.OldStatus == SessionStatus.Connecting && args.NewStatus == SessionStatus.Connected) + if (args.NewStatus != SessionStatus.Disconnected) + { mind.Session = session; + _pvsOverride.AddSessionOverride(mindId.Value, session); + } DebugTools.Assert(mind.Session == session); } @@ -109,7 +112,10 @@ private async void PlayerStatusChanged(object? sender, SessionStatusEventArgs ar { _chatManager.SendAdminAnnouncement(Loc.GetString("player-leave-message", ("name", args.Session.Name))); if (mind != null) + { + _pvsOverride.ClearOverride(mindId!.Value); mind.Session = null; + } _userDb.ClientDisconnected(session); break; diff --git a/Content.Server/Mind/MindSystem.cs b/Content.Server/Mind/MindSystem.cs index 06f97bd3b9f..373007fd1b5 100644 --- a/Content.Server/Mind/MindSystem.cs +++ b/Content.Server/Mind/MindSystem.cs @@ -7,6 +7,7 @@ using Content.Shared.Mind.Components; using Content.Shared.Players; using Robust.Server.GameObjects; +using Robust.Server.GameStates; using Robust.Server.Player; using Robust.Shared.Map; using Robust.Shared.Network; @@ -25,6 +26,7 @@ public sealed class MindSystem : SharedMindSystem [Dependency] private readonly MetaDataSystem _metaData = default!; [Dependency] private readonly SharedGhostSystem _ghosts = default!; [Dependency] private readonly SharedTransformSystem _transform = default!; + [Dependency] private readonly PvsOverrideSystem _pvsOverride = default!; public override void Initialize() { @@ -258,6 +260,8 @@ public override void TransferTo(EntityUid mindId, EntityUid? entity, bool ghostC var oldEntity = mind.OwnedEntity; if (oldComp != null && oldEntity != null) { + if (oldComp.Mind != null) + _pvsOverride.ClearOverride(oldComp.Mind.Value); oldComp.Mind = null; RaiseLocalEvent(oldEntity.Value, new MindRemovedMessage(oldEntity.Value, mind), true); } @@ -309,6 +313,7 @@ public override void SetUserId(EntityUid mindId, NetUserId? userId, MindComponen if (mind.UserId == userId) return; + _pvsOverride.ClearOverride(mindId); if (userId != null && !_players.TryGetPlayerData(userId.Value, out _)) { Log.Error($"Attempted to set mind user to invalid value {userId}"); @@ -350,6 +355,7 @@ public override void SetUserId(EntityUid mindId, NetUserId? userId, MindComponen if (_players.TryGetSessionById(userId.Value, out var ret)) { mind.Session = ret; + _pvsOverride.AddSessionOverride(mindId, ret); _actor.Attach(mind.CurrentEntity, ret); } From d4667477a5ada5d1c96c2ed25064695c909d9b27 Mon Sep 17 00:00:00 2001 From: nmajask Date: Wed, 11 Oct 2023 01:05:18 -0400 Subject: [PATCH 076/127] Add casual jumpsuit/skirts (#20422) --- .../Inventories/clothesmate.yml | 6 ++ .../Entities/Clothing/Uniforms/jumpskirts.yml | 90 ++++++++++++++++++ .../Entities/Clothing/Uniforms/jumpsuits.yml | 90 ++++++++++++++++++ ...quipped-INNERCLOTHING-jumpskirt-monkey.png | Bin 0 -> 754 bytes .../equipped-INNERCLOTHING-jumpskirt.png | Bin 0 -> 350 bytes ...equipped-INNERCLOTHING-jumpsuit-monkey.png | Bin 0 -> 749 bytes .../equipped-INNERCLOTHING-jumpsuit.png | Bin 0 -> 435 bytes .../equipped-INNERCLOTHING-shirt-monkey.png | Bin 0 -> 1005 bytes .../equipped-INNERCLOTHING-shirt.png | Bin 0 -> 570 bytes .../Jumpsuit/casual.rsi/icon-jumpskirt.png | Bin 0 -> 226 bytes .../Jumpsuit/casual.rsi/icon-jumpsuit.png | Bin 0 -> 170 bytes .../Jumpsuit/casual.rsi/icon-shirt.png | Bin 0 -> 287 bytes .../casual.rsi/inhand-left-jumpskirt.png | Bin 0 -> 210 bytes .../casual.rsi/inhand-left-jumpsuit.png | Bin 0 -> 224 bytes .../Jumpsuit/casual.rsi/inhand-left-shirt.png | Bin 0 -> 295 bytes .../casual.rsi/inhand-right-jumpskirt.png | Bin 0 -> 216 bytes .../casual.rsi/inhand-right-jumpsuit.png | Bin 0 -> 228 bytes .../casual.rsi/inhand-right-shirt.png | Bin 0 -> 313 bytes .../Uniforms/Jumpsuit/casual.rsi/meta.json | 68 +++++++++++++ 19 files changed, 254 insertions(+) create mode 100644 Resources/Textures/Clothing/Uniforms/Jumpsuit/casual.rsi/equipped-INNERCLOTHING-jumpskirt-monkey.png create mode 100644 Resources/Textures/Clothing/Uniforms/Jumpsuit/casual.rsi/equipped-INNERCLOTHING-jumpskirt.png create mode 100644 Resources/Textures/Clothing/Uniforms/Jumpsuit/casual.rsi/equipped-INNERCLOTHING-jumpsuit-monkey.png create mode 100644 Resources/Textures/Clothing/Uniforms/Jumpsuit/casual.rsi/equipped-INNERCLOTHING-jumpsuit.png create mode 100644 Resources/Textures/Clothing/Uniforms/Jumpsuit/casual.rsi/equipped-INNERCLOTHING-shirt-monkey.png create mode 100644 Resources/Textures/Clothing/Uniforms/Jumpsuit/casual.rsi/equipped-INNERCLOTHING-shirt.png create mode 100644 Resources/Textures/Clothing/Uniforms/Jumpsuit/casual.rsi/icon-jumpskirt.png create mode 100644 Resources/Textures/Clothing/Uniforms/Jumpsuit/casual.rsi/icon-jumpsuit.png create mode 100644 Resources/Textures/Clothing/Uniforms/Jumpsuit/casual.rsi/icon-shirt.png create mode 100644 Resources/Textures/Clothing/Uniforms/Jumpsuit/casual.rsi/inhand-left-jumpskirt.png create mode 100644 Resources/Textures/Clothing/Uniforms/Jumpsuit/casual.rsi/inhand-left-jumpsuit.png create mode 100644 Resources/Textures/Clothing/Uniforms/Jumpsuit/casual.rsi/inhand-left-shirt.png create mode 100644 Resources/Textures/Clothing/Uniforms/Jumpsuit/casual.rsi/inhand-right-jumpskirt.png create mode 100644 Resources/Textures/Clothing/Uniforms/Jumpsuit/casual.rsi/inhand-right-jumpsuit.png create mode 100644 Resources/Textures/Clothing/Uniforms/Jumpsuit/casual.rsi/inhand-right-shirt.png create mode 100644 Resources/Textures/Clothing/Uniforms/Jumpsuit/casual.rsi/meta.json diff --git a/Resources/Prototypes/Catalog/VendingMachines/Inventories/clothesmate.yml b/Resources/Prototypes/Catalog/VendingMachines/Inventories/clothesmate.yml index 373c8663abc..3c2fff3e753 100644 --- a/Resources/Prototypes/Catalog/VendingMachines/Inventories/clothesmate.yml +++ b/Resources/Prototypes/Catalog/VendingMachines/Inventories/clothesmate.yml @@ -38,6 +38,12 @@ ClothingUniformJumpsuitHawaiRed: 2 ClothingUniformJumpsuitHawaiYellow: 2 ClothingUniformJumpsuitFlannel: 2 + ClothingUniformJumpsuitCasualBlue: 2 + ClothingUniformJumpskirtCasualBlue: 2 + ClothingUniformJumpsuitCasualPurple: 2 + ClothingUniformJumpskirtCasualPurple: 2 + ClothingUniformJumpsuitCasualRed: 2 + ClothingUniformJumpskirtCasualRed: 2 ClothingShoesColorBlack: 8 ClothingShoesColorBrown: 4 ClothingShoesColorWhite: 3 diff --git a/Resources/Prototypes/Entities/Clothing/Uniforms/jumpskirts.yml b/Resources/Prototypes/Entities/Clothing/Uniforms/jumpskirts.yml index d0eeb5b64b9..ea1c933b4c2 100644 --- a/Resources/Prototypes/Entities/Clothing/Uniforms/jumpskirts.yml +++ b/Resources/Prototypes/Entities/Clothing/Uniforms/jumpskirts.yml @@ -835,3 +835,93 @@ - type: Construction graph: WebObjects node: jumpskirt + +- type: entity + parent: ClothingUniformSkirtBase + id: ClothingUniformJumpskirtCasualBlue + name: casual blue jumpskirt + description: A loose worn blue shirt with a grey skirt, perfect for someone looking to relax. + components: + - type: Sprite + sprite: Clothing/Uniforms/Jumpsuit/casual.rsi + layers: + - state: icon-jumpskirt + - state: icon-shirt + color: "#134fc1" + - type: Item + inhandVisuals: + left: + - state: inhand-left-jumpskirt + - state: inhand-left-shirt + color: "#134fc1" + right: + - state: inhand-right-jumpskirt + - state: inhand-right-shirt + color: "#134fc1" + - type: Clothing + sprite: Clothing/Uniforms/Jumpsuit/casual.rsi + clothingVisuals: + jumpsuit: + - state: equipped-INNERCLOTHING-jumpskirt + - state: equipped-INNERCLOTHING-shirt + color: "#134fc1" + +- type: entity + parent: ClothingUniformSkirtBase + id: ClothingUniformJumpskirtCasualPurple + name: casual purple jumpskirt + description: A loose worn purple shirt with a grey skirt, perfect for someone looking to relax. + components: + - type: Sprite + sprite: Clothing/Uniforms/Jumpsuit/casual.rsi + layers: + - state: icon-jumpskirt + - state: icon-shirt + color: "#9c0dff" + - type: Item + inhandVisuals: + left: + - state: inhand-left-jumpskirt + - state: inhand-left-shirt + color: "#9c0dff" + right: + - state: inhand-right-jumpskirt + - state: inhand-right-shirt + color: "#9c0dff" + - type: Clothing + sprite: Clothing/Uniforms/Jumpsuit/casual.rsi + clothingVisuals: + jumpsuit: + - state: equipped-INNERCLOTHING-jumpskirt + - state: equipped-INNERCLOTHING-shirt + color: "#9c0dff" + +- type: entity + parent: ClothingUniformSkirtBase + id: ClothingUniformJumpskirtCasualRed + name: casual red jumpskirt + description: A loose worn red shirt with a grey skirt, perfect for someone looking to relax. + components: + - type: Sprite + sprite: Clothing/Uniforms/Jumpsuit/casual.rsi + layers: + - state: icon-jumpskirt + - state: icon-shirt + color: "#b30000" + - type: Item + inhandVisuals: + left: + - state: inhand-left-jumpskirt + - state: inhand-left-shirt + color: "#b30000" + right: + - state: inhand-right-jumpskirt + - state: inhand-right-shirt + color: "#b30000" + - type: Clothing + sprite: Clothing/Uniforms/Jumpsuit/casual.rsi + clothingVisuals: + jumpsuit: + - state: equipped-INNERCLOTHING-jumpskirt + - state: equipped-INNERCLOTHING-shirt + color: "#b30000" diff --git a/Resources/Prototypes/Entities/Clothing/Uniforms/jumpsuits.yml b/Resources/Prototypes/Entities/Clothing/Uniforms/jumpsuits.yml index 5e857141b85..8f4dbddaa9a 100644 --- a/Resources/Prototypes/Entities/Clothing/Uniforms/jumpsuits.yml +++ b/Resources/Prototypes/Entities/Clothing/Uniforms/jumpsuits.yml @@ -1338,3 +1338,93 @@ sprite: Clothing/Uniforms/Jumpsuit/gladiator.rsi - type: Clothing sprite: Clothing/Uniforms/Jumpsuit/gladiator.rsi + +- type: entity + parent: ClothingUniformBase + id: ClothingUniformJumpsuitCasualBlue + name: casual blue jumpsuit + description: A loose worn blue shirt with a grey pants, perfect for someone looking to relax. + components: + - type: Sprite + sprite: Clothing/Uniforms/Jumpsuit/casual.rsi + layers: + - state: icon-jumpsuit + - state: icon-shirt + color: "#134fc1" + - type: Item + inhandVisuals: + left: + - state: inhand-left-jumpsuit + - state: inhand-left-shirt + color: "#134fc1" + right: + - state: inhand-right-jumpsuit + - state: inhand-right-shirt + color: "#134fc1" + - type: Clothing + sprite: Clothing/Uniforms/Jumpsuit/casual.rsi + clothingVisuals: + jumpsuit: + - state: equipped-INNERCLOTHING-jumpsuit + - state: equipped-INNERCLOTHING-shirt + color: "#134fc1" + +- type: entity + parent: ClothingUniformBase + id: ClothingUniformJumpsuitCasualPurple + name: casual purple jumpsuit + description: A loose worn purple shirt with a grey pants, perfect for someone looking to relax. + components: + - type: Sprite + sprite: Clothing/Uniforms/Jumpsuit/casual.rsi + layers: + - state: icon-jumpsuit + - state: icon-shirt + color: "#9c0dff" + - type: Item + inhandVisuals: + left: + - state: inhand-left-jumpsuit + - state: inhand-left-shirt + color: "#9c0dff" + right: + - state: inhand-right-jumpsuit + - state: inhand-right-shirt + color: "#9c0dff" + - type: Clothing + sprite: Clothing/Uniforms/Jumpsuit/casual.rsi + clothingVisuals: + jumpsuit: + - state: equipped-INNERCLOTHING-jumpsuit + - state: equipped-INNERCLOTHING-shirt + color: "#9c0dff" + +- type: entity + parent: ClothingUniformBase + id: ClothingUniformJumpsuitCasualRed + name: casual red jumpsuit + description: A loose worn red shirt with a grey pants, perfect for someone looking to relax. + components: + - type: Sprite + sprite: Clothing/Uniforms/Jumpsuit/casual.rsi + layers: + - state: icon-jumpsuit + - state: icon-shirt + color: "#b30000" + - type: Item + inhandVisuals: + left: + - state: inhand-left-jumpsuit + - state: inhand-left-shirt + color: "#b30000" + right: + - state: inhand-right-jumpsuit + - state: inhand-right-shirt + color: "#b30000" + - type: Clothing + sprite: Clothing/Uniforms/Jumpsuit/casual.rsi + clothingVisuals: + jumpsuit: + - state: equipped-INNERCLOTHING-jumpsuit + - state: equipped-INNERCLOTHING-shirt + color: "#b30000" diff --git a/Resources/Textures/Clothing/Uniforms/Jumpsuit/casual.rsi/equipped-INNERCLOTHING-jumpskirt-monkey.png b/Resources/Textures/Clothing/Uniforms/Jumpsuit/casual.rsi/equipped-INNERCLOTHING-jumpskirt-monkey.png new file mode 100644 index 0000000000000000000000000000000000000000..e6db1f9f0a6ae441723b537a5d21b88ad3f4404a GIT binary patch literal 754 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=jKx9jP7LeL$-HD>U|Qqp;uumf z=k2VGS+^Y|j{iRuDr)vAVZ}%0j(H3CFC68#a*=g=u-t;xCns&3;kR^hyN%;?zF422 z9{B}rm-rf;!k4$O*xYQ>G0S_M5Z~_B_vXeXd)HTvpZ+><+@1UG|9<~Vb4%145+&MT zNUf4(J+^AD6V zGR%9fd3&3oRPVE&^7Hl|IQa14pB=v2HhUE8<4-96lCGFPwQhSI!<)AgO*|NHw3S^F zZF{wbv(fEPsq~aXL0(f&KV@LJnIrc2W5qu9hKB_mcP|G&zFRVD!`ZiA{r&tra+O5G zybhMeZq?g=&(^q4-FS&;!z_Ue3%@1*PRCDQVs*0LVQ+OB!-2=D3+IQ+UbsF*O8$!M zwfapl3U2BiPMWRVPIBU{HZ^~CE1m7(l#lT6=a#>|*l~fpT<(;p>f$x6e>iN6*ZF70 z&y3jjDtA-w+Yi(Grhm29W<9K6%4r=U?A~hg%~;LL>C9yy)yGvirNv|IM}`0)Cf?go zEAMYu8&Numx!}42`vdP6N0VoNS@P3t?!-&xg|F=n#A{vdOHH;8%WS>;=nJFDqc5BO zPqz5Cga1OVgSiaDUAB_LjM$jM*-?AcSmxQ?VJu}b(w!wKe0*}n{KG1X_HD~rC@IyJ z_)h<7R_JzCq3?APDhsDLec*3+UTNOOqPg@{iPg%g2|@QRe6{iC&EYQm$FFdni@D+T zu2m5_N)hwy^XgFTDS*{5^Bh7PFUiGtZ_~B+r_d{YAcb-^Z87tM}~n`Da==`P*yHa}}lkYzt$d eNoQyCAJ*A+LLtp=Gu45Kn8DN4&t;ucLK6VV=2r~> literal 0 HcmV?d00001 diff --git a/Resources/Textures/Clothing/Uniforms/Jumpsuit/casual.rsi/equipped-INNERCLOTHING-jumpskirt.png b/Resources/Textures/Clothing/Uniforms/Jumpsuit/casual.rsi/equipped-INNERCLOTHING-jumpskirt.png new file mode 100644 index 0000000000000000000000000000000000000000..39d5c95a89345cce5d0625d6df8917394d8be978 GIT binary patch literal 350 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=jKx9jP7LeL$-D%zB|KdmLn`LH zy=B|iY#`9~P=EDWfy+fLCpBvr-rX;3*|P0UmGlkYMIH7JLvPf|a|Yh{R3lNI%n39G z1m;coSoqz@{QO<-owMz&E1mD|{d)aJg!Hplac6vL@9&S<{r-1S+Ah78JFCO~o;RJW zHz_9QvdN?+0#2E?!!%WW^Lrl~y2Wl&iCAI1GPM3G=ZC`Y#pmuHowsz#l;UYKb>*(E z&AJx9H}dkLG_{w{^F4yjMNSe)o}$8gxZsN7in#jX3p?+w{rK>Gm^{QaK=Oan?&$)D zPG1Y*SSWK>{*M`maTg&ck9yk_qX3JlStkw7u(CTTHnK?U-qW$V|NRy!Px%r%6OXRCt{2nz4)8U>L@q+;?e+WN|QHmktMUJxJ(K3)-#Q{U1)f*|}4f{uM65 zfm^pmde@;OaH}pIx+&ZgJZNjb4)zPt8ug9F56<@oqJAcMo;=}uWAX-I7=~dOhG7_n zVHoDrFenR89ShCpFC+kr$K!Ne&+{YzeE9L*cqPsN03RQJ<8D4jxQDrR=5yb%0AQ>B z)#ERc1}T76tA!*{Wh6Q;5g3G_J+eD$;>8Q#WsDaCMf_ZC4wN3uInO65;%^N zzE36-yuH6S-p}VG0~ESK;M3)08i3LU76C+2WEci%muLa_zMt;=Y&J{BE0xMoLRi(0 zjT)nbk90R2f0Q>5b(o)3+0P6L+@%r`_0MNgF((JMi8in_UKVXE&O}qkO7*)!q?%I7yj61{7r{4~ zA`|{Iaknz(L$ZzCXs>)<)&DFds6~)m18!x@0AG@XG=6Bl&i|0cx3PB(Xs;|27P7G$>$I|CMQQ+vB31U76!FJ3 zK(_(iZ~(du=!OH(Z9q31fNlf2;Q(|S&%ZY0xzGPf!c&9i-B$8+s|T` z!z4CcZFMtuXc&e$T{@kPZVMz%{xnEJN{NAOV(M5+Z7PN5d2%!wmFgi+cj{Oe*d}>< z`IY2Xp96%IB8^z1)9pr6W9fT-~$OnNu1puJYXsmTouh)$*45=Q-Y|=05*#w4R f7=~dO=Be=)!vIeqL5ot<00000NkvXXu0mjfy0A)! literal 0 HcmV?d00001 diff --git a/Resources/Textures/Clothing/Uniforms/Jumpsuit/casual.rsi/equipped-INNERCLOTHING-jumpsuit.png b/Resources/Textures/Clothing/Uniforms/Jumpsuit/casual.rsi/equipped-INNERCLOTHING-jumpsuit.png new file mode 100644 index 0000000000000000000000000000000000000000..b570cd06383437a9295a1a48c17923a7fa56fbf8 GIT binary patch literal 435 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=jKx9jP7LeL$-D%zb3I)gLn`LH zy=9x%Vj#f!K+&t!X03k16YhXw2EO;)KiDov?NoJ5d7}D8E%}W9r0=2H5#M@y6S^gp zfF?megL;qQ=XsyY&(u$@nK^Ui>s@Cjtb3i7Htkurf$`Sd-81iR%MJUt`wP=jk*~G( z!h*h+UA$I4jp1;NX$XnE?)}fAZ^_nW5#E0LDwvZbE8m}GRvJCrg Zum{cE|8@S9{Hq}MdAjPx&r%6OXRCt{2nlWhGKoo|5`Rp1OFBv>&=vV?BO=(H8xNBtU!AtgRf`n#P#&$1B z$dakEAwfmTm>NnFC|GL=ow`^!_r0+CRaQel$~kp<i7k8y;EK=kjS)oeCV8@8`aPhPmsot+&Jk(9R3EN~P>!X36H z#AW+*7(-iNdOM0DkJx_=MP&{bl{wTf$cS4ipazWCXGIObdAW%5 zaxvC-7>hNzk1|6*Xc~;72!=6e`o{SCk@nDubk^I#@^aKt@6-BUhC`Hygo~hbsoby3 zVWU*QQer%AlnU6d%wdVKnSFTxSYiyVa&fFae@>8PigU%|L^=Rpdp#-pwBe7&qV`GL zxdzlyZQDw2h%rtpX;Y~ILL_H_hm6WBpld+Z4rGlEK-LaqjSfK84rGlEK-LaqjSfK8 z4rGlEK-Laqjr5uzFj$3o^(2QzYF#iZ+)@GGuGRhyOaB5K#<1YJ#99Z$*W|eUzDR01 zjDfWdXu)-9GcTV{=}#=UZoE$q*ChaOhWqgjV-Ve!SA}cvL;!=W@-Phfd#SStN;QC= z39u{+rfFiqb;-7Em9CVqZ97f`_aS{=V5;y1k>oyor_+h|HocLn3)lN(Sjg(a%qx zV3Fle>0Kdx6s2CT8)s){n4h0laz>PKy65F0PWlnv{<_9yK0otftkGyR8jVJy(P%Up b%_HUyK{#;AB$-Mn00000NkvXXu0mjfv*y}$ literal 0 HcmV?d00001 diff --git a/Resources/Textures/Clothing/Uniforms/Jumpsuit/casual.rsi/equipped-INNERCLOTHING-shirt.png b/Resources/Textures/Clothing/Uniforms/Jumpsuit/casual.rsi/equipped-INNERCLOTHING-shirt.png new file mode 100644 index 0000000000000000000000000000000000000000..e89f172b4a6a5b486e5b3cae737e27e20f9e39d3 GIT binary patch literal 570 zcmV-A0>%A_P)Px$^hrcPRCt{2nqiKFAPj};W-q}tm}BU1;TUiXdkpr+P7Sh%z=*S(eP3dt0=~9l zLo7r900000;D0ie8bfkzjR{IAdORLe+%^%Bb1pD5&C9ZTW>MgToW7hZrMCObyq&k| zf7BWy&Jz(CW5V=&`1HIMqhcekMD&$XG|w|J^LEVhOwx9#es~_nn6R#E5Y}}K;`C9Q zj2)q0;!6FZxCoWnt_VPj^F8`ipMX+|thMC5-`&$%@4iLvJy~ma_pTtPpQA^=m?Mla zL2JDePMsE*`A0wRJuOL6YT*w3(-|NcHqEX_NWVBUzrtw!>Hr*FxAtpgwEkzQu{P>g zjeCcF^*SJC)Z4BlO@?R5u|(5KP!>IDB9a8OEX$M|)60=QQGO-ZqhB3>xTDFew&HAi zG_I9*>jMA)0000000000000qv|CDsj4Jm{7;G7G&AEh-k*9A$&(0zgEY@GIiIq zT4@e|_kJry#e#PSAU#j_2h{R%aWof<(Zo*YY-*uc9?y}A-syM_vFEk`5Z(K>&p6sI zSj#1!05k8B;%Kb3n{Ljg7P_j(XXWWT_zgAy000000Pu(T0y1w&6`{e&`~Uy|07*qo IM6N<$fz>% literal 0 HcmV?d00001 diff --git a/Resources/Textures/Clothing/Uniforms/Jumpsuit/casual.rsi/icon-jumpskirt.png b/Resources/Textures/Clothing/Uniforms/Jumpsuit/casual.rsi/icon-jumpskirt.png new file mode 100644 index 0000000000000000000000000000000000000000..ced9f44050a3572ab6c0288e8e1940db080376cb GIT binary patch literal 226 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz#^NA%Cx&(BWL^R}b39!fLn2z= zUbN*qtiaRu&^&ZGNBm(+SH1&(&DSx0@)CdHFJgM`ox2lH#IwT=9EvRhP8@u-I-zg> zzY5uUK5BjY_JZKIN>1l~ZmB=Fvzz0#>xsq7muE1FL|hkbsJ&n9)p<>-IDO9bsK`8) z0$+#Yug|`zy&0IzYwYZzxBt~_>o+-CN(a)V7}D4r)`~U+b?tsXH}fxxW%2Vz0*AgZ YRkfSueLtWP3Unufr>mdKI;Vst06P9y?EnA( literal 0 HcmV?d00001 diff --git a/Resources/Textures/Clothing/Uniforms/Jumpsuit/casual.rsi/icon-jumpsuit.png b/Resources/Textures/Clothing/Uniforms/Jumpsuit/casual.rsi/icon-jumpsuit.png new file mode 100644 index 0000000000000000000000000000000000000000..ea1c19df7228170bd1b54a738896bfa00386c5d5 GIT binary patch literal 170 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz#^NA%Cx&(BWL^R}DV{ElArY-_ zFYe}TFyL{$$i8UP8`DkyZ6cMK9av2|3l=Qcx%`WHkqS_0f|F+I|4Hv7)26w%L}eeI zWgMUFd;adGRzXGM$um=|3SJ{kZ3 literal 0 HcmV?d00001 diff --git a/Resources/Textures/Clothing/Uniforms/Jumpsuit/casual.rsi/icon-shirt.png b/Resources/Textures/Clothing/Uniforms/Jumpsuit/casual.rsi/icon-shirt.png new file mode 100644 index 0000000000000000000000000000000000000000..4f6448c92ef122ebf4737f49251631de50708fd1 GIT binary patch literal 287 zcmV+)0pR|LP)Px#*-1n}R9J=Wl)(+dAPhx+sxIL*Sfh+jck8w0TDq&psI(p5CUpj06q-BE~q> znC?I+1px4x{HRj>YTS(F1g^fn_3L?#jH^}OiCcaLT7Iqeb^>%QLar%Ty_gFbL|Npv!CHuGM>|>0F-38BOvgyPbCYK8X)dPXW(yiCd*X*x) ze`0yklC9UKr=GMqUps5ro8R;98+*oI|5|$e-ih5wDxTYNrRSBum(|>PH04kBzt2%u zt0DS71cZLwv4k&v?IyYDS0Anpz54igSlCyI6(3lIj>Pb`?#|)?sq=L8b6Mw<&;$To C4OQ9z literal 0 HcmV?d00001 diff --git a/Resources/Textures/Clothing/Uniforms/Jumpsuit/casual.rsi/inhand-left-jumpsuit.png b/Resources/Textures/Clothing/Uniforms/Jumpsuit/casual.rsi/inhand-left-jumpsuit.png new file mode 100644 index 0000000000000000000000000000000000000000..346f153e134321211629a109ecbbfc4ce2605dcd GIT binary patch literal 224 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=jKx9jP7LeL$-D$|W_h|ehE&XX zd()chkb?;81?`B|FE^?f+f> zd~eXF?vsTk)$gZ2|GfV*#HmdKI;Vst04T9u`~Uy| literal 0 HcmV?d00001 diff --git a/Resources/Textures/Clothing/Uniforms/Jumpsuit/casual.rsi/inhand-left-shirt.png b/Resources/Textures/Clothing/Uniforms/Jumpsuit/casual.rsi/inhand-left-shirt.png new file mode 100644 index 0000000000000000000000000000000000000000..fd167d63e424e16076d0ea600c6018fbf1865a3a GIT binary patch literal 295 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=jKx9jP7LeL$-D$|9(uYshE&XX zd-EXgVFdw~i@v)S@V+Y8d7CZQLGnq9Xrhj4MH1`F{mLH6Ir_^DnSnZhz~J!RY_FAl z*U~@#+Bzj@?pf>4AuT(qdky)%C-ubFvy|TR-&uXu^19mdJ@W5r-(Gh9UYWbMzU`H= zhuVTENlQhHjky)yw7>nH_URUPy8vHx{o=d-C(f*1eQvj_{jPBL(7EMqMXa;xOxE|U zvdVw5kVpFO+}zvC<}W-4wVoj%aFtn9RL`B%mER(K@4D$*GQKjavh?0|JZsgrij&$G lG;Td!Iy>xEG6RENCF8=>S(l|I@hX5E?&<31vd$@?2>|Qbc!K}{ literal 0 HcmV?d00001 diff --git a/Resources/Textures/Clothing/Uniforms/Jumpsuit/casual.rsi/inhand-right-jumpskirt.png b/Resources/Textures/Clothing/Uniforms/Jumpsuit/casual.rsi/inhand-right-jumpskirt.png new file mode 100644 index 0000000000000000000000000000000000000000..e9a1b16700b5e55c25919190751c8be944b0b697 GIT binary patch literal 216 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=jKx9jP7LeL$-D$|CV9FzhE&XX zd()chuz>*U0bh@oaqI>^{yo1a7_+*3l>^u5AHp3|&X{mBb+WI1=L*yT1RtI+%Z%!q zQ-AyBp8i`)3uTm-Zs9pBuyjhre8G)R=Hy>bu0J+)&-Yu4KilM=yEf-+^xa3-u4iWc z*5CV-6|8?j=3did)oZpL&aTSt`MwHDTWm4p)%lP;@5Y)K-ZH_KRFG0nS3j3^P6CsK)Hz%vLV`mlD^<6e`J!g4qTkX5~XRqx! z8ea3)N^|M6;=T5t%42o)A%-n4+j?w=TWLCo3fm|fR|KSwtrEX{fNB3T#-gvq20qFn Q8$e1uUHx3vIVCg!0Q|LH7XSbN literal 0 HcmV?d00001 diff --git a/Resources/Textures/Clothing/Uniforms/Jumpsuit/casual.rsi/inhand-right-shirt.png b/Resources/Textures/Clothing/Uniforms/Jumpsuit/casual.rsi/inhand-right-shirt.png new file mode 100644 index 0000000000000000000000000000000000000000..9304ca453af4d37718cbdae95abb7a8b20e5dd80 GIT binary patch literal 313 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=jKx9jP7LeL$-D$|K6|=2hE&XX zd-EXgVFjMn#HdovYYBZluT3Kk%N@2Abe*EM#VdNnzxN!RRbF#q;y8d>K){K^(PdBE zY0K*DS{9{8me1RB+$-0g=kwMy&G*ohmHU;u{F$g=c&PrVUuC|b?K4}f)~{N(v+9$X z`hhb|GuO7SSan=N{+rvzvm(hc@nL(fudVUdRsP3rH)*@v+KX=czvbO~rXFx*vGJ`J z*YBOIzIi*xc5iBA+54YMZ+>EeIDnzeEIRp4@^*=vv(_5gUCrtJsGYZ0JnwdRdATvS zviY&)v)3B_>$oZPSnjUc|az4y85}Sb4q9e E0A+uGWdHyG literal 0 HcmV?d00001 diff --git a/Resources/Textures/Clothing/Uniforms/Jumpsuit/casual.rsi/meta.json b/Resources/Textures/Clothing/Uniforms/Jumpsuit/casual.rsi/meta.json new file mode 100644 index 00000000000..91a74ea1726 --- /dev/null +++ b/Resources/Textures/Clothing/Uniforms/Jumpsuit/casual.rsi/meta.json @@ -0,0 +1,68 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Made by nmajask (github) for ss14, based on sprites by Tokiko (github)", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "icon-jumpsuit" + }, + { + "name": "icon-jumpskirt" + }, + { + "name": "icon-shirt" + }, + { + "name": "equipped-INNERCLOTHING-jumpsuit", + "directions": 4 + }, + { + "name": "equipped-INNERCLOTHING-jumpskirt", + "directions": 4 + }, + { + "name": "equipped-INNERCLOTHING-shirt", + "directions": 4 + }, + { + "name": "equipped-INNERCLOTHING-jumpsuit-monkey", + "directions": 4 + }, + { + "name": "equipped-INNERCLOTHING-jumpskirt-monkey", + "directions": 4 + }, + { + "name": "equipped-INNERCLOTHING-shirt-monkey", + "directions": 4 + }, + { + "name": "inhand-left-jumpsuit", + "directions": 4 + }, + { + "name": "inhand-left-jumpskirt", + "directions": 4 + }, + { + "name": "inhand-left-shirt", + "directions": 4 + }, + { + "name": "inhand-right-jumpsuit", + "directions": 4 + }, + { + "name": "inhand-right-jumpskirt", + "directions": 4 + }, + { + "name": "inhand-right-shirt", + "directions": 4 + } + ] +} From e911c9e516dd0ccbc1ff9e4adb8e73a9b7bc87d7 Mon Sep 17 00:00:00 2001 From: deltanedas <39013340+deltanedas@users.noreply.github.com> Date: Wed, 11 Oct 2023 07:34:51 +0100 Subject: [PATCH 077/127] Rename SmokeDissipateSpawnComponent to SpawnOnDespawnComponent (#20782) --- .../SmokeDissipateSpawnComponent.cs | 16 -------------- .../Fluids/EntitySystems/SmokeSystem.cs | 11 ---------- .../Components/SpawnOnDespawnComponent.cs | 18 +++++++++++++++ .../EntitySystems/SpawnOnDespawnSystem.cs | 22 +++++++++++++++++++ .../Entities/Effects/chemistry_effects.yml | 4 ++-- 5 files changed, 42 insertions(+), 29 deletions(-) delete mode 100644 Content.Server/Chemistry/Components/SmokeDissipateSpawnComponent.cs create mode 100644 Content.Server/Spawners/Components/SpawnOnDespawnComponent.cs create mode 100644 Content.Server/Spawners/EntitySystems/SpawnOnDespawnSystem.cs diff --git a/Content.Server/Chemistry/Components/SmokeDissipateSpawnComponent.cs b/Content.Server/Chemistry/Components/SmokeDissipateSpawnComponent.cs deleted file mode 100644 index 068ac432b65..00000000000 --- a/Content.Server/Chemistry/Components/SmokeDissipateSpawnComponent.cs +++ /dev/null @@ -1,16 +0,0 @@ -using Content.Server.Fluids.EntitySystems; -using Robust.Shared.Prototypes; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; - -namespace Content.Server.Chemistry.Components; - - -/// -/// When a despawns this will spawn another entity in its place. -/// -[RegisterComponent, Access(typeof(SmokeSystem))] -public sealed partial class SmokeDissipateSpawnComponent : Component -{ - [DataField("prototype", required: true, customTypeSerializer:typeof(PrototypeIdSerializer))] - public string Prototype = string.Empty; -} diff --git a/Content.Server/Fluids/EntitySystems/SmokeSystem.cs b/Content.Server/Fluids/EntitySystems/SmokeSystem.cs index b3590fec402..2f62f54fd16 100644 --- a/Content.Server/Fluids/EntitySystems/SmokeSystem.cs +++ b/Content.Server/Fluids/EntitySystems/SmokeSystem.cs @@ -38,17 +38,6 @@ public override void Initialize() SubscribeLocalEvent(OnSmokeUnpaused); SubscribeLocalEvent(OnReactionAttempt); SubscribeLocalEvent(OnSmokeSpread); - SubscribeLocalEvent(OnSmokeDissipate); - } - - private void OnSmokeDissipate(EntityUid uid, SmokeDissipateSpawnComponent component, ref TimedDespawnEvent args) - { - if (!TryComp(uid, out var xform)) - { - return; - } - - Spawn(component.Prototype, xform.Coordinates); } private void OnSmokeSpread(EntityUid uid, SmokeComponent component, ref SpreadNeighborsEvent args) diff --git a/Content.Server/Spawners/Components/SpawnOnDespawnComponent.cs b/Content.Server/Spawners/Components/SpawnOnDespawnComponent.cs new file mode 100644 index 00000000000..24b57a4b1c0 --- /dev/null +++ b/Content.Server/Spawners/Components/SpawnOnDespawnComponent.cs @@ -0,0 +1,18 @@ +using Content.Server.Spawners.EntitySystems; +using Robust.Shared.Prototypes; +using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; + +namespace Content.Server.Spawners.Components; + +/// +/// When a TimedDespawnComponent" despawns, another one will be spawned in its place. +/// +[RegisterComponent, Access(typeof(SpawnOnDespawnSystem))] +public sealed partial class SpawnOnDespawnComponent : Component +{ + /// + /// Entity prototype to spawn. + /// + [DataField(required: true)] + public EntProtoId Prototype = string.Empty; +} diff --git a/Content.Server/Spawners/EntitySystems/SpawnOnDespawnSystem.cs b/Content.Server/Spawners/EntitySystems/SpawnOnDespawnSystem.cs new file mode 100644 index 00000000000..77927c9bba9 --- /dev/null +++ b/Content.Server/Spawners/EntitySystems/SpawnOnDespawnSystem.cs @@ -0,0 +1,22 @@ +using Content.Server.Spawners.Components; +using Robust.Shared.Spawners; + +namespace Content.Server.Spawners.EntitySystems; + +public sealed class SpawnOnDespawnSystem : EntitySystem +{ + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnDespawn); + } + + private void OnDespawn(EntityUid uid, SpawnOnDespawnComponent comp, ref TimedDespawnEvent args) + { + if (!TryComp(uid, out var xform)) + return; + + Spawn(comp.Prototype, xform.Coordinates); + } +} diff --git a/Resources/Prototypes/Entities/Effects/chemistry_effects.yml b/Resources/Prototypes/Entities/Effects/chemistry_effects.yml index 10e2f1f7db7..415ecd4a986 100644 --- a/Resources/Prototypes/Entities/Effects/chemistry_effects.yml +++ b/Resources/Prototypes/Entities/Effects/chemistry_effects.yml @@ -89,7 +89,7 @@ animationTime: 0.6 animationState: mfoam-dissolve - type: Smoke - - type: SmokeDissipateSpawn + - type: SpawnOnDespawn prototype: FoamedIronMetal - type: entity @@ -109,7 +109,7 @@ animationTime: 0.6 animationState: mfoam-dissolve - type: Smoke - - type: SmokeDissipateSpawn + - type: SpawnOnDespawn prototype: FoamedAluminiumMetal - type: entity From 1dd0327d73de69b1f240d723fa5e12bd375f63b5 Mon Sep 17 00:00:00 2001 From: RadioMull <147113069+RadioMull@users.noreply.github.com> Date: Wed, 11 Oct 2023 02:36:17 -0400 Subject: [PATCH 078/127] Fix typo (#20772) --- .../Client/UserInterface/Controls/ListContainerTest.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Content.Tests/Client/UserInterface/Controls/ListContainerTest.cs b/Content.Tests/Client/UserInterface/Controls/ListContainerTest.cs index d7303470693..690bda505cc 100644 --- a/Content.Tests/Client/UserInterface/Controls/ListContainerTest.cs +++ b/Content.Tests/Client/UserInterface/Controls/ListContainerTest.cs @@ -80,7 +80,7 @@ public void TestOnlyVisibleItemsAreAdded() { /* * 6 items * 10 height + 5 separation * 3 height = 75 - * One items should be off the render + * One item should be off the render * 0 13 26 39 52 65 | 75 height */ var root = new Control { MinSize = new Vector2(50, 60) }; From 756fd6f309f4e603ce0e0c77f24b778007e00c0a Mon Sep 17 00:00:00 2001 From: Kara Date: Wed, 11 Oct 2023 02:04:33 -0700 Subject: [PATCH 079/127] Kill `GravityExtensions` (#20911) --- .../MovementIgnoreGravityComponent.cs | 55 ------------------- 1 file changed, 55 deletions(-) diff --git a/Content.Shared/Movement/Components/MovementIgnoreGravityComponent.cs b/Content.Shared/Movement/Components/MovementIgnoreGravityComponent.cs index bade6287e8b..77c468e871f 100644 --- a/Content.Shared/Movement/Components/MovementIgnoreGravityComponent.cs +++ b/Content.Shared/Movement/Components/MovementIgnoreGravityComponent.cs @@ -31,59 +31,4 @@ public MovementIgnoreGravityComponentState(MovementIgnoreGravityComponent compon Weightless = component.Weightless; } } - - public static class GravityExtensions - { - [Obsolete("Use GravitySystem")] - public static bool IsWeightless(this EntityUid entity, PhysicsComponent? body = null, EntityCoordinates? coords = null, IMapManager? mapManager = null, IEntityManager? entityManager = null) - { - entityManager ??= IoCManager.Resolve(); - - if (body == null) - entityManager.TryGetComponent(entity, out body); - - if ((body?.BodyType & (BodyType.Static | BodyType.Kinematic)) != 0) - return false; - - if (entityManager.TryGetComponent(entity, out var ignoreGravityComponent)) - return ignoreGravityComponent.Weightless; - - var transform = entityManager.GetComponent(entity); - var gridId = transform.GridUid; - - if ((entityManager.TryGetComponent(transform.GridUid, out var gravity) || - entityManager.TryGetComponent(transform.MapUid, out gravity)) && gravity.EnabledVV) - return false; - - if (gridId == null) - { - return true; - } - - mapManager ??= IoCManager.Resolve(); - var grid = mapManager.GetGrid(gridId.Value); - var invSys = EntitySystem.Get(); - - if (invSys.TryGetSlotEntity(entity, "shoes", out var ent)) - { - if (entityManager.TryGetComponent(ent, out var boots) && boots.On) - return false; - } - - if (!entityManager.GetComponent(grid.Owner).EnabledVV) - { - return true; - } - - coords ??= transform.Coordinates; - - if (!coords.Value.IsValid(entityManager)) - { - return true; - } - - var tile = grid.GetTileRef(coords.Value).Tile; - return tile.IsEmpty; - } - } } From 14dac914ce773a9da085dd57c69aaa21eb228fd2 Mon Sep 17 00:00:00 2001 From: Kara Date: Wed, 11 Oct 2023 02:17:59 -0700 Subject: [PATCH 080/127] Kill `UserInterfaceHelpers` (#20912) --- .../CommunicationsConsoleComponent.cs | 2 - .../CommunicationsConsoleSystem.cs | 47 ++++++----- Content.Server/Crayon/CrayonComponent.cs | 2 - Content.Server/Crayon/CrayonSystem.cs | 28 +++---- .../Instruments/InstrumentComponent.cs | 2 - .../Instruments/InstrumentSystem.cs | 6 +- .../Components/HealthAnalyzerComponent.cs | 2 - .../Medical/HealthAnalyzerSystem.cs | 12 +-- .../UserInterface/ActivatableUIComponent.cs | 2 - .../UserInterface/ActivatableUISystem.cs | 77 ++++++++++++------- .../UserInterface/IntrinsicUISystem.cs | 9 +-- .../UserInterface/UserInterfaceHelpers.cs | 13 ---- 12 files changed, 104 insertions(+), 98 deletions(-) delete mode 100644 Content.Server/UserInterface/UserInterfaceHelpers.cs diff --git a/Content.Server/Communications/CommunicationsConsoleComponent.cs b/Content.Server/Communications/CommunicationsConsoleComponent.cs index 82a4a945397..e2aa0d76201 100644 --- a/Content.Server/Communications/CommunicationsConsoleComponent.cs +++ b/Content.Server/Communications/CommunicationsConsoleComponent.cs @@ -55,7 +55,5 @@ public sealed partial class CommunicationsConsoleComponent : SharedCommunication /// [DataField] public SoundSpecifier Sound = new SoundPathSpecifier("/Audio/Announcements/announce.ogg"); - - public PlayerBoundUserInterface? UserInterface => Owner.GetUIOrNull(CommunicationsConsoleUiKey.Key); } } diff --git a/Content.Server/Communications/CommunicationsConsoleSystem.cs b/Content.Server/Communications/CommunicationsConsoleSystem.cs index e2a96335d01..b5c93854929 100644 --- a/Content.Server/Communications/CommunicationsConsoleSystem.cs +++ b/Content.Server/Communications/CommunicationsConsoleSystem.cs @@ -72,8 +72,8 @@ public override void Update(float frameTime) comp.UIUpdateAccumulator -= UIUpdateInterval; - if (comp.UserInterface is { } ui && ui.SubscribedSessions.Count > 0) - UpdateCommsConsoleInterface(uid, comp); + if (_uiSystem.TryGetUi(uid, CommunicationsConsoleUiKey.Key, out var ui) && ui.SubscribedSessions.Count > 0) + UpdateCommsConsoleInterface(uid, comp, ui); } base.Update(frameTime); @@ -121,9 +121,11 @@ public void UpdateCommsConsoleInterface() /// /// Updates the UI for a particular comms console. /// - /// - public void UpdateCommsConsoleInterface(EntityUid uid, CommunicationsConsoleComponent comp) + public void UpdateCommsConsoleInterface(EntityUid uid, CommunicationsConsoleComponent comp, PlayerBoundUserInterface? ui = null) { + if (ui == null && !_uiSystem.TryGetUi(uid, CommunicationsConsoleUiKey.Key, out ui)) + return; + var stationUid = _stationSystem.GetOwningStation(uid); List? levels = null; string currentLevel = default!; @@ -151,15 +153,14 @@ public void UpdateCommsConsoleInterface(EntityUid uid, CommunicationsConsoleComp } } - if (comp.UserInterface is not null) - _uiSystem.SetUiState(comp.UserInterface, new CommunicationsConsoleInterfaceState( - CanAnnounce(comp), - CanCallOrRecall(comp), - levels, - currentLevel, - currentDelay, - _roundEndSystem.ExpectedCountdownEnd - )); + _uiSystem.SetUiState(ui, new CommunicationsConsoleInterfaceState( + CanAnnounce(comp), + CanCallOrRecall(comp), + levels, + currentLevel, + currentDelay, + _roundEndSystem.ExpectedCountdownEnd + )); } private static bool CanAnnounce(CommunicationsConsoleComponent comp) @@ -203,7 +204,9 @@ private bool CanCallOrRecall(CommunicationsConsoleComponent comp) private void OnSelectAlertLevelMessage(EntityUid uid, CommunicationsConsoleComponent comp, CommunicationsConsoleSelectAlertLevelMessage message) { - if (message.Session.AttachedEntity is not { Valid: true } mob) return; + if (message.Session.AttachedEntity is not { Valid: true } mob) + return; + if (!CanUse(mob, uid)) { _popupSystem.PopupCursor(Loc.GetString("comms-console-permission-denied"), message.Session, PopupType.Medium); @@ -284,8 +287,12 @@ private void OnAnnounceMessage(EntityUid uid, CommunicationsConsoleComponent com private void OnCallShuttleMessage(EntityUid uid, CommunicationsConsoleComponent comp, CommunicationsConsoleCallEmergencyShuttleMessage message) { - if (!CanCallOrRecall(comp)) return; - if (message.Session.AttachedEntity is not { Valid: true } mob) return; + if (!CanCallOrRecall(comp)) + return; + + if (message.Session.AttachedEntity is not { Valid: true } mob) + return; + if (!CanUse(mob, uid)) { _popupSystem.PopupEntity(Loc.GetString("comms-console-permission-denied"), uid, message.Session); @@ -306,8 +313,12 @@ private void OnCallShuttleMessage(EntityUid uid, CommunicationsConsoleComponent private void OnRecallShuttleMessage(EntityUid uid, CommunicationsConsoleComponent comp, CommunicationsConsoleRecallEmergencyShuttleMessage message) { - if (!CanCallOrRecall(comp)) return; - if (message.Session.AttachedEntity is not { Valid: true } mob) return; + if (!CanCallOrRecall(comp)) + return; + + if (message.Session.AttachedEntity is not { Valid: true } mob) + return; + if (!CanUse(mob, uid)) { _popupSystem.PopupEntity(Loc.GetString("comms-console-permission-denied"), uid, message.Session); diff --git a/Content.Server/Crayon/CrayonComponent.cs b/Content.Server/Crayon/CrayonComponent.cs index 6f2cd6d397e..df20681938d 100644 --- a/Content.Server/Crayon/CrayonComponent.cs +++ b/Content.Server/Crayon/CrayonComponent.cs @@ -24,7 +24,5 @@ public sealed partial class CrayonComponent : SharedCrayonComponent [ViewVariables(VVAccess.ReadWrite)] [DataField("deleteEmpty")] public bool DeleteEmpty = true; - - [ViewVariables] public PlayerBoundUserInterface? UserInterface => Owner.GetUIOrNull(CrayonUiKey.Key); } } diff --git a/Content.Server/Crayon/CrayonSystem.cs b/Content.Server/Crayon/CrayonSystem.cs index 7cc2c20d897..d225df2daea 100644 --- a/Content.Server/Crayon/CrayonSystem.cs +++ b/Content.Server/Crayon/CrayonSystem.cs @@ -74,7 +74,8 @@ private void OnCrayonAfterInteract(EntityUid uid, CrayonComponent component, Aft // Decrease "Ammo" component.Charges--; - Dirty(component); + Dirty(uid, component); + _adminLogger.Add(LogType.CrayonDraw, LogImpact.Low, $"{EntityManager.ToPrettyString(args.User):user} drew a {component.Color:color} {component.SelectedState}"); args.Handled = true; @@ -89,17 +90,16 @@ private void OnCrayonUse(EntityUid uid, CrayonComponent component, UseInHandEven return; if (!TryComp(args.User, out var actor) || - component.UserInterface == null) + !_uiSystem.TryGetUi(uid, SharedCrayonComponent.CrayonUiKey.Key, out var ui)) { return; } - _uiSystem.ToggleUi(component.UserInterface, actor.PlayerSession); - - if (component.UserInterface?.SubscribedSessions.Contains(actor.PlayerSession) == true) + _uiSystem.ToggleUi(ui, actor.PlayerSession); + if (ui.SubscribedSessions.Contains(actor.PlayerSession)) { // Tell the user interface the selected stuff - _uiSystem.SetUiState(component.UserInterface, new CrayonBoundUserInterfaceState(component.SelectedState, component.SelectableColor, component.Color)); + _uiSystem.SetUiState(ui, new CrayonBoundUserInterfaceState(component.SelectedState, component.SelectableColor, component.Color)); } args.Handled = true; @@ -108,22 +108,22 @@ private void OnCrayonUse(EntityUid uid, CrayonComponent component, UseInHandEven private void OnCrayonBoundUI(EntityUid uid, CrayonComponent component, CrayonSelectMessage args) { // Check if the selected state is valid - if (!_prototypeManager.TryIndex(args.State, out var prototype) || !prototype.Tags.Contains("crayon")) return; + if (!_prototypeManager.TryIndex(args.State, out var prototype) || !prototype.Tags.Contains("crayon")) + return; component.SelectedState = args.State; - Dirty(component); + Dirty(uid, component); } private void OnCrayonBoundUIColor(EntityUid uid, CrayonComponent component, CrayonColorMessage args) { // you still need to ensure that the given color is a valid color - if (component.SelectableColor && args.Color != component.Color) - { - component.Color = args.Color; + if (!component.SelectableColor || args.Color == component.Color) + return; - Dirty(component); - } + component.Color = args.Color; + Dirty(uid, component); } @@ -134,7 +134,7 @@ private void OnCrayonInit(EntityUid uid, CrayonComponent component, ComponentIni // Get the first one from the catalog and set it as default var decal = _prototypeManager.EnumeratePrototypes().FirstOrDefault(x => x.Tags.Contains("crayon")); component.SelectedState = decal?.ID ?? string.Empty; - Dirty(component); + Dirty(uid, component); } private void OnCrayonDropped(EntityUid uid, CrayonComponent component, DroppedEvent args) diff --git a/Content.Server/Instruments/InstrumentComponent.cs b/Content.Server/Instruments/InstrumentComponent.cs index 5a6b5828da2..810d2653146 100644 --- a/Content.Server/Instruments/InstrumentComponent.cs +++ b/Content.Server/Instruments/InstrumentComponent.cs @@ -20,8 +20,6 @@ public sealed partial class InstrumentComponent : SharedInstrumentComponent public IPlayerSession? InstrumentPlayer => _entMan.GetComponentOrNull(Owner)?.CurrentSingleUser ?? _entMan.GetComponentOrNull(Owner)?.PlayerSession; - - [ViewVariables] public PlayerBoundUserInterface? UserInterface => Owner.GetUIOrNull(InstrumentUiKey.Key); } [RegisterComponent] diff --git a/Content.Server/Instruments/InstrumentSystem.cs b/Content.Server/Instruments/InstrumentSystem.cs index 4e002eb677c..ec233821051 100644 --- a/Content.Server/Instruments/InstrumentSystem.cs +++ b/Content.Server/Instruments/InstrumentSystem.cs @@ -5,7 +5,6 @@ using Content.Shared.Administration; using Content.Shared.Instruments; using Content.Shared.Instruments.UI; -using Content.Shared.Interaction; using Content.Shared.Physics; using Content.Shared.Popups; using JetBrains.Annotations; @@ -17,7 +16,6 @@ using Robust.Shared.Console; using Robust.Shared.GameStates; using Robust.Shared.Timing; -using Robust.Shared.Utility; namespace Content.Server.Instruments; @@ -435,9 +433,7 @@ public override void Update(float frameTime) // Just in case Clean(uid); - - if (instrument.UserInterface is not null) - _bui.CloseAll(instrument.UserInterface); + _bui.TryCloseAll(uid, InstrumentUiKey.Key); } instrument.Timer += frameTime; diff --git a/Content.Server/Medical/Components/HealthAnalyzerComponent.cs b/Content.Server/Medical/Components/HealthAnalyzerComponent.cs index 4b0bb5ff1fb..39b1df573f2 100644 --- a/Content.Server/Medical/Components/HealthAnalyzerComponent.cs +++ b/Content.Server/Medical/Components/HealthAnalyzerComponent.cs @@ -17,8 +17,6 @@ public sealed partial class HealthAnalyzerComponent : Component [DataField("scanDelay")] public float ScanDelay = 0.8f; - public PlayerBoundUserInterface? UserInterface => Owner.GetUIOrNull(HealthAnalyzerUiKey.Key); - /// /// Sound played on scanning begin /// diff --git a/Content.Server/Medical/HealthAnalyzerSystem.cs b/Content.Server/Medical/HealthAnalyzerSystem.cs index 79d55e8068c..6e2f7fdf368 100644 --- a/Content.Server/Medical/HealthAnalyzerSystem.cs +++ b/Content.Server/Medical/HealthAnalyzerSystem.cs @@ -51,12 +51,12 @@ private void OnDoAfter(EntityUid uid, HealthAnalyzerComponent component, DoAfter args.Handled = true; } - private void OpenUserInterface(EntityUid user, HealthAnalyzerComponent healthAnalyzer) + private void OpenUserInterface(EntityUid user, EntityUid analyzer) { - if (!TryComp(user, out var actor) || healthAnalyzer.UserInterface == null) + if (!TryComp(user, out var actor) || !_uiSystem.TryGetUi(analyzer, HealthAnalyzerUiKey.Key, out var ui)) return; - _uiSystem.OpenUi(healthAnalyzer.UserInterface ,actor.PlayerSession); + _uiSystem.OpenUi(ui ,actor.PlayerSession); } public void UpdateScannedUser(EntityUid uid, EntityUid user, EntityUid? target, HealthAnalyzerComponent? healthAnalyzer) @@ -64,7 +64,7 @@ public void UpdateScannedUser(EntityUid uid, EntityUid user, EntityUid? target, if (!Resolve(uid, ref healthAnalyzer)) return; - if (target == null || healthAnalyzer.UserInterface == null) + if (target == null || !_uiSystem.TryGetUi(uid, HealthAnalyzerUiKey.Key, out var ui)) return; if (!HasComp(target)) @@ -73,9 +73,9 @@ public void UpdateScannedUser(EntityUid uid, EntityUid user, EntityUid? target, TryComp(target, out var temp); TryComp(target, out var bloodstream); - OpenUserInterface(user, healthAnalyzer); + OpenUserInterface(user, uid); - _uiSystem.SendUiMessage(healthAnalyzer.UserInterface, new HealthAnalyzerScannedUserMessage(GetNetEntity(target), temp != null ? temp.CurrentTemperature : float.NaN, + _uiSystem.SendUiMessage(ui, new HealthAnalyzerScannedUserMessage(GetNetEntity(target), temp != null ? temp.CurrentTemperature : float.NaN, bloodstream != null ? bloodstream.BloodSolution.FillFraction : float.NaN)); } } diff --git a/Content.Server/UserInterface/ActivatableUIComponent.cs b/Content.Server/UserInterface/ActivatableUIComponent.cs index ff605c81190..bb020608e20 100644 --- a/Content.Server/UserInterface/ActivatableUIComponent.cs +++ b/Content.Server/UserInterface/ActivatableUIComponent.cs @@ -11,8 +11,6 @@ public sealed partial class ActivatableUIComponent : Component, [ViewVariables] public Enum? Key { get; set; } - [ViewVariables] public PlayerBoundUserInterface? UserInterface => (Key != null) ? Owner.GetUIOrNull(Key) : null; - [ViewVariables(VVAccess.ReadWrite)] [DataField] public bool InHandsOnly { get; set; } = false; diff --git a/Content.Server/UserInterface/ActivatableUISystem.cs b/Content.Server/UserInterface/ActivatableUISystem.cs index c200d7a3f00..59086415b46 100644 --- a/Content.Server/UserInterface/ActivatableUISystem.cs +++ b/Content.Server/UserInterface/ActivatableUISystem.cs @@ -76,7 +76,7 @@ private void AddOpenUiVerb(EntityUid uid, ActivatableUIComponent component, GetV return; ActivationVerb verb = new(); - verb.Act = () => InteractUI(args.User, component); + verb.Act = () => InteractUI(args.User, uid, component); verb.Text = Loc.GetString(component.VerbText); // TODO VERBS add "open UI" icon? args.Verbs.Add(verb); @@ -84,16 +84,24 @@ private void AddOpenUiVerb(EntityUid uid, ActivatableUIComponent component, GetV private void OnActivate(EntityUid uid, ActivatableUIComponent component, ActivateInWorldEvent args) { - if (args.Handled) return; - if (component.InHandsOnly) return; - args.Handled = InteractUI(args.User, component); + if (args.Handled) + return; + + if (component.InHandsOnly) + return; + + args.Handled = InteractUI(args.User, uid, component); } private void OnUseInHand(EntityUid uid, ActivatableUIComponent component, UseInHandEvent args) { - if (args.Handled) return; - if (component.rightClickOnly) return; - args.Handled = InteractUI(args.User, component); + if (args.Handled) + return; + + if (component.rightClickOnly) + return; + + args.Handled = InteractUI(args.User, uid, component); } private void OnParentChanged(EntityUid uid, ActivatableUIComponent aui, ref EntParentChangedMessage args) @@ -103,53 +111,64 @@ private void OnParentChanged(EntityUid uid, ActivatableUIComponent aui, ref EntP private void OnUIClose(EntityUid uid, ActivatableUIComponent component, BoundUIClosedEvent args) { - if (args.Session != component.CurrentSingleUser) return; - if (args.UiKey != component.Key) return; + if (args.Session != component.CurrentSingleUser) + return; + + if (!Equals(args.UiKey, component.Key)) + return; + SetCurrentSingleUser(uid, null, component); } - private bool InteractUI(EntityUid user, ActivatableUIComponent aui) + private bool InteractUI(EntityUid user, EntityUid uiEntity, ActivatableUIComponent aui) { - if (!_blockerSystem.CanInteract(user, aui.Owner) && (!aui.AllowSpectator || !HasComp(user))) + if (!_blockerSystem.CanInteract(user, uiEntity) && (!aui.AllowSpectator || !HasComp(user))) return false; if (aui.RequireHands && !HasComp(user)) return false; - if (!EntityManager.TryGetComponent(user, out ActorComponent? actor)) return false; + if (!EntityManager.TryGetComponent(user, out ActorComponent? actor)) + return false; + + if (aui.AdminOnly && !_adminManager.IsAdmin(actor.PlayerSession)) + return false; - if (aui.AdminOnly && !_adminManager.IsAdmin(actor.PlayerSession)) return false; + if (aui.Key == null) + return false; - var ui = aui.UserInterface; - if (ui == null) return false; + if (!_uiSystem.TryGetUi(uiEntity, aui.Key, out var ui)) + return false; if (aui.SingleUser && (aui.CurrentSingleUser != null) && (actor.PlayerSession != aui.CurrentSingleUser)) { // If we get here, supposedly, the object is in use. // Check with BUI that it's ACTUALLY in use just in case. // Since this could brick the object if it goes wrong. - if (ui.SubscribedSessions.Count != 0) return false; + if (ui.SubscribedSessions.Count != 0) + return false; } // If we've gotten this far, fire a cancellable event that indicates someone is about to activate this. // This is so that stuff can require further conditions (like power). var oae = new ActivatableUIOpenAttemptEvent(user); - var uae = new UserOpenActivatableUIAttemptEvent(user, aui.Owner); - RaiseLocalEvent(user, uae, false); - RaiseLocalEvent((aui).Owner, oae, false); - if (oae.Cancelled || uae.Cancelled) return false; + var uae = new UserOpenActivatableUIAttemptEvent(user, uiEntity); + RaiseLocalEvent(user, uae); + RaiseLocalEvent(uiEntity, oae); + if (oae.Cancelled || uae.Cancelled) + return false; // Give the UI an opportunity to prepare itself if it needs to do anything // before opening var bae = new BeforeActivatableUIOpenEvent(user); - RaiseLocalEvent((aui).Owner, bae, false); + RaiseLocalEvent(uiEntity, bae); - SetCurrentSingleUser((aui).Owner, actor.PlayerSession, aui); + SetCurrentSingleUser(uiEntity, actor.PlayerSession, aui); _uiSystem.ToggleUi(ui, actor.PlayerSession); //Let the component know a user opened it so it can do whatever it needs to do var aae = new AfterActivatableUIOpenEvent(user, actor.PlayerSession); - RaiseLocalEvent((aui).Owner, aae, false); + RaiseLocalEvent(uiEntity, aae); return true; } @@ -163,24 +182,28 @@ public void SetCurrentSingleUser(EntityUid uid, IPlayerSession? v, ActivatableUI aui.CurrentSingleUser = v; - RaiseLocalEvent(uid, new ActivatableUIPlayerChangedEvent(), false); + RaiseLocalEvent(uid, new ActivatableUIPlayerChangedEvent()); } public void CloseAll(EntityUid uid, ActivatableUIComponent? aui = null) { if (!Resolve(uid, ref aui, false)) return; - if (aui.UserInterface is null) + + if (aui.Key == null || !_uiSystem.TryGetUi(uid, aui.Key, out var ui)) return; - _uiSystem.CloseAll(aui.UserInterface); + _uiSystem.CloseAll(ui); } private void OnHandDeselected(EntityUid uid, ActivatableUIComponent? aui, HandDeselectedEvent args) { - if (!Resolve(uid, ref aui, false)) return; + if (!Resolve(uid, ref aui, false)) + return; + if (!aui.CloseOnHandDeselect) return; + CloseAll(uid, aui); } } diff --git a/Content.Server/UserInterface/IntrinsicUISystem.cs b/Content.Server/UserInterface/IntrinsicUISystem.cs index bd449df5f5d..27b682cd41e 100644 --- a/Content.Server/UserInterface/IntrinsicUISystem.cs +++ b/Content.Server/UserInterface/IntrinsicUISystem.cs @@ -1,5 +1,4 @@ using Content.Server.Actions; -using Content.Shared.Actions; using Content.Shared.UserInterface; using Robust.Server.GameObjects; @@ -36,19 +35,19 @@ public bool InteractUI(EntityUid uid, Enum? key, IntrinsicUIComponent? iui = nul if (key is null) { - Logger.ErrorS("bui", $"Entity {ToPrettyString(uid)} has an invalid intrinsic UI."); + Log.Error($"Entity {ToPrettyString(uid)} has an invalid intrinsic UI."); } var ui = GetUIOrNull(uid, key, iui); if (ui is null) { - Logger.ErrorS("bui", $"Couldn't get UI {key} on {ToPrettyString(uid)}"); + Log.Error($"Couldn't get UI {key} on {ToPrettyString(uid)}"); return false; } var attempt = new IntrinsicUIOpenAttemptEvent(uid, key); - RaiseLocalEvent(uid, attempt, false); + RaiseLocalEvent(uid, attempt); if (attempt.Cancelled) return false; @@ -61,7 +60,7 @@ public bool InteractUI(EntityUid uid, Enum? key, IntrinsicUIComponent? iui = nul if (!Resolve(uid, ref component)) return null; - return key is null ? null : uid.GetUIOrNull(key); + return key is null ? null : _uiSystem.GetUiOrNull(uid, key); } } diff --git a/Content.Server/UserInterface/UserInterfaceHelpers.cs b/Content.Server/UserInterface/UserInterfaceHelpers.cs deleted file mode 100644 index 865772c772c..00000000000 --- a/Content.Server/UserInterface/UserInterfaceHelpers.cs +++ /dev/null @@ -1,13 +0,0 @@ -using Robust.Server.GameObjects; - -namespace Content.Server.UserInterface -{ - public static class UserInterfaceHelpers - { - [Obsolete("Use UserInterfaceSystem")] - public static PlayerBoundUserInterface? GetUIOrNull(this EntityUid entity, Enum uiKey) - { - return IoCManager.Resolve().GetEntitySystem().GetUiOrNull(entity, uiKey); - } - } -} From dbb7c7065adbaf11477d1b97561ea093496ba2fd Mon Sep 17 00:00:00 2001 From: Kara Date: Wed, 11 Oct 2023 02:18:49 -0700 Subject: [PATCH 081/127] Kill `ContainerHelpers` (#20908) --- .../Commands/HideMechanismsCommand.cs | 3 ++- .../Instruments/UI/InstrumentMenu.xaml.cs | 3 ++- .../Interactable/InteractionSystem.cs | 6 +++-- .../EmptyOnMachineDeconstructSystem.cs | 6 +++-- .../Destructible/DestructibleSystem.cs | 2 ++ .../Behaviors/EmptyAllContainersBehaviour.cs | 2 +- Content.Server/Guardian/GuardianSystem.cs | 3 ++- Content.Server/Hands/Systems/HandsSystem.cs | 4 +-- .../Nutrition/EntitySystems/SmokingSystem.cs | 8 +++--- .../Resist/EscapeInventorySystem.cs | 6 ++--- .../EntitySystems/SharedHandsSystem.Drop.cs | 26 +++++++++---------- .../EntitySystems/SharedHandsSystem.Pickup.cs | 4 +-- .../SharedHandsSystem.Virtual.cs | 2 +- .../Hands/EntitySystems/SharedHandsSystem.cs | 25 +++++++++--------- 14 files changed, 54 insertions(+), 46 deletions(-) diff --git a/Content.Client/Commands/HideMechanismsCommand.cs b/Content.Client/Commands/HideMechanismsCommand.cs index 88100a0f8c1..e9c2073b20a 100644 --- a/Content.Client/Commands/HideMechanismsCommand.cs +++ b/Content.Client/Commands/HideMechanismsCommand.cs @@ -15,6 +15,7 @@ public sealed class HideMechanismsCommand : IConsoleCommand public void Execute(IConsoleShell shell, string argStr, string[] args) { var entityManager = IoCManager.Resolve(); + var containerSys = entityManager.System(); var organs = entityManager.EntityQuery(true); foreach (var part in organs) @@ -27,7 +28,7 @@ public void Execute(IConsoleShell shell, string argStr, string[] args) sprite.ContainerOccluded = false; var tempParent = part.Owner; - while (tempParent.TryGetContainer(out var container)) + while (containerSys.TryGetContainingContainer(tempParent, out var container)) { if (!container.ShowContents) { diff --git a/Content.Client/Instruments/UI/InstrumentMenu.xaml.cs b/Content.Client/Instruments/UI/InstrumentMenu.xaml.cs index b50ab96251e..201b7b63041 100644 --- a/Content.Client/Instruments/UI/InstrumentMenu.xaml.cs +++ b/Content.Client/Instruments/UI/InstrumentMenu.xaml.cs @@ -174,8 +174,9 @@ private bool PlayCheck() if (localPlayer.ControlledEntity == instrumentEnt) return true; + var container = _owner.Entities.System(); // If we're a handheld instrument, we might be in a container. Get it just in case. - instrumentEnt.TryGetContainerMan(out var conMan); + container.TryGetContainingContainer(instrumentEnt, out var conMan); // If the instrument is handheld and we're not holding it, we return. if ((instrument.Handheld && (conMan == null || conMan.Owner != localPlayer.ControlledEntity))) diff --git a/Content.Client/Interactable/InteractionSystem.cs b/Content.Client/Interactable/InteractionSystem.cs index cdfd3aa54fa..0af8830e9ac 100644 --- a/Content.Client/Interactable/InteractionSystem.cs +++ b/Content.Client/Interactable/InteractionSystem.cs @@ -6,15 +6,17 @@ namespace Content.Client.Interactable { public sealed class InteractionSystem : SharedInteractionSystem { + [Dependency] private readonly SharedContainerSystem _container = default!; + public override bool CanAccessViaStorage(EntityUid user, EntityUid target) { if (!EntityManager.EntityExists(target)) return false; - if (!target.TryGetContainer(out var container)) + if (!_container.TryGetContainingContainer(target, out var container)) return false; - if (!TryComp(container.Owner, out StorageComponent? storage)) + if (!HasComp(container.Owner)) return false; // we don't check if the user can access the storage entity itself. This should be handed by the UI system. diff --git a/Content.Server/Containers/EmptyOnMachineDeconstructSystem.cs b/Content.Server/Containers/EmptyOnMachineDeconstructSystem.cs index 234408c3bab..c0cae8fdf7c 100644 --- a/Content.Server/Containers/EmptyOnMachineDeconstructSystem.cs +++ b/Content.Server/Containers/EmptyOnMachineDeconstructSystem.cs @@ -11,6 +11,8 @@ namespace Content.Server.Containers [UsedImplicitly] public sealed class EmptyOnMachineDeconstructSystem : EntitySystem { + [Dependency] private readonly SharedContainerSystem _container = default!; + public override void Initialize() { base.Initialize(); @@ -33,12 +35,12 @@ private void OnDeconstruct(EntityUid uid, EmptyOnMachineDeconstructComponent com { if (!EntityManager.TryGetComponent(uid, out var mComp)) return; - var baseCoords = EntityManager.GetComponent(component.Owner).Coordinates; + var baseCoords = EntityManager.GetComponent(uid).Coordinates; foreach (var v in component.Containers) { if (mComp.TryGetContainer(v, out var container)) { - container.EmptyContainer(true, baseCoords); + _container.EmptyContainer(container, true, baseCoords); } } } diff --git a/Content.Server/Destructible/DestructibleSystem.cs b/Content.Server/Destructible/DestructibleSystem.cs index b9c260a7d9b..0ef0d621f31 100644 --- a/Content.Server/Destructible/DestructibleSystem.cs +++ b/Content.Server/Destructible/DestructibleSystem.cs @@ -16,6 +16,7 @@ using Content.Shared.FixedPoint; using JetBrains.Annotations; using Robust.Server.GameObjects; +using Robust.Shared.Containers; using Robust.Shared.Prototypes; using Robust.Shared.Random; @@ -36,6 +37,7 @@ public sealed class DestructibleSystem : SharedDestructibleSystem [Dependency] public readonly TriggerSystem TriggerSystem = default!; [Dependency] public readonly SolutionContainerSystem SolutionContainerSystem = default!; [Dependency] public readonly PuddleSystem PuddleSystem = default!; + [Dependency] public readonly SharedContainerSystem ContainerSystem = default!; [Dependency] public readonly IPrototypeManager PrototypeManager = default!; [Dependency] public readonly IComponentFactory ComponentFactory = default!; [Dependency] public readonly IAdminLogManager _adminLogger = default!; diff --git a/Content.Server/Destructible/Thresholds/Behaviors/EmptyAllContainersBehaviour.cs b/Content.Server/Destructible/Thresholds/Behaviors/EmptyAllContainersBehaviour.cs index 406e7bf7e28..e696ad92580 100644 --- a/Content.Server/Destructible/Thresholds/Behaviors/EmptyAllContainersBehaviour.cs +++ b/Content.Server/Destructible/Thresholds/Behaviors/EmptyAllContainersBehaviour.cs @@ -15,7 +15,7 @@ public void Execute(EntityUid owner, DestructibleSystem system, EntityUid? cause foreach (var container in containerManager.GetAllContainers()) { - container.EmptyContainer(true, system.EntityManager.GetComponent(owner).Coordinates); + system.ContainerSystem.EmptyContainer(container, true, system.EntityManager.GetComponent(owner).Coordinates); } } } diff --git a/Content.Server/Guardian/GuardianSystem.cs b/Content.Server/Guardian/GuardianSystem.cs index f34b765ac77..118574db3f7 100644 --- a/Content.Server/Guardian/GuardianSystem.cs +++ b/Content.Server/Guardian/GuardianSystem.cs @@ -31,6 +31,7 @@ public sealed class GuardianSystem : EntitySystem [Dependency] private readonly SharedHandsSystem _handsSystem = default!; [Dependency] private readonly SharedAudioSystem _audio = default!; [Dependency] private readonly BodySystem _bodySystem = default!; + [Dependency] private readonly SharedContainerSystem _container = default!; public override void Initialize() { @@ -88,7 +89,7 @@ private void OnGuardianPlayer(EntityUid uid, GuardianComponent component, Player private void OnHostInit(EntityUid uid, GuardianHostComponent component, ComponentInit args) { - component.GuardianContainer = uid.EnsureContainer("GuardianContainer"); + component.GuardianContainer = _container.EnsureContainer(uid, "GuardianContainer"); _actionSystem.AddAction(uid, ref component.ActionEntity, component.Action); } diff --git a/Content.Server/Hands/Systems/HandsSystem.cs b/Content.Server/Hands/Systems/HandsSystem.cs index 1cae95c78eb..298aa57ccf2 100644 --- a/Content.Server/Hands/Systems/HandsSystem.cs +++ b/Content.Server/Hands/Systems/HandsSystem.cs @@ -169,9 +169,9 @@ private bool HandleThrowItem(ICommonSession? session, EntityCoordinates coordina if (playerSession.AttachedEntity is not {Valid: true} player || !Exists(player) || - player.IsInContainer() || + ContainerSystem.IsEntityInContainer(player) || !TryComp(player, out HandsComponent? hands) || - hands.ActiveHandEntity is not EntityUid throwEnt || + hands.ActiveHandEntity is not { } throwEnt || !_actionBlockerSystem.CanThrow(player, throwEnt)) return false; diff --git a/Content.Server/Nutrition/EntitySystems/SmokingSystem.cs b/Content.Server/Nutrition/EntitySystems/SmokingSystem.cs index 772e8721105..96c7f8a64c4 100644 --- a/Content.Server/Nutrition/EntitySystems/SmokingSystem.cs +++ b/Content.Server/Nutrition/EntitySystems/SmokingSystem.cs @@ -2,7 +2,6 @@ using Content.Server.Body.Components; using Content.Server.Body.Systems; using Content.Server.Chemistry.EntitySystems; -using Content.Server.Nutrition.Components; using Content.Shared.Nutrition.Components; using Content.Shared.Chemistry; using Content.Shared.Chemistry.Reagent; @@ -29,11 +28,12 @@ public sealed partial class SmokingSystem : EntitySystem [Dependency] private readonly InventorySystem _inventorySystem = default!; [Dependency] private readonly ClothingSystem _clothing = default!; [Dependency] private readonly SharedItemSystem _items = default!; + [Dependency] private readonly SharedContainerSystem _container = default!; [Dependency] private readonly SharedAppearanceSystem _appearance = default!; private const float UpdateTimer = 3f; - private float _timer = 0f; + private float _timer; /// /// We keep a list of active smokables, because iterating all existing smokables would be dumb. @@ -130,8 +130,8 @@ public override void Update(float frameTime) // This is awful. I hate this so much. // TODO: Please, someone refactor containers and free me from this bullshit. - if (!smokable.Owner.TryGetContainerMan(out var containerManager) || - !(_inventorySystem.TryGetSlotEntity(containerManager.Owner, "mask", out var inMaskSlotUid) && inMaskSlotUid == smokable.Owner) || + if (!_container.TryGetContainingContainer(uid, out var containerManager) || + !(_inventorySystem.TryGetSlotEntity(containerManager.Owner, "mask", out var inMaskSlotUid) && inMaskSlotUid == uid) || !TryComp(containerManager.Owner, out BloodstreamComponent? bloodstream)) { continue; diff --git a/Content.Server/Resist/EscapeInventorySystem.cs b/Content.Server/Resist/EscapeInventorySystem.cs index eb7c4c84786..ea603084b55 100644 --- a/Content.Server/Resist/EscapeInventorySystem.cs +++ b/Content.Server/Resist/EscapeInventorySystem.cs @@ -80,7 +80,7 @@ private void AttemptEscape(EntityUid user, EntityUid container, CanEscapeInvento if (!_doAfterSystem.TryStartDoAfter(doAfterEventArgs, out component.DoAfter)) return; - Dirty(component); + Dirty(user, component); _popupSystem.PopupEntity(Loc.GetString("escape-inventory-component-start-resisting"), user, user); _popupSystem.PopupEntity(Loc.GetString("escape-inventory-component-start-resisting-target"), container, container); } @@ -88,12 +88,12 @@ private void AttemptEscape(EntityUid user, EntityUid container, CanEscapeInvento private void OnEscape(EntityUid uid, CanEscapeInventoryComponent component, EscapeInventoryEvent args) { component.DoAfter = null; - Dirty(component); + Dirty(uid, component); if (args.Handled || args.Cancelled) return; - Transform(uid).AttachParentToContainerOrGrid(EntityManager); + _containerSystem.AttachParentToContainerOrGrid(Transform(uid)); args.Handled = true; } diff --git a/Content.Shared/Hands/EntitySystems/SharedHandsSystem.Drop.cs b/Content.Shared/Hands/EntitySystems/SharedHandsSystem.Drop.cs index e43f2561a16..06d6526566b 100644 --- a/Content.Shared/Hands/EntitySystems/SharedHandsSystem.Drop.cs +++ b/Content.Shared/Hands/EntitySystems/SharedHandsSystem.Drop.cs @@ -6,10 +6,8 @@ namespace Content.Shared.Hands.EntitySystems; -public abstract partial class SharedHandsSystem : EntitySystem +public abstract partial class SharedHandsSystem { - [Dependency] private readonly SharedContainerSystem _container = default!; - private void InitializeDrop() { SubscribeLocalEvent(HandleEntityRemoved); @@ -23,10 +21,10 @@ protected virtual void HandleEntityRemoved(EntityUid uid, HandsComponent hands, } var gotUnequipped = new GotUnequippedHandEvent(uid, args.Entity, hand); - RaiseLocalEvent(args.Entity, gotUnequipped, false); + RaiseLocalEvent(args.Entity, gotUnequipped); var didUnequip = new DidUnequipHandEvent(uid, args.Entity, hand); - RaiseLocalEvent(uid, didUnequip, false); + RaiseLocalEvent(uid, didUnequip); } /// @@ -37,7 +35,7 @@ public bool CanDropHeld(EntityUid uid, Hand hand, bool checkActionBlocker = true if (hand.Container?.ContainedEntity is not {} held) return false; - if (!_container.CanRemove(held, hand.Container)) + if (!ContainerSystem.CanRemove(held, hand.Container)) return false; if (checkActionBlocker && !_actionBlocker.CanDrop(uid)) @@ -90,7 +88,7 @@ public bool TryDrop(EntityUid uid, Hand hand, EntityCoordinates? targetDropLocat var userXform = Transform(uid); var itemXform = Transform(entity); - var isInContainer = _containerSystem.IsEntityInContainer(uid); + var isInContainer = ContainerSystem.IsEntityInContainer(uid); if (targetDropLocation == null || isInContainer) { @@ -98,14 +96,14 @@ public bool TryDrop(EntityUid uid, Hand hand, EntityCoordinates? targetDropLocat // TODO recursively check upwards for containers if (!isInContainer - || !_containerSystem.TryGetContainingContainer(userXform.ParentUid, uid, out var container, skipExistCheck: true) + || !ContainerSystem.TryGetContainingContainer(userXform.ParentUid, uid, out var container, skipExistCheck: true) || !container.Insert(entity, EntityManager, itemXform)) - itemXform.AttachToGridOrMap(); + TransformSystem.AttachToGridOrMap(entity, itemXform); return true; } - var target = targetDropLocation.Value.ToMap(EntityManager); - itemXform.WorldPosition = GetFinalDropCoordinates(uid, userXform.MapPosition, target); + var target = targetDropLocation.Value.ToMap(EntityManager, TransformSystem); + TransformSystem.SetWorldPosition(userXform, GetFinalDropCoordinates(uid, userXform.MapPosition, target)); return true; } @@ -123,7 +121,7 @@ public bool TryDropIntoContainer(EntityUid uid, EntityUid entity, BaseContainer if (!CanDropHeld(uid, hand, checkActionBlocker)) return false; - if (!_container.CanInsert(entity, targetContainer)) + if (!ContainerSystem.CanInsert(entity, targetContainer)) return false; DoDrop(uid, hand, false, handsComp); @@ -171,12 +169,12 @@ public virtual void DoDrop(EntityUid uid, Hand hand, bool doDropInteraction = tr return; } - Dirty(handsComp); + Dirty(uid, handsComp); if (doDropInteraction) _interactionSystem.DroppedInteraction(uid, entity); if (hand == handsComp.ActiveHand) - RaiseLocalEvent(entity, new HandDeselectedEvent(uid), false); + RaiseLocalEvent(entity, new HandDeselectedEvent(uid)); } } diff --git a/Content.Shared/Hands/EntitySystems/SharedHandsSystem.Pickup.cs b/Content.Shared/Hands/EntitySystems/SharedHandsSystem.Pickup.cs index 278470c4a2c..0171b9f70c9 100644 --- a/Content.Shared/Hands/EntitySystems/SharedHandsSystem.Pickup.cs +++ b/Content.Shared/Hands/EntitySystems/SharedHandsSystem.Pickup.cs @@ -180,7 +180,7 @@ public bool CanPickupToHand(EntityUid uid, EntityUid entity, Hand hand, bool che return false; // check can insert (including raising attempt events). - return _containerSystem.CanInsert(entity, handContainer); + return ContainerSystem.CanInsert(entity, handContainer); } /// @@ -202,7 +202,7 @@ public void PickupOrDrop( { // TODO make this check upwards for any container, and parent to that. // Currently this just checks the direct parent, so items can still teleport through containers. - Transform(entity).AttachParentToContainerOrGrid(EntityManager); + ContainerSystem.AttachParentToContainerOrGrid(Transform(entity)); } } diff --git a/Content.Shared/Hands/EntitySystems/SharedHandsSystem.Virtual.cs b/Content.Shared/Hands/EntitySystems/SharedHandsSystem.Virtual.cs index 36498d929b1..b83ec8c128c 100644 --- a/Content.Shared/Hands/EntitySystems/SharedHandsSystem.Virtual.cs +++ b/Content.Shared/Hands/EntitySystems/SharedHandsSystem.Virtual.cs @@ -12,7 +12,7 @@ private void InitializeVirtual() private void OnVirtualAfter(EntityUid uid, HandVirtualItemComponent component, ref AfterAutoHandleStateEvent args) { // update hands GUI with new entity. - if (_containerSystem.IsEntityInContainer(uid)) + if (ContainerSystem.IsEntityInContainer(uid)) _items.VisualsChanged(uid); } } diff --git a/Content.Shared/Hands/EntitySystems/SharedHandsSystem.cs b/Content.Shared/Hands/EntitySystems/SharedHandsSystem.cs index af53b2625c0..9f7623329e4 100644 --- a/Content.Shared/Hands/EntitySystems/SharedHandsSystem.cs +++ b/Content.Shared/Hands/EntitySystems/SharedHandsSystem.cs @@ -11,11 +11,11 @@ namespace Content.Shared.Hands.EntitySystems; -public abstract partial class SharedHandsSystem : EntitySystem +public abstract partial class SharedHandsSystem { [Dependency] private readonly ISharedAdminLogManager _adminLogger = default!; [Dependency] private readonly ActionBlockerSystem _actionBlocker = default!; - [Dependency] private readonly SharedContainerSystem _containerSystem = default!; + [Dependency] protected readonly SharedContainerSystem ContainerSystem = default!; [Dependency] private readonly SharedInteractionSystem _interactionSystem = default!; [Dependency] private readonly SharedItemSystem _items = default!; [Dependency] private readonly SharedStorageSystem _storage = default!; @@ -47,7 +47,7 @@ public virtual void AddHand(EntityUid uid, string handName, HandLocation handLoc if (handsComp.Hands.ContainsKey(handName)) return; - var container = _containerSystem.EnsureContainer(uid, handName); + var container = ContainerSystem.EnsureContainer(uid, handName); container.OccludesLight = false; var newHand = new Hand(handName, handLocation, container); @@ -57,8 +57,8 @@ public virtual void AddHand(EntityUid uid, string handName, HandLocation handLoc if (handsComp.ActiveHand == null) SetActiveHand(uid, newHand, handsComp); - RaiseLocalEvent(uid, new HandCountChangedEvent(uid), false); - Dirty(handsComp); + RaiseLocalEvent(uid, new HandCountChangedEvent(uid)); + Dirty(uid, handsComp); } public virtual void RemoveHand(EntityUid uid, string handName, HandsComponent? handsComp = null) @@ -76,8 +76,8 @@ public virtual void RemoveHand(EntityUid uid, string handName, HandsComponent? h if (handsComp.ActiveHand == hand) TrySetActiveHand(uid, handsComp.SortedHands.FirstOrDefault(), handsComp); - RaiseLocalEvent(uid, new HandCountChangedEvent(uid), false); - Dirty(handsComp); + RaiseLocalEvent(uid, new HandCountChangedEvent(uid)); + Dirty(uid, handsComp); } /// @@ -169,7 +169,7 @@ public IEnumerable EnumerateHeld(EntityUid uid, HandsComponent? hands if (name == handsComp.ActiveHand?.Name) continue; - if (handsComp.Hands[name].HeldEntity is EntityUid held) + if (handsComp.Hands[name].HeldEntity is { } held) yield return held; } } @@ -206,8 +206,8 @@ public bool SetActiveHand(EntityUid uid, Hand? hand, HandsComponent? handComp = if (hand == handComp.ActiveHand) return false; - if (handComp.ActiveHand?.HeldEntity is EntityUid held) - RaiseLocalEvent(held, new HandDeselectedEvent(uid), false); + if (handComp.ActiveHand?.HeldEntity is { } held) + RaiseLocalEvent(held, new HandDeselectedEvent(uid)); if (hand == null) { @@ -219,8 +219,9 @@ public bool SetActiveHand(EntityUid uid, Hand? hand, HandsComponent? handComp = OnHandSetActive?.Invoke(handComp); if (hand.HeldEntity != null) - RaiseLocalEvent(hand.HeldEntity.Value, new HandSelectedEvent(uid), false); - Dirty(handComp); + RaiseLocalEvent(hand.HeldEntity.Value, new HandSelectedEvent(uid)); + + Dirty(uid, handComp); return true; } From 7dd20f7af1f443678c3a1c3e4ba6d3e442485e76 Mon Sep 17 00:00:00 2001 From: Kara Date: Wed, 11 Oct 2023 02:19:46 -0700 Subject: [PATCH 082/127] Kill `ComponentExt` (#20907) --- .../Click/InteractionSystemTests.cs | 20 +++++++------- .../SolutionInjectOnCollideSystem.cs | 7 ----- Content.Server/Ghost/Roles/GhostRoleSystem.cs | 2 +- .../Tabletop/TabletopSystem.Session.cs | 4 +-- .../SingularityDistortionComponent.cs | 26 +++++-------------- .../EntitySystems/SharedSingularitySystem.cs | 1 + 6 files changed, 20 insertions(+), 40 deletions(-) diff --git a/Content.IntegrationTests/Tests/Interaction/Click/InteractionSystemTests.cs b/Content.IntegrationTests/Tests/Interaction/Click/InteractionSystemTests.cs index b05f2732651..cef74aa386f 100644 --- a/Content.IntegrationTests/Tests/Interaction/Click/InteractionSystemTests.cs +++ b/Content.IntegrationTests/Tests/Interaction/Click/InteractionSystemTests.cs @@ -63,11 +63,11 @@ await server.WaitAssertion(() => await server.WaitAssertion(() => { user = sEntities.SpawnEntity(null, coords); - user.EnsureComponent(); + sEntities.EnsureComponent(user); handSys.AddHand(user, "hand", HandLocation.Left); target = sEntities.SpawnEntity(null, coords); item = sEntities.SpawnEntity(null, coords); - item.EnsureComponent(); + sEntities.EnsureComponent(item); }); await server.WaitRunTicks(1); @@ -134,11 +134,11 @@ await server.WaitAssertion(() => await server.WaitAssertion(() => { user = sEntities.SpawnEntity(null, coords); - user.EnsureComponent(); + sEntities.EnsureComponent(user); handSys.AddHand(user, "hand", HandLocation.Left); target = sEntities.SpawnEntity(null, new MapCoordinates(new Vector2(1.9f, 0), mapId)); item = sEntities.SpawnEntity(null, coords); - item.EnsureComponent(); + sEntities.EnsureComponent(item); wall = sEntities.SpawnEntity("DummyDebugWall", new MapCoordinates(new Vector2(1, 0), sEntities.GetComponent(user).MapID)); }); @@ -204,11 +204,11 @@ await server.WaitAssertion(() => await server.WaitAssertion(() => { user = sEntities.SpawnEntity(null, coords); - user.EnsureComponent(); + sEntities.EnsureComponent(user); handSys.AddHand(user, "hand", HandLocation.Left); target = sEntities.SpawnEntity(null, new MapCoordinates(new Vector2(SharedInteractionSystem.InteractionRange - 0.1f, 0), mapId)); item = sEntities.SpawnEntity(null, coords); - item.EnsureComponent(); + sEntities.EnsureComponent(item); }); await server.WaitRunTicks(1); @@ -274,11 +274,11 @@ await server.WaitAssertion(() => await server.WaitAssertion(() => { user = sEntities.SpawnEntity(null, coords); - user.EnsureComponent(); + sEntities.EnsureComponent(user); handSys.AddHand(user, "hand", HandLocation.Left); target = sEntities.SpawnEntity(null, new MapCoordinates(new Vector2(SharedInteractionSystem.InteractionRange + 0.01f, 0), mapId)); item = sEntities.SpawnEntity(null, coords); - item.EnsureComponent(); + sEntities.EnsureComponent(item); }); await server.WaitRunTicks(1); @@ -346,11 +346,11 @@ await server.WaitAssertion(() => await server.WaitAssertion(() => { user = sEntities.SpawnEntity(null, coords); - user.EnsureComponent(); + sEntities.EnsureComponent(user); handSys.AddHand(user, "hand", HandLocation.Left); target = sEntities.SpawnEntity(null, coords); item = sEntities.SpawnEntity(null, coords); - item.EnsureComponent(); + sEntities.EnsureComponent(item); containerEntity = sEntities.SpawnEntity(null, coords); container = conSystem.EnsureContainer(containerEntity, "InteractionTestContainer"); }); diff --git a/Content.Server/Chemistry/EntitySystems/SolutionInjectOnCollideSystem.cs b/Content.Server/Chemistry/EntitySystems/SolutionInjectOnCollideSystem.cs index 9848463e3f0..666a90ce73d 100644 --- a/Content.Server/Chemistry/EntitySystems/SolutionInjectOnCollideSystem.cs +++ b/Content.Server/Chemistry/EntitySystems/SolutionInjectOnCollideSystem.cs @@ -22,16 +22,9 @@ internal sealed class SolutionInjectOnCollideSystem : EntitySystem public override void Initialize() { base.Initialize(); - SubscribeLocalEvent(HandleInit); SubscribeLocalEvent(HandleInjection); } - private void HandleInit(EntityUid uid, SolutionInjectOnCollideComponent component, ComponentInit args) - { - component.Owner - .EnsureComponentWarn($"{nameof(SolutionInjectOnCollideComponent)} requires a SolutionContainerManager on {component.Owner}!"); - } - private void HandleInjection(EntityUid uid, SolutionInjectOnCollideComponent component, ref StartCollideEvent args) { var target = args.OtherEntity; diff --git a/Content.Server/Ghost/Roles/GhostRoleSystem.cs b/Content.Server/Ghost/Roles/GhostRoleSystem.cs index 98a62d39707..671b91392c4 100644 --- a/Content.Server/Ghost/Roles/GhostRoleSystem.cs +++ b/Content.Server/Ghost/Roles/GhostRoleSystem.cs @@ -343,7 +343,7 @@ private void OnSpawnerTakeRole(EntityUid uid, GhostRoleMobSpawnerComponent compo if (ghostRole.MakeSentient) MakeSentientCommand.MakeSentient(mob, EntityManager, ghostRole.AllowMovement, ghostRole.AllowSpeech); - mob.EnsureComponent(); + EnsureComp(mob); GhostRoleInternalCreateMindAndTransfer(args.Player, uid, mob, ghostRole); diff --git a/Content.Server/Tabletop/TabletopSystem.Session.cs b/Content.Server/Tabletop/TabletopSystem.Session.cs index ef96733a121..e9dea0c66a2 100644 --- a/Content.Server/Tabletop/TabletopSystem.Session.cs +++ b/Content.Server/Tabletop/TabletopSystem.Session.cs @@ -81,7 +81,7 @@ public void OpenSessionFor(IPlayerSession player, EntityUid uid) CloseSessionFor(player, gamer.Tabletop, false); // Set the entity as an absolute GAMER. - attachedEntity.EnsureComponent().Tabletop = uid; + EnsureComp(attachedEntity).Tabletop = uid; // Create a camera for the gamer to use var camera = CreateCamera(tabletop, player); @@ -139,7 +139,7 @@ private EntityUid CreateCamera(TabletopGameComponent tabletop, IPlayerSession pl var camera = EntityManager.SpawnEntity(null, session.Position.Offset(offset)); // Add an eye component and disable FOV - var eyeComponent = camera.EnsureComponent(); + var eyeComponent = EnsureComp(camera); _eye.SetDrawFov(camera, false, eyeComponent); _eye.SetZoom(camera, tabletop.CameraZoom, eyeComponent); diff --git a/Content.Shared/Singularity/Components/SingularityDistortionComponent.cs b/Content.Shared/Singularity/Components/SingularityDistortionComponent.cs index 73313661de1..1382dd45f49 100644 --- a/Content.Shared/Singularity/Components/SingularityDistortionComponent.cs +++ b/Content.Shared/Singularity/Components/SingularityDistortionComponent.cs @@ -1,31 +1,17 @@ +using Content.Shared.Singularity.EntitySystems; using Robust.Shared.GameStates; -using Robust.Shared.Serialization; namespace Content.Shared.Singularity.Components { [RegisterComponent, NetworkedComponent] [AutoGenerateComponentState] + [Access(typeof(SharedSingularitySystem))] public sealed partial class SingularityDistortionComponent : Component { - // TODO: use access and remove this funny stuff - [DataField("intensity")] - private float _intensity = 31.25f; + [DataField, AutoNetworkedField, ViewVariables(VVAccess.ReadWrite)] + public float Intensity = 31.25f; - [DataField("falloffPower")] - private float _falloffPower = MathF.Sqrt(2f); - - [ViewVariables(VVAccess.ReadWrite), AutoNetworkedField] - public float Intensity - { - get => _intensity; - set => this.SetAndDirtyIfChanged(ref _intensity, value); - } - - [ViewVariables(VVAccess.ReadWrite), AutoNetworkedField] - public float FalloffPower - { - get => _falloffPower; - set => this.SetAndDirtyIfChanged(ref _falloffPower, value); - } + [DataField, AutoNetworkedField, ViewVariables(VVAccess.ReadWrite)] + public float FalloffPower = MathF.Sqrt(2f); } } diff --git a/Content.Shared/Singularity/EntitySystems/SharedSingularitySystem.cs b/Content.Shared/Singularity/EntitySystems/SharedSingularitySystem.cs index 56be197e1df..2ea40308b94 100644 --- a/Content.Shared/Singularity/EntitySystems/SharedSingularitySystem.cs +++ b/Content.Shared/Singularity/EntitySystems/SharedSingularitySystem.cs @@ -312,6 +312,7 @@ private void UpdateDistortion(EntityUid uid, SingularityDistortionComponent comp comp.FalloffPower = newFalloffPower; comp.Intensity = newIntensity; + Dirty(uid, comp); } /// From 201e39b42ea3ee8cf200f4487cbdf4c9e3929164 Mon Sep 17 00:00:00 2001 From: deltanedas <39013340+deltanedas@users.noreply.github.com> Date: Wed, 11 Oct 2023 10:22:09 +0100 Subject: [PATCH 083/127] show battery charge when recharger is examined (#20098) Co-authored-by: deltanedas <@deltanedas:kde.org> --- .../Entities/Structures/Power/chargers.yml | 197 ++++++------------ 1 file changed, 64 insertions(+), 133 deletions(-) diff --git a/Resources/Prototypes/Entities/Structures/Power/chargers.yml b/Resources/Prototypes/Entities/Structures/Power/chargers.yml index 520b293cb5d..e5edc63df3c 100644 --- a/Resources/Prototypes/Entities/Structures/Power/chargers.yml +++ b/Resources/Prototypes/Entities/Structures/Power/chargers.yml @@ -1,57 +1,54 @@ - type: entity - name: cell recharger - id: PowerCellRecharger - parent: ConstructibleMachine + abstract: true + parent: [BaseMachinePowered, ConstructibleMachine] + id: BaseRecharger placement: mode: SnapgridCenter components: - type: Transform anchored: true + noRot: false - type: Sprite - sprite: Structures/Power/cell_recharger.rsi - drawdepth: SmallObjects snapCardinals: true + - type: Appearance + - type: Charger + slotId: charger_slot + - type: Anchorable + delay: 1 + - type: Destructible + thresholds: + - trigger: + !type:DamageTrigger + damage: 80 + behaviors: + - !type:DoActsBehavior + acts: ["Destruction"] + - trigger: + !type:DamageTrigger + damage: 40 + behaviors: + - !type:EmptyAllContainersBehaviour + - !type:DoActsBehavior + acts: ["Destruction"] + - !type:PlaySoundBehavior + sound: + path: /Audio/Effects/metalbreak.ogg + - type: StaticPrice + price: 25 + +- type: entity + abstract: true + parent: BaseRecharger + id: BaseItemRecharger + components: + - type: Sprite + drawdepth: SmallObjects layers: - map: ["enum.PowerChargerVisualLayers.Base"] state: "empty" - map: ["enum.PowerChargerVisualLayers.Light"] state: "light-off" shader: "unshaded" - - type: Charger - slotId: charger_slot - - type: ApcPowerReceiver - - type: ExtensionCableReceiver - - type: Machine - board: CellRechargerCircuitboard - - type: Appearance - - type: PowerChargerVisuals - - type: Anchorable - - type: Pullable - - type: Clickable - - type: InteractionOutline - - type: Damageable - damageContainer: Inorganic - damageModifierSet: Metallic - - type: Destructible - thresholds: - - trigger: - !type:DamageTrigger - damage: 80 - behaviors: - - !type:DoActsBehavior - acts: [ "Destruction" ] - - trigger: - !type:DamageTrigger - damage: 40 - behaviors: - - !type:EmptyAllContainersBehaviour - - !type:DoActsBehavior - acts: [ "Destruction" ] - - !type:PlaySoundBehavior - sound: - path: /Audio/Effects/metalbreak.ogg - - type: Physics - bodyType: Static - type: Fixtures fixtures: fix1: @@ -60,7 +57,26 @@ bounds: "-0.10,-0.10,0.10,0.10" density: 500 mask: - - TabletopMachineMask + - TabletopMachineMask + - type: PowerChargerVisuals + - type: ContainerContainer + containers: + charger_slot: !type:ContainerSlot + machine_board: !type:Container + machine_parts: !type:Container + +- type: entity + parent: BaseItemRecharger + id: PowerCellRecharger + name: cell recharger + components: + - type: Sprite + sprite: Structures/Power/cell_recharger.rsi + - type: Machine + board: CellRechargerCircuitboard + - type: PowerCellSlot + cellSlotId: charger_slot + # fitsInCharger is true i dont think this will ever affect anything negatively but it lets it function - type: ItemSlots slots: charger_slot: @@ -68,26 +84,18 @@ name: Power cell whitelist: components: - - PowerCell - - type: ContainerContainer - containers: - charger_slot: !type:ContainerSlot - machine_board: !type:Container - machine_parts: !type:Container - - type: StaticPrice - price: 15 + - PowerCell - type: entity - name: recharger + parent: BaseItemRecharger id: WeaponCapacitorRecharger - parent: PowerCellRecharger + name: recharger components: - type: Sprite sprite: Structures/Power/recharger.rsi - type: Machine board: WeaponCapacitorRechargerCircuitboard - - type: Charger - slotId: charger_slot + # no powercellslot since stun baton etc arent powercells - type: ItemSlots slots: charger_slot: @@ -97,19 +105,14 @@ - HitscanBatteryAmmoProvider - ProjectileBatteryAmmoProvider - Stunbaton - - type: StaticPrice - price: 15 - type: entity - name: wall recharger + parent: BaseItemRecharger id: WallWeaponCapacitorRecharger - placement: - mode: SnapgridCenter + name: wall recharger components: - type: Sprite sprite: Structures/Power/wall_recharger.rsi - drawdepth: SmallObjects - snapCardinals: true layers: - map: ["enum.PowerChargerVisualLayers.Base"] state: "empty" @@ -119,49 +122,6 @@ - type: WallMount - type: Charger chargeRate: 25 - slotId: charger_slot - - type: Transform - anchored: true - - type: ApcPowerReceiver - - type: ExtensionCableReceiver - - type: Appearance - - type: PowerChargerVisuals - - type: Anchorable - - type: Pullable - - type: Clickable - - type: InteractionOutline - - type: Damageable - damageContainer: Inorganic - damageModifierSet: Metallic - - type: Destructible - thresholds: - - trigger: - !type:DamageTrigger - damage: 80 - behaviors: - - !type:DoActsBehavior - acts: [ "Destruction" ] - - trigger: - !type:DamageTrigger - damage: 40 - behaviors: - - !type:EmptyAllContainersBehaviour - - !type:DoActsBehavior - acts: [ "Destruction" ] - - !type:PlaySoundBehavior - sound: - path: /Audio/Effects/metalbreak.ogg - - type: Physics - bodyType: Static - - type: Fixtures - fixtures: - fix1: - shape: - !type:PhysShapeAabb - bounds: "-0.10,-0.10,0.10,0.10" - density: 500 - mask: - - TabletopMachineMask - type: ItemSlots slots: charger_slot: @@ -171,23 +131,15 @@ - HitscanBatteryAmmoProvider - ProjectileBatteryAmmoProvider - Stunbaton - - type: ContainerContainer - containers: - charger_slot: !type:ContainerSlot - machine_board: !type:Container - machine_parts: !type:Container - type: entity + parent: BaseRecharger id: BorgCharger - parent: [ BaseMachinePowered, ConstructibleMachine ] name: cyborg recharging station description: A stationary charger for various robotic and cyborg entities. Surprisingly spacious. - placement: - mode: SnapgridCenter components: - type: Sprite sprite: Structures/Power/borg_charger.rsi - snapCardinals: true layers: - state: borgcharger-u1 map: ["base"] @@ -218,7 +170,6 @@ - type: WiresVisuals - type: Machine board: BorgChargerCircuitboard - - type: Appearance - type: GenericVisualizer visuals: enum.StorageVisuals.Open: @@ -248,24 +199,6 @@ Charged: visible: true state: borgcharger1 - - type: Destructible - thresholds: - - trigger: - !type:DamageTrigger - damage: 80 - behaviors: - - !type:DoActsBehavior - acts: [ "Destruction" ] - - trigger: - !type:DamageTrigger - damage: 40 - behaviors: - - !type:EmptyAllContainersBehaviour - - !type:DoActsBehavior - acts: [ "Destruction" ] - - !type:PlaySoundBehavior - sound: - path: /Audio/Effects/metalbreak.ogg - type: EntityStorage capacity: 1 whitelist: @@ -276,5 +209,3 @@ entity_storage: !type:Container machine_board: !type:Container machine_parts: !type:Container - - type: StaticPrice - price: 15 From f339ba0404df7c4b488941ebefd8d07c01740ddf Mon Sep 17 00:00:00 2001 From: PJBot Date: Wed, 11 Oct 2023 05:23:14 -0400 Subject: [PATCH 084/127] Automatic changelog update --- Resources/Changelog/Changelog.yml | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index d9502b721c3..f84ac42a72a 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,11 +1,4 @@ Entries: -- author: Lank - changes: - - {message: What Moths consider to be made of cloth should now be more accurate., - type: Tweak} - - {message: Moths are now able to squeak., type: Tweak} - id: 4492 - time: '2023-08-09T04:05:06.0000000+00:00' - author: metalgearsloth changes: - {message: Added toggle to hide clothing in the character editor., type: Add} @@ -2957,3 +2950,9 @@ Entries: in replay mode to look similar to ingame.', type: Add} id: 4991 time: '2023-10-11T03:43:48.0000000+00:00' +- author: deltanedas + changes: + - {message: Rehargers can be examined to show the charge of the battery or weapon + inside., type: Tweak} + id: 4992 + time: '2023-10-11T09:22:09.0000000+00:00' From 071f75d1461ae2def1e02737220326232418122b Mon Sep 17 00:00:00 2001 From: mokiros Date: Wed, 11 Oct 2023 16:26:22 +0300 Subject: [PATCH 085/127] Fixed "Dropping things makes you teleport" (#20919) --- Content.Shared/Hands/EntitySystems/SharedHandsSystem.Drop.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Content.Shared/Hands/EntitySystems/SharedHandsSystem.Drop.cs b/Content.Shared/Hands/EntitySystems/SharedHandsSystem.Drop.cs index 06d6526566b..77752c4fbde 100644 --- a/Content.Shared/Hands/EntitySystems/SharedHandsSystem.Drop.cs +++ b/Content.Shared/Hands/EntitySystems/SharedHandsSystem.Drop.cs @@ -103,7 +103,7 @@ public bool TryDrop(EntityUid uid, Hand hand, EntityCoordinates? targetDropLocat } var target = targetDropLocation.Value.ToMap(EntityManager, TransformSystem); - TransformSystem.SetWorldPosition(userXform, GetFinalDropCoordinates(uid, userXform.MapPosition, target)); + TransformSystem.SetWorldPosition(itemXform, GetFinalDropCoordinates(uid, userXform.MapPosition, target)); return true; } From 16032cf421a43608d5c04dad04a3fd43290240f4 Mon Sep 17 00:00:00 2001 From: Skarletto <122584947+Skarletto@users.noreply.github.com> Date: Wed, 11 Oct 2023 11:20:21 -0400 Subject: [PATCH 086/127] today i will not stack 50 scrubbers (#20917) --- .../Structures/Piping/Atmospherics/unary.yml | 5 +++++ .../Prototypes/Recipes/Construction/utilities.yml | 12 ++++++++---- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/Resources/Prototypes/Entities/Structures/Piping/Atmospherics/unary.yml b/Resources/Prototypes/Entities/Structures/Piping/Atmospherics/unary.yml index e9d1c4a30d0..1d08bd8c6e5 100644 --- a/Resources/Prototypes/Entities/Structures/Piping/Atmospherics/unary.yml +++ b/Resources/Prototypes/Entities/Structures/Piping/Atmospherics/unary.yml @@ -6,6 +6,9 @@ mode: SnapgridCenter components: - type: AtmosDevice + - type: Tag + tags: + - Unstackable - type: SubFloorHide blockInteractions: false blockAmbience: false @@ -53,6 +56,7 @@ - type: Tag tags: - GasVent + - Unstackable - type: Sprite drawdepth: FloorObjects sprite: Structures/Piping/Atmospherics/vent.rsi @@ -143,6 +147,7 @@ - type: Tag tags: - GasScrubber + - Unstackable - type: Sprite drawdepth: FloorObjects sprite: Structures/Piping/Atmospherics/scrubber.rsi diff --git a/Resources/Prototypes/Recipes/Construction/utilities.yml b/Resources/Prototypes/Recipes/Construction/utilities.yml index 40fe9b68830..d1dac1d1b05 100644 --- a/Resources/Prototypes/Recipes/Construction/utilities.yml +++ b/Resources/Prototypes/Recipes/Construction/utilities.yml @@ -445,7 +445,8 @@ state: vent_off conditions: - !type:TileNotBlocked {} - + - !type:NoUnstackableInTile + - type: construction name: passive vent description: Unpowered vent that equalises gases on both sides. @@ -466,7 +467,8 @@ state: vent_off conditions: - !type:TileNotBlocked {} - + - !type:NoUnstackableInTile + - type: construction name: air scrubber description: Sucks gas into connected pipes. @@ -487,7 +489,8 @@ state: scrub_off conditions: - !type:TileNotBlocked {} - + - !type:NoUnstackableInTile + - type: construction name: air injector description: Injects air into the atmosphere. @@ -508,7 +511,8 @@ state: injector conditions: - !type:TileNotBlocked {} - + - !type:NoUnstackableInTile + # ATMOS BINARY - type: construction name: gas pump From 6d34f19030a4559a425ebc44757dca0289be4dc6 Mon Sep 17 00:00:00 2001 From: PJBot Date: Wed, 11 Oct 2023 11:21:26 -0400 Subject: [PATCH 087/127] Automatic changelog update --- Resources/Changelog/Changelog.yml | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index f84ac42a72a..9071419f44d 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,9 +1,4 @@ Entries: -- author: metalgearsloth - changes: - - {message: Added toggle to hide clothing in the character editor., type: Add} - id: 4493 - time: '2023-08-09T06:26:34.0000000+00:00' - author: Vordenburg changes: - {message: Diona are no longer inhibited by kudzu., type: Tweak} @@ -2956,3 +2951,9 @@ Entries: inside., type: Tweak} id: 4992 time: '2023-10-11T09:22:09.0000000+00:00' +- author: Skarletto + changes: + - {message: Changed unary devices such as scrubbers and vents to not be able to + stack with each other, type: Tweak} + id: 4993 + time: '2023-10-11T15:20:21.0000000+00:00' From 1f21826c21006cee1c4724e99e24d8faff0484d2 Mon Sep 17 00:00:00 2001 From: Leon Friedrich <60421075+ElectroJr@users.noreply.github.com> Date: Thu, 12 Oct 2023 03:31:10 +1100 Subject: [PATCH 088/127] Fix inventory relay by-ref events (#20816) * Fix inventory relay ref events * this works too (avoid duplication) --------- Co-authored-by: Slava0135 --- .../EntitySystems/ExplosionSystem.cs | 3 +-- .../Inventory/InventorySystem.Relay.cs | 24 +++++++++++-------- Content.Shared/Verbs/Verb.cs | 8 ++++--- 3 files changed, 20 insertions(+), 15 deletions(-) diff --git a/Content.Server/Explosion/EntitySystems/ExplosionSystem.cs b/Content.Server/Explosion/EntitySystems/ExplosionSystem.cs index aa007c61c05..5e5af03c17b 100644 --- a/Content.Server/Explosion/EntitySystems/ExplosionSystem.cs +++ b/Content.Server/Explosion/EntitySystems/ExplosionSystem.cs @@ -116,8 +116,7 @@ public override void Shutdown() private void RelayedResistance(EntityUid uid, ExplosionResistanceComponent component, InventoryRelayedEvent args) { - var a = args.Args; - OnGetResistance(uid, component, ref a); + OnGetResistance(uid, component, ref args.Args); } private void OnGetResistance(EntityUid uid, ExplosionResistanceComponent component, ref GetExplosionResistanceEvent args) diff --git a/Content.Shared/Inventory/InventorySystem.Relay.cs b/Content.Shared/Inventory/InventorySystem.Relay.cs index 83b47542e29..fbe744911fd 100644 --- a/Content.Shared/Inventory/InventorySystem.Relay.cs +++ b/Content.Shared/Inventory/InventorySystem.Relay.cs @@ -24,12 +24,14 @@ public void InitializeRelay() SubscribeLocalEvent(RelayInventoryEvent); SubscribeLocalEvent(RelayInventoryEvent); SubscribeLocalEvent(RelayInventoryEvent); - SubscribeLocalEvent(RefRelayInventoryEvent); SubscribeLocalEvent(RelayInventoryEvent); SubscribeLocalEvent(RelayInventoryEvent); SubscribeLocalEvent(RelayInventoryEvent); SubscribeLocalEvent(RelayInventoryEvent); + // by-ref events + SubscribeLocalEvent(RefRelayInventoryEvent); + // Eye/vision events SubscribeLocalEvent(RelayInventoryEvent); SubscribeLocalEvent(RelayInventoryEvent); @@ -41,22 +43,24 @@ public void InitializeRelay() SubscribeLocalEvent>(RelayInventoryEvent); SubscribeLocalEvent>(RelayInventoryEvent); - SubscribeLocalEvent>(OnGetStrippingVerbs); + SubscribeLocalEvent>(OnGetEquipmentVerbs); } protected void RefRelayInventoryEvent(EntityUid uid, InventoryComponent component, ref T args) where T : IInventoryRelayEvent { - // Just so I don't have to update 20 morbillion events at once. - if (args.TargetSlots == SlotFlags.NONE) - return; - var containerEnumerator = new ContainerSlotEnumerator(uid, component.TemplateId, _prototypeManager, this, args.TargetSlots); + + // this copies the by-ref event var ev = new InventoryRelayedEvent(args); + while (containerEnumerator.MoveNext(out var container)) { if (!container.ContainedEntity.HasValue) continue; - RaiseLocalEvent(container.ContainedEntity.Value, ev, broadcast: false); + RaiseLocalEvent(container.ContainedEntity.Value, ev); } + + // and now we copy it back + args = ev.Args; } protected void RelayInventoryEvent(EntityUid uid, InventoryComponent component, T args) where T : IInventoryRelayEvent @@ -69,11 +73,11 @@ protected void RelayInventoryEvent(EntityUid uid, InventoryComponent componen while (containerEnumerator.MoveNext(out var container)) { if (!container.ContainedEntity.HasValue) continue; - RaiseLocalEvent(container.ContainedEntity.Value, ev, broadcast: false); + RaiseLocalEvent(container.ContainedEntity.Value, ev); } } - private void OnGetStrippingVerbs(EntityUid uid, InventoryComponent component, GetVerbsEvent args) + private void OnGetEquipmentVerbs(EntityUid uid, InventoryComponent component, GetVerbsEvent args) { // Automatically relay stripping related verbs to all equipped clothing. @@ -112,7 +116,7 @@ private void OnGetStrippingVerbs(EntityUid uid, InventoryComponent component, Ge /// public sealed class InventoryRelayedEvent : EntityEventArgs { - public readonly TEvent Args; + public TEvent Args; public InventoryRelayedEvent(TEvent args) { diff --git a/Content.Shared/Verbs/Verb.cs b/Content.Shared/Verbs/Verb.cs index 76ed2073075..660a3bdf948 100644 --- a/Content.Shared/Verbs/Verb.cs +++ b/Content.Shared/Verbs/Verb.cs @@ -1,5 +1,6 @@ using Content.Shared.Database; using Content.Shared.Interaction.Events; +using Content.Shared.Inventory; using Robust.Shared.Serialization; using Robust.Shared.Utility; @@ -349,9 +350,10 @@ public sealed class ExamineVerb : Verb } /// - /// Verbs specifically for interactions that occur with equipped entities. These verbs should be accessible via - /// the stripping UI, and may optionally also be accessible via a verb on the equipee if the via inventory relay - /// events.get-verbs event. + /// Verbs specifically for interactions that occur with equipped entities. These verbs are unique in that they + /// can be used via the stripping UI. Additionally, when getting verbs on an entity with an inventory it will + /// these automatically relay the event to all equipped items via a + /// . /// [Serializable, NetSerializable] public sealed class EquipmentVerb : Verb From 9ea55c5417ff6e60d887e71b6722f763ac61038f Mon Sep 17 00:00:00 2001 From: PJBot Date: Wed, 11 Oct 2023 12:32:14 -0400 Subject: [PATCH 089/127] Automatic changelog update --- Resources/Changelog/Changelog.yml | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 9071419f44d..6ed28abb162 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,9 +1,4 @@ Entries: -- author: Vordenburg - changes: - - {message: Diona are no longer inhibited by kudzu., type: Tweak} - id: 4494 - time: '2023-08-09T15:24:41.0000000+00:00' - author: themias changes: - {message: Taxibots have robot speech bubbles, type: Tweak} @@ -2957,3 +2952,9 @@ Entries: stack with each other, type: Tweak} id: 4993 time: '2023-10-11T15:20:21.0000000+00:00' +- author: ElectroJr + changes: + - {message: Fixed explosion resistance from clothing/equipment not being applied., + type: Fix} + id: 4994 + time: '2023-10-11T16:31:10.0000000+00:00' From b7d96c6538ef4ab0f00c6441ba42b0c8d34bbb19 Mon Sep 17 00:00:00 2001 From: brainfood1183 <113240905+brainfood1183@users.noreply.github.com> Date: Wed, 11 Oct 2023 17:43:54 +0100 Subject: [PATCH 090/127] Honk reagent now makes you Honk. (#20838) --- Resources/Prototypes/Reagents/toxins.yml | 7 ++++++- Resources/Prototypes/Voice/disease_emotes.yml | 5 ----- Resources/Prototypes/Voice/speech_emotes.yml | 5 +++++ 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/Resources/Prototypes/Reagents/toxins.yml b/Resources/Prototypes/Reagents/toxins.yml index e2a40ffbb31..7e206cc9d8f 100644 --- a/Resources/Prototypes/Reagents/toxins.yml +++ b/Resources/Prototypes/Reagents/toxins.yml @@ -508,6 +508,10 @@ Poison: metabolismRate: 0.05 effects: + - !type:Emote + emote: Honk + showInChat: true + probability: 0.2 - !type:HealthChange conditions: - !type:ReagentThreshold @@ -517,6 +521,7 @@ damage: types: Poison: 0.06 + - type: reagent id: Lead @@ -548,4 +553,4 @@ - !type:HealthChange damage: types: - Poison: 1.8 \ No newline at end of file + Poison: 1.8 diff --git a/Resources/Prototypes/Voice/disease_emotes.yml b/Resources/Prototypes/Voice/disease_emotes.yml index fa5f1cd6109..af93025cae0 100644 --- a/Resources/Prototypes/Voice/disease_emotes.yml +++ b/Resources/Prototypes/Voice/disease_emotes.yml @@ -43,8 +43,3 @@ id: Snore category: Vocal chatMessages: [snores] - -- type: emote - id: Honk - category: Vocal - chatMessages: [honks] diff --git a/Resources/Prototypes/Voice/speech_emotes.yml b/Resources/Prototypes/Voice/speech_emotes.yml index ca8b9d55021..133c9249190 100644 --- a/Resources/Prototypes/Voice/speech_emotes.yml +++ b/Resources/Prototypes/Voice/speech_emotes.yml @@ -53,6 +53,11 @@ - giggling - giggled +- type: emote + id: Honk + category: Vocal + chatMessages: [honks] + - type: emote id: Sigh category: Vocal From 0cb46632fd0d38ab2d026c30cb11a7217520eb9e Mon Sep 17 00:00:00 2001 From: JoeHammad1844 <130668733+JoeHammad1844@users.noreply.github.com> Date: Thu, 12 Oct 2023 03:47:25 +1100 Subject: [PATCH 091/127] nukie shuttle gets syndicate airlocks (#20417) --- Resources/Maps/infiltrator.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Resources/Maps/infiltrator.yml b/Resources/Maps/infiltrator.yml index 0cba6c828b2..6670301e909 100644 --- a/Resources/Maps/infiltrator.yml +++ b/Resources/Maps/infiltrator.yml @@ -574,7 +574,7 @@ entities: - type: GasTileOverlay - type: SpreaderGrid - type: GridPathfinding -- proto: AirlockExternal +- proto: AirlockSyndicateLocked entities: - uid: 69 components: @@ -616,7 +616,7 @@ entities: - pos: -4.5,-10.5 parent: 73 type: Transform -- proto: AirlockSecurity +- proto: AirlockSyndicateLocked entities: - uid: 201 components: @@ -637,7 +637,7 @@ entities: - pos: -0.5,-14.5 parent: 73 type: Transform -- proto: AirlockSecurityGlass +- proto: AirlockSyndicateGlassLocked entities: - uid: 371 components: From 8177c406f6fa5a9fb1e01ee330f2ac9026bc2f79 Mon Sep 17 00:00:00 2001 From: PJBot Date: Wed, 11 Oct 2023 12:48:31 -0400 Subject: [PATCH 092/127] Automatic changelog update --- Resources/Changelog/Changelog.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 6ed28abb162..a21254b1320 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,9 +1,4 @@ Entries: -- author: themias - changes: - - {message: Taxibots have robot speech bubbles, type: Tweak} - id: 4495 - time: '2023-08-09T16:48:08.0000000+00:00' - author: Ilya246 changes: - {message: The air alarm UI now allows copying settings of one device to all similar @@ -2958,3 +2953,8 @@ Entries: type: Fix} id: 4994 time: '2023-10-11T16:31:10.0000000+00:00' +- author: JoeHammad + changes: + - {message: The nukie ship now has syndicate access airlocks, type: Add} + id: 4995 + time: '2023-10-11T16:47:25.0000000+00:00' From fcd0d9ef0f4d3ce43fd97ac204f7e3b0275a79cd Mon Sep 17 00:00:00 2001 From: Leon Friedrich <60421075+ElectroJr@users.noreply.github.com> Date: Thu, 12 Oct 2023 04:50:10 +1100 Subject: [PATCH 093/127] Add methods to transfer actions between containers (#20901) --- .../Systems/Actions/ActionUIController.cs | 5 +- .../Actions/ActionContainerSystem.cs | 100 +++++++++++++++--- Content.Shared/Actions/SharedActionsSystem.cs | 10 +- 3 files changed, 98 insertions(+), 17 deletions(-) diff --git a/Content.Client/UserInterface/Systems/Actions/ActionUIController.cs b/Content.Client/UserInterface/Systems/Actions/ActionUIController.cs index b2ff36d05c3..e2de86201e7 100644 --- a/Content.Client/UserInterface/Systems/Actions/ActionUIController.cs +++ b/Content.Client/UserInterface/Systems/Actions/ActionUIController.cs @@ -769,10 +769,9 @@ private bool OnMenuBeginDrag() { if (_actionsSystem != null && _actionsSystem.TryGetActionData(_menuDragHelper.Dragged?.ActionId, out var action)) { - if (action.EntityIcon is {} entIcon) + if (EntityManager.TryGetComponent(action.EntityIcon, out SpriteComponent? sprite)) { - _dragShadow.Texture = EntityManager.GetComponent(entIcon).Icon? - .GetFrame(RsiDirection.South, 0); + _dragShadow.Texture = sprite.Icon?.GetFrame(RsiDirection.South, 0); } else if (action.Icon != null) { diff --git a/Content.Shared/Actions/ActionContainerSystem.cs b/Content.Shared/Actions/ActionContainerSystem.cs index 27cd8dcce68..bce0836efb6 100644 --- a/Content.Shared/Actions/ActionContainerSystem.cs +++ b/Content.Shared/Actions/ActionContainerSystem.cs @@ -1,4 +1,5 @@ using System.Diagnostics.CodeAnalysis; +using System.Linq; using Robust.Shared.Containers; using Robust.Shared.Network; using Robust.Shared.Timing; @@ -15,6 +16,7 @@ public sealed class ActionContainerSystem : EntitySystem [Dependency] private readonly SharedContainerSystem _container = default!; [Dependency] private readonly SharedActionsSystem _actions = default!; [Dependency] private readonly INetManager _netMan = default!; + [Dependency] private readonly SharedTransformSystem _transform = default!; public override void Initialize() { @@ -96,7 +98,61 @@ public bool EnsureAction(EntityUid uid, } /// - /// Adds a pre-existing action to an action container. + /// Transfers an action from one container to another, while keeping the attached entity the same. + /// + /// + /// While the attached entity should be the same at the end, this will actually remove and then re-grant the action. + /// + public void TransferAction( + EntityUid actionId, + EntityUid newContainer, + BaseActionComponent? action = null, + ActionsContainerComponent? container = null) + { + if (!_actions.ResolveActionData(actionId, ref action)) + return; + + if (action.Container == newContainer) + return; + + var attached = action.AttachedEntity; + if (!AddAction(newContainer, actionId, action, container)) + return; + + DebugTools.AssertEqual(action.Container, newContainer); + DebugTools.AssertNull(action.AttachedEntity); + + if (attached != null) + _actions.AddActionDirect(attached.Value, actionId, action: action); + + DebugTools.AssertEqual(action.AttachedEntity, attached); + } + + /// + /// Transfers all actions from one container to another, while keeping the attached entity the same. + /// + /// <remarks> + /// While the attached entity should be the same at the end, this will actually remove and then re-grant the action. + /// </remarks> + public void TransferAllActions( + EntityUid from, + EntityUid to, + ActionsContainerComponent? oldContainer = null, + ActionsContainerComponent? newContainer = null) + { + if (!Resolve(from, ref oldContainer) || !Resolve(to, ref newContainer)) + return; + + foreach (var action in oldContainer.Container.ContainedEntities.ToArray()) + { + TransferAction(action, to, container: newContainer); + } + + DebugTools.AssertEqual(oldContainer.Container.Count, 0); + } + + /// + /// Adds a pre-existing action to an action container. If the action is already in some container it will first remove it. /// public bool AddAction(EntityUid uid, EntityUid actionId, BaseActionComponent? action = null, ActionsContainerComponent? comp = null) { @@ -104,10 +160,7 @@ public bool AddAction(EntityUid uid, EntityUid actionId, BaseActionComponent? ac return false; if (action.Container != null) - { - Log.Error($"Attempted to insert an action {ToPrettyString(actionId)} that was already in a container {ToPrettyString(action.Container.Value)}"); - return false; - } + RemoveAction(actionId, action); DebugTools.Assert(comp == null || comp.Owner == uid); comp ??= EnsureComp(uid); @@ -124,6 +177,35 @@ public bool AddAction(EntityUid uid, EntityUid actionId, BaseActionComponent? ac return true; } + /// + /// Removes an action from its container and any action-performer and moves the action to null-space + /// + public void RemoveAction(EntityUid actionId, BaseActionComponent? action = null) + { + if (!_actions.ResolveActionData(actionId, ref action)) + return; + + if (action.Container == null) + return; + + _transform.DetachParentToNull(actionId, Transform(actionId)); + + // Container removal events should have removed the action from the action container. + // However, just in case the container was already deleted we will still manually clear the container field + if (action.Container != null) + { + if (Exists(action.Container)) + Log.Error($"Failed to remove action {ToPrettyString(actionId)} from its container {ToPrettyString(action.Container)}?"); + action.Container = null; + } + + // If the action was granted to some entity, then the removal from the container should have automatically removed it. + // However, if the action was granted without ever being placed in an action container, it will not have been removed. + // Therefore, to ensure that the behaviour of the method is consistent we will also explicitly remove the action. + if (action.AttachedEntity != null) + _actions.RemoveAction(action.AttachedEntity.Value, actionId, action: action); + } + private void OnInit(EntityUid uid, ActionsContainerComponent component, ComponentInit args) { component.Container = _container.EnsureContainer(uid, ActionsContainerComponent.ContainerId); @@ -171,13 +253,7 @@ private void OnEntityRemoved(EntityUid uid, ActionsContainerComponent component, var ev = new ActionRemovedEvent(args.Entity, data); RaiseLocalEvent(uid, ref ev); - - if (_netMan.IsServer) - { - // TODO Actions - // log an error or warning here once gibbing code is fixed. - QueueDel(args.Entity); - } + data.Container = null; } } diff --git a/Content.Shared/Actions/SharedActionsSystem.cs b/Content.Shared/Actions/SharedActionsSystem.cs index 86379277e23..8d2c8c28e3e 100644 --- a/Content.Shared/Actions/SharedActionsSystem.cs +++ b/Content.Shared/Actions/SharedActionsSystem.cs @@ -586,9 +586,16 @@ public void RemoveAction(EntityUid performer, EntityUid? actionId, ActionsCompon if (!ResolveActionData(actionId, ref action)) return; + if (action.AttachedEntity != performer) + { + Log.Error($"Attempted to remove an action {ToPrettyString(actionId)} from an entity that it was never attached to: {ToPrettyString(performer)}"); + return; + } + if (!Resolve(performer, ref comp, false)) { - DebugTools.AssertNull(action.AttachedEntity); + DebugTools.Assert(action.AttachedEntity == null || TerminatingOrDeleted(action.AttachedEntity.Value)); + action.AttachedEntity = null; return; } @@ -599,7 +606,6 @@ public void RemoveAction(EntityUid performer, EntityUid? actionId, ActionsCompon return; } - DebugTools.Assert(action.AttachedEntity == performer); comp.Actions.Remove(actionId.Value); action.AttachedEntity = null; Dirty(actionId.Value, action); From 0afc03558508060a7de6361b6a513e1441049d3c Mon Sep 17 00:00:00 2001 From: Colin-Tel <113523727+Colin-Tel@users.noreply.github.com> Date: Wed, 11 Oct 2023 16:49:49 -0500 Subject: [PATCH 094/127] Prettified human_hair.rsi meta.json (#20873) * Prettified human_hair.rsi meta.json * Update meta.json removed delay field --- .../Customization/human_hair.rsi/meta.json | 748 +++++++++++++++++- 1 file changed, 747 insertions(+), 1 deletion(-) diff --git a/Resources/Textures/Mobs/Customization/human_hair.rsi/meta.json b/Resources/Textures/Mobs/Customization/human_hair.rsi/meta.json index 142fc9c1aa3..9b7d68a1671 100644 --- a/Resources/Textures/Mobs/Customization/human_hair.rsi/meta.json +++ b/Resources/Textures/Mobs/Customization/human_hair.rsi/meta.json @@ -1 +1,747 @@ -{"version":1,"size":{"x":32,"y":32},"copyright":"Taken from https://github.com/tgstation/tgstation/blob/05ec94e46349c35e29ca91e5e97d0c88ae26ad44/icons/mob/species/human/human_face.dmi , resprited by Alekshhh, a modified by potato1234x","license":"CC-BY-SA-3.0","states":[{"name":"80s","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"a","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"afro","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"afro2","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"antenna","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"b","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"baldfade","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"bedhead","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"bedheadv2","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"bedheadv3","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"beehive","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"beehivev2","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"bigafro","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"bigflattop","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"bigpompadour","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"bob","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"bob2","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"bob4","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"bobcurl","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"bobcut","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"boddicker","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"bowlcut","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"bowlcut2","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"braid","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"braid2","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"braided","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"braidfront","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"braidtail","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"bun","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"bun3","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"bunhead2","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"business","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"business2","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"business3","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"business4","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"buzzcut","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"c","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"classicafro","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"classicbigafro","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"classiccia","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"classicfloorlength_bedhead","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"classicmodern","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"classicmulder","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"classicwisp","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"cia","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"coffeehouse","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"combover","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"cornrowbraid","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"cornrowbun","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"cornrows","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"cornrows2","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"cornrowtail","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"country","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"crewcut","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"curls","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"d","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"dandypompadour","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"devilock","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"doublebun","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"dreads","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"drillhair","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"drillhairextended","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"drillruru","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"e","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"emo","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"emo2","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"emofringe","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"f","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"father","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"feather","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"flair","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"floorlength_bedhead","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"fringetail","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"gelled","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"gentle","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"halfbang","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"halfbang2","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"halfshaved","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"hbraid","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"hedgehog","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"highfade","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"highponytail","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"himecut","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"himecut2","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"himeup","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"hitop","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"jade","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"jensen","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"joestar","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"kagami","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"keanu","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"kusanagi","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"largebun","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"lbangs","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"long","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"long2","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"long3","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"long_bedhead","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"longemo","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"longest","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"longest2","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"longfringe","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"longovereye","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"longsidepart","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"longstraightponytail","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"lowfade","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"manbun","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"medfade","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"megaeyebrows","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"messy","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"modern","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"mulder","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"nitori","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"nofade","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"odango","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"ombre","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"oneshoulder","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"oxton","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"part","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"parted","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"pigtails","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"pigtails2","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"pixie","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"pompadour","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"ponytail","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"ponytail2","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"ponytail3","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"ponytail4","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"ponytail5","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"ponytail6","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"ponytail7","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"poofy","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"protagonist","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"quiff","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"reversemohawk","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"ronin","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"rosa","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"sargeant","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"shaved","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"shavedmohawk","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"shavedpart","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"shortbangs","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"shortbraid","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"shorthair2","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"shorthair3","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"shorthairg","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"shorthime","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"shortovereye","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"sidecut","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"sidetail","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"sidetail2","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"sidetail3","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"sidetail4","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"skinhead","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"spikey","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"spiky","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"spiky2","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"spikyponytail","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"stail","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"swept","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"swept2","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"shoulderlengthovereye","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"thinning","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"thinningfront","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"thinningrear","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"tightbun","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"topknot","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"tressshoulder","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"trimflat","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"trimmed","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"twintail","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"twostrands","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"undercut","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"undercutleft","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"undercutright","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"unkept","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"unshaven_mohawk","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"updo","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"veryshortovereyealternate","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"vlong","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"vlongfringe","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"volaju","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"wisp","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]},{"name":"bald","directions":4,"delays":[[1.0],[1.0],[1.0],[1.0]]}]} +{ + "version": 1, + "size": { + "x": 32, + "y": 32 + }, + "copyright": "Taken from https://github.com/tgstation/tgstation/blob/05ec94e46349c35e29ca91e5e97d0c88ae26ad44/icons/mob/species/human/human_face.dmi , resprited by Alekshhh, a modified by potato1234x", + "license": "CC-BY-SA-3.0", + "states": [ + { + "name": "80s", + "directions": 4 + }, + { + "name": "a", + "directions": 4 + }, + { + "name": "afro", + "directions": 4 + }, + { + "name": "afro2", + "directions": 4 + }, + { + "name": "antenna", + "directions": 4 + }, + { + "name": "b", + "directions": 4 + }, + { + "name": "baldfade", + "directions": 4 + }, + { + "name": "bedhead", + "directions": 4 + }, + { + "name": "bedheadv2", + "directions": 4 + }, + { + "name": "bedheadv3", + "directions": 4 + }, + { + "name": "beehive", + "directions": 4 + }, + { + "name": "beehivev2", + "directions": 4 + }, + { + "name": "bigafro", + "directions": 4 + }, + { + "name": "bigflattop", + "directions": 4 + }, + { + "name": "bigpompadour", + "directions": 4 + }, + { + "name": "bob", + "directions": 4 + }, + { + "name": "bob2", + "directions": 4 + }, + { + "name": "bob4", + "directions": 4 + }, + { + "name": "bobcurl", + "directions": 4 + }, + { + "name": "bobcut", + "directions": 4 + }, + { + "name": "boddicker", + "directions": 4 + }, + { + "name": "bowlcut", + "directions": 4 + }, + { + "name": "bowlcut2", + "directions": 4 + }, + { + "name": "braid", + "directions": 4 + }, + { + "name": "braid2", + "directions": 4 + }, + { + "name": "braided", + "directions": 4 + }, + { + "name": "braidfront", + "directions": 4 + }, + { + "name": "braidtail", + "directions": 4 + }, + { + "name": "bun", + "directions": 4 + }, + { + "name": "bun3", + "directions": 4 + }, + { + "name": "bunhead2", + "directions": 4 + }, + { + "name": "business", + "directions": 4 + }, + { + "name": "business2", + "directions": 4 + }, + { + "name": "business3", + "directions": 4 + }, + { + "name": "business4", + "directions": 4 + }, + { + "name": "buzzcut", + "directions": 4 + }, + { + "name": "c", + "directions": 4 + }, + { + "name": "classicafro", + "directions": 4 + }, + { + "name": "classicbigafro", + "directions": 4 + }, + { + "name": "classiccia", + "directions": 4 + }, + { + "name": "classicfloorlength_bedhead", + "directions": 4 + }, + { + "name": "classicmodern", + "directions": 4 + }, + { + "name": "classicmulder", + "directions": 4 + }, + { + "name": "classicwisp", + "directions": 4 + }, + { + "name": "cia", + "directions": 4 + }, + { + "name": "coffeehouse", + "directions": 4 + }, + { + "name": "combover", + "directions": 4 + }, + { + "name": "cornrowbraid", + "directions": 4 + }, + { + "name": "cornrowbun", + "directions": 4 + }, + { + "name": "cornrows", + "directions": 4 + }, + { + "name": "cornrows2", + "directions": 4 + }, + { + "name": "cornrowtail", + "directions": 4 + }, + { + "name": "country", + "directions": 4 + }, + { + "name": "crewcut", + "directions": 4 + }, + { + "name": "curls", + "directions": 4 + }, + { + "name": "d", + "directions": 4 + }, + { + "name": "dandypompadour", + "directions": 4 + }, + { + "name": "devilock", + "directions": 4 + }, + { + "name": "doublebun", + "directions": 4 + }, + { + "name": "dreads", + "directions": 4 + }, + { + "name": "drillhair", + "directions": 4 + }, + { + "name": "drillhairextended", + "directions": 4 + }, + { + "name": "drillruru", + "directions": 4 + }, + { + "name": "e", + "directions": 4 + }, + { + "name": "emo", + "directions": 4 + }, + { + "name": "emo2", + "directions": 4 + }, + { + "name": "emofringe", + "directions": 4 + }, + { + "name": "f", + "directions": 4 + }, + { + "name": "father", + "directions": 4 + }, + { + "name": "feather", + "directions": 4 + }, + { + "name": "flair", + "directions": 4 + }, + { + "name": "floorlength_bedhead", + "directions": 4 + }, + { + "name": "fringetail", + "directions": 4 + }, + { + "name": "gelled", + "directions": 4 + }, + { + "name": "gentle", + "directions": 4 + }, + { + "name": "halfbang", + "directions": 4 + }, + { + "name": "halfbang2", + "directions": 4 + }, + { + "name": "halfshaved", + "directions": 4 + }, + { + "name": "hbraid", + "directions": 4 + }, + { + "name": "hedgehog", + "directions": 4 + }, + { + "name": "highfade", + "directions": 4 + }, + { + "name": "highponytail", + "directions": 4 + }, + { + "name": "himecut", + "directions": 4 + }, + { + "name": "himecut2", + "directions": 4 + }, + { + "name": "himeup", + "directions": 4 + }, + { + "name": "hitop", + "directions": 4 + }, + { + "name": "jade", + "directions": 4 + }, + { + "name": "jensen", + "directions": 4 + }, + { + "name": "joestar", + "directions": 4 + }, + { + "name": "kagami", + "directions": 4 + }, + { + "name": "keanu", + "directions": 4 + }, + { + "name": "kusanagi", + "directions": 4 + }, + { + "name": "largebun", + "directions": 4 + }, + { + "name": "lbangs", + "directions": 4 + }, + { + "name": "long", + "directions": 4 + }, + { + "name": "long2", + "directions": 4 + }, + { + "name": "long3", + "directions": 4 + }, + { + "name": "long_bedhead", + "directions": 4 + }, + { + "name": "longemo", + "directions": 4 + }, + { + "name": "longest", + "directions": 4 + }, + { + "name": "longest2", + "directions": 4 + }, + { + "name": "longfringe", + "directions": 4 + }, + { + "name": "longovereye", + "directions": 4 + }, + { + "name": "longsidepart", + "directions": 4 + }, + { + "name": "longstraightponytail", + "directions": 4 + }, + { + "name": "lowfade", + "directions": 4 + }, + { + "name": "manbun", + "directions": 4 + }, + { + "name": "medfade", + "directions": 4 + }, + { + "name": "megaeyebrows", + "directions": 4 + }, + { + "name": "messy", + "directions": 4 + }, + { + "name": "modern", + "directions": 4 + }, + { + "name": "mulder", + "directions": 4 + }, + { + "name": "nitori", + "directions": 4 + }, + { + "name": "nofade", + "directions": 4 + }, + { + "name": "odango", + "directions": 4 + }, + { + "name": "ombre", + "directions": 4 + }, + { + "name": "oneshoulder", + "directions": 4 + }, + { + "name": "oxton", + "directions": 4 + }, + { + "name": "part", + "directions": 4 + }, + { + "name": "parted", + "directions": 4 + }, + { + "name": "pigtails", + "directions": 4 + }, + { + "name": "pigtails2", + "directions": 4 + }, + { + "name": "pixie", + "directions": 4 + }, + { + "name": "pompadour", + "directions": 4 + }, + { + "name": "ponytail", + "directions": 4 + }, + { + "name": "ponytail2", + "directions": 4 + }, + { + "name": "ponytail3", + "directions": 4 + }, + { + "name": "ponytail4", + "directions": 4 + }, + { + "name": "ponytail5", + "directions": 4 + }, + { + "name": "ponytail6", + "directions": 4 + }, + { + "name": "ponytail7", + "directions": 4 + }, + { + "name": "poofy", + "directions": 4 + }, + { + "name": "protagonist", + "directions": 4 + }, + { + "name": "quiff", + "directions": 4 + }, + { + "name": "reversemohawk", + "directions": 4 + }, + { + "name": "ronin", + "directions": 4 + }, + { + "name": "rosa", + "directions": 4 + }, + { + "name": "sargeant", + "directions": 4 + }, + { + "name": "shaved", + "directions": 4 + }, + { + "name": "shavedmohawk", + "directions": 4 + }, + { + "name": "shavedpart", + "directions": 4 + }, + { + "name": "shortbangs", + "directions": 4 + }, + { + "name": "shortbraid", + "directions": 4 + }, + { + "name": "shorthair2", + "directions": 4 + }, + { + "name": "shorthair3", + "directions": 4 + }, + { + "name": "shorthairg", + "directions": 4 + }, + { + "name": "shorthime", + "directions": 4 + }, + { + "name": "shortovereye", + "directions": 4 + }, + { + "name": "sidecut", + "directions": 4 + }, + { + "name": "sidetail", + "directions": 4 + }, + { + "name": "sidetail2", + "directions": 4 + }, + { + "name": "sidetail3", + "directions": 4 + }, + { + "name": "sidetail4", + "directions": 4 + }, + { + "name": "skinhead", + "directions": 4 + }, + { + "name": "spikey", + "directions": 4 + }, + { + "name": "spiky", + "directions": 4 + }, + { + "name": "spiky2", + "directions": 4 + }, + { + "name": "spikyponytail", + "directions": 4 + }, + { + "name": "stail", + "directions": 4 + }, + { + "name": "swept", + "directions": 4 + }, + { + "name": "swept2", + "directions": 4 + }, + { + "name": "shoulderlengthovereye", + "directions": 4 + }, + { + "name": "thinning", + "directions": 4 + }, + { + "name": "thinningfront", + "directions": 4 + }, + { + "name": "thinningrear", + "directions": 4 + }, + { + "name": "tightbun", + "directions": 4 + }, + { + "name": "topknot", + "directions": 4 + }, + { + "name": "tressshoulder", + "directions": 4 + }, + { + "name": "trimflat", + "directions": 4 + }, + { + "name": "trimmed", + "directions": 4 + }, + { + "name": "twintail", + "directions": 4 + }, + { + "name": "twostrands", + "directions": 4 + }, + { + "name": "undercut", + "directions": 4 + }, + { + "name": "undercutleft", + "directions": 4 + }, + { + "name": "undercutright", + "directions": 4 + }, + { + "name": "unkept", + "directions": 4 + }, + { + "name": "unshaven_mohawk", + "directions": 4 + }, + { + "name": "updo", + "directions": 4 + }, + { + "name": "veryshortovereyealternate", + "directions": 4 + }, + { + "name": "vlong", + "directions": 4 + }, + { + "name": "vlongfringe", + "directions": 4 + }, + { + "name": "volaju", + "directions": 4 + }, + { + "name": "wisp", + "directions": 4 + }, + { + "name": "bald", + "directions": 4 + } + ] + } \ No newline at end of file From b53f10fbb268bb1cdd7e3a2256cd8cc424485cd3 Mon Sep 17 00:00:00 2001 From: DrSmugleaf Date: Wed, 11 Oct 2023 15:14:00 -0700 Subject: [PATCH 095/127] Fix not removing RevolutionaryRoleComponent from minds on mindshield application (#20832) * Fix not removing RevolutionaryRoleComponent from minds on mindshield application * Simplify other part of the mindshield code * Fix being able to mindshield head revs * Other way around --- Content.Server/Mindshield/MindShieldSystem.cs | 31 ++++++++++--------- .../SharedRevolutionarySystem.cs | 14 +++++---- 2 files changed, 24 insertions(+), 21 deletions(-) diff --git a/Content.Server/Mindshield/MindShieldSystem.cs b/Content.Server/Mindshield/MindShieldSystem.cs index 714055bd942..bfca6c008ea 100644 --- a/Content.Server/Mindshield/MindShieldSystem.cs +++ b/Content.Server/Mindshield/MindShieldSystem.cs @@ -1,13 +1,13 @@ -using Content.Shared.Mindshield.Components; -using Content.Shared.Revolutionary.Components; -using Content.Server.Popups; -using Content.Shared.Database; using Content.Server.Administration.Logs; using Content.Server.Mind; -using Content.Shared.Implants; -using Content.Shared.Tag; +using Content.Server.Popups; using Content.Server.Roles; +using Content.Shared.Database; +using Content.Shared.Implants; using Content.Shared.Implants.Components; +using Content.Shared.Mindshield.Components; +using Content.Shared.Revolutionary.Components; +using Content.Shared.Tag; namespace Content.Server.Mindshield; @@ -39,25 +39,26 @@ public void ImplantCheck(EntityUid uid, SubdermalImplantComponent comp, ref Impl if (_tag.HasTag(ev.Implant, MindShieldTag) && ev.Implanted != null) { EnsureComp(ev.Implanted.Value); - MindShieldRemovalCheck(ev.Implanted, ev.Implant); + MindShieldRemovalCheck(ev.Implanted.Value, ev.Implant); } } /// /// Checks if the implanted person was a Rev or Head Rev and remove role or destroy mindshield respectively. /// - public void MindShieldRemovalCheck(EntityUid? implanted, EntityUid implant) + public void MindShieldRemovalCheck(EntityUid implanted, EntityUid implant) { - if (HasComp(implanted) && !HasComp(implanted)) + if (HasComp(implanted)) { - _mindSystem.TryGetMind(implanted.Value, out var mindId, out _); - _adminLogManager.Add(LogType.Mind, LogImpact.Medium, $"{ToPrettyString(implanted.Value)} was deconverted due to being implanted with a Mindshield."); - _roleSystem.MindTryRemoveRole(mindId); + _popupSystem.PopupEntity(Loc.GetString("head-rev-break-mindshield"), implanted); + QueueDel(implant); + return; } - else if (HasComp(implanted)) + + if (_mindSystem.TryGetMind(implanted, out var mindId, out _) && + _roleSystem.MindTryRemoveRole(mindId)) { - _popupSystem.PopupEntity(Loc.GetString("head-rev-break-mindshield"), implanted.Value); - QueueDel(implant); + _adminLogManager.Add(LogType.Mind, LogImpact.Medium, $"{ToPrettyString(implanted)} was deconverted due to being implanted with a Mindshield."); } } } diff --git a/Content.Shared/Revolutionary/SharedRevolutionarySystem.cs b/Content.Shared/Revolutionary/SharedRevolutionarySystem.cs index e2a8192716c..1399b116e0f 100644 --- a/Content.Shared/Revolutionary/SharedRevolutionarySystem.cs +++ b/Content.Shared/Revolutionary/SharedRevolutionarySystem.cs @@ -1,7 +1,7 @@ -using Content.Shared.Revolutionary.Components; using Content.Shared.IdentityManagement; using Content.Shared.Mindshield.Components; using Content.Shared.Popups; +using Content.Shared.Revolutionary.Components; using Content.Shared.Stunnable; namespace Content.Shared.Revolutionary; @@ -22,7 +22,13 @@ public override void Initialize() /// private void MindShieldImplanted(EntityUid uid, MindShieldComponent comp, MapInitEvent init) { - if (HasComp(uid) && !HasComp(uid)) + if (HasComp(uid)) + { + RemCompDeferred(uid); + return; + } + + if (HasComp(uid)) { var stunTime = TimeSpan.FromSeconds(4); var name = Identity.Entity(uid, EntityManager); @@ -30,9 +36,5 @@ private void MindShieldImplanted(EntityUid uid, MindShieldComponent comp, MapIni _sharedStun.TryParalyze(uid, stunTime, true); _popupSystem.PopupEntity(Loc.GetString("rev-break-control", ("name", name)), uid); } - else if (HasComp(uid)) - { - RemCompDeferred(uid); - } } } From 1508f513bf883ad8047dd952a0571258c539b9a1 Mon Sep 17 00:00:00 2001 From: Psychpsyo <60073468+Psychpsyo@users.noreply.github.com> Date: Thu, 12 Oct 2023 00:57:09 +0200 Subject: [PATCH 096/127] Jittering System Fix + Cleanup (#20921) --- Content.Client/Jittering/JitteringSystem.cs | 21 ++++++++----------- .../Jittering/SharedJitteringSystem.cs | 2 +- 2 files changed, 10 insertions(+), 13 deletions(-) diff --git a/Content.Client/Jittering/JitteringSystem.cs b/Content.Client/Jittering/JitteringSystem.cs index 032eb3e18f2..41f20634ab5 100644 --- a/Content.Client/Jittering/JitteringSystem.cs +++ b/Content.Client/Jittering/JitteringSystem.cs @@ -1,13 +1,7 @@ -using System; -using System.Collections.Immutable; using System.Numerics; using Content.Shared.Jittering; using Robust.Client.Animations; using Robust.Client.GameObjects; -using Robust.Shared.Animations; -using Robust.Shared.GameObjects; -using Robust.Shared.IoC; -using Robust.Shared.Maths; using Robust.Shared.Random; namespace Content.Client.Jittering @@ -15,6 +9,7 @@ namespace Content.Client.Jittering public sealed class JitteringSystem : SharedJitteringSystem { [Dependency] private readonly IRobustRandom _random = default!; + [Dependency] private readonly AnimationPlayerSystem _animationPlayer = default!; private readonly float[] _sign = { -1, 1 }; private readonly string _jitterAnimationKey = "jittering"; @@ -35,13 +30,13 @@ private void OnStartup(EntityUid uid, JitteringComponent jittering, ComponentSta var animationPlayer = EntityManager.EnsureComponent(uid); - animationPlayer.Play(GetAnimation(jittering, sprite), _jitterAnimationKey); + _animationPlayer.Play(animationPlayer, GetAnimation(jittering, sprite), _jitterAnimationKey); } private void OnShutdown(EntityUid uid, JitteringComponent jittering, ComponentShutdown args) { if (EntityManager.TryGetComponent(uid, out AnimationPlayerComponent? animationPlayer)) - animationPlayer.Stop(_jitterAnimationKey); + _animationPlayer.Stop(animationPlayer, _jitterAnimationKey); if (EntityManager.TryGetComponent(uid, out SpriteComponent? sprite)) sprite.Offset = Vector2.Zero; @@ -52,9 +47,9 @@ private void OnAnimationCompleted(EntityUid uid, JitteringComponent jittering, A if(args.Key != _jitterAnimationKey) return; - if(EntityManager.TryGetComponent(uid, out AnimationPlayerComponent? animationPlayer) + if (EntityManager.TryGetComponent(uid, out AnimationPlayerComponent? animationPlayer) && EntityManager.TryGetComponent(uid, out SpriteComponent? sprite)) - animationPlayer.Play(GetAnimation(jittering, sprite), _jitterAnimationKey); + _animationPlayer.Play(animationPlayer, GetAnimation(jittering, sprite), _jitterAnimationKey); } private Animation GetAnimation(JitteringComponent jittering, SpriteComponent sprite) @@ -77,8 +72,10 @@ private Animation GetAnimation(JitteringComponent jittering, SpriteComponent spr offset.Y *= -1; } - // Animation length shouldn't be too high so we will cap it at 2 seconds... - var length = Math.Min((1f/jittering.Frequency), 2f); + var length = 0f; + // avoid dividing by 0 so animations don't try to be infinitely long + if (jittering.Frequency > 0) + length = 1f / jittering.Frequency; jittering.LastJitter = offset; diff --git a/Content.Shared/Jittering/SharedJitteringSystem.cs b/Content.Shared/Jittering/SharedJitteringSystem.cs index 327a4521752..1ac8413375e 100644 --- a/Content.Shared/Jittering/SharedJitteringSystem.cs +++ b/Content.Shared/Jittering/SharedJitteringSystem.cs @@ -72,7 +72,7 @@ public void AddJitter(EntityUid uid, float amplitude = 10f, float frequency = 4f var jitter = EnsureComp(uid); jitter.Amplitude = amplitude; jitter.Frequency = frequency; - Dirty(jitter); + Dirty(uid, jitter); } } } From 1e1433374a30baf48b3d4082f2d3cefb300c6468 Mon Sep 17 00:00:00 2001 From: DrSmugleaf Date: Wed, 11 Oct 2023 23:30:52 -0700 Subject: [PATCH 097/127] Update Patrons list in the credits (#20937) --- Resources/Credits/Patrons.yml | 226 +++++++++++++++++++--------------- 1 file changed, 128 insertions(+), 98 deletions(-) diff --git a/Resources/Credits/Patrons.yml b/Resources/Credits/Patrons.yml index 99f51c15676..acb9eb229a5 100644 --- a/Resources/Credits/Patrons.yml +++ b/Resources/Credits/Patrons.yml @@ -1,160 +1,190 @@ -- Name: AAbcoi - Tier: Syndicate Agent -- Name: tomhendo - Tier: Syndicate Agent -- Name: M4shr00m - Tier: Syndicate Agent -- Name: Aleksey - Tier: Syndicate Agent -- Name: Skarlet - Tier: Revolutionary -- Name: March - Tier: Syndicate Agent -- Name: Александр Белошапка - Tier: Revolutionary -- Name: Dave +- Name: "Tomeno" Tier: Revolutionary -- Name: Akira Shiroyanagi [無情な男] +- Name: "Daniel Thompson" Tier: Revolutionary -- Name: Alix Shepard +- Name: "Farewell Fire" + Tier: Syndicate Agent +- Name: "MetalClone" Tier: Nuclear Operative -- Name: JhenMaster +- Name: "CPM311" Tier: Revolutionary -- Name: Lieutenant Colonel Orangejuice - Tier: Syndicate Agent -- Name: TheGoldElite +- Name: "Bobberunio" Tier: Revolutionary -- Name: Gnomo - Tier: Nuclear Operative -- Name: Never Solus +- Name: "vifs_vestige" Tier: Syndicate Agent -- Name: Ari. - Tier: Revolutionary -- Name: russell +- Name: "Anthony Fleck" Tier: Nuclear Operative -- Name: Kevin +- Name: "Nico Thate" + Tier: Revolutionary +- Name: "Zandario" Tier: Nuclear Operative -- Name: DubzyVEVO +- Name: "Darren Brady" Tier: Revolutionary -- Name: ikamuse johnson +- Name: "DramaBuns" Tier: Revolutionary -- Name: Saphire +- Name: "Ethan Keller" Tier: Revolutionary -- Name: Gavin Simmons +- Name: "Eric VW" Tier: Revolutionary -- Name: Tamora Droppa +- Name: "Joshington Awesomahee" Tier: Revolutionary -- Name: Gaxeer - Tier: Syndicate Agent -- Name: rosysyntax +- Name: "Altana" Tier: Revolutionary -- Name: Scott MacCombie +- Name: "clyf" Tier: Nuclear Operative -- Name: Jeremy Hernandez +- Name: "spinnermaster" Tier: Syndicate Agent -- Name: Dan - Tier: Syndicate Agent -- Name: Carbonhell +- Name: "Will M." + Tier: Revolutionary +- Name: "The Hateful Flesh" + Tier: Revolutionary +- Name: "Viridian" + Tier: Revolutionary +- Name: "Nicholas Hillblom" + Tier: Revolutionary +- Name: "Austin Nelson" Tier: Syndicate Agent -- Name: Rasmus Cedergren +- Name: "John Edward Hamilton Barchard" + Tier: Revolutionary +- Name: "Cormos Lemming" + Tier: Nuclear Operative +- Name: "Hamcha" Tier: Revolutionary -- Name: Pasemi +- Name: "Peter \"Azmond\" Newhouse" Tier: Revolutionary -- Name: Unknown Kiwi +- Name: "Zakanater 19" Tier: Revolutionary -- Name: Mitchell Marry +- Name: "Kris Piper" Tier: Revolutionary -- Name: Matouš Hrdlička +- Name: "Mikhail" + Tier: Revolutionary +- Name: "osborn" + Tier: Syndicate Agent +- Name: "Uinseann" + Tier: Revolutionary +- Name: "Brandon Campbell" Tier: Nuclear Operative -- Name: BokChoy +- Name: "KevKev" + Tier: Revolutionary +- Name: "Jacob Schramm" + Tier: Revolutionary +- Name: "Matouš Hrdlička" Tier: Nuclear Operative -- Name: KevKev +- Name: "Pasemi" + Tier: Revolutionary +- Name: "Late Fox" Tier: Revolutionary -- Name: Gothryd +- Name: "Dan" Tier: Syndicate Agent -- Name: Brandon Campbell +- Name: "Scott MacCombie" Tier: Nuclear Operative -- Name: Matthew C Miklaucic +- Name: "Gaxeer" + Tier: Syndicate Agent +- Name: "Tamora Droppa" Tier: Revolutionary -- Name: lapatison +- Name: "Gavin Simmons" + Tier: Syndicate Agent +- Name: "Saphire" Tier: Revolutionary -- Name: Uinseann +- Name: "DubzyVEVO" Tier: Revolutionary -- Name: osborn +- Name: "Never Solus" Tier: Syndicate Agent -- Name: Ramiro Agis +- Name: "Gnomo" + Tier: Nuclear Operative +- Name: "TheGoldElite" Tier: Revolutionary -- Name: Mikhail +- Name: "JhenMaster" Tier: Revolutionary -- Name: liltenhead +- Name: "Akira" Tier: Revolutionary -- Name: Kris Piper +- Name: "Dave" Tier: Revolutionary -- Name: Peter "Azmond" Newhouse +- Name: "Александр Белошапка" Tier: Revolutionary -- Name: Hamcha +- Name: "Gordod" + Tier: Syndicate Agent +- Name: "tomhendo" + Tier: Syndicate Agent +- Name: "Odin The Wanderer" Tier: Revolutionary -- Name: Oxyclean114 +- Name: "Wallace Megas" Tier: Revolutionary -- Name: Cormos Lemming - Tier: Nuclear Operative -- Name: John Edward Hamilton Barchard +- Name: "Vandell" Tier: Revolutionary -- Name: Wrexbe +- Name: "Enricoc3l" Tier: Revolutionary -- Name: Austin Nelson +- Name: "DadNotTheBelt" + Tier: Nuclear Operative +- Name: "David" + Tier: Revolutionary +- Name: "Watson Whittington" Tier: Syndicate Agent -- Name: AquaDraco +- Name: "Raw Toast" Tier: Revolutionary -- Name: Nicholas Hillblom +- Name: "Tim Foley" + Tier: Syndicate Agent +- Name: "Blight" + Tier: Syndicate Agent +- Name: "Katarn" Tier: Revolutionary -- Name: Florian +- Name: "eric156" Tier: Revolutionary -- Name: Viridian +- Name: "Glenn Olsen" Tier: Syndicate Agent -- Name: Daskata - Tier: Nuclear Operative -- Name: The Hateful Flesh +- Name: "Constellations" + Tier: Syndicate Agent +- Name: "Charles Baron" + Tier: Syndicate Agent +- Name: "Shaina Gibson" Tier: Revolutionary -- Name: Will M. +- Name: "Wolfie" Tier: Revolutionary -- Name: spinnermaster - Tier: Nuclear Operative -- Name: clyf +- Name: "Alexandre Courtin" + Tier: Revolutionary +- Name: "Geekyhobo2" + Tier: Revolutionary +- Name: "Nicholas" Tier: Nuclear Operative -- Name: Robin Rottstock +- Name: "GeneralMarty" Tier: Revolutionary -- Name: Altana +- Name: "HCG" Tier: Revolutionary -- Name: Durp +- Name: "ShaunTexas" + Tier: Syndicate Agent +- Name: "Fallcon" Tier: Revolutionary -- Name: Joshington Awesomahee +- Name: "Malachi Housewright" Tier: Revolutionary -- Name: Eric VW +- Name: "Petalmeat" + Tier: Syndicate Agent +- Name: "Jakub Kędziora" + Tier: Syndicate Agent +- Name: "Adam Smedstad" Tier: Revolutionary -- Name: Evan Armstrong +- Name: "oBerry" + Tier: Nuclear Operative +- Name: "DireBoar" Tier: Revolutionary -- Name: Mono +- Name: "Ignoramis" Tier: Revolutionary -- Name: Ethan Keller +- Name: "Repo" + Tier: Nuclear Operative +- Name: "612" Tier: Revolutionary -- Name: DramaBuns +- Name: "Higgtastic" Tier: Revolutionary -- Name: Darren Brady +- Name: "Sandvich enjoyer" Tier: Revolutionary -- Name: Zandario - Tier: Nuclear Operative -- Name: Anthony Fleck - Tier: Nuclear Operative -- Name: vifs_vestige +- Name: "Mihailo Trickovic" Tier: Syndicate Agent -- Name: Bobberunio +- Name: "Vice Emargo" Tier: Revolutionary -- Name: CPM311 +- Name: "awndrssk" Tier: Revolutionary -- Name: Farewell Fire - Tier: Syndicate Agent -- Name: Daniel Thompson +- Name: "François Desautels" + Tier: Revolutionary +- Name: "Christian Hicks" Tier: Revolutionary -- Name: Tomeno +- Name: "MasterFurret" Tier: Revolutionary From 388e424a17f8c964fb5696377c6bfc58e99998bc Mon Sep 17 00:00:00 2001 From: DrSmugleaf Date: Thu, 12 Oct 2023 00:33:30 -0700 Subject: [PATCH 098/127] Add project to update Patrons.yml from a csv file containing Patreon webhooks, add missing Patrons (#20942) --- Content.PatreonParser/Attributes.cs | 15 +++ .../Content.PatreonParser.csproj | 14 ++ .../CurrentlyEntitledTiers.cs | 9 ++ Content.PatreonParser/Data.cs | 18 +++ Content.PatreonParser/Included.cs | 15 +++ Content.PatreonParser/Patron.cs | 3 + Content.PatreonParser/Program.cs | 125 ++++++++++++++++++ Content.PatreonParser/Relationships.cs | 9 ++ Content.PatreonParser/Root.cs | 12 ++ Content.PatreonParser/Row.cs | 19 +++ Content.PatreonParser/TierData.cs | 12 ++ Resources/Credits/Patrons.yml | 6 + SpaceStation14.sln | 10 ++ 13 files changed, 267 insertions(+) create mode 100644 Content.PatreonParser/Attributes.cs create mode 100644 Content.PatreonParser/Content.PatreonParser.csproj create mode 100644 Content.PatreonParser/CurrentlyEntitledTiers.cs create mode 100644 Content.PatreonParser/Data.cs create mode 100644 Content.PatreonParser/Included.cs create mode 100644 Content.PatreonParser/Patron.cs create mode 100644 Content.PatreonParser/Program.cs create mode 100644 Content.PatreonParser/Relationships.cs create mode 100644 Content.PatreonParser/Root.cs create mode 100644 Content.PatreonParser/Row.cs create mode 100644 Content.PatreonParser/TierData.cs diff --git a/Content.PatreonParser/Attributes.cs b/Content.PatreonParser/Attributes.cs new file mode 100644 index 00000000000..d3ebeb5f7c8 --- /dev/null +++ b/Content.PatreonParser/Attributes.cs @@ -0,0 +1,15 @@ +using System.Text.Json.Serialization; + +namespace Content.PatreonParser; + +public sealed class Attributes +{ + [JsonPropertyName("full_name")] + public string FullName = default!; + + [JsonPropertyName("pledge_relationship_start")] + public DateTime? PledgeRelationshipStart; + + [JsonPropertyName("title")] + public string Title = default!; +} diff --git a/Content.PatreonParser/Content.PatreonParser.csproj b/Content.PatreonParser/Content.PatreonParser.csproj new file mode 100644 index 00000000000..53b06b265b6 --- /dev/null +++ b/Content.PatreonParser/Content.PatreonParser.csproj @@ -0,0 +1,14 @@ + + + + Exe + net7.0 + enable + enable + + + + + + + diff --git a/Content.PatreonParser/CurrentlyEntitledTiers.cs b/Content.PatreonParser/CurrentlyEntitledTiers.cs new file mode 100644 index 00000000000..fd1747efda9 --- /dev/null +++ b/Content.PatreonParser/CurrentlyEntitledTiers.cs @@ -0,0 +1,9 @@ +using System.Text.Json.Serialization; + +namespace Content.PatreonParser; + +public sealed class CurrentlyEntitledTiers +{ + [JsonPropertyName("data")] + public List Data = default!; +} diff --git a/Content.PatreonParser/Data.cs b/Content.PatreonParser/Data.cs new file mode 100644 index 00000000000..cdc7d79bff5 --- /dev/null +++ b/Content.PatreonParser/Data.cs @@ -0,0 +1,18 @@ +using System.Text.Json.Serialization; + +namespace Content.PatreonParser; + +public sealed class Data +{ + [JsonPropertyName("id")] + public string Id = default!; + + [JsonPropertyName("type")] + public string Type = default!; + + [JsonPropertyName("attributes")] + public Attributes Attributes = default!; + + [JsonPropertyName("relationships")] + public Relationships Relationships = default!; +} diff --git a/Content.PatreonParser/Included.cs b/Content.PatreonParser/Included.cs new file mode 100644 index 00000000000..ec3363579b9 --- /dev/null +++ b/Content.PatreonParser/Included.cs @@ -0,0 +1,15 @@ +using System.Text.Json.Serialization; + +namespace Content.PatreonParser; + +public sealed class Included +{ + [JsonPropertyName("id")] + public int Id; + + [JsonPropertyName("type")] + public string Type = default!; + + [JsonPropertyName("attributes")] + public Attributes Attributes = default!; +} diff --git a/Content.PatreonParser/Patron.cs b/Content.PatreonParser/Patron.cs new file mode 100644 index 00000000000..d9943a6a265 --- /dev/null +++ b/Content.PatreonParser/Patron.cs @@ -0,0 +1,3 @@ +namespace Content.PatreonParser; + +public readonly record struct Patron(string FullName, string TierName, DateTime Start); diff --git a/Content.PatreonParser/Program.cs b/Content.PatreonParser/Program.cs new file mode 100644 index 00000000000..60a320006fe --- /dev/null +++ b/Content.PatreonParser/Program.cs @@ -0,0 +1,125 @@ +using System.Globalization; +using System.Text.Json; +using System.Text.Json.Serialization; +using Content.PatreonParser; +using CsvHelper; +using CsvHelper.Configuration; +using static System.Environment; + +var repository = new DirectoryInfo(Directory.GetCurrentDirectory()).Parent!.Parent!.Parent!.Parent!; +var patronsPath = Path.Combine(repository.FullName, "Resources/Credits/Patrons.yml"); +if (!File.Exists(patronsPath)) +{ + Console.WriteLine($"File {patronsPath} not found."); + return; +} + +Console.WriteLine($"Updating {patronsPath}"); +Console.WriteLine("Is this correct? [Y/N]"); +var response = Console.ReadLine()?.ToUpper(); +if (response != "Y") +{ + Console.WriteLine("Exiting"); + return; +} + +var delimiter = ","; +var hasHeaderRecord = false; +var mode = CsvMode.RFC4180; +var escape = '\''; +Console.WriteLine($""" +Delimiter: {delimiter} +HasHeaderRecord: {hasHeaderRecord} +Mode: {mode} +Escape Character: {escape} +"""); + +Console.WriteLine("Enter the full path to the .csv file containing the Patreon webhook data:"); +var filePath = Console.ReadLine(); +if (filePath == null) +{ + Console.Write("No path given."); + return; +} + +var file = File.OpenRead(filePath); +var csvConfig = new CsvConfiguration(CultureInfo.InvariantCulture) +{ + Delimiter = delimiter, + HasHeaderRecord = hasHeaderRecord, + Mode = mode, + Escape = escape, +}; + +using var reader = new CsvReader(new StreamReader(file), csvConfig); + +// This does not handle tier name changes, but we haven't had any yet +var patrons = new Dictionary(); +var jsonOptions = new JsonSerializerOptions +{ + IncludeFields = true, + NumberHandling = JsonNumberHandling.AllowReadingFromString +}; + +// This assumes that the rows are already sorted by id +foreach (var record in reader.GetRecords()) +{ + if (record.Trigger == "members:create") + continue; + + var content = JsonSerializer.Deserialize(record.ContentJson, jsonOptions)!; + + var id = Guid.Parse(content.Data.Id); + patrons.Remove(id); + + var tiers = content.Data.Relationships.CurrentlyEntitledTiers.Data; + if (tiers.Count == 0) + continue; + else if (tiers.Count > 1) + throw new ArgumentException("Found more than one tier"); + + var tier = tiers[0]; + var tierName = content.Included.SingleOrDefault(i => i.Id == tier.Id && i.Type == tier.Type)?.Attributes.Title; + if (tierName == null) + continue; + + if (record.Trigger == "members:delete") + continue; + + var fullName = content.Data.Attributes.FullName.Trim(); + var pledgeStart = content.Data.Attributes.PledgeRelationshipStart; + + switch (record.Trigger) + { + case "members:create": + break; + case "members:delete": + break; + case "members:update": + patrons.Add(id, new Patron(fullName, tierName, pledgeStart!.Value)); + break; + case "members:pledge:create": + if (pledgeStart == null) + continue; + + patrons.Add(id, new Patron(fullName, tierName, pledgeStart.Value)); + break; + case "members:pledge:delete": + // Deleted pledge but still not expired, expired is handled earlier + patrons.Add(id, new Patron(fullName, tierName, pledgeStart!.Value)); + break; + case "members:pledge:update": + patrons.Add(id, new Patron(fullName, tierName, pledgeStart!.Value)); + break; + } +} + +var patronList = patrons.Values.ToList(); +patronList.Sort((a, b) => a.Start.CompareTo(b.Start)); +var yaml = patronList.Select(p => $""" +- Name: "{p.FullName.Replace("\"", "\\\"")}" + Tier: {p.TierName} +"""); +var output = string.Join(NewLine, yaml) + NewLine; +File.WriteAllText(patronsPath, output); +Console.WriteLine($"Updated {patronsPath} with {patronList.Count} patrons."); diff --git a/Content.PatreonParser/Relationships.cs b/Content.PatreonParser/Relationships.cs new file mode 100644 index 00000000000..f919f812f62 --- /dev/null +++ b/Content.PatreonParser/Relationships.cs @@ -0,0 +1,9 @@ +using System.Text.Json.Serialization; + +namespace Content.PatreonParser; + +public sealed class Relationships +{ + [JsonPropertyName("currently_entitled_tiers")] + public CurrentlyEntitledTiers CurrentlyEntitledTiers = default!; +} diff --git a/Content.PatreonParser/Root.cs b/Content.PatreonParser/Root.cs new file mode 100644 index 00000000000..2a772a12143 --- /dev/null +++ b/Content.PatreonParser/Root.cs @@ -0,0 +1,12 @@ +using System.Text.Json.Serialization; + +namespace Content.PatreonParser; + +public sealed class Root +{ + [JsonPropertyName("data")] + public Data Data = default!; + + [JsonPropertyName("included")] + public List Included = default!; +} diff --git a/Content.PatreonParser/Row.cs b/Content.PatreonParser/Row.cs new file mode 100644 index 00000000000..f4d25046165 --- /dev/null +++ b/Content.PatreonParser/Row.cs @@ -0,0 +1,19 @@ +using CsvHelper.Configuration.Attributes; + +namespace Content.PatreonParser; + +// These need to be properties or CSVHelper will not find them +public sealed class Row +{ + [Name("Id"), Index(0)] + public int Id { get; set; } + + [Name("Trigger"), Index(1)] + public string Trigger { get; set; } = default!; + + [Name("Time"), Index(2)] + public DateTime Time { get; set; } + + [Name("Content"), Index(3)] + public string ContentJson { get; set; } = default!; +} diff --git a/Content.PatreonParser/TierData.cs b/Content.PatreonParser/TierData.cs new file mode 100644 index 00000000000..a840b21d359 --- /dev/null +++ b/Content.PatreonParser/TierData.cs @@ -0,0 +1,12 @@ +using System.Text.Json.Serialization; + +namespace Content.PatreonParser; + +public sealed class TierData +{ + [JsonPropertyName("id")] + public int Id; + + [JsonPropertyName("type")] + public string Type = default!; +} diff --git a/Resources/Credits/Patrons.yml b/Resources/Credits/Patrons.yml index acb9eb229a5..427a8f62f09 100644 --- a/Resources/Credits/Patrons.yml +++ b/Resources/Credits/Patrons.yml @@ -58,6 +58,8 @@ Tier: Revolutionary - Name: "Mikhail" Tier: Revolutionary +- Name: "Ramiro Agis" + Tier: Revolutionary - Name: "osborn" Tier: Syndicate Agent - Name: "Uinseann" @@ -108,6 +110,8 @@ Tier: Syndicate Agent - Name: "Odin The Wanderer" Tier: Revolutionary +- Name: "tokie" + Tier: Nuclear Operative - Name: "Wallace Megas" Tier: Revolutionary - Name: "Vandell" @@ -130,6 +134,8 @@ Tier: Revolutionary - Name: "eric156" Tier: Revolutionary +- Name: "SHANE ALAN ZINDA" + Tier: Nuclear Operative - Name: "Glenn Olsen" Tier: Syndicate Agent - Name: "Constellations" diff --git a/SpaceStation14.sln b/SpaceStation14.sln index 2dc4c95508d..a94daa316dd 100644 --- a/SpaceStation14.sln +++ b/SpaceStation14.sln @@ -127,6 +127,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Robust.Shared.CompNetworkGe EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Robust.Serialization.Generator", "RobustToolbox\Robust.Serialization.Generator\Robust.Serialization.Generator.csproj", "{6FBF108E-5CB5-47DE-8D7E-B496ABA9E3E2}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Content.PatreonParser", "Content.PatreonParser\Content.PatreonParser.csproj", "{D97D8258-D915-4D1D-B1E3-1A8D00CF9EB5}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -430,6 +432,14 @@ Global {6FBF108E-5CB5-47DE-8D7E-B496ABA9E3E2}.DebugOpt|Any CPU.Build.0 = Debug|Any CPU {6FBF108E-5CB5-47DE-8D7E-B496ABA9E3E2}.Tools|Any CPU.ActiveCfg = Debug|Any CPU {6FBF108E-5CB5-47DE-8D7E-B496ABA9E3E2}.Tools|Any CPU.Build.0 = Debug|Any CPU + {D97D8258-D915-4D1D-B1E3-1A8D00CF9EB5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D97D8258-D915-4D1D-B1E3-1A8D00CF9EB5}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D97D8258-D915-4D1D-B1E3-1A8D00CF9EB5}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D97D8258-D915-4D1D-B1E3-1A8D00CF9EB5}.Release|Any CPU.Build.0 = Release|Any CPU + {D97D8258-D915-4D1D-B1E3-1A8D00CF9EB5}.DebugOpt|Any CPU.ActiveCfg = Debug|Any CPU + {D97D8258-D915-4D1D-B1E3-1A8D00CF9EB5}.DebugOpt|Any CPU.Build.0 = Debug|Any CPU + {D97D8258-D915-4D1D-B1E3-1A8D00CF9EB5}.Tools|Any CPU.ActiveCfg = Debug|Any CPU + {D97D8258-D915-4D1D-B1E3-1A8D00CF9EB5}.Tools|Any CPU.Build.0 = Debug|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE From 99f777ca9d98494f6da4f219c50e4e16473740e6 Mon Sep 17 00:00:00 2001 From: Kevin Zheng Date: Wed, 11 Oct 2023 23:35:31 -0800 Subject: [PATCH 099/127] Increase carbon dioxide poisoning damage (#20939) * Increase CO2 poisoning damage * Fix --- Resources/Prototypes/Reagents/gases.yml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/Resources/Prototypes/Reagents/gases.yml b/Resources/Prototypes/Reagents/gases.yml index 9fa06f632c6..367ffa0894b 100644 --- a/Resources/Prototypes/Reagents/gases.yml +++ b/Resources/Prototypes/Reagents/gases.yml @@ -135,7 +135,13 @@ damage: types: Poison: - 0.2 + 0.8 + - !type:Oxygenate # carbon dioxide displaces oxygen from the bloodstream, causing asphyxiation + conditions: + - !type:OrganType + type: Plant + shouldHave: false + factor: -4 # Cant be added until I add metabolism effects on reagent removal #- !type:AdjustAlert # alertType: CarbonDioxide From 3323b617dd671bc14289d40c0c4f308d623bf397 Mon Sep 17 00:00:00 2001 From: PJBot Date: Thu, 12 Oct 2023 03:36:37 -0400 Subject: [PATCH 100/127] Automatic changelog update --- Resources/Changelog/Changelog.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index a21254b1320..820b9a0a138 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,10 +1,4 @@ Entries: -- author: Ilya246 - changes: - - {message: The air alarm UI now allows copying settings of one device to all similar - devices., type: Add} - id: 4496 - time: '2023-08-09T18:20:20.0000000+00:00' - author: Nairodian changes: - {message: 'Changed Dark & Bushy, Death''s-Head, Firewatch, Moffra, Plasmafire, @@ -2958,3 +2952,9 @@ Entries: - {message: The nukie ship now has syndicate access airlocks, type: Add} id: 4995 time: '2023-10-11T16:47:25.0000000+00:00' +- author: notafet + changes: + - {message: Carbon dioxide poisoning is now more deadly. Victims of carbon dioxide + poisoning now gasp visibly., type: Tweak} + id: 4996 + time: '2023-10-12T07:35:31.0000000+00:00' From 535b013f63e3628ad690f446462afe32160bce54 Mon Sep 17 00:00:00 2001 From: chromiumboy <50505512+chromiumboy@users.noreply.github.com> Date: Thu, 12 Oct 2023 11:06:03 -0500 Subject: [PATCH 101/127] SMES and substation require power cells as machine parts (#20344) * Initial commit * Balancing and tweaks --- .../Components/UpgradeBatteryComponent.cs | 2 +- .../UpgradePowerSupplyRampingComponent.cs | 38 ++++++++++++++++ .../EntitySystems/UpgradeBatterySystem.cs | 6 ++- .../Power/EntitySystems/UpgradePowerSystem.cs | 43 ++++++++++++++++++- Resources/Locale/en-US/machine/machine.ftl | 1 + .../Circuitboards/Machine/production.yml | 8 +++- .../Entities/Objects/Power/powercells.yml | 16 ++++++- .../Entities/Structures/Power/smes.yml | 3 ++ .../Entities/Structures/Power/substation.yml | 3 ++ .../Prototypes/MachineParts/machine_parts.yml | 6 +++ 10 files changed, 117 insertions(+), 9 deletions(-) create mode 100644 Content.Server/Power/Components/UpgradePowerSupplyRampingComponent.cs diff --git a/Content.Server/Power/Components/UpgradeBatteryComponent.cs b/Content.Server/Power/Components/UpgradeBatteryComponent.cs index e1fc4d2bb82..ff91cfa7559 100644 --- a/Content.Server/Power/Components/UpgradeBatteryComponent.cs +++ b/Content.Server/Power/Components/UpgradeBatteryComponent.cs @@ -11,7 +11,7 @@ public sealed partial class UpgradeBatteryComponent : Component /// The machine part that affects the power capacity. /// [DataField("machinePartPowerCapacity", customTypeSerializer: typeof(PrototypeIdSerializer))] - public string MachinePartPowerCapacity = "Capacitor"; + public string MachinePartPowerCapacity = "PowerCell"; /// /// The machine part rating is raised to this power when calculating power gain diff --git a/Content.Server/Power/Components/UpgradePowerSupplyRampingComponent.cs b/Content.Server/Power/Components/UpgradePowerSupplyRampingComponent.cs new file mode 100644 index 00000000000..7bd29f2de71 --- /dev/null +++ b/Content.Server/Power/Components/UpgradePowerSupplyRampingComponent.cs @@ -0,0 +1,38 @@ +using Content.Server.Construction.Components; +using Content.Shared.Construction.Prototypes; +using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; + +namespace Content.Server.Power.Components +{ + + [RegisterComponent] + public sealed partial class UpgradePowerSupplyRampingComponent : Component + { + [ViewVariables(VVAccess.ReadWrite)] + public float BaseRampRate; + + /// + /// The machine part that affects the power supply ramping + /// + [DataField("machinePartPowerCapacity", customTypeSerializer: typeof(PrototypeIdSerializer))] + public string MachinePartRampRate = "Capacitor"; + + /// + /// The multiplier used for scaling the power supply ramping + /// + [DataField("supplyRampingMultiplier")] + public float SupplyRampingMultiplier = 1f; + + /// + /// What type of scaling is being used? + /// + [DataField("scaling", required: true), ViewVariables(VVAccess.ReadWrite)] + public MachineUpgradeScalingType Scaling; + + /// + /// The current value that the power supply is being scaled by + /// + [DataField("actualScalar"), ViewVariables(VVAccess.ReadWrite)] + public float ActualScalar = 1f; + } +} diff --git a/Content.Server/Power/EntitySystems/UpgradeBatterySystem.cs b/Content.Server/Power/EntitySystems/UpgradeBatterySystem.cs index 6571e1cf097..734cf9d89ce 100644 --- a/Content.Server/Power/EntitySystems/UpgradeBatterySystem.cs +++ b/Content.Server/Power/EntitySystems/UpgradeBatterySystem.cs @@ -7,6 +7,8 @@ namespace Content.Server.Power.EntitySystems [UsedImplicitly] public sealed class UpgradeBatterySystem : EntitySystem { + [Dependency] private readonly BatterySystem _batterySystem = default!; + public override void Initialize() { base.Initialize(); @@ -17,11 +19,11 @@ public override void Initialize() public void OnRefreshParts(EntityUid uid, UpgradeBatteryComponent component, RefreshPartsEvent args) { - var capacitorRating = args.PartRatings[component.MachinePartPowerCapacity]; + var powerCellRating = args.PartRatings[component.MachinePartPowerCapacity]; if (TryComp(uid, out var batteryComp)) { - batteryComp.MaxCharge = MathF.Pow(component.MaxChargeMultiplier, capacitorRating - 1) * component.BaseMaxCharge; + _batterySystem.SetMaxCharge(uid, MathF.Pow(component.MaxChargeMultiplier, powerCellRating - 1) * component.BaseMaxCharge, batteryComp); } } diff --git a/Content.Server/Power/EntitySystems/UpgradePowerSystem.cs b/Content.Server/Power/EntitySystems/UpgradePowerSystem.cs index 0d43f60a2bf..9cf28c386a6 100644 --- a/Content.Server/Power/EntitySystems/UpgradePowerSystem.cs +++ b/Content.Server/Power/EntitySystems/UpgradePowerSystem.cs @@ -1,4 +1,4 @@ -using Content.Server.Construction; +using Content.Server.Construction; using Content.Server.Construction.Components; using Content.Server.Power.Components; @@ -20,6 +20,10 @@ public override void Initialize() SubscribeLocalEvent(OnSupplierMapInit); SubscribeLocalEvent(OnSupplierRefreshParts); SubscribeLocalEvent(OnSupplierUpgradeExamine); + + SubscribeLocalEvent(OnSupplyRampingMapInit); + SubscribeLocalEvent(OnSupplyRampingRefreshParts); + SubscribeLocalEvent(OnSupplyRampingUpgradeExamine); } private void OnMapInit(EntityUid uid, UpgradePowerDrawComponent component, MapInitEvent args) @@ -76,7 +80,7 @@ private void OnSupplierRefreshParts(EntityUid uid, UpgradePowerSupplierComponent switch (component.Scaling) { case MachineUpgradeScalingType.Linear: - supply += component.BaseSupplyRate * (rating - 1); + supply += component.PowerSupplyMultiplier * component.BaseSupplyRate * (rating - 1); break; case MachineUpgradeScalingType.Exponential: supply *= MathF.Pow(component.PowerSupplyMultiplier, rating - 1); @@ -97,4 +101,39 @@ private void OnSupplierUpgradeExamine(EntityUid uid, UpgradePowerSupplierCompone { args.AddPercentageUpgrade("upgrade-power-supply", component.ActualScalar); } + + private void OnSupplyRampingMapInit(EntityUid uid, UpgradePowerSupplyRampingComponent component, MapInitEvent args) + { + if (TryComp(uid, out var battery)) + component.BaseRampRate = battery.SupplyRampRate; + } + + private void OnSupplyRampingRefreshParts(EntityUid uid, UpgradePowerSupplyRampingComponent component, RefreshPartsEvent args) + { + var rampRate = component.BaseRampRate; + var rating = args.PartRatings[component.MachinePartRampRate]; + switch (component.Scaling) + { + case MachineUpgradeScalingType.Linear: + rampRate += component.SupplyRampingMultiplier * component.BaseRampRate * (rating - 1); + break; + case MachineUpgradeScalingType.Exponential: + rampRate *= MathF.Pow(component.SupplyRampingMultiplier, rating - 1); + break; + default: + Log.Error($"invalid power supply ramping type for {ToPrettyString(uid)}."); + rampRate = component.BaseRampRate; + break; + } + + component.ActualScalar = rampRate / component.BaseRampRate; + + if (TryComp(uid, out var battery)) + battery.SupplyRampRate = rampRate; + } + + private void OnSupplyRampingUpgradeExamine(EntityUid uid, UpgradePowerSupplyRampingComponent component, UpgradeExamineEvent args) + { + args.AddPercentageUpgrade("upgrade-power-supply-ramping", component.ActualScalar); + } } diff --git a/Resources/Locale/en-US/machine/machine.ftl b/Resources/Locale/en-US/machine/machine.ftl index 1d086e4fdb5..20a7eb440ff 100644 --- a/Resources/Locale/en-US/machine/machine.ftl +++ b/Resources/Locale/en-US/machine/machine.ftl @@ -15,6 +15,7 @@ machine-part-name-matter-bin = Matter Bin upgrade-power-draw = power draw upgrade-max-charge = max charge upgrade-power-supply = power supply +upgrade-power-supply-ramping = power ramp rate two-way-lever-left = push left two-way-lever-right = push right diff --git a/Resources/Prototypes/Entities/Objects/Devices/Circuitboards/Machine/production.yml b/Resources/Prototypes/Entities/Objects/Devices/Circuitboards/Machine/production.yml index 9c60e725350..a25e5b7069d 100644 --- a/Resources/Prototypes/Entities/Objects/Devices/Circuitboards/Machine/production.yml +++ b/Resources/Prototypes/Entities/Objects/Devices/Circuitboards/Machine/production.yml @@ -476,7 +476,10 @@ - type: MachineBoard prototype: SMESBasicEmpty requirements: - Capacitor: 5 + Capacitor: 1 + PowerCell: 4 + materialRequirements: + CableHV: 10 - type: entity id: CellRechargerCircuitboard @@ -553,7 +556,8 @@ - type: MachineBoard prototype: SubstationBasicEmpty requirements: - Capacitor: 3 + Capacitor: 1 + PowerCell: 1 materialRequirements: CableMV: 5 CableHV: 5 diff --git a/Resources/Prototypes/Entities/Objects/Power/powercells.yml b/Resources/Prototypes/Entities/Objects/Power/powercells.yml index 4b1c9104285..82c1bb37e96 100644 --- a/Resources/Prototypes/Entities/Objects/Power/powercells.yml +++ b/Resources/Prototypes/Entities/Objects/Power/powercells.yml @@ -62,6 +62,9 @@ - type: Battery maxCharge: 360 startingCharge: 360 + - type: MachinePart + part: PowerCell + rating: 1 - type: Tag tags: - PowerCellSmall @@ -100,6 +103,9 @@ - type: Battery maxCharge: 720 startingCharge: 720 + - type: MachinePart + part: PowerCell + rating: 2 - type: entity id: PowerCellMediumPrinted @@ -135,7 +141,10 @@ - type: Battery maxCharge: 1080 startingCharge: 1080 - + - type: MachinePart + part: PowerCell + rating: 3 + - type: entity id: PowerCellHighPrinted suffix: Empty @@ -170,7 +179,10 @@ - type: Battery maxCharge: 1800 startingCharge: 1800 - + - type: MachinePart + part: PowerCell + rating: 4 + - type: entity id: PowerCellHyperPrinted suffix: Empty diff --git a/Resources/Prototypes/Entities/Structures/Power/smes.yml b/Resources/Prototypes/Entities/Structures/Power/smes.yml index 68d72f64f89..92451918c7b 100644 --- a/Resources/Prototypes/Entities/Structures/Power/smes.yml +++ b/Resources/Prototypes/Entities/Structures/Power/smes.yml @@ -32,6 +32,9 @@ - type: UpgradeBattery maxChargeMultiplier: 2 baseMaxCharge: 8000000 + - type: UpgradePowerSupplyRamping + scaling: Linear + supplyRampingMultiplier: 1 - type: Appearance - type: Battery startingCharge: 0 diff --git a/Resources/Prototypes/Entities/Structures/Power/substation.yml b/Resources/Prototypes/Entities/Structures/Power/substation.yml index 6e3ef2f7f1a..bd3dcc4b8ca 100644 --- a/Resources/Prototypes/Entities/Structures/Power/substation.yml +++ b/Resources/Prototypes/Entities/Structures/Power/substation.yml @@ -20,6 +20,9 @@ - type: UpgradeBattery maxChargeMultiplier: 2 baseMaxCharge: 2500000 + - type: UpgradePowerSupplyRamping + scaling: Linear + supplyRampingMultiplier: 1 - type: Battery startingCharge: 0 - type: ExaminableBattery diff --git a/Resources/Prototypes/MachineParts/machine_parts.yml b/Resources/Prototypes/MachineParts/machine_parts.yml index 444bc37356c..317e4b80866 100644 --- a/Resources/Prototypes/MachineParts/machine_parts.yml +++ b/Resources/Prototypes/MachineParts/machine_parts.yml @@ -12,3 +12,9 @@ id: MatterBin name: machine-part-name-matter-bin stockPartPrototype: MatterBinStockPart + +- type: machinePart + id: PowerCell + name: machine-part-name-power-cell + stockPartPrototype: PowerCellSmall + From 1b46acac6428c920d70942a1650a375cbfc4ab7d Mon Sep 17 00:00:00 2001 From: Ubaser <134914314+UbaserB@users.noreply.github.com> Date: Fri, 13 Oct 2023 09:20:23 +1100 Subject: [PATCH 102/127] Paramedic Suit [RESPRITE] (#20619) * add sprites * fix copyright * update sprites --- .../paramedhelm.rsi/equipped-HELMET.png | Bin 1097 -> 2321 bytes .../Head/Helmets/paramedhelm.rsi/icon.png | Bin 716 -> 1724 bytes .../Helmets/paramedhelm.rsi/inhand-left.png | Bin 1332 -> 2082 bytes .../Helmets/paramedhelm.rsi/inhand-right.png | Bin 1314 -> 2097 bytes .../Head/Helmets/paramedhelm.rsi/meta.json | 2 +- .../paramed.rsi/equipped-OUTERCLOTHING.png | Bin 1884 -> 3568 bytes .../Hardsuits/paramed.rsi/icon.png | Bin 808 -> 1888 bytes .../Hardsuits/paramed.rsi/inhand-left.png | Bin 1037 -> 1932 bytes .../Hardsuits/paramed.rsi/inhand-right.png | Bin 1037 -> 1907 bytes .../Hardsuits/paramed.rsi/meta.json | 2 +- 10 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Resources/Textures/Clothing/Head/Helmets/paramedhelm.rsi/equipped-HELMET.png b/Resources/Textures/Clothing/Head/Helmets/paramedhelm.rsi/equipped-HELMET.png index d09e0347f5010eb891e24d1a5a7fa93f344e729c..e6810d74524c335fd9232b1a3cdca9184d481fca 100644 GIT binary patch literal 2321 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 a4Zv4G$t4JU$3tNN0000G?W zUP)qwZeFo6#1NP{E~&-IMVSR9nfZANAafIw@=Hr>m6Sjh!2!gbDamkq3QCJ|z_z3$ z>!;?V=BDPA6zd!68R}!xSCW~AaA96CG&q0(qYsh+YBRv9&9k5+*#sC;t`$J{K>Y`F zXfoK|;*u17BnA3L1_l&2TID3>rQ0f1=%%EmC6?xtDA{F{<|gLZ=tGpCYK4fRnrNes#c~^vm#rd$Qj7C* zN?N>Ymoihv0VY@ZR-I@~JI z%|h56nwME(2QvUo7)cjW#8^2Nm6YcfWru(x0UClh<)LOkLK7)vLXtf=|?L zo`>wX%#G9R7#LWrJzX3_Dj46+^39NT7difaQ<7(&N_cPY?Pl5SeVIwgleV!7GbtG^ z)m@tTVx>e>mF|?fxmjN4Tdmq-iacMkzdbwMiDOEgL*WVyT~3vis=EsdE^!=HEK_}b zdQ;dXugjH--$ZS@#v7-v=ymTvM%w*7Gb`V3H{N{gGlQQ`1E&F_+5wgs48jRaD4c#V z#_7WEp6T~=KX@_4^4jV2I^kTs&w;)lA6q}{ZTdgc;?GUXhwpf1NnMSRo9OR9#iC#*J{i}b3@8*zPNnl>D}|Em-Y1Ae`8}hY0pK@&4-trYE19%zO(banP=nQ_Bhec z^?w)4srx@gdEaWwTeH$`H7?lweZzuxM>pM@;+eN4_^y`i&yt9Wy>S_{+G_0b)2hDx ztXWXDy3Tr{B~wD?&v>5NFTEdr{n0pbFGOXx{?Tf=@glt_Q&M(cnaI+4 zp_fz^yjv#_v~o(;zcPV}>V^BRa561@w@xo5Kkne!nB`SvkB$p6xUOxQ_tg4C_-YTg zbIOzB9LxRtGvkXgIe+Dd?0#ZY_vTz~@Vy8{%e_yJJ=s+~q3_IG_mUSGwWUj*1!RWY zO1wK!_d?|#Ulk$F6eGzOLQQhB4<_ifiOZc|J!y`*Y-@hHlAFn!- zws}WUsp!ewR$*;YxqF+BU%6MQ|L~ynLXnsv?cTp7CtW`sZH>Pwv-tcRkX%p z*6+O7Ty0>w_1|~5$%}XoPCIr(!rSWS9EIcG-@ZQn^>v{L*Xj?ynV)T5HdUZEuBgP% zy3Fib;S(MMww|MU+RtAYXp3;IxZ3hlSA8z~*~-ItdNVOnAWCxdc@U`h!QpTJzqkwW zKb02c^}hIJYxc8qW!@dFnN7JNGCQSiAFJ6G%KN;RvFiJ`B;R{Z*Dog~iZ?A5S8glx zn||ESzx&vN?kKh8bJoB3q_i!{*+61X`iG-oW?Rp2Wt1d@-ZKs2Vqsd*vv0+#r}OuR zKP{_|Vq(}^csR4DAoX2&MaoRSSjOO8bzjDdot}ps?Wr^SA?_|tY7c{)6BY> z_hyjC)t9xx3|1_fU2hit;|ln}>$u>+YUT6mkIMx4FCWD delta 1314 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 GLSTZx&WL&d diff --git a/Resources/Textures/Clothing/Head/Helmets/paramedhelm.rsi/meta.json b/Resources/Textures/Clothing/Head/Helmets/paramedhelm.rsi/meta.json index c402402b13b..4ec7339a888 100644 --- a/Resources/Textures/Clothing/Head/Helmets/paramedhelm.rsi/meta.json +++ b/Resources/Textures/Clothing/Head/Helmets/paramedhelm.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from paradise station at commit https://github.com/ParadiseSS13/Paradise/commit/e5e584804b4b0b373a6a69d23afb73fd3c094365", + "copyright": "Taken from paradise station at commit https://github.com/ParadiseSS13/Paradise/commit/e5e584804b4b0b373a6a69d23afb73fd3c094365, redrawn by Ubaser", "size": { "x": 32, "y": 32 diff --git a/Resources/Textures/Clothing/OuterClothing/Hardsuits/paramed.rsi/equipped-OUTERCLOTHING.png b/Resources/Textures/Clothing/OuterClothing/Hardsuits/paramed.rsi/equipped-OUTERCLOTHING.png index da0a69c9c4dbd45072654bb7d9e4b6dfaafc3c68..24837f4d9aa989b61f0838d5e0ee0ce7330c1017 100644 GIT binary patch literal 3568 zcmZ`+2{@G78=oP2k}M^WOQme1u@6R;Fok5uuErP)W-&&_R+h3a*()(_Zl>WaINi37d_^+>jV_RX-MCd;b{-gd0_0z>bbO}U19Kq9a=Mug%_SI741ClC>&)^H-s}yCCg!jKvqDefNNRsjv4& z{mBb%sF)4Hr-LfD(y7NZKBH!cYOGLkHqmhdreG0g~F>8SSPXtiP&&AM?Tq^L+CHKX9r7wYogw6=03mG%31Y_dIPM&A3) zokAe~ko!X0+OnE8d?&hCOrIPWQNALVrI=q^viZEc{6c%Wv#cuWiHf#cbkM4a)b5ur z`j>9gr=3Kp;MA1#d6hb@2D=Us^o(tF!x>Z4(lsmtZjrvIe+ACCA(i931yz=0pH}#6 zn0wn3^%4*WJ$8(pU$!P3t)dc@kdU5KTdsa@J~&mm5n#G**ms#aVC%%5NDD71DX|~T zq6;H(btn|VGp(e^0AC_8XL=&Zel;?X%OeEVdAOu0@i55u>@vAnH$vdaCl}2esI9H- z#Psy@(!Y)rjMdl7lscCMJRcLdI@}QL9Mackhd6uYjGlwTq1ght>we|?A2_lNS7uth z6IWI%=s#}|bXGn+{mUg|M$Y@eO7B9OY_V7k7=~V&MgKtVmz6jlYmFFxyMI^Qi2<&5 z!h+E1bn&L~1Z?hz+>1DtF?3Mt;w8Y=7lryvQE?Rw5E`9b9&WzN&OytNTaOG|^1&o)CHudd2N?CtQYqp+n!QE5W(vw_;$TEN=K$Wijx zsFcn&1;#yYNaNItdGyDNJc=hUEHPj$lKZ$xP~ds~N8NUHgpU)VYS;rq99b;zbh$?T z%xrzk$l!3jc(ds_BP3iPATx00$vu-Oqbsg?qe>}^7f)ttL#;1fa2n#ud^O2BpP{p^ z)TQEhdLE0c4S; zia(gWog^6rkFtnNX^_Z#*n|`qW^1eY^36!`g||@J@`{gy4aE zDN%BAau|1Mnd=FuE}2@9%_b%CC{GoAkB}$BjMX|slc%Bg!}1;(N^HQSmOq|;FW$}a zx~ELlBb)9;nxJCg%T%e*uSip`<6=@($J42kh9=cY7e(u%#S?a$-w()AHUqL_74814 z9hx-Yg7qSmR}R&%=;Gzd!)M13)lsjkoCM}4Jvv{@ zjY!^~Z|Uso^N7PKvy^Rl)HulU-+Xgm?J4Qfrn@%B^Bxp3TE}jN^99$h-)SlvRI}t5 zeLvmtV@$%<-zsmrS9=CSikqMHsm`Vaeh%gE5^yQ(^EeblOmufj;h?P1Q%hNVd5<}CX;br6gH@0EY>>b3h(FVa#qUb_|F+sFzho6ugnECn51X|qi(A9#JpS4JOoiX zKvV9h>jhkWpB~P3E+e*WD&ONIOQ?t#Npi?vM69|o5%DUo(Xd9*H1(O-t6-iBw&nf= zF4h^1ua`%tDWYH}*5PrCuAiS8Yrg<=&j;9 zevt>x8F?;VA!};^&jS6A(P~GVvI384wckHEVBdcteYNsL8629uRa(7~uk3)tGS(v{ zBOpm-<{VQpw{)xHcoi+1q^`=;wP#$3mlG0oamdd7LseCH%$?M^~VRcT@ zu6Z$*^U(Sjj2g%c!sg=@a@wAp(pyulM7I*kcg5WxK?<_=QDSb=;ZOF2^QZJ42|gTJ zp>Z_OCe!i`bi;|qTWPOKV8TQDZpw|fSDj|rg7U-uLW&&Z>q<15uS{9G)#?@BdMzyj z)EF$Cz^eTTKUDv6@}SM!*hNvaN!_vS1|-W_-LUVquvCMb5F$Cr>B-fv+VhgzH{j1(W-e|ind;_L42 zjxUTD;m=80>bC0SiLU5(zgO_-Ui6~AzukVdM~?9!b-k5*@Hg-VAVO}|tkd2ovteVb z>RQt=Uy!uC$lT_Oa^WIFKvmtNahuQ7+4{JbIy9RBo-)VB`?&W@3mkHX|B(dRnFqe{F_`HYQ|?tpihwkPCgX$ku19X2S~!CA%*j zQ+?{xuRkaT+y_^K0;Vet0zYh(F6#erWW9k%_id}jMQZPRxW(E8bFGmze37>Ow*@BPeDeQl_Uq6xn delta 1857 zcmV-H2fq058{7_%Fnp0Kbwi{e1w-7ZexRQ0a@Hzt-2=%*nEFT2hB&gp)CL;= z`6_|HXLqdGiuJUw;FE)Jyzv>Hv>5_c1^JplO42>V&GbDn!E}3Cjp^3rGNMsB0A1}fNI3)y z1J{5SRWP*;DPIOa$_`){DTnB4pK;kuXZp$p#ZOx{@qg{DH2}mv{Xp9=96`#L5#k6P!4Wq3eDt0A9^l6?cFA=5hefXix%&OX z&6%?J&6}BRH3Loq(AhTSO2423Zl601oaScgHon#i0=^}MXabT*32+sFs;ZX|qKU!L z6!2S-9DjL1ZmdyFi-5~s+en-}$;z!a*l?er^_w%(dO4NKbitef0R6+0B02JcT)CCj z=M~l{=z!`czd|~#MgYD6fRxt}Vv}h`rmmFNGuyt_AD~8H95}yLKUc-S=K$&S6S|!X zS!KVPwM@6qfVIxc#qnLBad2ABcKj0fyB_@-;D1v9r2HVK-rt-y>xgu^3Bx!l)9FiG zy3~Xap{(*95B*5r0nqiD9JlSr0gYZ&LQCnL}U7eq| z{C*;1L5}VI(6JGPP@|}bh8Kv(6ZDwjkElebAE63lkImMJ?Fd^@v!V)QB7Ip4(Z_p{wsP3+1wW;=Eky$G(RZ`aPX!L9z9 z#x)L3OF%ai(Th+6<^rhL0?g^{VTcVMVY?*U4`ci{7SFI!)gFSyos@qZ``y#o&e(AoAr{lnIAb?@D)_lE91v4nKB z&*(KMTferp7Vwu<8#M)gEFmHf1s|0F>Nlc~J9%6C@6vblC~P7p-_u(SoEY5=pnn^3 z%F9DJ^j%#7BG7`Ie3P50+W`1lAvtmmILF4CYDA!g^*s383w>7(h=v!mh{*+ft$$Bu zmG=&~(sxBU^j$dstVL)!nc~DK914zczptiJi%`k+*YQaV)JKQaj+Yvx)73sN=meGU8t9JG=yzk+RSW&YTu@ z)|z|nwZ4akhlhuUhlj`i9)2{Ic7Pd!e|F!QJdu|KkkB(DQpR_(h)k!OkTOJW#||p!_aehf_OZ^Z-$=E)QLYbUZ90+96P|A0g1CG0oYhmP1UYv zbZLxAblyaWR{;3Q?^HbS&VR&f{Nnq{F8`hbw%mcWaWw%HI74=Z*fEnJRj$G=?DkY> z5V|FF%g(ldG`A}tT7MQBT(1FO<>>SeKgH@PE0tgi{lj}R_M8}X-$Ieo#q{OSAeqS z1?0ojwcAq6AQZg@R5B-^5ZU2!_vaVo023=75Ad+#e^OXK-8#}f<2u{kFS@05FM?3c vyny`LcjpRJcoDR?sts9RD{fJaE)D+yLs~f*E%MI%00000NkvXXu0mjfl991T diff --git a/Resources/Textures/Clothing/OuterClothing/Hardsuits/paramed.rsi/icon.png b/Resources/Textures/Clothing/OuterClothing/Hardsuits/paramed.rsi/icon.png index 5a1e8bf19485767bd80c3cccc213507c5d8c427b..31f9e2f0e943f1d0edb1ff212b90dc9d49070869 100644 GIT binary patch literal 1888 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz#^NA%Cx&(BWL^R}e5nzhX}-P; zT0k}j5QD&_;K@Lev%n*=7^q+l2s5%z3BJp~z?_pA5>XQ2>tmIipR1RclAn~SSCLx) z)@4&+1!U%?mLw`v zE(HYzo1&C7s~{IQsCFRFRw<*Tq`*pFzr4I$uiRKKzbIYb(9+UU-@r)U$VeBcLbtdw zuOzWTH?LS3VhGF}m(=3qqRfJl%=|nBkhzIT`K2YcN=hJ$-~i&zlw`O)1*JtfU|Uj> z^;2_Fb5rw5iuDck4E3?;E6GelxG=968XUlY(Fe%@wHaX5=2=jZYyu1^*9xF}p#B3o zG#PAfaY>3kk^+4r0|N_P10!7{OMSTifX=r`NwzA8(5=(PRl4Skm)1?YK5yc?zx=n$j+)xO2+92O z@2N49zE#=H?}ty`I=>;<|HG>6wE=w<0vtyRw?6G-xm;tx-y#&?r5$kf4%e@2v&DwT zPb4m{O)3#OZ5t~g=G7FnHf+thbx9Qw8Aps0ceS3nb!x6++kal;19vNG@*l|0J`nRg z_{r0!Cy&4W>Q&G;tMA*%iG>&J@9IdTDZG$%5a7C%RxP;3u4SRXfw|gUO>3Ub*7*8+ z;_TVlCr!AkJwJ$AJr_-=J5cbw_0BJ?dFx%n~ryzuGlthp5_{(X}z7@2HEeNGd}4CX;pyGqlbGGltz160 zF7%|uG3m}cHn&B7e|U~;+_59}N-tB&p7qknwGLyIr}-o>)x!mnRe zdEfWAp5J^tA~NED`h0%QZr62tFaDN^j*j+t^4#0@?U%*&k0tU|cCmQr#kvK%i!WEZlhGO%ub{Ex|9&gWbxj61_@?;otWPn^zNVEcInrW#Fv+ zUiD&6noAlV_m%_hH{1RnlMuXc&EV7Ivdw>|WNp5A;8j}VCPvrAfmfdXpH#eTPQGJQ zx9Z%IeuYxSrrU4JIG>5BRGd?v^x(?nc`IMYIlf9dv-)I8Q{7rhU@@&Bgg%H_7fCp#Pt z?)>~hd~TsmQu~|VOudW!8G`lSZ1mw=61wqG_VebTs!bWE{yz@L$yJ^ho3PS6Wo2e_{FeVwW02xme?LTM7YoNC#${|p=d@>> gZ7f(PxPh`m@5#8yias9>N6QHv7dp$EyOA|8u}dMUk_gNS(W&|Zp%A_Nh{QbCA6 zhoq!vYz-EbcnB&K3sIYGw!wz+&CG7PwI#br8$`&1&CGoB_J4ifyf=B)Iv z-{+2_+6ovMJj23MIVj3+FjgSMPh?TK$%POxW8<_Rp@l}Ho7Oqwy&2mqILg4ab02W; ziMi@Bo;O6kpMS`%3Y4)Rkzb)v`U4&(q00+!xkl*}C&5n^^54R$t|JmRMR5CRkdBKn z=#8OSRY~l1A;9H2!HUJPvRNoAU_CKSztdPNtV8uJP@v09Q923J#Yusz@M~ze3yw$P zyhQgEJ$94ram&z3_YN}9*mD-eqRaqrNnnhv5?Qn1k$)@sa@;i4cLOp5a}cGfR)Ezy zBJ(UAyhF23#_8Sk{4&Vj{^j@4X;^0hhGxB(`%$2qy^NI=4f%W?lTrQ`kf#p$-=nFi z2`w!iJoR{l|3vS*oeMbl-~u}L?G@yjrXf6axU?7WJ}b>9qy43M$AAW&`13E0U~#z( z>EKxP0)NuMV+tsxr8$O-?$?fo@qUYED?ORgJG=~wn)yz7vn_!&$jIPVQ3BZ$+AUrg z@!#hq2v0d9b}YbZW(h+6SCsY*JmgQ3s8hyjrjn4=e2!bi1q^s+sSGJ4;62JFqrH%2 z$W|P!A_466OKL0^A@2Z3QZ)9$EQj2$p#Y`3i+@NSiO$GP^-)iZC1{oa?|gjUuJP>sRO72j=Fxwiqe;X`? zYRpE!Fn#?Fh#6yR2A0KEEQ4yzMnH~8wtiT)!)hd8!f{8dk$~D;UBDj$8X)jK&JAq< P015yANkvXXu0mjf4N!8C diff --git a/Resources/Textures/Clothing/OuterClothing/Hardsuits/paramed.rsi/inhand-left.png b/Resources/Textures/Clothing/OuterClothing/Hardsuits/paramed.rsi/inhand-left.png index 1a4f03fa5d11ccd5ab45640ff423052937c89cc3..02bb28f88c61f89274c6fe62222f900cb5e86d96 100644 GIT binary patch literal 1932 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=jKx9jP7LeL$-D$|_);T0(|mmy zw18|5AO?X;!IOa`XMsm#F;KxA5N2eb5`33|fjKQRB%&n3*T*V3KUXg?B|j-uuOhbq ztjngt3dqb&ElE_U$j!+swyLmI0;{kBvO&W7N(x{lCE2!05xxNm&iO^D3TAo+dIm~% zTnY*bHbp6ERzWUqQ0+jTtx`rwNr9EVetCJhUb(Seeo?xG?W zUP)qwZeFo6#1NP{E~&-IMVSR9nfZANAafIw@=Hr>m6Sjh!2!gbDamkq3QCJ|z_z3$ z>!;?V=BDPA6zd!68R}!xSCW~AaA96CG&q0(qYsh+YBRv9&9k5+*#sC;t`$J{K>Y`F zXfoK|;*u17BnA3L1_l&2TID3>rQ0f1=%%EmC6?xtDA{F{<|gLZ=tGpCYK4fRnrNes#c~^vm#rd$Qj7C* zN?N>Ymoihv0VY@ZR-I@~JI z%|h56nwME(2QvUo7)cjW#8^2Nm6YcfWru(x0UClh<)LOkLK7)vLXtf=|?L zo`>wX%#G9RfH`idr;B4q1>@UUwm!juBFFu^oh1d@mUVLWGF#nvrO@fd)^toFM|mwz zMvp}Yv!J+otjeq%3tnh&c5aXm?=?Kik(9)AkR`c=QA6*jt5Boa#Que;2cG}F|7~yA z#+Q5bzdt-+=~;XJcj39c`^(SoeezdcP+B;F$)|zSfKlxL%M1o|&hE|z_vuCc5;ykXWtd!MWASL2_(nwqI{dD*8N>&nH`xqNv)x#>ZzwielZ^31FNi-?s@bw+-+Sz*^`^w)MhaB?q77}j`d56gU!o( za?HG?rKL-LCC>j~e&?pj-TK=MD*raSFY>*qrn_+OmM>2=&zhBA$Vzh9vc5BZvGV2S zE$j6Xm^5A=%4;}zxaqC=%g=vrKl%Lgjg@)cmL&&f|16!gR^LyKIaXRqB=xfdsH+%4DLX|&oeHQ|HcTY2*dQ9o9G z3C&%d%Gy(6)+G~rZpqsp-Y@^`4NVU}ac9Qrg#WjXw_GXu%yJ-L3&VzICh5xv-|oV?+4;%zueo}HFf=o|7YK^|E!zrd+Kkf zRfcuku1AFvSL-jE=K5#buZ9TD+Rm1uo@;Gv$&Yp``Y~(|cDT(Y;k7PMZSq2o#Orc0 z@e3Rj7JM>riO#7y{5kVg#;ViIKAO89@ZpX`kWAwwmMQmdO#8$VC|tTwK;_e(UbT4{ zpYwnI`P?PG;$guJy+f~m?0gcgYUn!KfGJQo%OEB9{miiHfV_JOajr|w@-ceGXSKIr)n7Rv5z+g%dX?Y)#Co zzahXKe)-`_#^1_ZM-D$xJn0-f#Wa_}04%MLzdKhT$;lYU$$niux3MrfybvCJafH1-ST7PNqe2epF8tr`34CFYbb zS2aUfvby)iIq&PQMo+Q{;$!oaTc&g}JC;%RndgIrSyB?-nsbjPUE%w8&~t)WuwInK mH-(eG|JJe3+j07x>IdnbQ-<#r_r1*o)r6j|elF{r5}E+~N$1S~ delta 1016 zcmVEX>4Tx04R}tkv&MmKpe$iQ%j3f9oj*} zAwzYtAS&XhRVYG*P%E_RU~>J0CJjl7i=*ILaPVWX>fqw6tAnc`2!4RLxj8AiNQwVT z3N2zhIPS;0dyl(!fY7Wm)$ADuRLwHd$%L5At%|`{gb_hMLVpOz%+%*3DFx5*bq^n3 z@8Uem``n+SFJCYj;1h{wnQmCb8^qI_md<&fILgX$p7@-2%%BSrKXP4h`HgeQVS#5x zjZAu;I7%#*x>)IARyI`PDdJdO)hJ)cx}4{{#aXS^S^J*+h2es>vdndw!$@KgOOPN! zK^+xTVIfYdMt_QlH0>um{6mgkB9}t03K%&SP=gBD@q_=t?{3ZF;acMz~GZE8?qz$X$r+6 z@P0<$lmjBSK<}E{TYDd;4?u>xO5Felhrnowve!M{9e?WX?cX!){(b=d19EuqpJ*!p z00KlwL_t(|obB1MYZGA{#_?}@j-6W2p^zXt2`-WbEQrubw+@w(rHdkF>3CCJM6e(Q z@h=c@vV`K+p@o!A6{H5C;O5XkC!tG%gK)eK?~=12J5RI0XRLq zZ!^RMW-H*^uRlPkucyTI^1=v}P5{{4nk9-V7Jow<$ZP^8-h5_lX}7n(wzSLc!{@2% ztgn6rO5FUk48Y9H7poy==XU*jyv%D3!g#B>i=U+tI@oaj*l>j7|C#QE*Tx)p=$>N-~(A|fIpA|fIp zA|mOSy>TrT7hS9M444G=34%$Y=vAg~bS)xz(_FyE*&Uz~$K2Vnh~&*Cpc`ZRSi6Cb zxwB*w$(yc#D5|izH5>1Zo(v7kB9b?ofN^e&?PKjy9CK&ODv~!6#&PyWE~&14ByS?W zSiAq6<3#et=`eg~EaQ$2tji8CmCzoJ`2@gO9B=1kyhz^kL1ks`uJeg5j24ThHGU*- mx&qEG9`d;lv=cUwVf_XCRMK?$_*;Mg0000NNK`9AI2oR36fCy2d(3X&FAdqBZvY7;QDxjz+ zI$VlWWS|uh2C$q(lyZ~-ff^AJtO_Yt056;oMRCAx0_7^cnYZt~|NY;8eEX)I0-gZSOmR3IMatuo0~ucPaP&k4A`wJF z20?{Ffmb-DKq8Sq0udwi!@*I z

o3w2l_WT%0`af**-oD%5%5aY0B3i6Ai|10C=V;A%KTz+a3|ESskTB?i>qpfJL! zFs20I?m(IHRHE_B=Z6N$)%lenJaCBuNF)%P?FmGCA_-i`4-KEf@7J zTZ_K;hy@7kKLaboOHfM+Lw1uQ3RoJ=(iLHz!4KZg+n8f>NoUTry^eXb?`ftKaN!Nn zOuupD)6f@}%w)K+l-OrKyZWx*ZQXj9r5ye2D{>&HxUEhVQo+77$r%^CUBqcsHR@(8UwSs`YE`w^gWv)pueQe!Ct>$0oLV ztJUgvGqkCG7pdB2u-V`|W__5RZ=4AMYum8m(D0r?e;a(HMD~u=ta%k%wJtN^ZmqJT zswdgpFk%fO$l3bxt+8?yy@e10rMGR_BUk6%9vSJDJn(S!xN0%uXdtPP#chD~3s1cq zcY9VhOzB~4_}*zpcx!t_`r5>h30p70!MwC=|AM>=wJwjvPg#~~Xu9kTF&dMb`#iT; zuQVO2Jqc_&yyw;jicuziBj_+&u8x6kPLCWeth$Gojcqa`NbIU$$<%0X z_0hW7bNdq#v%)%ms~_Y2>FTWiPtQ|nMpRUk`IiI7u<@ZlYHn%zS)e#z_J8%rYVy`a9}D*mt?elmI_oQF}qnl%uqZg(b~3)+%D z;r@L!Vs7urFE|uh+{`kyj#Vl2`y(BItgVJ9~D@a%E zHX_xsO#q9@y5TOn%`qNLAgdfP9>foYVBa=kv*ToYX59ut%l2Y4@y#RG6`6ZCQN7B- zj_2lEcJ82g-WliQgImwGb@v`(b?24bFCJ~5j)W&dI% zI(zs~VmWLQmp#e7jO4Uu0-T4WV|S&BuQeScBbDAwO@4-I^MN7jlwH4Muh}12i5NGP zW@M|2TbmE_>LQBT1|*&7z_+8uFLiXbq`DU7hbgMZ2$lO delta 1016 zcmVEX>4Tx04R}tkv&MmKpe$iQ%j3f9oj*} zAwzYtAS&XhRVYG*P%E_RU~>J0CJjl7i=*ILaPVWX>fqw6tAnc`2!4RLxj8AiNQwVT z3N2zhIPS;0dyl(!fY7Wm)$ADuRLwHd$%L5At%|`{gb_hMLVpOz%+%*3DFx5*bq^n3 z@8Uem``n+SFJCYj;1h{wnQmCb8^qI_md<&fILgX$p7@-2%%BSrKXP4h`HgeQVS#5x zjZAu;I7%#*x>)IARyI`PDdJdO)hJ)cx}4{{#aXS^S^J*+h2es>vdndw!$@KgOOPN! zK^+xTVIfYdMt_QlH0>um{6mgkB9}t03K%&SP=gBD@q_=t?{3ZF;acMz~GZE8?qz$X$r+6 z@P0<$lmjBSK<}E{TYDd;4?u>xO5Felhrnowve!M{9e?WX?cX!){(b=d19EuqpJ*!p z00KlwL_t(|obB1aYZGA{$MJVO$GWtjLm@$Q(Wz(}QLsY`ZXFcq(nS%nbiAouM6d`2 z@h@<25X%j2=}<^lLE7NdsSXWv60$UO5FWk`&&B?F?%Etr?mYay;Nb4bJ(uTs^4yc- zKA@CRN`EP(lu}A5rIh-gREloEs8p*@q}zQ3i~(B&!5GH8IoIE-?&_g%?-q1^+QYy5 z?@KjcL9mN4cYy}RxX-!bDy&oo-t4QGZh7dVS7s>qcyH@*4m*zdQwMEH8e) zY}J-bZS2X?{ER?Tpeal9GcvWYC*_&}q1=vs2&@W(mv6VN1h(^Gyfx+YXJrw}%ei{$ z0Hmzyq1Z(b;2LH72e3kcab)`|mHLje{mwPO8c*0Sn;t74ZX|x1G64Gt`{nWc(Ix=z zK7ZdyJSSmVC*3n;yA96v<9z!Qo&*ow#U&F(4^DM>VWFs&D5aEAN-3q3Qc5ZH&nU%9 z&LDU##`J+%pii~>k#2X>OWPA(il)gwI=2xwK%XGk^?L1;T)?fE===z1$5Hoj^zFlt z15i|SZiAV%^=XW0c)jw_GoXm*+(z5AIC1Jej=l>}WON=1tj3Y|5OKFp#YX2BN8MRu zT)Fd)&Sm?)RO-)wp4aaidJVAhkIrqx-Sd9kj02E=bUui<2a&fg8KzPZ(fP$OcUBpm m1oMr~qbPziKa|GY9{mAXnbuT~1Aq7c0000 Date: Thu, 12 Oct 2023 18:21:28 -0400 Subject: [PATCH 103/127] Automatic changelog update --- Resources/Changelog/Changelog.yml | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 820b9a0a138..661b3e08389 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,10 +1,4 @@ Entries: -- author: Nairodian - changes: - - {message: 'Changed Dark & Bushy, Death''s-Head, Firewatch, Moffra, Plasmafire, - and Royal moth wings to now have two separate color layers.', type: Tweak} - id: 4497 - time: '2023-08-10T01:32:01.0000000+00:00' - author: Interrobang01 changes: - {message: Added Mustard. It can be found in condiment stations., type: Add} @@ -2958,3 +2952,8 @@ Entries: poisoning now gasp visibly., type: Tweak} id: 4996 time: '2023-10-12T07:35:31.0000000+00:00' +- author: Ubaser + changes: + - {message: Revamped the Paramedic Void Suit sprite., type: Tweak} + id: 4997 + time: '2023-10-12T22:20:24.0000000+00:00' From d6575eb556ecf407964f37194916ec7540ad2e9d Mon Sep 17 00:00:00 2001 From: DrSmugleaf Date: Thu, 12 Oct 2023 15:45:04 -0700 Subject: [PATCH 104/127] Add support for multiple changelog files, add admin changelog (#20849) --- .../Managers/ClientAdminManager.cs | 8 + .../Managers/IClientAdminManager.cs | 24 ++- Content.Client/Changelog/ChangelogManager.cs | 112 ++++++++-- Content.Client/Changelog/ChangelogTab.xaml | 9 + Content.Client/Changelog/ChangelogTab.xaml.cs | 175 +++++++++++++++ Content.Client/Changelog/ChangelogWindow.xaml | 9 +- .../Changelog/ChangelogWindow.xaml.cs | 204 ++++++------------ Content.Client/Stylesheets/StyleSpace.cs | 17 +- Resources/Changelog/Admin.yml | 9 + .../en-US/changelog/changelog-window.ftl | 3 + 10 files changed, 402 insertions(+), 168 deletions(-) create mode 100644 Content.Client/Changelog/ChangelogTab.xaml create mode 100644 Content.Client/Changelog/ChangelogTab.xaml.cs create mode 100644 Resources/Changelog/Admin.yml diff --git a/Content.Client/Administration/Managers/ClientAdminManager.cs b/Content.Client/Administration/Managers/ClientAdminManager.cs index 66c8b8a0630..8978e2fd6dd 100644 --- a/Content.Client/Administration/Managers/ClientAdminManager.cs +++ b/Content.Client/Administration/Managers/ClientAdminManager.cs @@ -130,5 +130,13 @@ void IPostInjectInit.PostInject() return null; } + + public AdminData? GetAdminData(bool includeDeAdmin = false) + { + if (_player.LocalPlayer is { Session: { } session }) + return GetAdminData(session, includeDeAdmin); + + return null; + } } } diff --git a/Content.Client/Administration/Managers/IClientAdminManager.cs b/Content.Client/Administration/Managers/IClientAdminManager.cs index 46e3a01537b..b4b5b48b814 100644 --- a/Content.Client/Administration/Managers/IClientAdminManager.cs +++ b/Content.Client/Administration/Managers/IClientAdminManager.cs @@ -1,5 +1,4 @@ -using System; -using Content.Shared.Administration; +using Content.Shared.Administration; namespace Content.Client.Administration.Managers { @@ -13,6 +12,15 @@ public interface IClientAdminManager ///

event Action AdminStatusUpdated; + /// + /// Gets the admin data for the client, if they are an admin. + /// + /// + /// Whether to return admin data for admins that are current de-adminned. + /// + /// if the player is not an admin. + AdminData? GetAdminData(bool includeDeAdmin = false); + /// /// Checks whether the local player is an admin. /// @@ -52,5 +60,17 @@ public interface IClientAdminManager bool CanAdminMenu(); void Initialize(); + + /// + /// Checks if the client is an admin. + /// + /// + /// Whether to return admin data for admins that are current de-adminned. + /// + /// true if the player is an admin, false otherwise. + bool IsAdmin(bool includeDeAdmin = false) + { + return GetAdminData(includeDeAdmin) != null; + } } } diff --git a/Content.Client/Changelog/ChangelogManager.cs b/Content.Client/Changelog/ChangelogManager.cs index 249332c337f..396af99d2cf 100644 --- a/Content.Client/Changelog/ChangelogManager.cs +++ b/Content.Client/Changelog/ChangelogManager.cs @@ -1,29 +1,29 @@ -using System; -using System.Collections.Generic; using System.Globalization; -using System.IO; using System.Linq; using System.Threading.Tasks; using Content.Shared.CCVar; using Robust.Shared.Configuration; using Robust.Shared.ContentPack; -using Robust.Shared.IoC; using Robust.Shared.Serialization; using Robust.Shared.Serialization.Manager; -using Robust.Shared.Serialization.Manager.Attributes; using Robust.Shared.Serialization.Markdown; using Robust.Shared.Serialization.Markdown.Mapping; using Robust.Shared.Utility; - namespace Content.Client.Changelog { - public sealed partial class ChangelogManager + public sealed partial class ChangelogManager : IPostInjectInit { + [Dependency] private readonly ILogManager _logManager = default!; [Dependency] private readonly IResourceManager _resource = default!; [Dependency] private readonly ISerializationManager _serialization = default!; [Dependency] private readonly IConfigurationManager _configManager = default!; + private const string SawmillName = "changelog"; + public const string MainChangelogName = "Changelog"; + + private ISawmill _sawmill = default!; + public bool NewChangelogEntries { get; private set; } public int LastReadId { get; private set; } public int MaxId { get; private set; } @@ -51,17 +51,39 @@ public void SaveNewReadId() public async void Initialize() { // Open changelog purely to compare to the last viewed date. - var changelog = await LoadChangelog(); + var changelogs = await LoadChangelog(); + UpdateChangelogs(changelogs); + } + + private void UpdateChangelogs(List changelogs) + { + if (changelogs.Count == 0) + { + return; + } + + var mainChangelogs = changelogs.Where(c => c.Name == MainChangelogName).ToArray(); + if (mainChangelogs.Length == 0) + { + _sawmill.Error($"No changelog file found in Resources/Changelog with name {MainChangelogName}"); + return; + } - if (changelog.Count == 0) + var changelog = changelogs[0]; + if (mainChangelogs.Length > 1) + { + _sawmill.Error($"More than one file found in Resource/Changelog with name {MainChangelogName}"); + } + + if (changelog.Entries.Count == 0) { return; } - MaxId = changelog.Max(c => c.Id); + MaxId = changelog.Entries.Max(c => c.Id); var path = new ResPath($"/changelog_last_seen_{_configManager.GetCVar(CCVars.ServerId)}"); - if(_resource.UserData.TryReadAllText(path, out var lastReadIdText)) + if (_resource.UserData.TryReadAllText(path, out var lastReadIdText)) { LastReadId = int.Parse(lastReadIdText); } @@ -71,20 +93,74 @@ public async void Initialize() NewChangelogEntriesChanged?.Invoke(); } - public Task> LoadChangelog() + public Task> LoadChangelog() { return Task.Run(() => { - var yamlData = _resource.ContentFileReadYaml(new ("/Changelog/Changelog.yml")); + var changelogs = new List(); + var directory = new ResPath("/Changelog"); + foreach (var file in _resource.ContentFindFiles(new ResPath("/Changelog/"))) + { + if (file.Directory != directory || file.Extension != "yml") + continue; + + var yamlData = _resource.ContentFileReadYaml(file); - if (yamlData.Documents.Count == 0) - return new List(); + if (yamlData.Documents.Count == 0) + continue; - var node = (MappingDataNode)yamlData.Documents[0].RootNode.ToDataNode(); - return _serialization.Read>(node["Entries"], notNullableOverride: true); + var node = yamlData.Documents[0].RootNode.ToDataNodeCast(); + var changelog = _serialization.Read(node, notNullableOverride: true); + if (string.IsNullOrWhiteSpace(changelog.Name)) + changelog.Name = file.FilenameWithoutExtension; + + changelogs.Add(changelog); + } + + changelogs.Sort((a, b) => a.Order.CompareTo(b.Order)); + return changelogs; }); } + public void PostInject() + { + _sawmill = _logManager.GetSawmill(SawmillName); + } + + [DataDefinition] + public sealed partial class Changelog + { + /// + /// The name to use for this changelog. + /// If left unspecified, the name of the file is used instead. + /// Used during localization to find the user-displayed name of this changelog. + /// + [DataField("Name")] + public string Name = string.Empty; + + /// + /// The individual entries in this changelog. + /// These are not kept around in memory in the changelog manager. + /// + [DataField("Entries")] + public List Entries = new(); + + /// + /// Whether or not this changelog will be displayed as a tab to non-admins. + /// These are still loaded by all clients, but not shown if they aren't an admin, + /// as they do not contain sensitive data and are publicly visible on GitHub. + /// + [DataField("AdminOnly")] + public bool AdminOnly; + + /// + /// Used when ordering the changelog tabs for the user to see. + /// Larger numbers are displayed later, smaller numbers are displayed earlier. + /// + [DataField("Order")] + public int Order; + } + [DataDefinition] public sealed partial class ChangelogEntry : ISerializationHooks { @@ -108,7 +184,7 @@ void ISerializationHooks.AfterDeserialization() } [DataDefinition] - public sealed partial class ChangelogChange : ISerializationHooks + public sealed partial class ChangelogChange { [DataField("type")] public ChangelogLineType Type { get; private set; } diff --git a/Content.Client/Changelog/ChangelogTab.xaml b/Content.Client/Changelog/ChangelogTab.xaml new file mode 100644 index 00000000000..7c049efacc7 --- /dev/null +++ b/Content.Client/Changelog/ChangelogTab.xaml @@ -0,0 +1,9 @@ + + + + + + + diff --git a/Content.Client/Changelog/ChangelogTab.xaml.cs b/Content.Client/Changelog/ChangelogTab.xaml.cs new file mode 100644 index 00000000000..d1e2bc7533e --- /dev/null +++ b/Content.Client/Changelog/ChangelogTab.xaml.cs @@ -0,0 +1,175 @@ +using System.Linq; +using System.Numerics; +using Content.Client.Resources; +using Content.Client.Stylesheets; +using Robust.Client.AutoGenerated; +using Robust.Client.ResourceManagement; +using Robust.Client.UserInterface; +using Robust.Client.UserInterface.Controls; +using Robust.Client.UserInterface.XAML; +using Robust.Shared.Utility; +using static Content.Client.Changelog.ChangelogManager; +using static Robust.Client.UserInterface.Controls.BoxContainer; + +namespace Content.Client.Changelog; + +[GenerateTypedNameReferences] +public sealed partial class ChangelogTab : Control +{ + [Dependency] private readonly ChangelogManager _changelog = default!; + [Dependency] private readonly IResourceCache _resourceCache = default!; + + public bool AdminOnly; + + public ChangelogTab() + { + RobustXamlLoader.Load(this); + IoCManager.InjectDependencies(this); + } + + public void PopulateChangelog(ChangelogManager.Changelog changelog) + { + var byDay = changelog.Entries + .GroupBy(e => e.Time.ToLocalTime().Date) + .OrderByDescending(c => c.Key); + + var hasRead = changelog.Name != MainChangelogName || + _changelog.MaxId <= _changelog.LastReadId; + + foreach (var dayEntries in byDay) + { + var day = dayEntries.Key; + + var groupedEntries = dayEntries + .GroupBy(c => (c.Author, Read: c.Id <= _changelog.LastReadId)) + .OrderBy(c => c.Key.Read) + .ThenBy(c => c.Key.Author); + + string dayNice; + var today = DateTime.Today; + if (day == today) + dayNice = Loc.GetString("changelog-today"); + else if (day == today.AddDays(-1)) + dayNice = Loc.GetString("changelog-yesterday"); + else + dayNice = day.ToShortDateString(); + + ChangelogBody.AddChild(new Label + { + Text = dayNice, + StyleClasses = { StyleBase.StyleClassLabelHeading }, + Margin = new Thickness(4, 6, 0, 0) + }); + + var first = true; + + foreach (var groupedEntry in groupedEntries) + { + var (author, read) = groupedEntry.Key; + + if (!first) + { + ChangelogBody.AddChild(new Control { Margin = new Thickness(4) }); + } + + if (read && !hasRead) + { + hasRead = true; + + var upArrow = + _resourceCache.GetTexture("/Textures/Interface/Changelog/up_arrow.svg.192dpi.png"); + + var readDivider = new BoxContainer + { + Orientation = LayoutOrientation.Vertical + }; + + var hBox = new BoxContainer + { + Orientation = LayoutOrientation.Horizontal, + HorizontalAlignment = HAlignment.Center, + Children = + { + new TextureRect + { + Texture = upArrow, + ModulateSelfOverride = Color.FromHex("#888"), + TextureScale = new Vector2(0.5f, 0.5f), + Margin = new Thickness(4, 3), + VerticalAlignment = VAlignment.Bottom + }, + new Label + { + Align = Label.AlignMode.Center, + Text = Loc.GetString("changelog-new-changes"), + FontColorOverride = Color.FromHex("#888"), + }, + new TextureRect + { + Texture = upArrow, + ModulateSelfOverride = Color.FromHex("#888"), + TextureScale = new Vector2(0.5f, 0.5f), + Margin = new Thickness(4, 3), + VerticalAlignment = VAlignment.Bottom + } + } + }; + + readDivider.AddChild(hBox); + readDivider.AddChild(new PanelContainer { StyleClasses = { StyleBase.ClassLowDivider } }); + ChangelogBody.AddChild(readDivider); + + if (first) + readDivider.SetPositionInParent(ChangelogBody.ChildCount - 2); + } + + first = false; + + var authorLabel = new RichTextLabel + { + Margin = new Thickness(6, 0, 0, 0), + }; + authorLabel.SetMessage( + FormattedMessage.FromMarkup(Loc.GetString("changelog-author-changed", ("author", author)))); + ChangelogBody.AddChild(authorLabel); + + foreach (var change in groupedEntry.SelectMany(c => c.Changes)) + { + var text = new RichTextLabel(); + text.SetMessage(FormattedMessage.FromMarkup(change.Message)); + ChangelogBody.AddChild(new BoxContainer + { + Orientation = LayoutOrientation.Horizontal, + Margin = new Thickness(14, 1, 10, 2), + Children = + { + GetIcon(change.Type), + text + } + }); + } + } + } + } + + private TextureRect GetIcon(ChangelogLineType type) + { + var (file, color) = type switch + { + ChangelogLineType.Add => ("plus.svg.192dpi.png", "#6ED18D"), + ChangelogLineType.Remove => ("minus.svg.192dpi.png", "#D16E6E"), + ChangelogLineType.Fix => ("bug.svg.192dpi.png", "#D1BA6E"), + ChangelogLineType.Tweak => ("wrench.svg.192dpi.png", "#6E96D1"), + _ => throw new ArgumentOutOfRangeException(nameof(type), type, null) + }; + + return new TextureRect + { + Texture = _resourceCache.GetTexture(new ResPath($"/Textures/Interface/Changelog/{file}")), + VerticalAlignment = VAlignment.Top, + TextureScale = new Vector2(0.5f, 0.5f), + Margin = new Thickness(2, 4, 6, 2), + ModulateSelfOverride = Color.FromHex(color) + }; + } +} diff --git a/Content.Client/Changelog/ChangelogWindow.xaml b/Content.Client/Changelog/ChangelogWindow.xaml index 888a8528d91..355452dbfad 100644 --- a/Content.Client/Changelog/ChangelogWindow.xaml +++ b/Content.Client/Changelog/ChangelogWindow.xaml @@ -3,15 +3,10 @@ Title="{Loc 'changelog-window-title'}" MinSize="500 400" SetSize="500 400"> - - - - - - + - diff --git a/Content.Client/Changelog/ChangelogWindow.xaml.cs b/Content.Client/Changelog/ChangelogWindow.xaml.cs index cea5bd9e7c2..e5f492900c2 100644 --- a/Content.Client/Changelog/ChangelogWindow.xaml.cs +++ b/Content.Client/Changelog/ChangelogWindow.xaml.cs @@ -1,28 +1,22 @@ using System.Linq; -using System.Numerics; -using Content.Client.Resources; +using Content.Client.Administration.Managers; using Content.Client.Stylesheets; using Content.Client.UserInterface.Controls; using Content.Client.UserInterface.Systems.EscapeMenu; using Content.Shared.Administration; using JetBrains.Annotations; using Robust.Client.AutoGenerated; -using Robust.Client.ResourceManagement; using Robust.Client.UserInterface; -using Robust.Client.UserInterface.Controls; using Robust.Client.UserInterface.XAML; using Robust.Shared.Console; -using Robust.Shared.Utility; -using static Content.Client.Changelog.ChangelogManager; -using static Robust.Client.UserInterface.Controls.BoxContainer; namespace Content.Client.Changelog { [GenerateTypedNameReferences] public sealed partial class ChangelogWindow : FancyWindow { + [Dependency] private readonly IClientAdminManager _adminManager = default!; [Dependency] private readonly ChangelogManager _changelog = default!; - [Dependency] private readonly IResourceCache _resourceCache = default!; public ChangelogWindow() { @@ -39,154 +33,84 @@ protected override void Opened() PopulateChangelog(); } + protected override void EnteredTree() + { + base.EnteredTree(); + _adminManager.AdminStatusUpdated += OnAdminStatusUpdated; + } + + protected override void ExitedTree() + { + base.ExitedTree(); + _adminManager.AdminStatusUpdated -= OnAdminStatusUpdated; + } + + private void OnAdminStatusUpdated() + { + TabsUpdated(); + } + private async void PopulateChangelog() { // Changelog is not kept in memory so load it again. - var changelog = await _changelog.LoadChangelog(); + var changelogs = await _changelog.LoadChangelog(); - var byDay = changelog - .GroupBy(e => e.Time.ToLocalTime().Date) - .OrderByDescending(c => c.Key); + Tabs.DisposeAllChildren(); - var hasRead = _changelog.MaxId <= _changelog.LastReadId; - foreach (var dayEntries in byDay) + var i = 0; + foreach (var changelog in changelogs) { - var day = dayEntries.Key; - - var groupedEntries = dayEntries - .GroupBy(c => (c.Author, Read: c.Id <= _changelog.LastReadId)) - .OrderBy(c => c.Key.Read) - .ThenBy(c => c.Key.Author); - - string dayNice; - var today = DateTime.Today; - if (day == today) - dayNice = Loc.GetString("changelog-today"); - else if (day == today.AddDays(-1)) - dayNice = Loc.GetString("changelog-yesterday"); - else - dayNice = day.ToShortDateString(); - - ChangelogBody.AddChild(new Label - { - Text = dayNice, - StyleClasses = { StyleBase.StyleClassLabelHeading }, - Margin = new Thickness(4, 6, 0, 0) - }); + var tab = new ChangelogTab { AdminOnly = changelog.AdminOnly }; + tab.PopulateChangelog(changelog); - var first = true; - - foreach (var groupedEntry in groupedEntries) - { - var (author, read) = groupedEntry.Key; - - if (!first) - { - ChangelogBody.AddChild(new Control { Margin = new Thickness(4) }); - } - - if (read && !hasRead) - { - hasRead = true; - - var upArrow = - _resourceCache.GetTexture("/Textures/Interface/Changelog/up_arrow.svg.192dpi.png"); - - var readDivider = new BoxContainer - { - Orientation = LayoutOrientation.Vertical - }; - - var hBox = new BoxContainer - { - Orientation = LayoutOrientation.Horizontal, - HorizontalAlignment = HAlignment.Center, - Children = - { - new TextureRect - { - Texture = upArrow, - ModulateSelfOverride = Color.FromHex("#888"), - TextureScale = new Vector2(0.5f, 0.5f), - Margin = new Thickness(4, 3), - VerticalAlignment = VAlignment.Bottom - }, - new Label - { - Align = Label.AlignMode.Center, - Text = Loc.GetString("changelog-new-changes"), - FontColorOverride = Color.FromHex("#888"), - }, - new TextureRect - { - Texture = upArrow, - ModulateSelfOverride = Color.FromHex("#888"), - TextureScale = new Vector2(0.5f, 0.5f), - Margin = new Thickness(4, 3), - VerticalAlignment = VAlignment.Bottom - } - } - }; - - readDivider.AddChild(hBox); - readDivider.AddChild(new PanelContainer { StyleClasses = { StyleBase.ClassLowDivider } }); - ChangelogBody.AddChild(readDivider); - - if (first) - readDivider.SetPositionInParent(ChangelogBody.ChildCount - 2); - } - - first = false; - - var authorLabel = new RichTextLabel - { - Margin = new Thickness(6, 0, 0, 0), - }; - authorLabel.SetMessage( - FormattedMessage.FromMarkup(Loc.GetString("changelog-author-changed", ("author", author)))); - ChangelogBody.AddChild(authorLabel); - - foreach (var change in groupedEntry.SelectMany(c => c.Changes)) - { - var text = new RichTextLabel(); - text.SetMessage(FormattedMessage.FromMarkup(change.Message)); - ChangelogBody.AddChild(new BoxContainer - { - Orientation = LayoutOrientation.Horizontal, - Margin = new Thickness(14, 1, 10, 2), - Children = - { - GetIcon(change.Type), - text - } - }); - } - } + Tabs.AddChild(tab); + Tabs.SetTabTitle(i++, Loc.GetString($"changelog-tab-title-{changelog.Name}")); } var version = typeof(ChangelogWindow).Assembly.GetName().Version ?? new Version(1, 0); VersionLabel.Text = Loc.GetString("changelog-version-tag", ("version", version.ToString())); + + TabsUpdated(); } - private TextureRect GetIcon(ChangelogLineType type) + private void TabsUpdated() { - var (file, color) = type switch + var tabs = Tabs.Children.OfType().ToArray(); + var isAdmin = _adminManager.IsAdmin(true); + + var visibleTabs = 0; + int? firstVisible = null; + for (var i = 0; i < tabs.Length; i++) { - ChangelogLineType.Add => ("plus.svg.192dpi.png", "#6ED18D"), - ChangelogLineType.Remove => ("minus.svg.192dpi.png", "#D16E6E"), - ChangelogLineType.Fix => ("bug.svg.192dpi.png", "#D1BA6E"), - ChangelogLineType.Tweak => ("wrench.svg.192dpi.png", "#6E96D1"), - _ => throw new ArgumentOutOfRangeException(nameof(type), type, null) - }; - - return new TextureRect + var tab = tabs[i]; + + if (!tab.AdminOnly || isAdmin) + { + Tabs.SetTabVisible(i, true); + tab.Visible = true; + visibleTabs++; + firstVisible ??= i; + } + else + { + Tabs.SetTabVisible(i, false); + tab.Visible = false; + } + } + + Tabs.TabsVisible = visibleTabs > 1; + + // Current tab became invisible, select the first one that is visible + if (!Tabs.GetTabVisible(Tabs.CurrentTab) && firstVisible != null) { - Texture = _resourceCache.GetTexture(new ResPath($"/Textures/Interface/Changelog/{file}")), - VerticalAlignment = VAlignment.Top, - TextureScale = new Vector2(0.5f, 0.5f), - Margin = new Thickness(2, 4, 6, 2), - ModulateSelfOverride = Color.FromHex(color) - }; + Tabs.CurrentTab = firstVisible.Value; + } + + // We are only displaying one tab, hide its header + if (!Tabs.TabsVisible && firstVisible != null) + { + Tabs.SetTabVisible(firstVisible.Value, false); + } } } diff --git a/Content.Client/Stylesheets/StyleSpace.cs b/Content.Client/Stylesheets/StyleSpace.cs index a82dba65bcc..3bb4e986af5 100644 --- a/Content.Client/Stylesheets/StyleSpace.cs +++ b/Content.Client/Stylesheets/StyleSpace.cs @@ -4,7 +4,6 @@ using Robust.Client.ResourceManagement; using Robust.Client.UserInterface; using Robust.Client.UserInterface.Controls; -using Robust.Shared.Maths; using static Robust.Client.UserInterface.StylesheetHelpers; namespace Content.Client.Stylesheets @@ -62,6 +61,14 @@ public StyleSpace(IResourceCache resCache) : base(resCache) var textureInvertedTriangle = resCache.GetTexture("/Textures/Interface/Nano/inverted_triangle.svg.png"); + var tabContainerPanel = new StyleBoxTexture(); + tabContainerPanel.SetPatchMargin(StyleBox.Margin.All, 2); + + var tabContainerBoxActive = new StyleBoxFlat {BackgroundColor = new Color(64, 64, 64)}; + tabContainerBoxActive.SetContentMarginOverride(StyleBox.Margin.Horizontal, 5); + var tabContainerBoxInactive = new StyleBoxFlat {BackgroundColor = new Color(32, 32, 32)}; + tabContainerBoxInactive.SetContentMarginOverride(StyleBox.Margin.Horizontal, 5); + Stylesheet = new Stylesheet(BaseRules.Concat(new StyleRule[] { Element [DataField("threshold")] - public float Threshold = 10f; + public float Threshold = 20f; /// /// How many tiles should this field check before giving up? From 60f88b1fd65b5954cc72ca10140f096841aaf78c Mon Sep 17 00:00:00 2001 From: liltenhead <104418166+liltenhead@users.noreply.github.com> Date: Fri, 13 Oct 2023 16:42:46 -0700 Subject: [PATCH 117/127] Decrease AME stability damage (#20963) --- Content.Server/Ame/AmeNodeGroup.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Content.Server/Ame/AmeNodeGroup.cs b/Content.Server/Ame/AmeNodeGroup.cs index ab29d7037fa..d0e854469f5 100644 --- a/Content.Server/Ame/AmeNodeGroup.cs +++ b/Content.Server/Ame/AmeNodeGroup.cs @@ -145,10 +145,10 @@ public float InjectFuel(int fuel, out bool overloading) instability = 1; // overloadVsSizeResult > 5: if (overloadVsSizeResult > 5) - instability = 5; - // overloadVsSizeResult > 10: This will explode in at most 5 injections. + instability = 3; + // overloadVsSizeResult > 10: This will explode in at most 20 injections. if (overloadVsSizeResult > 10) - instability = 20; + instability = 5; // Apply calculated instability if (instability == 0) From 0603671c968dbeb1a4ab184a669c21904c7ad3ae Mon Sep 17 00:00:00 2001 From: PJBot Date: Fri, 13 Oct 2023 19:42:48 -0400 Subject: [PATCH 118/127] Automatic changelog update --- Resources/Changelog/Changelog.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 478dc6cfaba..8994e72886a 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,9 +1,4 @@ Entries: -- author: metalgearsloth - changes: - - {message: Potentially fix invalid moth markings leading to issues spawning., type: Fix} - id: 4501 - time: '2023-08-10T03:34:01.0000000+00:00' - author: ElectroJr changes: - {message: Fixed a bug that was causing entity names to not update after being @@ -2951,3 +2946,8 @@ Entries: on its status., type: Tweak} id: 5000 time: '2023-10-13T23:08:00.0000000+00:00' +- author: liltenhead + changes: + - {message: Increased containment field duration after power loss., type: Tweak} + id: 5001 + time: '2023-10-13T23:41:43.0000000+00:00' From 516aa1d7bf5eb46e5e1e6a0a818bb7560bb10870 Mon Sep 17 00:00:00 2001 From: PJBot Date: Fri, 13 Oct 2023 19:43:54 -0400 Subject: [PATCH 119/127] Automatic changelog update --- Resources/Changelog/Changelog.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 8994e72886a..3e5f72dae35 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,10 +1,4 @@ Entries: -- author: ElectroJr - changes: - - {message: Fixed a bug that was causing entity names to not update after being - modified., type: Fix} - id: 4502 - time: '2023-08-10T04:42:09.0000000+00:00' - author: Whisper changes: - {message: 'Added the SecHud to lockers, sec vendor, secfab.', type: Add} @@ -2951,3 +2945,9 @@ Entries: - {message: Increased containment field duration after power loss., type: Tweak} id: 5001 time: '2023-10-13T23:41:43.0000000+00:00' +- author: liltenhead + changes: + - {message: 'Increased the stability of the AME, it now takes about three minutes + for the AME to overload.', type: Tweak} + id: 5002 + time: '2023-10-13T23:42:46.0000000+00:00' From 69995ef0202ae56fc3883ea81c69bf79ff00b983 Mon Sep 17 00:00:00 2001 From: chromiumboy <50505512+chromiumboy@users.noreply.github.com> Date: Fri, 13 Oct 2023 21:35:47 -0500 Subject: [PATCH 120/127] Added missing name (#20979) --- Resources/Locale/en-US/machine/machine.ftl | 1 + 1 file changed, 1 insertion(+) diff --git a/Resources/Locale/en-US/machine/machine.ftl b/Resources/Locale/en-US/machine/machine.ftl index 20a7eb440ff..e23c9791cda 100644 --- a/Resources/Locale/en-US/machine/machine.ftl +++ b/Resources/Locale/en-US/machine/machine.ftl @@ -11,6 +11,7 @@ machine-upgrade-not-upgraded = [color=yellow]{CAPITALIZE($upgraded)}[/color] not machine-part-name-capacitor = Capacitor machine-part-name-manipulator = Manipulator machine-part-name-matter-bin = Matter Bin +machine-part-name-power-cell = Power Cell upgrade-power-draw = power draw upgrade-max-charge = max charge From 4c9246589b0d31ceea0136bfefa982e479921916 Mon Sep 17 00:00:00 2001 From: deltanedas <39013340+deltanedas@users.noreply.github.com> Date: Sat, 14 Oct 2023 06:49:04 +0100 Subject: [PATCH 121/127] add flash and dash sounds to paracusia (#20983) Co-authored-by: deltanedas <@deltanedas:kde.org> --- Resources/Prototypes/SoundCollections/traits.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Resources/Prototypes/SoundCollections/traits.yml b/Resources/Prototypes/SoundCollections/traits.yml index 5b140541a4b..557632c6bba 100644 --- a/Resources/Prototypes/SoundCollections/traits.yml +++ b/Resources/Prototypes/SoundCollections/traits.yml @@ -41,9 +41,11 @@ - /Audio/Machines/phasein.ogg - /Audio/Machines/vending_restock_start.ogg - /Audio/Machines/vending_restock_done.ogg + - /Audio/Magic/blink.ogg - /Audio/Magic/disintegrate.ogg - /Audio/Magic/staff_animation.ogg - /Audio/Weapons/ebladeon.ogg + - /Audio/Weapons/flash.ogg - /Audio/Weapons/smash.ogg - /Audio/Weapons/bladeslice.ogg - /Audio/Weapons/punch1.ogg From acb390e8ccf507e27210bee1a6e93c62c942772e Mon Sep 17 00:00:00 2001 From: Ed <96445749+TheShuEd@users.noreply.github.com> Date: Sat, 14 Oct 2023 10:09:25 +0300 Subject: [PATCH 122/127] Small Liquid Anomaly Patch (#20967) --- Resources/Prototypes/Entities/Structures/Specific/anomalies.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Resources/Prototypes/Entities/Structures/Specific/anomalies.yml b/Resources/Prototypes/Entities/Structures/Specific/anomalies.yml index d227e57ff3b..736834fa2f1 100644 --- a/Resources/Prototypes/Entities/Structures/Specific/anomalies.yml +++ b/Resources/Prototypes/Entities/Structures/Specific/anomalies.yml @@ -305,6 +305,7 @@ solution: anomaly - type: InjectionAnomaly solution: anomaly + superCriticalInjectRadius: 10 - type: ReagentProducerAnomaly solution: anomaly needRecolor: true @@ -354,6 +355,7 @@ - Cognizine - Beer - SpaceGlue + - SpaceLube - CogChamp - Honk - Carpetium From 4fb8fa3f221ba9429d82a52130ceac1c6fda5335 Mon Sep 17 00:00:00 2001 From: deltanedas <39013340+deltanedas@users.noreply.github.com> Date: Sat, 14 Oct 2023 08:09:47 +0100 Subject: [PATCH 123/127] update landmine sprites from tg (#20977) Co-authored-by: deltanedas <@deltanedas:kde.org> --- .../Entities/Objects/Misc/land_mine.yml | 4 +- .../Recipes/Construction/modular.yml | 4 +- .../Misc/landmine.rsi/landmine-inactive.png | Bin 0 -> 305 bytes .../Objects/Misc/landmine.rsi/landmine.png | Bin 0 -> 555 bytes .../Objects/Misc/landmine.rsi/meta.json | 24 ++++++++++++ .../Objects/Misc/uglymine.rsi/meta.json | 35 ------------------ .../Misc/uglymine.rsi/uglymine-inactive.png | Bin 247 -> 0 bytes .../Objects/Misc/uglymine.rsi/uglymine.png | Bin 246 -> 0 bytes 8 files changed, 28 insertions(+), 39 deletions(-) create mode 100644 Resources/Textures/Objects/Misc/landmine.rsi/landmine-inactive.png create mode 100644 Resources/Textures/Objects/Misc/landmine.rsi/landmine.png create mode 100644 Resources/Textures/Objects/Misc/landmine.rsi/meta.json delete mode 100644 Resources/Textures/Objects/Misc/uglymine.rsi/meta.json delete mode 100644 Resources/Textures/Objects/Misc/uglymine.rsi/uglymine-inactive.png delete mode 100644 Resources/Textures/Objects/Misc/uglymine.rsi/uglymine.png diff --git a/Resources/Prototypes/Entities/Objects/Misc/land_mine.yml b/Resources/Prototypes/Entities/Objects/Misc/land_mine.yml index 10dd2296061..9088edc8159 100644 --- a/Resources/Prototypes/Entities/Objects/Misc/land_mine.yml +++ b/Resources/Prototypes/Entities/Objects/Misc/land_mine.yml @@ -21,8 +21,8 @@ - LowImpassable - type: Sprite drawdepth: Items - sprite: Objects/Misc/uglymine.rsi - state: uglymine + sprite: Objects/Misc/landmine.rsi + state: landmine - type: Damageable damageContainer: Inorganic - type: Destructible diff --git a/Resources/Prototypes/Recipes/Construction/modular.yml b/Resources/Prototypes/Recipes/Construction/modular.yml index 73d08693724..affacb098b8 100644 --- a/Resources/Prototypes/Recipes/Construction/modular.yml +++ b/Resources/Prototypes/Recipes/Construction/modular.yml @@ -20,6 +20,6 @@ category: construction-category-weapons description: Construct a landmine using a payload. icon: - sprite: Objects/Misc/uglymine.rsi - state: uglymine + sprite: Objects/Misc/landmine.rsi + state: landmine objectType: Item diff --git a/Resources/Textures/Objects/Misc/landmine.rsi/landmine-inactive.png b/Resources/Textures/Objects/Misc/landmine.rsi/landmine-inactive.png new file mode 100644 index 0000000000000000000000000000000000000000..dcc68ec28b01e53c0e687bc445f9334f3b14138d GIT binary patch literal 305 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz&H|6fVg?4jBOuH;Rhv&5DEQdZ z#WAE}PI96|g2AhXK=vN1ge#1T`6OoXUAS)ir{DL_qotpFOiCRxCS3m?T|Up4gPXhg z=Ogp^jW4Ia3Myz{xzfXEP2Be0jCO&y3=^K#FxeE?o%j?|>e%-D{XN4R#!ZQR3@aH| zs$LUJS3Tix@(quAla_WX%YLNXsWh@X#d%(S;xZ}Xk~ zEisgN((f-1xnp!gWj{z|81Pu!mJ+ sIc@SAh9aE>yO>w-y2-*kb3m4X;rRNHmFilOpfF(YboFyt=akR{0NSZ{=>Px# literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Misc/landmine.rsi/landmine.png b/Resources/Textures/Objects/Misc/landmine.rsi/landmine.png new file mode 100644 index 0000000000000000000000000000000000000000..1a95e1c37381f93e669632760d0511bb87ead813 GIT binary patch literal 555 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=oCO|{#S9F5M?jcysy3fA0|Vn- zPZ!6KiaBp*?e$`I6lp!*q|hO#+N9CZE0wz_Q%A?;sF$M00rwBAIkoKZ2iygkST=Iq z>R4;v+j)btvz}AP<@Ai1JDhnK%gu|G5ATgP-h6ZRoW1g=Cp`MrXsN_-MvyU~kAtDu zg<*y=(*YSlfv4WwCqwpLer~=!T&}9&?4JOpGNajFf43Vw`nY4Coc6RYzvj#^;5W0j z?OXgtv$NydpYx})_wwoJyPf0LacJe|<)4*(^-o?B%hN1T_1?Yuj#pPi-4?p_IrQ`G zV8cCEvvy>>spU-ktURA_)kEjMY!%CX#x0VvyO!UOKC9m;gK_Dl#W%y?a;rtlenZ3cWBk9@tkWr7^YL(W zcCO=8`3Q%H>mDT5t@{@~m+Si0X$w#Bm$I=`a&$e@{Ol~>G==w{`@TP-Y;X@VJnLXE zaA#@23=8$=%sH2?)*QH38MmH2Te@oLJpKg=pK2Pi>a>Nk<5E7mF-~t9; z>eXWTJ3Lk#yZ8IrKEq|j=kuSri+6ie@Y$$JF&LZ=O}=Z%o}Ig%|D#s?YZitDA^*zi zLMC>!+s0|Z_yw_zwPO`gnsjwKQ369!LLKbLh*2~7ZapJN&T diff --git a/Resources/Textures/Objects/Misc/uglymine.rsi/uglymine.png b/Resources/Textures/Objects/Misc/uglymine.rsi/uglymine.png deleted file mode 100644 index 52da78b13b58b5e691d7b33d9fe33369664ce6cc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 246 zcmVP>*7l7tjeCAG-@8~<-E&}Ujv^uwF2 Date: Sat, 14 Oct 2023 08:11:50 +0100 Subject: [PATCH 124/127] add igniter (#20962) Co-authored-by: deltanedas <@deltanedas:kde.org> --- .../IgniteOnTriggerComponent.cs | 30 ++++++++++ .../IgnitionSource/IgniteOnTriggerSystem.cs | 55 ++++++++++++++++++ .../IgnitionSource/IgnitionSourceSystem.cs | 12 +++- .../VendingMachines/Inventories/robotics.yml | 1 + .../VendingMachines/Inventories/vendomat.yml | 3 +- .../Objects/Devices/Electronics/igniter.yml | 25 ++++++++ .../Entities/Structures/Machines/lathe.yml | 1 + .../Prototypes/Recipes/Lathes/devices.yml | 9 +++ Resources/Prototypes/Research/arsenal.yml | 1 + Resources/Prototypes/tags.yml | 3 + .../Objects/Devices/igniter.rsi/icon.png | Bin 0 -> 389 bytes .../Objects/Devices/igniter.rsi/meta.json | 14 +++++ 12 files changed, 150 insertions(+), 4 deletions(-) create mode 100644 Content.Server/IgnitionSource/IgniteOnTriggerComponent.cs create mode 100644 Content.Server/IgnitionSource/IgniteOnTriggerSystem.cs create mode 100644 Resources/Prototypes/Entities/Objects/Devices/Electronics/igniter.yml create mode 100644 Resources/Textures/Objects/Devices/igniter.rsi/icon.png create mode 100644 Resources/Textures/Objects/Devices/igniter.rsi/meta.json diff --git a/Content.Server/IgnitionSource/IgniteOnTriggerComponent.cs b/Content.Server/IgnitionSource/IgniteOnTriggerComponent.cs new file mode 100644 index 00000000000..2037b2ea492 --- /dev/null +++ b/Content.Server/IgnitionSource/IgniteOnTriggerComponent.cs @@ -0,0 +1,30 @@ +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/IgnitionSource/IgniteOnTriggerSystem.cs b/Content.Server/IgnitionSource/IgniteOnTriggerSystem.cs new file mode 100644 index 00000000000..1e425886996 --- /dev/null +++ b/Content.Server/IgnitionSource/IgniteOnTriggerSystem.cs @@ -0,0 +1,55 @@ +using Content.Server.Explosion.EntitySystems; +using Content.Shared.Timing; +using Robust.Shared.Audio; +using Robust.Shared.Timing; + +namespace Content.Server.IgnitionSource; + +/// +/// Handles igniting when triggered and stopping ignition after the delay. +/// +public sealed class IgniteOnTriggerSystem : EntitySystem +{ + [Dependency] private readonly IGameTiming _timing = default!; + [Dependency] private readonly IgnitionSourceSystem _source = default!; + [Dependency] private readonly SharedAudioSystem _audio = default!; + [Dependency] private readonly UseDelaySystem _useDelay = default!; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnTrigger); + } + + public override void Update(float deltaTime) + { + base.Update(deltaTime); + + var query = EntityQueryEnumerator(); + while (query.MoveNext(out var uid, out var comp, out var source)) + { + if (!source.Ignited) + continue; + + if (_timing.CurTime < comp.IgnitedUntil) + continue; + + _source.SetIgnited(uid, false, source); + } + } + + private void OnTrigger(EntityUid uid, IgniteOnTriggerComponent comp, TriggerEvent args) + { + // prevent spamming sound and ignition + TryComp(uid, out var delay); + if (_useDelay.ActiveDelay(uid, delay)) + return; + + _source.SetIgnited(uid); + _audio.PlayPvs(comp.IgniteSound, uid); + + _useDelay.BeginDelay(uid, delay); + comp.IgnitedUntil = _timing.CurTime + comp.IgnitedTime; + } +} diff --git a/Content.Server/IgnitionSource/IgnitionSourceSystem.cs b/Content.Server/IgnitionSource/IgnitionSourceSystem.cs index 25a625180d0..6984dbf56bc 100644 --- a/Content.Server/IgnitionSource/IgnitionSourceSystem.cs +++ b/Content.Server/IgnitionSource/IgnitionSourceSystem.cs @@ -23,12 +23,18 @@ public override void Initialize() private void OnIsHot(EntityUid uid, IgnitionSourceComponent component, IsHotEvent args) { - SetIgnited(uid,component,args.IsHot); + SetIgnited(uid, args.IsHot, component); } - private void SetIgnited(EntityUid uid, IgnitionSourceComponent component, bool newState) + /// + /// Simply sets the ignited field to the ignited param. + /// + public void SetIgnited(EntityUid uid, bool ignited = true, IgnitionSourceComponent? comp = null) { - component.Ignited = newState; + if (!Resolve(uid, ref comp)) + return; + + comp.Ignited = ignited; } public override void Update(float frameTime) diff --git a/Resources/Prototypes/Catalog/VendingMachines/Inventories/robotics.yml b/Resources/Prototypes/Catalog/VendingMachines/Inventories/robotics.yml index 94e46d371a4..06a7398a23c 100644 --- a/Resources/Prototypes/Catalog/VendingMachines/Inventories/robotics.yml +++ b/Resources/Prototypes/Catalog/VendingMachines/Inventories/robotics.yml @@ -5,6 +5,7 @@ Flash: 4 ProximitySensor: 3 RemoteSignaller: 3 + Igniter: 3 # its more ordnance but yeah HandheldHealthAnalyzer: 3 Scalpel: 2 SawElectric: 2 diff --git a/Resources/Prototypes/Catalog/VendingMachines/Inventories/vendomat.yml b/Resources/Prototypes/Catalog/VendingMachines/Inventories/vendomat.yml index 2ef1ad62fe6..da7e30fd763 100644 --- a/Resources/Prototypes/Catalog/VendingMachines/Inventories/vendomat.yml +++ b/Resources/Prototypes/Catalog/VendingMachines/Inventories/vendomat.yml @@ -2,10 +2,11 @@ id: VendomatInventory startingInventory: RemoteSignaller: 1 + Igniter: 2 Wirecutter: 1 CableApcStack: 2 FlashlightLantern: 2 PowerCellSmallPrinted: 3 MatterBinStockPart: 4 CapacitorStockPart: 4 - MicroManipulatorStockPart: 4 \ No newline at end of file + MicroManipulatorStockPart: 4 diff --git a/Resources/Prototypes/Entities/Objects/Devices/Electronics/igniter.yml b/Resources/Prototypes/Entities/Objects/Devices/Electronics/igniter.yml new file mode 100644 index 00000000000..24843f608a7 --- /dev/null +++ b/Resources/Prototypes/Entities/Objects/Devices/Electronics/igniter.yml @@ -0,0 +1,25 @@ +- type: entity + parent: BaseItem + id: Igniter + name: igniter + description: Creates a spark when activated by a signal. + components: + - type: Sprite + sprite: Objects/Devices/igniter.rsi + state: icon + - type: IgnitionSource + temperature: 800 + - type: IgniteOnTrigger + - type: TriggerOnSignal + - type: DeviceNetwork + deviceNetId: Wireless + receiveFrequencyId: BasicDevice + - type: WirelessNetworkConnection + range: 200 + - type: DeviceLinkSink + ports: + - Trigger + - type: UseDelay # prevent sound spam + - type: Tag + tags: + - Igniter diff --git a/Resources/Prototypes/Entities/Structures/Machines/lathe.yml b/Resources/Prototypes/Entities/Structures/Machines/lathe.yml index b1ea5f9e3d1..045ee40556f 100644 --- a/Resources/Prototypes/Entities/Structures/Machines/lathe.yml +++ b/Resources/Prototypes/Entities/Structures/Machines/lathe.yml @@ -243,6 +243,7 @@ - Signaller - SignalTrigger - VoiceTrigger + - Igniter - PowerCellMedium - PowerCellHigh - WeaponPistolCHIMP diff --git a/Resources/Prototypes/Recipes/Lathes/devices.yml b/Resources/Prototypes/Recipes/Lathes/devices.yml index ed73dc1b644..01178b386c3 100644 --- a/Resources/Prototypes/Recipes/Lathes/devices.yml +++ b/Resources/Prototypes/Recipes/Lathes/devices.yml @@ -22,6 +22,15 @@ Steel: 300 Plastic: 200 +- type: latheRecipe + id: Igniter + result: Igniter + completetime: 2 + materials: + Steel: 300 + Plastic: 100 + Glass: 100 + - type: latheRecipe id: ChemicalPayload result: ChemicalPayload diff --git a/Resources/Prototypes/Research/arsenal.yml b/Resources/Prototypes/Research/arsenal.yml index cfd0faecd3c..75107a1b5e9 100644 --- a/Resources/Prototypes/Research/arsenal.yml +++ b/Resources/Prototypes/Research/arsenal.yml @@ -51,6 +51,7 @@ - TimerTrigger - FlashPayload - ExplosivePayload + - Igniter - type: technology id: WeaponizedLaserManipulation diff --git a/Resources/Prototypes/tags.yml b/Resources/Prototypes/tags.yml index ccd042dd002..d7397d483c0 100644 --- a/Resources/Prototypes/tags.yml +++ b/Resources/Prototypes/tags.yml @@ -599,6 +599,9 @@ - type: Tag id: Hotsauce +- type: Tag + id: Igniter + - type: Tag #Drop this innate tool instead of deleting it. id: InnateDontDelete diff --git a/Resources/Textures/Objects/Devices/igniter.rsi/icon.png b/Resources/Textures/Objects/Devices/igniter.rsi/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..4074df008790dbf6a2437f6eb65cb6275650355a GIT binary patch literal 389 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz&H|6fVg?4jBOuH;Rhv(mfq~K7 z)5S5QVoq|RM1sMqhCp_nT=o+uPyVg{@(~6rlP5E#7;*%^;^30b6x-HJhfU=7t-a)6Yxr$=UpnU)C1mE>Oa7 zqCLRf;LiSf`JRa~Z0XH13zjWoOPchAqlu3})xy=)b;tR_#>MXaMt}bOo!uDX5F*0z zX->ikGa=T^{P%yIcwph#lvsa{n=RV3Zim#<#XdYw7$ylRo+)bc=82GX3}#n|K6in| zhrP5bq>$z1Q-%|tx&x|um6(?{WUx2XaDG~=eBqL@xVZ6*7soHDb2;41{wvPiHu<^2 z&V(|djyW7h)CB%n&e&!9K*#HA5ktf$LnhvT{d4|rWQ_QGz(Gkti%VneM~yND-GeKb h-DJUG)MLfK@Kt?6{_Oe*Nx*Pr@O1TaS?83{1OVL!lga=9 literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Devices/igniter.rsi/meta.json b/Resources/Textures/Objects/Devices/igniter.rsi/meta.json new file mode 100644 index 00000000000..81a3a327867 --- /dev/null +++ b/Resources/Textures/Objects/Devices/igniter.rsi/meta.json @@ -0,0 +1,14 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Taken from tgstation at https://github.com/tgstation/tgstation/blob/9a401d19045574f3ea7f2cf3feebf65989903ccc/icons/obj/assemblies/new_assemblies.dmi", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "icon" + } + ] +} From 65f5703731e1d46328acf6080cfdf74df57d76c9 Mon Sep 17 00:00:00 2001 From: PJBot Date: Sat, 14 Oct 2023 03:12:57 -0400 Subject: [PATCH 125/127] Automatic changelog update --- Resources/Changelog/Changelog.yml | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 3e5f72dae35..f6513b06f67 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,11 +1,4 @@ Entries: -- author: Whisper - changes: - - {message: 'Added the SecHud to lockers, sec vendor, secfab.', type: Add} - - {message: Security will now receive the correct glasses box with their security - supplies from cargo., type: Fix} - id: 4503 - time: '2023-08-10T06:04:43.0000000+00:00' - author: emogarbage changes: - {message: Re-sprited grappling gun per artist request., type: Tweak} @@ -2951,3 +2944,9 @@ Entries: for the AME to overload.', type: Tweak} id: 5002 time: '2023-10-13T23:42:46.0000000+00:00' +- author: deltanedas + changes: + - {message: 'Added the igniter for sparking flames, can be found in the vendomat + and robotics vendor or produced by science.', type: Add} + id: 5003 + time: '2023-10-14T07:11:50.0000000+00:00' From 5ecd5f752179fe664a45bb81534f3423f013235a Mon Sep 17 00:00:00 2001 From: Nemanja <98561806+EmoGarbage404@users.noreply.github.com> Date: Sat, 14 Oct 2023 03:15:20 -0400 Subject: [PATCH 126/127] Fix hostile simplemob rotation (#20900) --- Content.Client/CombatMode/CombatModeSystem.cs | 6 ++++++ Content.Server/CombatMode/CombatModeSystem.cs | 5 +++++ Content.Shared/CombatMode/SharedCombatModeSystem.cs | 10 ++++++++-- 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/Content.Client/CombatMode/CombatModeSystem.cs b/Content.Client/CombatMode/CombatModeSystem.cs index 69f149c310a..34ae0b1338b 100644 --- a/Content.Client/CombatMode/CombatModeSystem.cs +++ b/Content.Client/CombatMode/CombatModeSystem.cs @@ -1,4 +1,5 @@ using Content.Client.Hands.Systems; +using Content.Client.NPC.HTN; using Content.Shared.CCVar; using Content.Shared.CombatMode; using Robust.Client.Graphics; @@ -59,6 +60,11 @@ public override void SetInCombatMode(EntityUid entity, bool value, CombatModeCom UpdateHud(entity); } + protected override bool IsNpc(EntityUid uid) + { + return HasComp(uid); + } + private void UpdateHud(EntityUid entity) { if (entity != _playerManager.LocalPlayer?.ControlledEntity || !Timing.IsFirstTimePredicted) diff --git a/Content.Server/CombatMode/CombatModeSystem.cs b/Content.Server/CombatMode/CombatModeSystem.cs index 1c1df817e68..e04463c534d 100644 --- a/Content.Server/CombatMode/CombatModeSystem.cs +++ b/Content.Server/CombatMode/CombatModeSystem.cs @@ -1,7 +1,12 @@ +using Content.Server.NPC.HTN; using Content.Shared.CombatMode; namespace Content.Server.CombatMode; public sealed class CombatModeSystem : SharedCombatModeSystem { + protected override bool IsNpc(EntityUid uid) + { + return HasComp(uid); + } } diff --git a/Content.Shared/CombatMode/SharedCombatModeSystem.cs b/Content.Shared/CombatMode/SharedCombatModeSystem.cs index 5fe763370fd..60d1362bb0b 100644 --- a/Content.Shared/CombatMode/SharedCombatModeSystem.cs +++ b/Content.Shared/CombatMode/SharedCombatModeSystem.cs @@ -82,7 +82,7 @@ public virtual void SetInCombatMode(EntityUid entity, bool value, CombatModeComp _actionsSystem.SetToggled(component.CombatToggleActionEntity, component.IsInCombatMode); // Change mouse rotator comps if flag is set - if (!component.ToggleMouseRotator) + if (!component.ToggleMouseRotator || IsNpc(entity)) return; SetMouseRotatorComponents(entity, value); @@ -101,6 +101,12 @@ private void SetMouseRotatorComponents(EntityUid uid, bool value) RemComp(uid); } } + + // todo: When we stop making fucking garbage abstract shared components, remove this shit too. + protected abstract bool IsNpc(EntityUid uid); } -public sealed partial class ToggleCombatActionEvent : InstantActionEvent { } +public sealed partial class ToggleCombatActionEvent : InstantActionEvent +{ + +} From 250d74779509f5bc55c3183864d3939fba61735a Mon Sep 17 00:00:00 2001 From: xTray Date: Sat, 14 Oct 2023 13:20:24 +0300 Subject: [PATCH 127/127] Fixes --- Resources/Maps/corvax_spectrum.yml | 35 ++----------------- .../Entities/Structures/Power/industrial.yml | 2 +- .../Catalog/Cargo/cargo_vending.yml | 2 +- .../Entities/Clothing/Uniforms/jumpskirts.yml | 21 +++++------ Resources/Prototypes/Voice/disease_emotes.yml | 5 --- Resources/Prototypes/Voice/speech_emotes.yml | 2 +- 6 files changed, 16 insertions(+), 51 deletions(-) diff --git a/Resources/Maps/corvax_spectrum.yml b/Resources/Maps/corvax_spectrum.yml index 6001c6f80da..b5462f1ff5a 100644 --- a/Resources/Maps/corvax_spectrum.yml +++ b/Resources/Maps/corvax_spectrum.yml @@ -20973,22 +20973,6 @@ entities: type: MetaData - parent: 24737 type: Transform -- proto: ActionToggleJetpack - entities: - - uid: 24743 - components: - - flags: InContainer - type: MetaData - - parent: 24737 - type: Transform -- proto: ActionToggleLight - entities: - - uid: 24900 - components: - - flags: InContainer - type: MetaData - - parent: 24898 - type: Transform #- uid: 36909 # components: # - flags: InContainer @@ -174099,12 +174083,9 @@ entities: type: Transform - toggleActionEntity: 24744 type: GasTank - - toggleActionEntity: 24743 - type: Jetpack - containers: ProvidedActionContainer: !type:Container ents: - - 24743 - 24744 type: ContainerContainer - proto: JetpackSecurityFilled @@ -179834,7 +179815,7 @@ entities: ████╗░██║╚══██╔══╝ Форма NT-№XXX-MED-PRQ - ██╔██╗██║░░░██║░░░ Запрос на производство + ██╔██╗██║░░░██║░░░ Запрос на производство ██║╚████║░░░██║░░░ лекарственных препаратов @@ -180523,7 +180504,7 @@ entities: Разрешение на ношение оружия - Должность: Священник + Должность: Священник Причина: Быть рукой господа и для защиты божьего дома. @@ -273528,18 +273509,6 @@ entities: pos: 36.400997,-24.892822 parent: 36907 type: Transform - - uid: 24898 - components: - - pos: 27.544739,-1.9702148 - parent: 36907 - type: Transform - - toggleActionEntity: 24900 - type: UnpoweredFlashlight - - containers: - ProvidedActionContainer: !type:Container - ents: - - 24900 - type: ContainerContainer - proto: WeaponDisabler entities: - uid: 2331 diff --git a/Resources/Prototypes/ADT/Entities/Structures/Power/industrial.yml b/Resources/Prototypes/ADT/Entities/Structures/Power/industrial.yml index 42b90b0adc0..2288d8d16f6 100644 --- a/Resources/Prototypes/ADT/Entities/Structures/Power/industrial.yml +++ b/Resources/Prototypes/ADT/Entities/Structures/Power/industrial.yml @@ -63,7 +63,7 @@ - type: WiresPanel - type: Wires BoardName: wires-board-name-smes - LayoutId: SMES + layoutId: SMES - type: Machine board: SMESMachineCircuitboard - type: StationInfiniteBatteryTarget diff --git a/Resources/Prototypes/Catalog/Cargo/cargo_vending.yml b/Resources/Prototypes/Catalog/Cargo/cargo_vending.yml index da82bd73dca..51949e7312a 100644 --- a/Resources/Prototypes/Catalog/Cargo/cargo_vending.yml +++ b/Resources/Prototypes/Catalog/Cargo/cargo_vending.yml @@ -33,7 +33,7 @@ sprite: Objects/Specific/Service/vending_machine_restock.rsi state: base product: CrateVendingMachineRestockClothesFilled - cost: 5520 + cost: 5700 category: Service group: market diff --git a/Resources/Prototypes/Corvax/Entities/Clothing/Uniforms/jumpskirts.yml b/Resources/Prototypes/Corvax/Entities/Clothing/Uniforms/jumpskirts.yml index b720c007963..17edb67f0ee 100644 --- a/Resources/Prototypes/Corvax/Entities/Clothing/Uniforms/jumpskirts.yml +++ b/Resources/Prototypes/Corvax/Entities/Clothing/Uniforms/jumpskirts.yml @@ -21,16 +21,17 @@ - type: Clothing sprite: Corvax/Clothing/Uniforms/Jumpskirt/centcom_officer.rsi -- type: entity - parent: ClothingUniformSkirtBase - id: ClothingUniformJumpskirtLibrarian - name: sensible suitskirt - description: It's very... sensible. - components: - - type: Sprite - sprite: Corvax/Clothing/Uniforms/Jumpskirt/librarian.rsi - - type: Clothing - sprite: Corvax/Clothing/Uniforms/Jumpskirt/librarian.rsi +# TODO xTray Disabled Duplicate ID +#- type: entity +# parent: ClothingUniformSkirtBase +# id: ClothingUniformJumpskirtLibrarian +# name: sensible suitskirt +# description: It's very... sensible. +# components: +# - type: Sprite +# sprite: Corvax/Clothing/Uniforms/Jumpskirt/librarian.rsi +# - type: Clothing +# sprite: Corvax/Clothing/Uniforms/Jumpskirt/librarian.rsi - type: entity parent: ClothingUniformSkirtBase diff --git a/Resources/Prototypes/Voice/disease_emotes.yml b/Resources/Prototypes/Voice/disease_emotes.yml index b1039be81ea..f73169c3e07 100644 --- a/Resources/Prototypes/Voice/disease_emotes.yml +++ b/Resources/Prototypes/Voice/disease_emotes.yml @@ -51,8 +51,3 @@ id: Snore category: Vocal chatMessages: [храпит] # Corvax-Localization - -- type: emote - id: Honk - category: Vocal - chatMessages: [хонкает] # Corvax-Localization diff --git a/Resources/Prototypes/Voice/speech_emotes.yml b/Resources/Prototypes/Voice/speech_emotes.yml index 55d77e3b307..c78763ab993 100644 --- a/Resources/Prototypes/Voice/speech_emotes.yml +++ b/Resources/Prototypes/Voice/speech_emotes.yml @@ -84,7 +84,7 @@ - type: emote id: Honk category: Vocal - chatMessages: [honks] + chatMessages: [хонкает] # Corvax-Localization - type: emote id: Sigh
/// Chance that an interaction attempt will succeed. /// 1 = always play "success" popup and sound. diff --git a/Content.Server/Interaction/InteractionPopupSystem.cs b/Content.Server/Interaction/InteractionPopupSystem.cs index 286919b64fc..86158fb7a89 100644 --- a/Content.Server/Interaction/InteractionPopupSystem.cs +++ b/Content.Server/Interaction/InteractionPopupSystem.cs @@ -58,6 +58,9 @@ private void OnInteractHand(EntityUid uid, InteractionPopupComponent component, if (component.InteractSuccessSound != null) sfx = component.InteractSuccessSound.GetSound(); + + if (component.InteractSuccessSpawn != null) + Spawn(component.InteractSuccessSpawn, Transform(uid).MapPosition); } else { @@ -66,6 +69,9 @@ private void OnInteractHand(EntityUid uid, InteractionPopupComponent component, if (component.InteractFailureSound != null) sfx = component.InteractFailureSound.GetSound(); + + if (component.InteractFailureSpawn != null) + Spawn(component.InteractFailureSpawn, Transform(uid).MapPosition); } if (component.MessagePerceivedByOthers != null) diff --git a/Resources/Prototypes/Entities/Effects/hearts.yml b/Resources/Prototypes/Entities/Effects/hearts.yml new file mode 100644 index 00000000000..042fdb5e8ab --- /dev/null +++ b/Resources/Prototypes/Entities/Effects/hearts.yml @@ -0,0 +1,16 @@ +- type: entity + id: EffectHearts + noSpawn: true + components: + - type: TimedDespawn + lifetime: 0.85 + - type: Sprite + noRot: true + drawdepth: Effects + sprite: Effects/hearts.rsi + state: hearts + - type: EffectVisuals + - type: Tag + tags: + - HideContextMenu + - type: AnimationPlayer \ No newline at end of file diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml b/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml index a79a0e0a99b..0077fddcfc4 100644 --- a/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml +++ b/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml @@ -41,6 +41,7 @@ successChance: 0.2 interactSuccessString: petting-success-soft-floofy interactFailureString: petting-failure-bat + interactSuccessSpawn: EffectHearts interactSuccessSound: path: /Audio/Animals/fox_squeak.ogg - type: SentienceTarget @@ -204,6 +205,7 @@ successChance: 0.8 interactSuccessString: petting-success-bird interactFailureString: petting-failure-generic + interactSuccessSpawn: EffectHearts interactSuccessSound: path: /Audio/Animals/chicken_cluck_happy.ogg - type: Bloodstream @@ -290,6 +292,7 @@ successChance: 0.9 interactSuccessString: petting-success-bird interactFailureString: petting-failure-generic + interactSuccessSpawn: EffectHearts interactSuccessSound: path: /Audio/Animals/duck_quack_happy.ogg - type: Bloodstream @@ -469,6 +472,7 @@ interactDelay: 2 # Avoids overlapping SFX due to spam - these SFX are a little longer than the typical 1 second. interactSuccessString: petting-success-soft-floofy interactFailureString: petting-failure-generic + interactSuccessSpawn: EffectHearts interactSuccessSound: path: /Audio/Animals/cow_moo.ogg - type: Perishable @@ -523,6 +527,7 @@ successChance: 0.5 interactSuccessString: petting-success-crab interactFailureString: petting-failure-crab + interactSuccessSpawn: EffectHearts - type: Bloodstream bloodMaxVolume: 50 - type: Tag @@ -598,6 +603,7 @@ successChance: 0.2 interactSuccessString: petting-success-goat interactFailureString: petting-failure-goat + interactSuccessSpawn: EffectHearts interactSuccessSound: path: /Audio/Animals/goat_bah.ogg - type: NpcFactionMember @@ -650,6 +656,7 @@ successChance: 0.1 # Yeah, good luck with that. interactSuccessString: petting-success-goose interactFailureString: petting-failure-goose + interactSuccessSpawn: EffectHearts interactSuccessSound: path: /Audio/Animals/goose_honk.ogg - type: Bloodstream @@ -1160,6 +1167,7 @@ successChance: 0.3 interactSuccessString: petting-success-reptile interactFailureString: petting-failure-generic + interactSuccessSpawn: EffectHearts interactSuccessSound: path: /Audio/Animals/lizard_happy.ogg - type: Bloodstream @@ -1215,6 +1223,7 @@ successChance: 0.3 interactSuccessString: petting-success-generic interactFailureString: petting-failure-generic + interactSuccessSpawn: EffectHearts - type: Bloodstream bloodMaxVolume: 50 @@ -1259,6 +1268,7 @@ successChance: 0.6 interactSuccessString: petting-success-frog interactFailureString: petting-failure-generic + interactSuccessSpawn: EffectHearts interactSuccessSound: path: /Audio/Animals/frog_ribbit.ogg - type: Bloodstream @@ -1310,6 +1320,7 @@ successChance: 0.6 interactSuccessString: petting-success-bird interactFailureString: petting-failure-generic + interactSuccessSpawn: EffectHearts interactSuccessSound: path: /Audio/Animals/parrot_raught.ogg - type: Bloodstream @@ -1353,6 +1364,7 @@ successChance: 0.5 interactSuccessString: petting-success-bird interactFailureString: petting-failure-generic + interactSuccessSpawn: EffectHearts interactSuccessSound: path: /Audio/Animals/penguin_squawk.ogg - type: Tag @@ -1578,6 +1590,7 @@ successChance: 0.6 interactSuccessString: petting-success-reptile interactFailureString: petting-failure-generic + interactSuccessSpawn: EffectHearts - type: Bloodstream bloodMaxVolume: 50 - type: Damageable @@ -1655,6 +1668,7 @@ successChance: 0.5 interactSuccessString: petting-success-tarantula interactFailureString: petting-failure-generic + interactSuccessSpawn: EffectHearts - type: NoSlip - type: Spider - type: IgnoreSpiderWeb @@ -1834,6 +1848,7 @@ successChance: 0.2 # Low when undomesticated. interactSuccessString: petting-success-soft-floofy interactFailureString: petting-failure-generic + interactSuccessSpawn: EffectHearts interactSuccessSound: path: /Audio/Animals/raccoon_chatter.ogg - type: Grammar @@ -1890,6 +1905,7 @@ successChance: 0.5 interactSuccessString: petting-success-soft-floofy interactFailureString: petting-failure-generic + interactSuccessSpawn: EffectHearts interactSuccessSound: path: /Audio/Animals/fox_squeak.ogg - type: Grammar @@ -1951,6 +1967,7 @@ - type: InteractionPopup interactSuccessString: petting-success-dog interactFailureString: petting-failure-generic + interactSuccessSpawn: EffectHearts interactSuccessSound: path: /Audio/Animals/small_dog_bark_happy.ogg - type: Grammar @@ -2100,6 +2117,7 @@ successChance: 0.7 interactSuccessString: petting-success-cat interactFailureString: petting-failure-generic + interactSuccessSpawn: EffectHearts interactSuccessSound: path: /Audio/Animals/cat_meow.ogg - type: Grammar @@ -2152,6 +2170,7 @@ successChance: 0.7 interactSuccessString: petting-success-space-cat interactFailureString: petting-failure-generic + interactSuccessSpawn: EffectHearts interactSuccessSound: path: /Audio/Animals/cat_meow.ogg - type: Respirator #It just works? @@ -2225,6 +2244,7 @@ successChance: 0.9 interactSuccessString: petting-success-sloth interactFailureString: petting-failure-sloth + interactSuccessSpawn: EffectHearts interactSuccessSound: path: /Audio/Animals/sloth_squeak.ogg - type: Grammar @@ -2282,6 +2302,7 @@ interactDelay: 1.5 # Avoids overlapping SFX due to spam - these SFX are a little longer than the typical 1 second. interactSuccessString: petting-success-soft-floofy interactFailureString: petting-failure-generic + interactSuccessSpawn: EffectHearts interactSuccessSound: path: /Audio/Animals/ferret_happy.ogg - type: Grammar @@ -2412,6 +2433,7 @@ successChance: 0.4 interactSuccessString: petting-success-hamster interactFailureString: petting-failure-hamster + interactSuccessSpawn: EffectHearts interactSuccessSound: path: /Audio/Animals/fox_squeak.ogg - type: Bloodstream @@ -2482,6 +2504,7 @@ successChance: 0.7 interactSuccessString: petting-success-pig interactFailureString: petting-failure-generic + interactSuccessSpawn: EffectHearts interactSuccessSound: path: /Audio/Animals/pig_oink.ogg - type: ReplacementAccent diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/pets.yml b/Resources/Prototypes/Entities/Mobs/NPCs/pets.yml index 1efa767af1b..21cc305acde 100644 --- a/Resources/Prototypes/Entities/Mobs/NPCs/pets.yml +++ b/Resources/Prototypes/Entities/Mobs/NPCs/pets.yml @@ -211,6 +211,7 @@ successChance: 0.9 interactSuccessString: petting-success-bingus interactFailureString: petting-failure-generic + interactSuccessSpawn: EffectHearts interactSuccessSound: path: /Audio/Animals/cat_meow.ogg - type: Grammar @@ -273,6 +274,7 @@ successChance: 0.5 interactSuccessString: petting-success-dog interactFailureString: petting-failure-generic + interactSuccessSpawn: EffectHearts interactSuccessSound: path: /Audio/Animals/small_dog_bark_happy.ogg - type: Grammar @@ -312,6 +314,7 @@ successChance: 1 interactSuccessString: petting-success-sloth interactFailureString: petting-failure-sloth + interactSuccessSpawn: EffectHearts - type: Grammar attributes: proper: true @@ -368,6 +371,7 @@ successChance: 0.7 interactSuccessString: petting-success-dog interactFailureString: petting-failure-generic + interactSuccessSpawn: EffectHearts interactSuccessSound: path: /Audio/Animals/small_dog_bark_happy.ogg - type: Grammar @@ -389,6 +393,7 @@ successChance: 1.0 # Hey, c'mon, this is Morty we're talking about here. interactSuccessString: petting-success-possum interactFailureString: petting-failure-possum + interactSuccessSpawn: EffectHearts interactSuccessSound: path: /Audio/Animals/snake_hiss.ogg - type: Grammar @@ -410,6 +415,7 @@ successChance: 0.7 interactSuccessString: petting-success-raccoon interactFailureString: petting-failure-raccoon + interactSuccessSpawn: EffectHearts interactSuccessSound: path: /Audio/Animals/raccoon_chatter.ogg - type: Grammar @@ -431,6 +437,7 @@ successChance: 1 interactSuccessString: petting-success-pig interactFailureString: petting-failure-pig + interactSuccessSpawn: EffectHearts interactSuccessSound: path: /Audio/Animals/pig_oink.ogg - type: Grammar @@ -452,6 +459,7 @@ successChance: 1 interactSuccessString: petting-success-soft-floofy interactFailureString: petting-failure-generic + interactSuccessSpawn: EffectHearts interactSuccessSound: path: /Audio/Animals/fox_squeak.ogg - type: Butcherable @@ -492,6 +500,7 @@ successChance: 1 interactSuccessString: petting-success-hamster interactFailureString: petting-failure-hamster + interactSuccessSpawn: EffectHearts interactSuccessSound: path: /Audio/Animals/fox_squeak.ogg - type: Butcherable @@ -518,6 +527,7 @@ successChance: 0.5 # spider is mean interactSuccessString: petting-success-tarantula interactFailureString: petting-failure-hamster + interactSuccessSpawn: EffectHearts interactSuccessSound: path: /Audio/Animals/snake_hiss.ogg - type: NpcFactionMember @@ -592,7 +602,8 @@ - type: InteractionPopup successChance: 0.8 interactSuccessString: petting-success-kangaroo - interactFailureString: petting-failure-kangaroo + interactFailureString: petting-failure-generic + interactSuccessSpawn: EffectHearts interactSuccessSound: path: /Audio/Animals/kangaroo_grunt.ogg - type: Grammar diff --git a/Resources/Textures/Effects/hearts.rsi/hearts.png b/Resources/Textures/Effects/hearts.rsi/hearts.png new file mode 100644 index 0000000000000000000000000000000000000000..25bf0a8b5a8d082603679b14adf3447ab45e9853 GIT binary patch literal 734 zcmV<40wMj0P)Px%m`OxIRCt{2o4sz^FcgI^RkcGicdP-sbC&F`-@>yOFMXvhp8WvXZy9AQswkiz0!QQ zQs#B`3Xm*>bK+y>iZ|Uzx(Tyk6s4hkT<}VrWv-~ zGo58*x~%Ce3vyb%reR+ns4VKEIAu{gn~mTK;3x!F>l!Nl6u!=BzFVo==ZZ>|6A@9V za=Lx4oE^`}3h?OzISRq`EesXkhOcdG?k`nNzIOB7jlO*#(SL_C`TUixbk!*nwlrPR z^0}9j^=P4epa1UW^=P55^Dl4zT|Zzr3c*KE7x9Co>xUD(evhCqLGrkmnak)i2Z*bg z!Ga7^d{--d(Ji2hrS3Dni!)?x0a9;YL+DyWXndCsI<^)d{q{A4exGoE5aK&J|v$nim!O-al@C8{6<+3^J(^7$Bk4^;j~tO zkDxxqcNsTQK84e|HPKa2-{QLrnkk>cIavWdf;hx?*_$cpbXca%ecTJ24ii3tE>1iE z00000kRr87u@tc$K<;C2Ca}{w88?K*l#f6X$3H(bm|_3`000000Dyk^2Qi9x)|JuV Qn*aa+07*qoM6N<$f`MgOzW@LL literal 0 HcmV?d00001 diff --git a/Resources/Textures/Effects/hearts.rsi/meta.json b/Resources/Textures/Effects/hearts.rsi/meta.json new file mode 100644 index 00000000000..0c90d63d886 --- /dev/null +++ b/Resources/Textures/Effects/hearts.rsi/meta.json @@ -0,0 +1,24 @@ +{ + "version": 1, + "size": { + "x": 32, + "y": 32 + }, + "license": "CC-BY-SA-3.0", + "copyright": "Created by TheShuEd (github) for ss14", + "states": [ + { + "name": "hearts", + "delays": [ + [ + 0.15, + 0.15, + 0.15, + 0.15, + 0.15, + 0.15 + ] + ] + } + ] +} \ No newline at end of file From 2ff8e149fbbfa3f9e12f1a1189d4c5c20193a440 Mon Sep 17 00:00:00 2001 From: PJBot Date: Fri, 13 Oct 2023 13:35:23 -0400 Subject: [PATCH 110/127] Automatic changelog update --- Resources/Changelog/Changelog.yml | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 0bcb9cadbc9..20101b3ae9a 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,14 +1,4 @@ Entries: -- author: Doru991 - changes: - - {message: 'Emagging the NutriMax will give a bottle of left-4-zed, for when you - need kudzu ASAP.', type: Add} - - {message: 'Since it got lost in translation last time, the NutriMax also has EZ - nutrient to satisfy increased nutrient demand.', type: Add} - - {message: New and improved formulas have increased the effectiveness of EZ nutrient - and Left-4-Zed., type: Tweak} - id: 4499 - time: '2023-08-10T01:43:07.0000000+00:00' - author: crazybrain changes: - {message: Admin ghosts can now analyse solutions easier., type: Tweak} @@ -2955,3 +2945,8 @@ Entries: - {message: Reptilians can now choose to have floppy kobold ears., type: Add} id: 4998 time: '2023-10-13T01:30:31.0000000+00:00' +- author: TheShuEd + changes: + - {message: Animals now give cute hearts when you pet them., type: Add} + id: 4999 + time: '2023-10-13T17:34:18.0000000+00:00' From e972ce7984ebd96eb0a962a5edc6a9d210922cb4 Mon Sep 17 00:00:00 2001 From: coolmankid12345 <55817627+coolmankid12345@users.noreply.github.com> Date: Fri, 13 Oct 2023 13:36:41 -0400 Subject: [PATCH 111/127] Add guidebook for revolutionaries (#20957) --- Resources/Locale/en-US/guidebook/guides.ftl | 1 + Resources/Prototypes/Guidebook/antagonist.yml | 6 +++ .../Guidebook/Antagonist/Revolutionaries.xml | 54 +++++++++++++++++++ 3 files changed, 61 insertions(+) create mode 100644 Resources/ServerInfo/Guidebook/Antagonist/Revolutionaries.xml diff --git a/Resources/Locale/en-US/guidebook/guides.ftl b/Resources/Locale/en-US/guidebook/guides.ftl index c03f1a8c575..9fc69839c08 100644 --- a/Resources/Locale/en-US/guidebook/guides.ftl +++ b/Resources/Locale/en-US/guidebook/guides.ftl @@ -50,6 +50,7 @@ guide-entry-antagonists = Antagonists guide-entry-nuclear-operatives = Nuclear Operatives guide-entry-traitors = Traitors guide-entry-zombies = Zombies +guide-entry-revolutionaries = Revolutionaries guide-entry-minor-antagonists = Minor Antagonists guide-entry-space-ninja = Space Ninja diff --git a/Resources/Prototypes/Guidebook/antagonist.yml b/Resources/Prototypes/Guidebook/antagonist.yml index e6e9afa0172..081ff7ef0ab 100644 --- a/Resources/Prototypes/Guidebook/antagonist.yml +++ b/Resources/Prototypes/Guidebook/antagonist.yml @@ -6,6 +6,7 @@ - Traitors - NuclearOperatives - Zombies + - Revolutionaries - MinorAntagonists - SpaceNinja @@ -24,6 +25,11 @@ name: guide-entry-zombies text: "/ServerInfo/Guidebook/Antagonist/Zombies.xml" +- type: guideEntry + id: Revolutionaries + name: guide-entry-revolutionaries + text: "/ServerInfo/Guidebook/Antagonist/Revolutionaries.xml" + - type: guideEntry id: MinorAntagonists name: guide-entry-minor-antagonists diff --git a/Resources/ServerInfo/Guidebook/Antagonist/Revolutionaries.xml b/Resources/ServerInfo/Guidebook/Antagonist/Revolutionaries.xml new file mode 100644 index 00000000000..5f6d4ea9376 --- /dev/null +++ b/Resources/ServerInfo/Guidebook/Antagonist/Revolutionaries.xml @@ -0,0 +1,54 @@ + + # Revolutionaries + + - Revolutionaries are antagonists that are sponsored by the Syndicate to take over the station. + + ## Head Revolutionaries + + + + + + + [color=#5e9cff]Head Revolutionaries[/color] are chosen at the start of the shift and are tasked with taking over the station by killing or exiling all of the Command staff. Head Revolutionaries will be given a [color=#a4885c]Flash[/color] and a pair of [color=#a4885c]Sunglasses[/color] to aid them. + + ## Conversion + + + + + + You can convert crew members by using a [color=#a4885c]Flash[/color] in [color=#ff0000]harm mode[/color] and attacking someone with it. Any flash can be used for conversion, but remember that flashes have limited charges. + + + + + + + + However, things such as [color=#a4885c]Sunglasses[/color] and [color=#a4885c]Welding Masks[/color] offer flash protection and people wearing these will not be able to be converted. + + + + + + While not flash protection, a [color=#a4885c]MindShield Implant[/color] will prevent the implanted person from being converted into a revolutionary. Assume all of [color=#a4885c]Security[/color] and [color=#a4885c]Command[/color] are implanted already. + + ## Revolutionary + + A [color=#ff0000]Revolutionary[/color] is the result of being converted by a [color=#5e9cff]Head Revolutionary[/color]. Revolutionaries are underlings of the Head Revolutionaries and should follow orders given by them and prioritize their well-being over anything else because if they die you will lose. + Keep in mind that you can't convert others as a regular revolutionary, only your boss can do that. + + ## Objectives + + You must eliminate or exile all of the following Command staff on station in no particular order. + - Captain + - Head of Personnel + - Chief Engineer + - Research Director + - Quartermaster + - Head of Security + - Chief Medical Officer + + Remember, your objective is to take over the station and not to destroy it so try to minimize damage where possible. Viva la revolución! + From db4ad40430242e957ba14f95cf6dbf53857fc1cb Mon Sep 17 00:00:00 2001 From: DrSmugleaf Date: Fri, 13 Oct 2023 11:56:12 -0700 Subject: [PATCH 112/127] Add panic bunker UI and automatic panic bunker (#20954) --- .../Administration/UI/AdminMenuWindow.xaml | 4 +- .../Administration/UI/AdminMenuWindow.xaml.cs | 7 +- .../PanicBunkerStatusWindow.xaml | 6 + .../PanicBunkerStatusWindow.xaml.cs | 14 ++ .../Tabs/PanicBunkerTab/PanicBunkerTab.xaml | 43 +++++ .../PanicBunkerTab/PanicBunkerTab.xaml.cs | 54 ++++++ .../Administration/UI/Tabs/ServerTab.xaml | 1 - .../Administration/UI/Tabs/ServerTab.xaml.cs | 7 - .../Systems/Admin/AdminUIController.cs | 24 +++ .../Commands/PanicBunkerCommand.cs | 175 ++++++++++++++++-- .../Administration/Systems/AdminSystem.cs | 111 ++++++++++- .../Events/PanicBunkerChangedEvent.cs | 26 +++ Content.Shared/CCVar/CCVars.cs | 20 ++ Resources/Changelog/Admin.yml | 7 + .../administration/commands/panicbunker.ftl | 32 ++++ .../administration/ui/admin-menu-window.ftl | 1 + .../ui/tabs/panicbunker-tab.ftl | 24 +++ .../administration/ui/tabs/server-tab.ftl | 1 - Resources/Locale/en-US/generic.ftl | 2 + SpaceStation14.sln.DotSettings | 1 + 20 files changed, 531 insertions(+), 29 deletions(-) create mode 100644 Content.Client/Administration/UI/Tabs/PanicBunkerTab/PanicBunkerStatusWindow.xaml create mode 100644 Content.Client/Administration/UI/Tabs/PanicBunkerTab/PanicBunkerStatusWindow.xaml.cs create mode 100644 Content.Client/Administration/UI/Tabs/PanicBunkerTab/PanicBunkerTab.xaml create mode 100644 Content.Client/Administration/UI/Tabs/PanicBunkerTab/PanicBunkerTab.xaml.cs create mode 100644 Content.Shared/Administration/Events/PanicBunkerChangedEvent.cs create mode 100644 Resources/Locale/en-US/administration/ui/tabs/panicbunker-tab.ftl diff --git a/Content.Client/Administration/UI/AdminMenuWindow.xaml b/Content.Client/Administration/UI/AdminMenuWindow.xaml index 49eb9c0de60..311d67b826c 100644 --- a/Content.Client/Administration/UI/AdminMenuWindow.xaml +++ b/Content.Client/Administration/UI/AdminMenuWindow.xaml @@ -5,13 +5,15 @@ xmlns:atmosTab="clr-namespace:Content.Client.Administration.UI.Tabs.AtmosTab" xmlns:tabs="clr-namespace:Content.Client.Administration.UI.Tabs" xmlns:playerTab="clr-namespace:Content.Client.Administration.UI.Tabs.PlayerTab" - xmlns:objectsTab="clr-namespace:Content.Client.Administration.UI.Tabs.ObjectsTab"> + xmlns:objectsTab="clr-namespace:Content.Client.Administration.UI.Tabs.ObjectsTab" + xmlns:panic="clr-namespace:Content.Client.Administration.UI.Tabs.PanicBunkerTab"> + diff --git a/Content.Client/Administration/UI/AdminMenuWindow.xaml.cs b/Content.Client/Administration/UI/AdminMenuWindow.xaml.cs index d4dfcc2042e..c3ea67a3edb 100644 --- a/Content.Client/Administration/UI/AdminMenuWindow.xaml.cs +++ b/Content.Client/Administration/UI/AdminMenuWindow.xaml.cs @@ -12,7 +12,7 @@ public sealed partial class AdminMenuWindow : DefaultWindow public AdminMenuWindow() { - MinSize = new Vector2(500, 250); + MinSize = new Vector2(650, 250); Title = Loc.GetString("admin-menu-title"); RobustXamlLoader.Load(this); MasterTabContainer.SetTabTitle(0, Loc.GetString("admin-menu-admin-tab")); @@ -20,8 +20,9 @@ public AdminMenuWindow() MasterTabContainer.SetTabTitle(2, Loc.GetString("admin-menu-atmos-tab")); MasterTabContainer.SetTabTitle(3, Loc.GetString("admin-menu-round-tab")); MasterTabContainer.SetTabTitle(4, Loc.GetString("admin-menu-server-tab")); - MasterTabContainer.SetTabTitle(5, Loc.GetString("admin-menu-players-tab")); - MasterTabContainer.SetTabTitle(6, Loc.GetString("admin-menu-objects-tab")); + MasterTabContainer.SetTabTitle(5, Loc.GetString("admin-menu-panic-bunker-tab")); + MasterTabContainer.SetTabTitle(6, Loc.GetString("admin-menu-players-tab")); + MasterTabContainer.SetTabTitle(7, Loc.GetString("admin-menu-objects-tab")); } protected override void Dispose(bool disposing) diff --git a/Content.Client/Administration/UI/Tabs/PanicBunkerTab/PanicBunkerStatusWindow.xaml b/Content.Client/Administration/UI/Tabs/PanicBunkerTab/PanicBunkerStatusWindow.xaml new file mode 100644 index 00000000000..633bef05148 --- /dev/null +++ b/Content.Client/Administration/UI/Tabs/PanicBunkerTab/PanicBunkerStatusWindow.xaml @@ -0,0 +1,6 @@ + + diff --git a/Content.Client/Administration/UI/Tabs/PanicBunkerTab/PanicBunkerStatusWindow.xaml.cs b/Content.Client/Administration/UI/Tabs/PanicBunkerTab/PanicBunkerStatusWindow.xaml.cs new file mode 100644 index 00000000000..ec16bf6aea7 --- /dev/null +++ b/Content.Client/Administration/UI/Tabs/PanicBunkerTab/PanicBunkerStatusWindow.xaml.cs @@ -0,0 +1,14 @@ +using Robust.Client.AutoGenerated; +using Robust.Client.UserInterface.CustomControls; +using Robust.Client.UserInterface.XAML; + +namespace Content.Client.Administration.UI.Tabs.PanicBunkerTab; + +[GenerateTypedNameReferences] +public sealed partial class PanicBunkerStatusWindow : DefaultWindow +{ + public PanicBunkerStatusWindow() + { + RobustXamlLoader.Load(this); + } +} diff --git a/Content.Client/Administration/UI/Tabs/PanicBunkerTab/PanicBunkerTab.xaml b/Content.Client/Administration/UI/Tabs/PanicBunkerTab/PanicBunkerTab.xaml new file mode 100644 index 00000000000..89827d06424 --- /dev/null +++ b/Content.Client/Administration/UI/Tabs/PanicBunkerTab/PanicBunkerTab.xaml @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + + diff --git a/Content.Client/Administration/UI/Tabs/PanicBunkerTab/PanicBunkerTab.xaml.cs b/Content.Client/Administration/UI/Tabs/PanicBunkerTab/PanicBunkerTab.xaml.cs new file mode 100644 index 00000000000..e9d3b95c5d8 --- /dev/null +++ b/Content.Client/Administration/UI/Tabs/PanicBunkerTab/PanicBunkerTab.xaml.cs @@ -0,0 +1,54 @@ +using Content.Shared.Administration.Events; +using Robust.Client.AutoGenerated; +using Robust.Client.UserInterface; +using Robust.Client.UserInterface.XAML; +using Robust.Shared.Console; + +namespace Content.Client.Administration.UI.Tabs.PanicBunkerTab; + +[GenerateTypedNameReferences] +public sealed partial class PanicBunkerTab : Control +{ + [Dependency] private readonly IConsoleHost _console = default!; + + public PanicBunkerTab() + { + RobustXamlLoader.Load(this); + IoCManager.InjectDependencies(this); + + DisableAutomaticallyButton.ToolTip = Loc.GetString("admin-ui-panic-bunker-disable-automatically-tooltip"); + + MinAccountAge.OnTextEntered += args => + { + if (string.IsNullOrWhiteSpace(args.Text) || !int.TryParse(args.Text, out var minutes)) + return; + + _console.ExecuteCommand($"panicbunker_min_account_age {minutes}"); + }; + + MinOverallHours.OnTextEntered += args => + { + if (string.IsNullOrWhiteSpace(args.Text) || !int.TryParse(args.Text, out var hours)) + return; + + _console.ExecuteCommand($"panicbunker_min_overall_hours {hours}"); + }; + } + + public void UpdateStatus(PanicBunkerStatus status) + { + EnabledButton.Pressed = status.Enabled; + EnabledButton.Text = Loc.GetString(status.Enabled + ? "admin-ui-panic-bunker-enabled" + : "admin-ui-panic-bunker-disabled" + ); + EnabledButton.ModulateSelfOverride = status.Enabled ? Color.Red : null; + + DisableAutomaticallyButton.Pressed = status.DisableWithAdmins; + EnableAutomaticallyButton.Pressed = status.EnableWithoutAdmins; + CountDeadminnedButton.Pressed = status.CountDeadminnedAdmins; + ShowReasonButton.Pressed = status.ShowReason; + MinAccountAge.Text = status.MinAccountAgeHours.ToString(); + MinOverallHours.Text = status.MinOverallHours.ToString(); + } +} diff --git a/Content.Client/Administration/UI/Tabs/ServerTab.xaml b/Content.Client/Administration/UI/Tabs/ServerTab.xaml index 7e15bc27539..b9984058358 100644 --- a/Content.Client/Administration/UI/Tabs/ServerTab.xaml +++ b/Content.Client/Administration/UI/Tabs/ServerTab.xaml @@ -8,6 +8,5 @@ - diff --git a/Content.Client/Administration/UI/Tabs/ServerTab.xaml.cs b/Content.Client/Administration/UI/Tabs/ServerTab.xaml.cs index b83a3d1ec03..24b92e42ce7 100644 --- a/Content.Client/Administration/UI/Tabs/ServerTab.xaml.cs +++ b/Content.Client/Administration/UI/Tabs/ServerTab.xaml.cs @@ -18,7 +18,6 @@ public ServerTab() _config.OnValueChanged(CCVars.OocEnabled, OocEnabledChanged, true); _config.OnValueChanged(CCVars.LoocEnabled, LoocEnabledChanged, true); - _config.OnValueChanged(CCVars.PanicBunkerEnabled, BunkerEnabledChanged, true); } private void OocEnabledChanged(bool value) @@ -31,11 +30,6 @@ private void LoocEnabledChanged(bool value) SetLoocButton.Pressed = value; } - private void BunkerEnabledChanged(bool value) - { - SetPanicbunkerButton.Pressed = value; - } - protected override void Dispose(bool disposing) { base.Dispose(disposing); @@ -44,7 +38,6 @@ protected override void Dispose(bool disposing) { _config.UnsubValueChanged(CCVars.OocEnabled, OocEnabledChanged); _config.UnsubValueChanged(CCVars.LoocEnabled, LoocEnabledChanged); - _config.UnsubValueChanged(CCVars.PanicBunkerEnabled, BunkerEnabledChanged); } } } diff --git a/Content.Client/UserInterface/Systems/Admin/AdminUIController.cs b/Content.Client/UserInterface/Systems/Admin/AdminUIController.cs index 47b93fdb09a..4a7a57e5272 100644 --- a/Content.Client/UserInterface/Systems/Admin/AdminUIController.cs +++ b/Content.Client/UserInterface/Systems/Admin/AdminUIController.cs @@ -2,11 +2,13 @@ using Content.Client.Administration.Systems; using Content.Client.Administration.UI; using Content.Client.Administration.UI.Tabs.ObjectsTab; +using Content.Client.Administration.UI.Tabs.PanicBunkerTab; using Content.Client.Administration.UI.Tabs.PlayerTab; using Content.Client.Gameplay; using Content.Client.Lobby; using Content.Client.UserInterface.Controls; using Content.Client.Verbs.UI; +using Content.Shared.Administration.Events; using Content.Shared.Input; using JetBrains.Annotations; using Robust.Client.Console; @@ -30,6 +32,25 @@ public sealed class AdminUIController : UIController, IOnStateEntered UIManager.GetActiveUIWidgetOrNull()?.AdminButton; + private PanicBunkerStatus? _panicBunker; + + public override void Initialize() + { + base.Initialize(); + SubscribeNetworkEvent(OnPanicBunkerUpdated); + } + + private void OnPanicBunkerUpdated(PanicBunkerChangedEvent msg, EntitySessionEventArgs args) + { + var showDialog = _panicBunker == null && msg.Status.Enabled; + _panicBunker = msg.Status; + _window?.PanicBunkerControl.UpdateStatus(msg.Status); + + if (showDialog) + { + UIManager.CreateWindow().OpenCentered(); + } + } public void OnStateEntered(GameplayState state) { @@ -73,6 +94,9 @@ private void EnsureWindow() _window = UIManager.CreateWindow(); LayoutContainer.SetAnchorPreset(_window, LayoutContainer.LayoutPreset.Center); + if (_panicBunker != null) + _window.PanicBunkerControl.UpdateStatus(_panicBunker); + _window.PlayerTabControl.OnEntryPressed += PlayerTabEntryPressed; _window.ObjectsTabControl.OnEntryPressed += ObjectsTabEntryPressed; _window.OnOpen += OnWindowOpen; diff --git a/Content.Server/Administration/Commands/PanicBunkerCommand.cs b/Content.Server/Administration/Commands/PanicBunkerCommand.cs index 0273ac313d6..de3f3cbaea2 100644 --- a/Content.Server/Administration/Commands/PanicBunkerCommand.cs +++ b/Content.Server/Administration/Commands/PanicBunkerCommand.cs @@ -6,36 +6,187 @@ namespace Content.Server.Administration.Commands; [AdminCommand(AdminFlags.Server)] -public sealed class PanicBunkerCommand : IConsoleCommand +public sealed class PanicBunkerCommand : LocalizedCommands { [Dependency] private readonly IConfigurationManager _cfg = default!; - public string Command => "panicbunker"; - public string Description => "Enables or disables the panic bunker functionality."; - public string Help => "panicbunker"; - public void Execute(IConsoleShell shell, string argStr, string[] args) + public override string Command => "panicbunker"; + + public override void Execute(IConsoleShell shell, string argStr, string[] args) + { + var toggle = Toggle(CCVars.PanicBunkerEnabled, shell, args, _cfg); + if (toggle == null) + return; + + shell.WriteLine(Loc.GetString(toggle.Value ? "panicbunker-command-enabled" : "panicbunker-command-disabled")); + } + + public static bool? Toggle(CVarDef cvar, IConsoleShell shell, string[] args, IConfigurationManager config) { if (args.Length > 1) { shell.WriteError(Loc.GetString("shell-need-between-arguments",("lower", 0), ("upper", 1))); - return; + return null; } - var enabled = _cfg.GetCVar(CCVars.PanicBunkerEnabled); - + var enabled = config.GetCVar(cvar); + if (args.Length == 0) { enabled = !enabled; } - + if (args.Length == 1 && !bool.TryParse(args[0], out enabled)) { shell.WriteError(Loc.GetString("shell-argument-must-be-boolean")); + return null; + } + + config.SetCVar(cvar, enabled); + return enabled; + } +} + +[AdminCommand(AdminFlags.Server)] +public sealed class PanicBunkerDisableWithAdminsCommand : LocalizedCommands +{ + [Dependency] private readonly IConfigurationManager _cfg = default!; + + public override string Command => "panicbunker_disable_with_admins"; + + public override void Execute(IConsoleShell shell, string argStr, string[] args) + { + var toggle = PanicBunkerCommand.Toggle(CCVars.PanicBunkerDisableWithAdmins, shell, args, _cfg); + if (toggle == null) + return; + + shell.WriteLine(Loc.GetString(toggle.Value + ? "panicbunker-command-disable-with-admins-enabled" + : "panicbunker-command-disable-with-admins-disabled" + )); + } +} + +[AdminCommand(AdminFlags.Server)] +public sealed class PanicBunkerEnableWithoutAdminsCommand : LocalizedCommands +{ + [Dependency] private readonly IConfigurationManager _cfg = default!; + + public override string Command => "panicbunker_enable_without_admins"; + + public override void Execute(IConsoleShell shell, string argStr, string[] args) + { + var toggle = PanicBunkerCommand.Toggle(CCVars.PanicBunkerEnableWithoutAdmins, shell, args, _cfg); + if (toggle == null) + return; + + shell.WriteLine(Loc.GetString(toggle.Value + ? "panicbunker-command-enable-without-admins-enabled" + : "panicbunker-command-enable-without-admins-disabled" + )); + } +} + +[AdminCommand(AdminFlags.Server)] +public sealed class PanicBunkerCountDeadminnedCommand : LocalizedCommands +{ + [Dependency] private readonly IConfigurationManager _cfg = default!; + + public override string Command => "panicbunker_count_deadminned_admins"; + + public override void Execute(IConsoleShell shell, string argStr, string[] args) + { + var toggle = PanicBunkerCommand.Toggle(CCVars.PanicBunkerCountDeadminnedAdmins, shell, args, _cfg); + if (toggle == null) + return; + + shell.WriteLine(Loc.GetString(toggle.Value + ? "panicbunker-command-count-deadminned-admins-enabled" + : "panicbunker-command-count-deadminned-admins-disabled" + )); + } +} + +[AdminCommand(AdminFlags.Server)] +public sealed class PanicBunkerShowReasonCommand : LocalizedCommands +{ + [Dependency] private readonly IConfigurationManager _cfg = default!; + + public override string Command => "panicbunker_show_reason"; + + public override void Execute(IConsoleShell shell, string argStr, string[] args) + { + var toggle = PanicBunkerCommand.Toggle(CCVars.PanicBunkerShowReason, shell, args, _cfg); + if (toggle == null) + return; + + shell.WriteLine(Loc.GetString(toggle.Value + ? "panicbunker-command-show-reason-enabled" + : "panicbunker-command-show-reason-disabled" + )); + } +} + +[AdminCommand(AdminFlags.Server)] +public sealed class PanicBunkerMinAccountAgeCommand : LocalizedCommands +{ + [Dependency] private readonly IConfigurationManager _cfg = default!; + + public override string Command => "panicbunker_min_account_age"; + + public override void Execute(IConsoleShell shell, string argStr, string[] args) + { + if (args.Length == 0) + { + var current = _cfg.GetCVar(CCVars.PanicBunkerMinAccountAge); + shell.WriteLine(Loc.GetString("panicbunker-command-min-account-age-is", ("hours", current / 60))); + } + + if (args.Length > 1) + { + shell.WriteError(Loc.GetString("shell-need-between-arguments",("lower", 0), ("upper", 1))); + return; + } + + if (!int.TryParse(args[0], out var hours)) + { + shell.WriteError(Loc.GetString("shell-argument-must-be-number")); + return; + } + + _cfg.SetCVar(CCVars.PanicBunkerMinAccountAge, hours * 60); + shell.WriteLine(Loc.GetString("panicbunker-command-min-account-age-set", ("hours", hours))); + } +} + +[AdminCommand(AdminFlags.Server)] +public sealed class PanicBunkerMinOverallHoursCommand : LocalizedCommands +{ + [Dependency] private readonly IConfigurationManager _cfg = default!; + + public override string Command => "panicbunker_min_overall_hours"; + + public override void Execute(IConsoleShell shell, string argStr, string[] args) + { + if (args.Length == 0) + { + var current = _cfg.GetCVar(CCVars.PanicBunkerMinOverallHours); + shell.WriteLine(Loc.GetString("panicbunker-command-min-overall-hours-is", ("minutes", current))); + } + + if (args.Length > 1) + { + shell.WriteError(Loc.GetString("shell-need-between-arguments",("lower", 0), ("upper", 1))); + return; + } + + if (!int.TryParse(args[0], out var hours)) + { + shell.WriteError(Loc.GetString("shell-argument-must-be-number")); return; } - _cfg.SetCVar(CCVars.PanicBunkerEnabled, enabled); - - shell.WriteLine(Loc.GetString(enabled ? "panicbunker-command-enabled" : "panicbunker-command-disabled")); + _cfg.SetCVar(CCVars.PanicBunkerMinOverallHours, hours); + shell.WriteLine(Loc.GetString("panicbunker-command-overall-hours-age-set", ("hours", hours))); } } diff --git a/Content.Server/Administration/Systems/AdminSystem.cs b/Content.Server/Administration/Systems/AdminSystem.cs index d54a7a2092a..8851680aea6 100644 --- a/Content.Server/Administration/Systems/AdminSystem.cs +++ b/Content.Server/Administration/Systems/AdminSystem.cs @@ -1,15 +1,18 @@ using System.Linq; using Content.Server.Administration.Managers; +using Content.Server.Chat.Managers; using Content.Server.IdentityManagement; using Content.Server.Mind; using Content.Shared.Administration; using Content.Shared.Administration.Events; +using Content.Shared.CCVar; using Content.Shared.GameTicking; using Content.Shared.IdentityManagement; using Content.Shared.Roles; using Content.Shared.Roles.Jobs; using Robust.Server.GameObjects; using Robust.Server.Player; +using Robust.Shared.Configuration; using Robust.Shared.Enums; using Robust.Shared.Network; using Robust.Shared.Player; @@ -18,8 +21,10 @@ namespace Content.Server.Administration.Systems { public sealed class AdminSystem : EntitySystem { - [Dependency] private readonly IPlayerManager _playerManager = default!; [Dependency] private readonly IAdminManager _adminManager = default!; + [Dependency] private readonly IChatManager _chat = default!; + [Dependency] private readonly IConfigurationManager _config = default!; + [Dependency] private readonly IPlayerManager _playerManager = default!; [Dependency] private readonly SharedJobSystem _jobs = default!; [Dependency] private readonly MindSystem _minds = default!; [Dependency] private readonly SharedRoleSystem _role = default!; @@ -32,6 +37,7 @@ public sealed class AdminSystem : EntitySystem public IReadOnlySet RoundActivePlayers => _roundActivePlayers; private readonly HashSet _roundActivePlayers = new(); + private readonly PanicBunkerStatus _panicBunker = new(); public override void Initialize() { @@ -39,6 +45,15 @@ public override void Initialize() _playerManager.PlayerStatusChanged += OnPlayerStatusChanged; _adminManager.OnPermsChanged += OnAdminPermsChanged; + + _config.OnValueChanged(CCVars.PanicBunkerEnabled, OnPanicBunkerChanged, true); + _config.OnValueChanged(CCVars.PanicBunkerDisableWithAdmins, OnPanicBunkerDisableWithAdminsChanged, true); + _config.OnValueChanged(CCVars.PanicBunkerEnableWithoutAdmins, OnPanicBunkerEnableWithoutAdminsChanged, true); + _config.OnValueChanged(CCVars.PanicBunkerCountDeadminnedAdmins, OnPanicBunkerCountDeadminnedAdminsChanged, true); + _config.OnValueChanged(CCVars.PanicBunkerShowReason, OnShowReasonChanged, true); + _config.OnValueChanged(CCVars.PanicBunkerMinAccountAge, OnPanicBunkerMinAccountAgeChanged, true); + _config.OnValueChanged(CCVars.PanicBunkerMinOverallHours, OnPanicBunkerMinOverallHoursChanged, true); + SubscribeLocalEvent(OnIdentityChanged); SubscribeLocalEvent(OnPlayerAttached); SubscribeLocalEvent(OnPlayerDetached); @@ -114,7 +129,9 @@ private void OnRoleEvent(RoleEvent ev) private void OnAdminPermsChanged(AdminPermsChangedEventArgs obj) { - if(!obj.IsAdmin) + UpdatePanicBunker(); + + if (!obj.IsAdmin) { RaiseNetworkEvent(new FullPlayerListEvent(), obj.Player.ConnectedClient); return; @@ -127,14 +144,16 @@ private void OnPlayerDetached(PlayerDetachedEvent ev) { // If disconnected then the player won't have a connected entity to get character name from. // The disconnected state gets sent by OnPlayerStatusChanged. - if(ev.Player.Status == SessionStatus.Disconnected) return; + if (ev.Player.Status == SessionStatus.Disconnected) + return; UpdatePlayerList(ev.Player); } private void OnPlayerAttached(PlayerAttachedEvent ev) { - if(ev.Player.Status == SessionStatus.Disconnected) return; + if (ev.Player.Status == SessionStatus.Disconnected) + return; _roundActivePlayers.Add(ev.Player.UserId); UpdatePlayerList(ev.Player); @@ -145,11 +164,20 @@ public override void Shutdown() base.Shutdown(); _playerManager.PlayerStatusChanged -= OnPlayerStatusChanged; _adminManager.OnPermsChanged -= OnAdminPermsChanged; + + _config.UnsubValueChanged(CCVars.PanicBunkerEnabled, OnPanicBunkerChanged); + _config.UnsubValueChanged(CCVars.PanicBunkerDisableWithAdmins, OnPanicBunkerDisableWithAdminsChanged); + _config.UnsubValueChanged(CCVars.PanicBunkerEnableWithoutAdmins, OnPanicBunkerEnableWithoutAdminsChanged); + _config.UnsubValueChanged(CCVars.PanicBunkerCountDeadminnedAdmins, OnPanicBunkerCountDeadminnedAdminsChanged); + _config.UnsubValueChanged(CCVars.PanicBunkerShowReason, OnShowReasonChanged); + _config.UnsubValueChanged(CCVars.PanicBunkerMinAccountAge, OnPanicBunkerMinAccountAgeChanged); + _config.UnsubValueChanged(CCVars.PanicBunkerMinOverallHours, OnPanicBunkerMinOverallHoursChanged); } private void OnPlayerStatusChanged(object? sender, SessionStatusEventArgs e) { UpdatePlayerList(e.Session); + UpdatePanicBunker(); } private void SendFullPlayerList(IPlayerSession playerSession) @@ -186,5 +214,80 @@ private PlayerInfo GetPlayerInfo(IPlayerData data, IPlayerSession? session) return new PlayerInfo(name, entityName, identityName, startingRole, antag, GetNetEntity(session?.AttachedEntity), data.UserId, connected, _roundActivePlayers.Contains(data.UserId)); } + + private void OnPanicBunkerChanged(bool enabled) + { + _panicBunker.Enabled = enabled; + _chat.SendAdminAlert(Loc.GetString(enabled + ? "admin-ui-panic-bunker-enabled-admin-alert" + : "admin-ui-panic-bunker-disabled-admin-alert" + )); + + SendPanicBunkerStatusAll(); + } + + private void OnPanicBunkerDisableWithAdminsChanged(bool enabled) + { + _panicBunker.DisableWithAdmins = enabled; + UpdatePanicBunker(); + } + + private void OnPanicBunkerEnableWithoutAdminsChanged(bool enabled) + { + _panicBunker.EnableWithoutAdmins = enabled; + UpdatePanicBunker(); + } + + private void OnPanicBunkerCountDeadminnedAdminsChanged(bool enabled) + { + _panicBunker.CountDeadminnedAdmins = enabled; + UpdatePanicBunker(); + } + + private void OnShowReasonChanged(bool enabled) + { + _panicBunker.ShowReason = enabled; + SendPanicBunkerStatusAll(); + } + + private void OnPanicBunkerMinAccountAgeChanged(int minutes) + { + _panicBunker.MinAccountAgeHours = minutes / 60; + SendPanicBunkerStatusAll(); + } + + private void OnPanicBunkerMinOverallHoursChanged(int hours) + { + _panicBunker.MinOverallHours = hours; + SendPanicBunkerStatusAll(); + } + + private void UpdatePanicBunker() + { + var admins = _panicBunker.CountDeadminnedAdmins + ? _adminManager.AllAdmins + : _adminManager.ActiveAdmins; + var hasAdmins = admins.Any(); + + if (hasAdmins && _panicBunker.DisableWithAdmins) + { + _config.SetCVar(CCVars.PanicBunkerEnabled, false); + } + else if (!hasAdmins && _panicBunker.EnableWithoutAdmins) + { + _config.SetCVar(CCVars.PanicBunkerEnabled, true); + } + + SendPanicBunkerStatusAll(); + } + + private void SendPanicBunkerStatusAll() + { + var ev = new PanicBunkerChangedEvent(_panicBunker); + foreach (var admin in _adminManager.AllAdmins) + { + RaiseNetworkEvent(ev, admin); + } + } } } diff --git a/Content.Shared/Administration/Events/PanicBunkerChangedEvent.cs b/Content.Shared/Administration/Events/PanicBunkerChangedEvent.cs new file mode 100644 index 00000000000..f809b67bc8d --- /dev/null +++ b/Content.Shared/Administration/Events/PanicBunkerChangedEvent.cs @@ -0,0 +1,26 @@ +using Robust.Shared.Serialization; + +namespace Content.Shared.Administration.Events; + +[Serializable, NetSerializable] +public sealed class PanicBunkerStatus +{ + public bool Enabled; + public bool DisableWithAdmins; + public bool EnableWithoutAdmins; + public bool CountDeadminnedAdmins; + public bool ShowReason; + public int MinAccountAgeHours; + public int MinOverallHours; +} + +[Serializable, NetSerializable] +public sealed class PanicBunkerChangedEvent : EntityEventArgs +{ + public PanicBunkerStatus Status; + + public PanicBunkerChangedEvent(PanicBunkerStatus status) + { + Status = status; + } +} diff --git a/Content.Shared/CCVar/CCVars.cs b/Content.Shared/CCVar/CCVars.cs index ccc8b6d51dc..0cf374fe4de 100644 --- a/Content.Shared/CCVar/CCVars.cs +++ b/Content.Shared/CCVar/CCVars.cs @@ -248,6 +248,26 @@ public static readonly CVarDef public static readonly CVarDef PanicBunkerEnabled = CVarDef.Create("game.panic_bunker.enabled", false, CVar.NOTIFY | CVar.REPLICATED); + /// + /// Whether or not the panic bunker will disable when an admin comes online. + /// + public static readonly CVarDef PanicBunkerDisableWithAdmins = + CVarDef.Create("game.panic_bunker.disable_with_admins", false, CVar.SERVERONLY); + + /// + /// Whether or not the panic bunker will enable when no admins are online. + /// + public static readonly CVarDef PanicBunkerEnableWithoutAdmins = + CVarDef.Create("game.panic_bunker.enable_without_admins", false, CVar.SERVERONLY); + + /// + /// Whether or not the panic bunker will count deadminned admins for + /// and + /// + /// + public static readonly CVarDef PanicBunkerCountDeadminnedAdmins = + CVarDef.Create("game.panic_bunker.count_deadminned_admins", false, CVar.SERVERONLY); + /// /// Show reason of disconnect for user or not. /// diff --git a/Resources/Changelog/Admin.yml b/Resources/Changelog/Admin.yml index 81bc934176c..aafb784ddc1 100644 --- a/Resources/Changelog/Admin.yml +++ b/Resources/Changelog/Admin.yml @@ -7,3 +7,10 @@ Entries: - {message: 'Created the admin changelog.', type: Add} id: 1 time: '2023-10-08T04:26:00.0000000+00:00' +- author: DrSmugleaf + changes: + - {message: 'Added a new panic bunker UI in the F7 admin panel.', type: Add} + - {message: 'Added being able to toggle the panic bunker automatically depending on + if admins are online or not.', type: Add} + id: 2 + time: '2023-10-12T22:46:00.0000000+00:00' diff --git a/Resources/Locale/en-US/administration/commands/panicbunker.ftl b/Resources/Locale/en-US/administration/commands/panicbunker.ftl index 46896500b8e..c16748c9926 100644 --- a/Resources/Locale/en-US/administration/commands/panicbunker.ftl +++ b/Resources/Locale/en-US/administration/commands/panicbunker.ftl @@ -1,2 +1,34 @@ +cmd-panicbunker-desc = Toggles the panic bunker, which enables stricter restrictions on who's allowed to join the server. +cmd-panicbunker-help = Usage: panicbunker panicbunker-command-enabled = Panic bunker has been enabled. panicbunker-command-disabled = Panic bunker has been disabled. + +cmd-panicbunker_disable_with_admins-desc = Toggles whether or not the panic bunker will disable when an admin connects. +cmd-panicbunker_disable_with_admins-help = Usage: panicbunker_disable_with_admins +panicbunker-command-disable-with-admins-enabled = The panic bunker will automatically disable with admins online. +panicbunker-command-disable-with-admins-disabled = The panic bunker will not automatically disable with admins online. + +cmd-panicbunker_enable_without_admins-desc = Toggles whether or not the panic bunker will enable when the last admin disconnects. +cmd-panicbunker_enable_without_admins-help = Usage: panicbunker_enable_without_admins +panicbunker-command-enable-without-admins-enabled = The panic bunker will automatically enable without admins online. +panicbunker-command-enable-without-admins-disabled = The panic bunker will not automatically enable without admins online. + +cmd-panicbunker_count_deadminned_admins-desc = Toggles whether or not to count deadminned admins when automatically enabling and disabling the panic bunker. +cmd-panicbunker_count_deadminned_admins-help = Usage: panicbunker_count_deadminned_admins +panicbunker-command-count-deadminned-admins-enabled = The panic bunker will count deadminned admins when made to automatically enable and disable. +panicbunker-command-count-deadminned-admins-disabled = The panic bunker will not count deadminned admins when made to automatically enable and disable. + +cmd-panicbunker_show_reason-desc = Toggles whether or not to show connecting clients the reason why the panic bunker blocked them from joining. +cmd-panicbunker_show_reason-help = Usage: panicbunker_show_reason +panicbunker-command-show-reason-enabled = The panic bunker will now show a reason to users it blocks from connecting. +panicbunker-command-show-reason-disabled = The panic bunker will no longer show a reason to users it blocks from connecting. + +cmd-panicbunker_min_account_age-desc = Gets or sets the minimum account age in hours that an account must have to be allowed to connect with the panic bunker enabled. +cmd-panicbunker_min_account_age-help = Usage: panicbunker_min_account_age +panicbunker-command-min-account-age-is = The minimum account age for the panic bunker is {$hours} hours. +panicbunker-command-min-account-age-set = Set the minimum account age for the panic bunker to {$hours} hours. + +cmd-panicbunker_min_overall_hours-desc = Gets or sets the minimum overall playtime in hours that an account must have to be allowed to connect with the panic bunker enabled. +cmd-panicbunker_min_overall_hours-help = Usage: panicbunker_min_overall_hours +panicbunker-command-min-overall-hours-is = The minimum overall playtime for the panic bunker is {$hours} hours. +panicbunker-command-min-overall-hours-set = Set the minimum overall playtime for the panic bunker to {$hours} hours. diff --git a/Resources/Locale/en-US/administration/ui/admin-menu-window.ftl b/Resources/Locale/en-US/administration/ui/admin-menu-window.ftl index ce256a2cd53..c759e4c2cb1 100644 --- a/Resources/Locale/en-US/administration/ui/admin-menu-window.ftl +++ b/Resources/Locale/en-US/administration/ui/admin-menu-window.ftl @@ -6,5 +6,6 @@ admin-menu-adminbus-tab = Adminbus admin-menu-atmos-tab = Atmos admin-menu-round-tab = Round admin-menu-server-tab = Server +admin-menu-panic-bunker-tab = Panic Bunker admin-menu-players-tab = Players admin-menu-objects-tab = Objects diff --git a/Resources/Locale/en-US/administration/ui/tabs/panicbunker-tab.ftl b/Resources/Locale/en-US/administration/ui/tabs/panicbunker-tab.ftl new file mode 100644 index 00000000000..730d0c2e3b3 --- /dev/null +++ b/Resources/Locale/en-US/administration/ui/tabs/panicbunker-tab.ftl @@ -0,0 +1,24 @@ +admin-ui-panic-bunker-window-title = Panic Bunker + +admin-ui-panic-bunker-enabled = Panic Bunker Enabled +admin-ui-panic-bunker-disabled = Panic Bunker Disabled +admin-ui-panic-bunker-tooltip = The panic bunker restricts players from joining if their account is too new or they do not have enough overall playtime on this server. + +admin-ui-panic-bunker-disable-automatically = Disable Automatically +admin-ui-panic-bunker-disable-automatically-tooltip = Disables the panic bunker automatically when an admin connects. +admin-ui-panic-bunker-enable-automatically = Enable Automatically +admin-ui-panic-bunker-enable-automatically-tooltip = Enables the panic bunker automatically when no admins are online. + +admin-ui-panic-bunker-count-deadminned-admins = Count Deadmins +admin-ui-panic-bunker-count-deadminned-admins-tooltip = Count deadminned admins when automatically enabling and disabling the panic bunker. + +admin-ui-panic-bunker-show-reason = Show Reason +admin-ui-panic-bunker-show-reason-tooltip = Show the user why they were blocked from connecting by the panic bunker. + +admin-ui-panic-bunker-min-account-age = Min. Account Age +admin-ui-panic-bunker-min-overall-hours = Min. Overall Playtime + +admin-ui-panic-bunker-is-enabled = The panic bunker is currently enabled. + +admin-ui-panic-bunker-enabled-admin-alert = The panic bunker has been enabled. +admin-ui-panic-bunker-disabled-admin-alert = The panic bunker has been disabled. diff --git a/Resources/Locale/en-US/administration/ui/tabs/server-tab.ftl b/Resources/Locale/en-US/administration/ui/tabs/server-tab.ftl index 713af85fa5b..7a41cbe2c75 100644 --- a/Resources/Locale/en-US/administration/ui/tabs/server-tab.ftl +++ b/Resources/Locale/en-US/administration/ui/tabs/server-tab.ftl @@ -1,4 +1,3 @@ server-shutdown = Shutdown server-ooc-toggle = Toggle OOC server-looc-toggle = Toggle LOOC -server-panicbunker-toggle = Toggle Panic bunker diff --git a/Resources/Locale/en-US/generic.ftl b/Resources/Locale/en-US/generic.ftl index 0ecfefdd1cb..7b3e0d3684e 100644 --- a/Resources/Locale/en-US/generic.ftl +++ b/Resources/Locale/en-US/generic.ftl @@ -8,3 +8,5 @@ generic-unknown = unknown generic-unknown-title = Unknown generic-error = error generic-invalid = invalid + +generic-hours = hours diff --git a/SpaceStation14.sln.DotSettings b/SpaceStation14.sln.DotSettings index 1d141ba58a4..57f0e3c4db6 100644 --- a/SpaceStation14.sln.DotSettings +++ b/SpaceStation14.sln.DotSettings @@ -584,6 +584,7 @@ public sealed partial class $CLASS$ : Shared$CLASS$ { True True True + True True True True From dd6b7b337ff27408d575aff72d67379cd7b55168 Mon Sep 17 00:00:00 2001 From: daerSeebaer <61566539+daerSeebaer@users.noreply.github.com> Date: Sat, 14 Oct 2023 00:07:23 +0200 Subject: [PATCH 113/127] Fix sprite alignment (#20975) --- .../pump.rsi/pumpVolumeBlocked.png | Bin 5060 -> 5051 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/Resources/Textures/Structures/Piping/Atmospherics/pump.rsi/pumpVolumeBlocked.png b/Resources/Textures/Structures/Piping/Atmospherics/pump.rsi/pumpVolumeBlocked.png index 27bb092f470b0b30826c979c9a6c701b8bbe641a..797a3b987adc6c89f3e530cb728bf625a6a0f0ea 100644 GIT binary patch delta 1765 zcmVu?fewx!Mu#I3Dqg5B;F^{LgNY$!zG18|C z>ns#;fBiAykEUV9ATws zGQcMi$C-a_Si~E|vzwOAd7n7KDw0BcPCRMQ1&JTIF1!53x$LmOGb2VWGfx~L7Rx;> z_b{s%D)9_)R8cj`7xFGEoVPfuwFc|llfN)j)K;=wr#XfsmXJakB4jjBMGY2Wv}&Z7 z$k2Ym!$0cy)8vxLRRtr*0_sp9Iezdz_}#5pnx21hlR^og|HZaH#(}^t&~DoH_pxoa zPXPZjaHVzq^%gMqNqV!ZMUQ~NZQ$a%tI2!7A(Ki)rXHD)w5Ic690EOG^Ldra<#2X?c7~;+ zBkgg#!=copl!8)<13^Tl2q8kBgRDsfd!A>R-0>*${cU*hyomkx%~071onXgt008Uj z>o`0-#KFM)=ip{KZ6r6DOu=;vf|WU+i{cUjVI%Sij$cZI|$@Sj6{M3+;A0(v3EqKgk#1 z*hhfpd6w%oaNh6XxP6S%)1PqNMr7~Bn9lb(j)PjQhHABH=FkyBsLHE8 z5fKp)5k)=|o>YJQtka$evp=4Q44e56L`+@-{Qh_r!9W29`{OGWhee380Dgb`y<`f7 zd;!_)9BjM9B52a;3rZ$`Q;<@^bsGSpSs*b^fv3@;GOheXn2l4YkPpC5F}9XCHV1sL^W-yhid!T&!xIkEo7{8$vg^E^vRY3wd&n)$Ig z0;2AIjw(OY0*%|SKq8hCG5>rx_*DUvW7B_`dYZ!&*cZZu~7tB+j>p(+&z+3Xy)wzdPGv|6oR{k+JyOy?Uf zKqiy9wgTQ?4LLtQk3zlxAh<{0@1@rHl3co#%OL_|bHL_|bHv*9-sf#(^DOg72R00000NkvXX Hu0mjfE^-}I delta 1747 zcmV;^1}yozC&VX^Bmu&aB_Ds=5yK!1`)7)d0G0tW4r$W6ZqV^-2PYSrDu?_Krx=Ir z^L~Ygff5JKRZ1%*D!6f@u8G8fzH^Ga^N!+@)>A*60%;2xF-mbE9sP6~jL|d8UZ$u<*OStHv$bIxk2y#lqU81gk_5}WSn5cGLL<$t8OfB&H5h@ZAgg9 z0FMD+2LWA^rVQ9c`z)`@8O6mh%|4=REd5mCrco$R6_ zj-`r4uu$3xtvZ-o`UOoIk`xz5!L{Jv$70pN#aUMeS3wZ`0C9D3Qgo3L|Cbb6#CUMr zk9YSTckck9US_J<5dl=qGLo^Vn8~h+U9afD7=|zaL1LyJPc5e5Ilk`UE-VLyD?VzL0TQ;k?CJEmv9dp8SP@oVJqUI?YkUu!J}g5Fw+A63Va; zrd1=wM3VNS9{v%>pCFe^t`ZnI7Epl-$?=2#!S8O({Pcg6n-quwoiDciF%ER?0*#t& ze;?a+;{@OcW@4-Q(Te?Y;ebrrF;QgST?69(72a000ekX;fHr zSWQeiV{fyG0zCpGFga#3V`O7uEn_xiGc7bRH#IF`G&DFZWMwxuFkvw@WHn?slj;N? zBs4KIVK-$nW-T>1V`D8eVP-ikIWsdhEoCt|Ib%3DGG$>hW|J)iCnPyHG&wmjGGr|| zF*Y_WG%#W|EjTncIW0IiW-wx9H8Nr|VK1d ze+eBHCJD-4i0c3V193@2K~#9!?cK3!8c`ev@b9$_)!|Ms5D=n}(k4U5(7Cjh7SE}< zI%aPEhqi-5{tYu{a0t&WCn>e1a|@)N295JEr*0RZqPBuYB-P1BUNT?7E+b9r1`{DEy3;ku2$MF{mae{^ka zP3!TuX<6E`lgSiZw}E%>KcHIOLNb|BdLCW}gcSBg$O34_0ipfRcK>u66K* zZa4M?P`VK7_j|DIB3={<_}OZq-EK!ZXx;gfd=UoT13b?&T(^O&No41fYDyKCS%N6kug#1;FqXDfN0C4;L4aNZiN2)r+!LtD#gX8J1;*x`*uN z4_g*h=yn6=$EE<=+uN6ue>}{mW)o-q9zK8h3eWS5QmF(0=yW=v3gG9DI@|`$k4*u_ zJ<<0EHh%E`PmYg`+n67V0(hQh2qCn+3z}wrZ1w;h-Oo|vhh8Cb7Zypx@qaTX`_^V>ZfBm5XAp|Dfqpvf6 zTCO!_-PFf!nx-t59b__ds8+W|K53;=x%_#NpmgVJFF-n-zOwq=UkN!sKaYGa4`6hU zzTZo)Vx0U@J^EqtwHKh%>0Frr&-0AEk4<@get}l&*X1M+W=^b002ovPDHLkV1ip~4krKr From 4c630d0b17f8d39c4bf1e8f4888e0d15d81eec28 Mon Sep 17 00:00:00 2001 From: chromiumboy <50505512+chromiumboy@users.noreply.github.com> Date: Fri, 13 Oct 2023 18:08:00 -0500 Subject: [PATCH 114/127] Radiation collector sprite update (#20956) --- .../EntitySystems/RadiationCollectorSystem.cs | 62 +++++++++++++++--- .../SharedRadiationCollectorComponent.cs | 8 ++- .../power/components/radiation-collector.ftl | 5 +- .../Generation/Singularity/collector.yml | 13 +++- .../Singularity/collector.rsi/ca-o0.png | Bin 0 -> 1477 bytes .../Singularity/collector.rsi/ca-o1.png | Bin 0 -> 1415 bytes .../Singularity/collector.rsi/ca-o2.png | Bin 0 -> 1383 bytes .../Singularity/collector.rsi/ca-o3.png | Bin 0 -> 1421 bytes .../Singularity/collector.rsi/ca-tank.png | Bin 0 -> 2071 bytes .../Singularity/collector.rsi/ca_active.png | Bin 1021 -> 10749 bytes .../Singularity/collector.rsi/ca_deactive.png | Bin 986 -> 10791 bytes .../Singularity/collector.rsi/ca_off.png | Bin 563 -> 2755 bytes .../Singularity/collector.rsi/ca_on.png | Bin 712 -> 3212 bytes .../Singularity/collector.rsi/meta.json | 23 ++++++- 14 files changed, 93 insertions(+), 18 deletions(-) create mode 100644 Resources/Textures/Structures/Power/Generation/Singularity/collector.rsi/ca-o0.png create mode 100644 Resources/Textures/Structures/Power/Generation/Singularity/collector.rsi/ca-o1.png create mode 100644 Resources/Textures/Structures/Power/Generation/Singularity/collector.rsi/ca-o2.png create mode 100644 Resources/Textures/Structures/Power/Generation/Singularity/collector.rsi/ca-o3.png create mode 100644 Resources/Textures/Structures/Power/Generation/Singularity/collector.rsi/ca-tank.png diff --git a/Content.Server/Singularity/EntitySystems/RadiationCollectorSystem.cs b/Content.Server/Singularity/EntitySystems/RadiationCollectorSystem.cs index 19d9b98f4ab..27219bb1837 100644 --- a/Content.Server/Singularity/EntitySystems/RadiationCollectorSystem.cs +++ b/Content.Server/Singularity/EntitySystems/RadiationCollectorSystem.cs @@ -10,6 +10,7 @@ using Content.Shared.Examine; using Content.Server.Atmos; using System.Diagnostics.CodeAnalysis; +using Content.Shared.Atmos; namespace Content.Server.Singularity.EntitySystems; @@ -27,6 +28,9 @@ public override void Initialize() SubscribeLocalEvent(OnRadiation); SubscribeLocalEvent(OnExamined); SubscribeLocalEvent(OnAnalyzed); + SubscribeLocalEvent(OnMapInit); + SubscribeLocalEvent(OnTankChanged); + SubscribeLocalEvent(OnTankChanged); } private bool TryGetLoadedGasTank(EntityUid uid, [NotNullWhen(true)] out GasTankComponent? gasTankComponent) @@ -43,6 +47,18 @@ private bool TryGetLoadedGasTank(EntityUid uid, [NotNullWhen(true)] out GasTankC return true; } + private void OnMapInit(EntityUid uid, RadiationCollectorComponent component, MapInitEvent args) + { + TryGetLoadedGasTank(uid, out var gasTank); + UpdateTankAppearance(uid, component, gasTank); + } + + private void OnTankChanged(EntityUid uid, RadiationCollectorComponent component, ContainerModifiedMessage args) + { + TryGetLoadedGasTank(uid, out var gasTank); + UpdateTankAppearance(uid, component, gasTank); + } + private void OnInteractHand(EntityUid uid, RadiationCollectorComponent component, InteractHandEvent args) { var curTime = _gameTiming.CurTime; @@ -97,22 +113,20 @@ private void OnRadiation(EntityUid uid, RadiationCollectorComponent component, O { batteryComponent.CurrentCharge += charge; } + + // Update appearance + UpdatePressureIndicatorAppearance(uid, component, gasTankComponent); } private void OnExamined(EntityUid uid, RadiationCollectorComponent component, ExaminedEvent args) { - if (!TryGetLoadedGasTank(uid, out var gasTankComponent)) + if (!TryGetLoadedGasTank(uid, out var gasTank)) { args.PushMarkup(Loc.GetString("power-radiation-collector-gas-tank-missing")); return; } args.PushMarkup(Loc.GetString("power-radiation-collector-gas-tank-present")); - - if (gasTankComponent.IsLowPressure) - { - args.PushMarkup(Loc.GetString("power-radiation-collector-gas-tank-low-pressure")); - } } private void OnAnalyzed(EntityUid uid, RadiationCollectorComponent component, GasAnalyzerScanEvent args) @@ -133,7 +147,7 @@ public void ToggleCollector(EntityUid uid, EntityUid? user = null, RadiationColl public void SetCollectorEnabled(EntityUid uid, bool enabled, EntityUid? user = null, RadiationCollectorComponent? component = null) { - if (!Resolve(uid, ref component)) + if (!Resolve(uid, ref component, false)) return; component.Enabled = enabled; @@ -146,15 +160,43 @@ public void SetCollectorEnabled(EntityUid uid, bool enabled, EntityUid? user = n } // Update appearance - UpdateAppearance(uid, component); + UpdateMachineAppearance(uid, component); } - private void UpdateAppearance(EntityUid uid, RadiationCollectorComponent? component, AppearanceComponent? appearance = null) + private void UpdateMachineAppearance(EntityUid uid, RadiationCollectorComponent component, AppearanceComponent? appearance = null) { - if (!Resolve(uid, ref component, ref appearance)) + if (!Resolve(uid, ref appearance)) return; var state = component.Enabled ? RadiationCollectorVisualState.Active : RadiationCollectorVisualState.Deactive; _appearance.SetData(uid, RadiationCollectorVisuals.VisualState, state, appearance); } + + private void UpdatePressureIndicatorAppearance(EntityUid uid, RadiationCollectorComponent component, GasTankComponent? gasTank = null, AppearanceComponent? appearance = null) + { + if (!Resolve(uid, ref appearance, false)) + return; + + if (gasTank == null || gasTank.Air.Pressure < 10) + _appearance.SetData(uid, RadiationCollectorVisuals.PressureState, 0, appearance); + + else if (gasTank.Air.Pressure < Atmospherics.OneAtmosphere) + _appearance.SetData(uid, RadiationCollectorVisuals.PressureState, 1, appearance); + + else if (gasTank.Air.Pressure < 3f * Atmospherics.OneAtmosphere) + _appearance.SetData(uid, RadiationCollectorVisuals.PressureState, 2, appearance); + + else + _appearance.SetData(uid, RadiationCollectorVisuals.PressureState, 3, appearance); + } + + private void UpdateTankAppearance(EntityUid uid, RadiationCollectorComponent component, GasTankComponent? gasTank = null, AppearanceComponent? appearance = null) + { + if (!Resolve(uid, ref appearance, false)) + return; + + _appearance.SetData(uid, RadiationCollectorVisuals.TankInserted, gasTank != null, appearance); + + UpdatePressureIndicatorAppearance(uid, component, gasTank, appearance); + } } diff --git a/Content.Shared/Singularity/Components/SharedRadiationCollectorComponent.cs b/Content.Shared/Singularity/Components/SharedRadiationCollectorComponent.cs index 44cdea4fb69..0b5fbea6489 100644 --- a/Content.Shared/Singularity/Components/SharedRadiationCollectorComponent.cs +++ b/Content.Shared/Singularity/Components/SharedRadiationCollectorComponent.cs @@ -1,16 +1,18 @@ -using Robust.Shared.Serialization; +using Robust.Shared.Serialization; namespace Content.Shared.Singularity.Components { [NetSerializable, Serializable] public enum RadiationCollectorVisuals { - VisualState + VisualState, + TankInserted, + PressureState, } [NetSerializable, Serializable] public enum RadiationCollectorVisualState - { + { Active = (1<<0), Activating = (1<<1) | Active, Deactivating = (1<<1), diff --git a/Resources/Locale/en-US/power/components/radiation-collector.ftl b/Resources/Locale/en-US/power/components/radiation-collector.ftl index d68296fbeac..c38050f1e0a 100644 --- a/Resources/Locale/en-US/power/components/radiation-collector.ftl +++ b/Resources/Locale/en-US/power/components/radiation-collector.ftl @@ -1,3 +1,2 @@ -power-radiation-collector-gas-tank-missing = [color=red]No gas tank attached.[/color] -power-radiation-collector-gas-tank-present = A gas tank is [color=darkgreen]connected[/color]. -power-radiation-collector-gas-tank-low-pressure = The gas tank [color=orange]low pressure[/color] light is on. \ No newline at end of file +power-radiation-collector-gas-tank-missing = [color=darkred]No plasma tank attached.[/color] +power-radiation-collector-gas-tank-present = A plasma tank is [color=darkgreen]connected[/color]. \ No newline at end of file diff --git a/Resources/Prototypes/Entities/Structures/Power/Generation/Singularity/collector.yml b/Resources/Prototypes/Entities/Structures/Power/Generation/Singularity/collector.yml index ecdc3b3fbcb..d83e8b21fe1 100644 --- a/Resources/Prototypes/Entities/Structures/Power/Generation/Singularity/collector.yml +++ b/Resources/Prototypes/Entities/Structures/Power/Generation/Singularity/collector.yml @@ -31,6 +31,18 @@ - state: ca_off map: ["enum.RadiationCollectorVisualLayers.Main"] - type: Appearance + - type: GenericVisualizer + visuals: + enum.RadiationCollectorVisuals.TankInserted: + tankInserted: + False: { state: ca-tank, visible: false } + True: { state: ca-tank, visible: true } + enum.RadiationCollectorVisuals.PressureState: + pressureLight: + 0: { state: ca-o0, shader: "unshaded" } + 1: { state: ca-o1, shader: "unshaded" } + 2: { state: ca-o2, shader: "unshaded" } + 3: { state: ca-o3, shader: "unshaded" } - type: AnimationPlayer - type: NodeContainer examinable: true @@ -44,7 +56,6 @@ - reactantPrototype: Plasma powerGenerationEfficiency: 1 reactantBreakdownRate: 0.0002 - byproductPrototype: Tritium # Note that this doesn't matter too much (see next comment) # However it does act as a cap on power receivable via the collector. - type: Battery diff --git a/Resources/Textures/Structures/Power/Generation/Singularity/collector.rsi/ca-o0.png b/Resources/Textures/Structures/Power/Generation/Singularity/collector.rsi/ca-o0.png new file mode 100644 index 0000000000000000000000000000000000000000..5eefb01db6a9d02c26a92a0504afb413f4dd4dc9 GIT binary patch literal 1477 zcmV;$1v>hPP) zaB^>EX>4U6ba`-PAZ2)IW&i+q+U-_f(5ex`{j-#J5y+MxOhwX3o+s!7~ zr0GnjQ)_HwgaE&XvD5nU=T3j%AXQFT%}Xuiz>#aN+%WOuI_i0)BcIpv$oCTN-{=!R z78ojll&9*bv<3n z1&EfrqK@=HC-%Uw19CaH6%50vnA&a&`JE_BANXS_j<$dh2o1ZN=p+arB%@n=Tb zdjv!jVETm>^5Q5_q!G-;6;_~t_RX7~06)e}|M658pz67Q9qU)HPlozt7=hGPg=DVDYA7n!-MaVM+d%n@Jam*{!$%!$@|1}- zG0U{+v(C0CEp&>Nm#(sG`KqgJ)Y_Jvx9+lS`>wmauy(Wh)%Xe4=w^*irozr%Sc5j1 zJzP+<6AjM57-s_G77RoO3(gLwoH>{a&W;*gP8msRaFZqlW1uiEV%_w@-79mS;w`Cv ziZ}idb1A6%9n2+A_cd=Hur}j6H%`W`w=gh01aBYKm$$^;;-l97uKW)=TD7Ac?~Tf4 zptaA=Uz=|-+oRX$cRSQY+tS^}UU3J0`m)WvE{MXR8z{eBlACOhx#wCsPh*+BN;zY$ zCg}I=OyKywOg}RCto+~6zs(VfZZ9H=;%J5%8LnqlRW&rXDJZ?fI`_^?Vxf}l-3b*q z^6rK{;d`J3%)Cudc5Cz<7FnY5$m)duUC}i}@Sjci)mHqBc+BD_^_OJ&)s6q8BVdU4 zHT?yjTG!~IK3Nt300D++LqkwWLqi~Na&Km7Y-Iodc$|HaJxIe)6opSyMJX)~b`WvM zP{qNbsEDIfu?QAQTcK44lb8NMlZGV4#ZhoAIQX+zb#QUk)xlK|1b;wWU7QqMq{RD@ zLW>wLJl@B7_Z;544-gs^rkY(7fT~$WDjpNFxmB^}6#<0c!#GAIX6lLbVg{b|bx)mC zcTt|@-S=mOl)T9RpGZ8%bi*RvAfDN@bk6(4VOEk9;&b9LgDyz?$aUG}H_ki6e@tQNECMS>e3JS*_Gq>z@3D!MwJT<~pq*#Ib|~k`N)I zhB7L!5T#us#YBqEV;=rN$DbsZOs+B*ITlcb3d!+<|H1FsnuV!JHz^ncx?gPjV;Jb! z1)6o+{yw(t<_X|`2ClTWzuEw1KS{5*wa5|Bw+&oew>5bWxZD8-o^;8O9LY~hC=`JA zGy0|+(0>aA*4(+Z&T;wxWN22)H^9LmFjA!Kb&q%VcFyhJp4R++0H*kIyuMxHF8}}l z24YJ`L;(K){{a7>y{D4^000SaNLh0L01mb60s$mh z(?A#i001>fL_t(&-tE`14FDhv1Hp*>cXk>EK%#=&NuI#fR{;RPvF!a|xf1{YfU87K f9;{?J3@}*(yT}FqG&W=c00000NkvXXu0mjfZ-2WV literal 0 HcmV?d00001 diff --git a/Resources/Textures/Structures/Power/Generation/Singularity/collector.rsi/ca-o1.png b/Resources/Textures/Structures/Power/Generation/Singularity/collector.rsi/ca-o1.png new file mode 100644 index 0000000000000000000000000000000000000000..1902bbd8b96f0cc2ef2b28c27b2314a8cb4c3697 GIT binary patch literal 1415 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 literal 0 HcmV?d00001 diff --git a/Resources/Textures/Structures/Power/Generation/Singularity/collector.rsi/ca-o3.png b/Resources/Textures/Structures/Power/Generation/Singularity/collector.rsi/ca-o3.png new file mode 100644 index 0000000000000000000000000000000000000000..3522af81e5c10f2a19cf15e3bd4f3d47b42b13e1 GIT binary patch literal 1421 zcmV;81# zaB^>EX>4U6ba`-PAZ2)IW&i+q+U-_tlH4c^{m&_K1SBCOj)VEA+8gBfd0=->_sr~W zCdr>vwJ9SkK$71BK^Wivnc*8Aj+8@E^IUR{cv4A)D;gfpr|gcaPvKHNKC zHVUMipH{E&6?%P}aPvXOvp)FM!+sgMI&KDKd0yW7W027Esi$-qD&uVA;`SKoafRBh zfjgAz%@pl2cFx6jcvK_bG`KP4$FLDgvO^Gq@RPoA%1Wy_lWqpqt=_Lk08(4ea>H? z=4(a8a6@O!!N3EM%bu1|46mYXyA%|UH8xP*V~Yn$qe2YyXP`u#Doq+&Hfjhl@nC~w zZY*2pVqCa^Ba*ZVO*Sdg#lc+T5kOfIzQ;n_Z`uADIXrj5P$n1y;s0L3e|3JPggM)S zh@#)ILR`F-D8g9Gts0|12+fN(-2mUpMSpx)KUk_@P&dquAFS~>O&m&ZYfCoIf^iCY zZXpWRF9U!Gz7@fcfB|eEQCho**@%FngP@AYSrQ*$fK<67NKPV|gR%4SjX6epEGuVT zYUCymp_0YGO_2(+Qc|oROO7>ERWzw;R#OjJv}VaEYtGs7N^;f2lBs1gb1PO|Jh^&y zbNAx4a1rD{ExB0nQcA5HDjZeVsu*9PIrxwx9eU)$4nN9K8ivcj-tI zJ$LKgORs~%K&BXJ=*Yu{k231STAMP{)S0JEpJmoNYZt2@$`@Fpi#6U%t#Ni|4ccIK zGeIkz=;92FaUw8oi-DEF7H82ZC0@)e&SF_vP8mV!;wE%jjDf;5h;`DPyEo>3inpNt zQ@rv2F&7qfe}cIH>OS)J32S|wb8Rzr?!tv>6zo3q53hl}u0yTd)TbI4q&7xzpEt*aiT;ntb@YWG^Eq)tgmXL6)^+*$B}lkq`@_ljSY zpBkcxvk2~29H4YFfA|+=@L!zx zGW2&F!oHZe*8Bj?$-5dWh-n}I00D++LqkwWLqi~Na&Km7Y-Iodc$|HaJxIe)6opSy zMJX)~b`WvMP{qNbsEDIfu?QAQTcK44lb8NMlZGV4#ZhoAIQX+zb#QUk)xlK|1b;wW zU7QqMq{RD@LW>wLJl@B7_Z;544-gs^rkY(7fT~$WDjpNFxmB^}6#<0c!#GAIX6lLb zVg{b|bx)mCcTt|@-S=mOl)T9RpGZ8%bi*RvAfDN@bk6(4VOEk9;&b9LgDyz?$aUG} zH_ki6e@tQNECMS>e3JS*_Gq>z@3D!MwJT<~pq* z#Ib|~k`N)IhB7L!5T#us#YBqEV;=rN$DbsZOs+B*ITlcb3d!+<|H1FsnuV!JHz^nc zx?gPjV;Jb!1)6o+{yw(t<_X|`2ClTWzuEw1KS{5*wa5|Bw+&oew>5bWxZD8-o^;8O z9LY~hC=`JAGy0|+(0>aA*4(+Z&T;wxWN22)H^9LmFjA!Kb&q%VcFyhJp4R++0H*kI zyuMxHF8}}l24YJ`L;(K){{a7>y{D4^000SaNLh0L01mb60XZV2Y3Gjs001dTL_t(o!|l+a5dbg@12JDg_TSi@p|p|slTQEu;2WK$)7R`c b2dsAiJzoS1;lkUK00000NkvXXu0mjf7g(FY literal 0 HcmV?d00001 diff --git a/Resources/Textures/Structures/Power/Generation/Singularity/collector.rsi/ca-tank.png b/Resources/Textures/Structures/Power/Generation/Singularity/collector.rsi/ca-tank.png new file mode 100644 index 0000000000000000000000000000000000000000..4d5049f7b4ee366690c43580e5345c5caa549154 GIT binary patch literal 2071 zcmV+y2 zaB^>EX>4U6ba`-PAZ2)IW&i+q+U-|cmgFW3{bva<{=C3;AA2h_L?p)59P5amp65sFhku#4p!exuIk6`qgu%n9u$E_@2V^%XoNB zFoqJ^bUkXjrqI=?@FzuE1YV*C380Tx8@~x<@t5d4!dsF*u z>bM1uDffS&sJF7~T|9^P16hI66fBgOSE3Zp-7cB5|5Ivv{M?zZ(Uv5|fF>rrEdd}e zpZ92Ed=JnI$d6w5i2k$p0eo)vc=~{4xiLcLyAvee2me6)ZsGK_h+ikXTtL2j&i(H` z&3#>8*Kz@(<@Tr;9_Sn;K06>!=d}{I$^u_8wEL>KEVej6`HUlWT!Shx(Dy)@CN*+e zryVq4V&=t)mU(bGW0sUF4-i8s?~9x@)ijfVxxp)d(46>b3!QcAS#OYG7q!kOCp(H*azPeq1;G@tyy`Rl%Sfm<=D;V!u>$ zp*P=3hvx)2L3@P|1)aA7K!mjg#!vzS2%sdiqlj6FfTMw+2FsCsxPt)_;Rz!-r&Ks7 z8}GI8j?$53;lg_uxd}u_DoMdjO$}t_Ebt%A1|MpYB#TH96$?_Ol~i((Qi_(H-oC@y-22=(j9pQOLETtkTBQcLl7W-o7ZTHq4UXdye zCBg?q2*QJ(fGyfcqBufr@jw;TPu-CarsDLeD2`BeINnMiw4kCvSD~1O+8m@CUp@Hx z#+Q1Mg&OM3yAUFmdnq}}tZnahF9hExpYp2k>RxTYLR9>MBe5pJ8O`|$S&`LI`yoae zN<8Un`uS3nQAKM5{iwGdK2xA!R78Ly#C(SsP}o7X<1ODAz;=s@3;gg=jQ}0p1D3lq zU$U3vw{pj-3+#vJi`pLYF8$zL2_2M*ILe^(8*@kODr936ME3@I2e;3BIS^8kw7M0004oX+uL$Nkc;*aB^>EX>4Tx0C=2zkv&MmP!xqv zQ$;B)4t5Z6$WX<>qNs?YRIvyaN?V~-2a}inL6e3g#l=x@EjakISaoo5*44pP5Cnff zTwRt63RCiIH<=yvZg_OL>0G~)a$8^IY-XNaYv~yF6ykH@F@r8h{K$3L z|nWrS;tqs!_g>by?xO#aXS?SnHnrg~7bGlIA+C zA;htS1dga5(r*_wr^NjE7N z1G-;q`(qgB*#(+)+x|Yb?dA#Ke+I6!w!hi{WoO54hX`2A*`u zkQ~WRODGh8_cQvY9MFFY1lHWSwa#(+0Ay%Z%QwKmAuv*;>~)WK_jb;x7OI00v@9M??Vs0RI60puMM)00009a7bBm000ic000ic0Tn1pfB*mh2XskI zMF-~!4FNI<>LJGj0002qNklRAJ9WdgONKa1sPe}93 zx$_YE>-qiOP!qjqM$bl!O3Q2dK!3Gcf2d zFz7Jc#H~|Doq^#Xf*bdZtN_670DNFNYbk_rlYxPO;T1zYo=~W-tbnr{+dHV^fR`^` z!PzffA=sj8FxBF+l%NCdJbuZ*aOEb}G!Oy}WF3|N41O0488&a*M*TFvz`($88`n!tJGYHuUxKBA5*+_5COq1q=)f3;@!OI}V_ia-RSI002ovPDHLkV1f(9 B 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 WEExArV|*9@0000 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 diff --git a/Resources/Textures/Structures/Power/Generation/Singularity/collector.rsi/ca_off.png b/Resources/Textures/Structures/Power/Generation/Singularity/collector.rsi/ca_off.png index fa2741995e7fc5ef59d4996c3d17c953462db377..a3cac04acb3b5f649436c9c04811396ee7ab9eb9 100644 GIT binary patch delta 2748 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 diff --git a/Resources/Textures/Structures/Power/Generation/Singularity/collector.rsi/ca_on.png b/Resources/Textures/Structures/Power/Generation/Singularity/collector.rsi/ca_on.png index 122c0ce45fba16f8503c1e86a73b5a1c409fe45b..b9a49e1ec9892b4a4beb9175fc56754b5d90d413 100644 GIT binary patch delta 3189 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 diff --git a/Resources/Textures/Structures/Power/Generation/Singularity/collector.rsi/meta.json b/Resources/Textures/Structures/Power/Generation/Singularity/collector.rsi/meta.json index f03f3b29a6b..f111c8a64ad 100644 --- a/Resources/Textures/Structures/Power/Generation/Singularity/collector.rsi/meta.json +++ b/Resources/Textures/Structures/Power/Generation/Singularity/collector.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from goonstation at https://github.com/goonstation/goonstation/commit/cbe076402ed43b1cd861295bbcb95608c453de7a", + "copyright": "Taken from goonstation at https://github.com/goonstation/goonstation/commit/cbe076402ed43b1cd861295bbcb95608c453de7a. Edited by chromiumboy", "size": { "x": 32, "y": 32 @@ -39,6 +39,27 @@ }, { "name": "cu" + }, + { + "name": "ca-o0", + "delays": [ + [ + 0.2, + 0.2 + ] + ] + }, + { + "name": "ca-o1" + }, + { + "name": "ca-o2" + }, + { + "name": "ca-o3" + }, + { + "name": "ca-tank" } ] } From 4c4f24422cefa7bbca4255772cc7ff86401de922 Mon Sep 17 00:00:00 2001 From: PJBot Date: Fri, 13 Oct 2023 19:09:05 -0400 Subject: [PATCH 115/127] Automatic changelog update --- Resources/Changelog/Changelog.yml | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 20101b3ae9a..478dc6cfaba 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,9 +1,4 @@ Entries: -- author: crazybrain - changes: - - {message: Admin ghosts can now analyse solutions easier., type: Tweak} - id: 4500 - time: '2023-08-10T02:03:21.0000000+00:00' - author: metalgearsloth changes: - {message: Potentially fix invalid moth markings leading to issues spawning., type: Fix} @@ -2950,3 +2945,9 @@ Entries: - {message: Animals now give cute hearts when you pet them., type: Add} id: 4999 time: '2023-10-13T17:34:18.0000000+00:00' +- author: chromiumboy + changes: + - {message: The radiation collector has been updated to provide better visual feedback + on its status., type: Tweak} + id: 5000 + time: '2023-10-13T23:08:00.0000000+00:00' From d5e5b80c97c133cb79ba4e3294ea8d2673c40a06 Mon Sep 17 00:00:00 2001 From: liltenhead <104418166+liltenhead@users.noreply.github.com> Date: Fri, 13 Oct 2023 16:41:43 -0700 Subject: [PATCH 116/127] Increase containment field connection duration (#20965) --- .../Components/ContainmentFieldGeneratorComponent.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Content.Shared/Singularity/Components/ContainmentFieldGeneratorComponent.cs b/Content.Shared/Singularity/Components/ContainmentFieldGeneratorComponent.cs index b8f5d1a1894..d9fc044dcea 100644 --- a/Content.Shared/Singularity/Components/ContainmentFieldGeneratorComponent.cs +++ b/Content.Shared/Singularity/Components/ContainmentFieldGeneratorComponent.cs @@ -53,7 +53,7 @@ public int PowerBuffer /// How many seconds should the generators wait before losing power? ///