From 9bf53a4218cf0b3bc28605dcce68a783bfc71a6b Mon Sep 17 00:00:00 2001 From: ShadowCommander <10494922+ShadowCommander@users.noreply.github.com> Date: Sun, 21 Jun 2020 18:31:56 -0700 Subject: [PATCH 01/25] Implement unarmed combat --- .../Weapon/Melee/UnarmedCombatComponent.cs | 12 +++++++ .../EntitySystems/Click/InteractionSystem.cs | 36 ++++++++++++------- Resources/Prototypes/Entities/Mobs/human.yml | 1 + 3 files changed, 37 insertions(+), 12 deletions(-) create mode 100644 Content.Server/GameObjects/Components/Weapon/Melee/UnarmedCombatComponent.cs diff --git a/Content.Server/GameObjects/Components/Weapon/Melee/UnarmedCombatComponent.cs b/Content.Server/GameObjects/Components/Weapon/Melee/UnarmedCombatComponent.cs new file mode 100644 index 0000000000..0cd7cb189c --- /dev/null +++ b/Content.Server/GameObjects/Components/Weapon/Melee/UnarmedCombatComponent.cs @@ -0,0 +1,12 @@ + +using Content.Server.GameObjects.EntitySystems; +using Robust.Shared.GameObjects; + +namespace Content.Server.GameObjects.Components.Weapon.Melee +{ + [RegisterComponent] + public class UnarmedCombatComponent : MeleeWeaponComponent + { + public override string Name => "UnarmedCombat"; + } +} diff --git a/Content.Server/GameObjects/EntitySystems/Click/InteractionSystem.cs b/Content.Server/GameObjects/EntitySystems/Click/InteractionSystem.cs index 66692a5543..c92df5fcc5 100644 --- a/Content.Server/GameObjects/EntitySystems/Click/InteractionSystem.cs +++ b/Content.Server/GameObjects/EntitySystems/Click/InteractionSystem.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Linq; using Content.Server.GameObjects.Components.Mobs; using Content.Server.GameObjects.Components.Timing; @@ -955,22 +955,34 @@ namespace Content.Server.GameObjects.EntitySystems return; } - // Verify player has a hand, and find what object he is currently holding in his active hand - if (!player.TryGetComponent(out var hands)) - { - return; - } - - var item = hands.GetActiveHand?.Owner; - - // TODO: If item is null we need some kinda unarmed combat. - if (!ActionBlockerSystem.CanAttack(player) || item == null) + if (!ActionBlockerSystem.CanAttack(player)) { return; } var eventArgs = new AttackEventArgs(player, coordinates); - foreach (var attackComponent in item.GetAllComponents()) + + // Verify player has a hand, and find what object he is currently holding in his active hand + if (player.TryGetComponent(out var hands)) + { + var item = hands.GetActiveHand?.Owner; + + if (item != null) + { + var attacked = false; + foreach (var attackComponent in item.GetAllComponents()) + { + attackComponent.Attack(eventArgs); + attacked = true; + } + if (attacked) + { + return; + } + } + } + + foreach (var attackComponent in player.GetAllComponents()) { attackComponent.Attack(eventArgs); } diff --git a/Resources/Prototypes/Entities/Mobs/human.yml b/Resources/Prototypes/Entities/Mobs/human.yml index 5bb8d68aaf..629926bc51 100644 --- a/Resources/Prototypes/Entities/Mobs/human.yml +++ b/Resources/Prototypes/Entities/Mobs/human.yml @@ -134,6 +134,7 @@ - type: HumanoidAppearance - type: Stunnable - type: AnimationPlayer + - type: UnarmedCombat - type: entity save: false From 2944652a5dd01861f8788fba75a7143104afb629 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Aguilera=20Puerto?= Date: Mon, 22 Jun 2020 04:07:04 +0200 Subject: [PATCH 02/25] Only read fields in Looping Sound Component if serializer is reading. --- .../Components/Sound/SharedLoopingSoundComponent.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Content.Shared/GameObjects/Components/Sound/SharedLoopingSoundComponent.cs b/Content.Shared/GameObjects/Components/Sound/SharedLoopingSoundComponent.cs index 18f7a9ff7e..b09d353b27 100644 --- a/Content.Shared/GameObjects/Components/Sound/SharedLoopingSoundComponent.cs +++ b/Content.Shared/GameObjects/Components/Sound/SharedLoopingSoundComponent.cs @@ -108,6 +108,9 @@ namespace Content.Shared.GameObjects.Components.Sound public void ExposeData(ObjectSerializer serializer) { + if (!serializer.Reading) + return; + Filename = serializer.ReadDataField("filename", ""); Delay = serializer.ReadDataField("delay", 0u); RandomDelay = serializer.ReadDataField("randomdelay", 0u); From 3f7bd3010c040294ec5bc01b23d19e47c1fa0fc8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Aguilera=20Puerto?= Date: Mon, 22 Jun 2020 04:10:44 +0200 Subject: [PATCH 03/25] Fix RevolverBarrelComponent ExposeData not checking if serializer is reading --- .../Ranged/Barrels/RevolverBarrelComponent.cs | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/Content.Server/GameObjects/Components/Weapon/Ranged/Barrels/RevolverBarrelComponent.cs b/Content.Server/GameObjects/Components/Weapon/Ranged/Barrels/RevolverBarrelComponent.cs index 04c2c7c56f..f9caf303b6 100644 --- a/Content.Server/GameObjects/Components/Weapon/Ranged/Barrels/RevolverBarrelComponent.cs +++ b/Content.Server/GameObjects/Components/Weapon/Ranged/Barrels/RevolverBarrelComponent.cs @@ -42,8 +42,15 @@ namespace Content.Server.GameObjects.Components.Weapon.Ranged.Barrels { base.ExposeData(serializer); serializer.DataField(ref _caliber, "caliber", BallisticCaliber.Unspecified); - var capacity = serializer.ReadDataField("capacity", 6); - _ammoSlots = new IEntity[capacity]; + + if (serializer.Reading) + { + var capacity = serializer.ReadDataField("capacity", 6); + _ammoSlots = new IEntity[capacity]; + } + + // TODO: Writing? + // Sounds serializer.DataField(ref _soundEject, "soundEject", "/Audio/Guns/MagOut/revolver_magout.ogg"); @@ -60,7 +67,7 @@ namespace Content.Server.GameObjects.Components.Weapon.Ranged.Barrels { _appearanceComponent = appearanceComponent; } - + _appearanceComponent?.SetData(MagazineBarrelVisuals.MagLoaded, true); } @@ -78,7 +85,7 @@ namespace Content.Server.GameObjects.Components.Weapon.Ranged.Barrels { return false; } - + if (ammoComponent.Caliber != _caliber) { Owner.PopupMessage(user, Loc.GetString("Wrong caliber")); @@ -208,7 +215,7 @@ namespace Content.Server.GameObjects.Components.Weapon.Ranged.Barrels { return TryInsertBullet(eventArgs.User, eventArgs.Using); } - + [Verb] private sealed class SpinRevolverVerb : Verb { From 4b64aa2b9dffdf76a0c17c47c4060cde0266f188 Mon Sep 17 00:00:00 2001 From: Tyler Young Date: Mon, 22 Jun 2020 04:43:47 -0400 Subject: [PATCH 04/25] fix benchmark improve some test diagnostics fix some bug where order of shutdown of AiControllerComponent mattered or Processor was never initialized --- .../ComponentManagerGetAllComponents.cs | 37 ++++++++++++++++++- Content.Benchmarks/Program.cs | 3 +- Content.IntegrationTests/Tests/EntityTest.cs | 3 +- .../Tests/SaveLoadSaveTest.cs | 22 +++++++++-- .../Items/Storage/ServerStorageComponent.cs | 4 +- .../Movement/AiControllerComponent.cs | 2 +- 6 files changed, 61 insertions(+), 10 deletions(-) diff --git a/Content.Benchmarks/ComponentManagerGetAllComponents.cs b/Content.Benchmarks/ComponentManagerGetAllComponents.cs index 95063ba8d0..a2db430944 100644 --- a/Content.Benchmarks/ComponentManagerGetAllComponents.cs +++ b/Content.Benchmarks/ComponentManagerGetAllComponents.cs @@ -2,9 +2,13 @@ using System; using System.Collections.Generic; using BenchmarkDotNet.Attributes; using Moq; +using Robust.Shared.Exceptions; using Robust.Shared.GameObjects; using Robust.Shared.Interfaces.GameObjects; +using Robust.Shared.Interfaces.Log; +using Robust.Shared.Interfaces.Reflection; using Robust.Shared.IoC; +using Robust.Shared.Log; namespace Content.Benchmarks { @@ -14,7 +18,17 @@ namespace Content.Benchmarks private IComponentManager _componentManager; - [Params(500, 1000, 5000)] public int N { get; set; } + [Params(5000)] public int N { get; set; } + + public static void TestRun() + { + var x = new ComponentManagerGetAllComponents + { + N = 500 + }; + x.Setup(); + x.Run(); + } [GlobalSetup] public void Setup() @@ -23,6 +37,13 @@ namespace Content.Benchmarks IoCManager.InitThread(); IoCManager.Register(); + IoCManager.Register(); + IoCManager.Register(); + IoCManager.Register(); + IoCManager.Register(); + var entityManager = new Mock().Object; + IoCManager.RegisterInstance(entityManager); + IoCManager.RegisterInstance(new Mock().Object); var dummyReg = new Mock(); dummyReg.SetupGet(p => p.Name).Returns("Dummy"); @@ -34,17 +55,19 @@ namespace Content.Benchmarks var componentFactory = new Mock(); componentFactory.Setup(p => p.GetComponent()).Returns(new DummyComponent()); componentFactory.Setup(p => p.GetRegistration(It.IsAny())).Returns(dummyReg.Object); + componentFactory.Setup(p => p.GetAllRefTypes()).Returns(new[] {typeof(DummyComponent)}); IoCManager.RegisterInstance(componentFactory.Object); IoCManager.BuildGraph(); - _componentManager = IoCManager.Resolve(); + _componentManager.Initialize(); // Initialize N entities with one component. for (var i = 0; i < N; i++) { var entity = new Entity(); + entity.SetManagers(entityManager); entity.SetUid(new EntityUid(i + 1)); _entities.Add(entity); @@ -65,6 +88,16 @@ namespace Content.Benchmarks return count; } + [Benchmark] + public int Noop() + { + var count = 0; + + _componentManager.TryGetComponent(default, out DummyComponent _); + + return count; + } + private class DummyComponent : Component { public override string Name => "Dummy"; diff --git a/Content.Benchmarks/Program.cs b/Content.Benchmarks/Program.cs index 7eb128092d..74ee4e265b 100644 --- a/Content.Benchmarks/Program.cs +++ b/Content.Benchmarks/Program.cs @@ -6,7 +6,8 @@ namespace Content.Benchmarks { public static void Main(string[] args) { - BenchmarkRunner.Run(); + BenchmarkRunner.Run(); + //ComponentManagerGetAllComponents.TestRun(); } } } diff --git a/Content.IntegrationTests/Tests/EntityTest.cs b/Content.IntegrationTests/Tests/EntityTest.cs index cab5f7b68c..288105ab42 100644 --- a/Content.IntegrationTests/Tests/EntityTest.cs +++ b/Content.IntegrationTests/Tests/EntityTest.cs @@ -69,7 +69,8 @@ namespace Content.IntegrationTests.Tests catch (Exception e) { Logger.LogS(LogLevel.Error, "EntityTest", "Entity '" + prototype.ID + "' threw: " + e.Message); - Assert.Fail(); + //Assert.Fail(); + throw; } } }); diff --git a/Content.IntegrationTests/Tests/SaveLoadSaveTest.cs b/Content.IntegrationTests/Tests/SaveLoadSaveTest.cs index 67c5df2ed3..d462beb279 100644 --- a/Content.IntegrationTests/Tests/SaveLoadSaveTest.cs +++ b/Content.IntegrationTests/Tests/SaveLoadSaveTest.cs @@ -1,4 +1,5 @@ using System.IO; +using System.Linq; using System.Threading.Tasks; using NUnit.Framework; using Robust.Server.Interfaces.Maps; @@ -37,19 +38,34 @@ namespace Content.IntegrationTests.Tests string one; string two; - using (var stream = userData.Open(new ResourcePath("save load save 1.yml"), FileMode.Open)) + var rp1 = new ResourcePath("save load save 1.yml"); + using (var stream = userData.Open(rp1, FileMode.Open)) using (var reader = new StreamReader(stream)) { one = reader.ReadToEnd(); } - using (var stream = userData.Open(new ResourcePath("save load save 2.yml"), FileMode.Open)) + var rp2 = new ResourcePath("save load save 2.yml"); + using (var stream = userData.Open(rp2, FileMode.Open)) using (var reader = new StreamReader(stream)) { two = reader.ReadToEnd(); } - Assert.That(one, Is.EqualTo(two)); + Assert.Multiple(() => { + Assert.That(one, Is.EqualTo(two)); + var failed = TestContext.CurrentContext.Result.Assertions.FirstOrDefault(); + if (failed != null) + { + var path1 = Path.Combine(userData.RootDir!,rp1.ToRelativeSystemPath()); + var path2 = Path.Combine(userData.RootDir!,rp2.ToRelativeSystemPath()); + TestContext.AddTestAttachment(path1); + TestContext.AddTestAttachment(path2); + TestContext.Error.WriteLine("Complete output:"); + TestContext.Error.WriteLine(path1); + TestContext.Error.WriteLine(path2); + } + }); } /// diff --git a/Content.Server/GameObjects/Components/Items/Storage/ServerStorageComponent.cs b/Content.Server/GameObjects/Components/Items/Storage/ServerStorageComponent.cs index 27bbc2c942..357a8acd72 100644 --- a/Content.Server/GameObjects/Components/Items/Storage/ServerStorageComponent.cs +++ b/Content.Server/GameObjects/Components/Items/Storage/ServerStorageComponent.cs @@ -60,7 +60,7 @@ namespace Content.Server.GameObjects base.ExposeData(serializer); serializer.DataField(ref StorageCapacityMax, "Capacity", 10000); - serializer.DataField(ref StorageUsed, "used", 0); + //serializer.DataField(ref StorageUsed, "used", 0); } /// @@ -348,7 +348,7 @@ namespace Content.Server.GameObjects foreach (var entity in storage.ContainedEntities) { - var item = entity.GetComponent(); + var item = entity.GetComponent(); StorageUsed += item.ObjectSize; } diff --git a/Content.Server/GameObjects/Components/Movement/AiControllerComponent.cs b/Content.Server/GameObjects/Components/Movement/AiControllerComponent.cs index 884e03479d..6a6747c6bb 100644 --- a/Content.Server/GameObjects/Components/Movement/AiControllerComponent.cs +++ b/Content.Server/GameObjects/Components/Movement/AiControllerComponent.cs @@ -61,7 +61,7 @@ namespace Content.Server.GameObjects.Components.Movement protected override void Shutdown() { base.Shutdown(); - Processor.Shutdown(); + Processor?.Shutdown(); } /// From ac2c7da31fadeb51987904ea1358d81125b2e3f2 Mon Sep 17 00:00:00 2001 From: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com> Date: Mon, 22 Jun 2020 23:18:41 +1000 Subject: [PATCH 05/25] Add magazine auto-eject message back in (#1191) I goofed. Co-authored-by: Metal Gear Sloth --- .../Ranged/Barrels/ClientMagazineBarrelComponent.cs | 7 ++++--- .../Ranged/Barrels/ServerMagazineBarrelComponent.cs | 2 ++ .../Weapons/Ranged/MagazineAutoEjectMessage.cs | 12 ++++++++++++ 3 files changed, 18 insertions(+), 3 deletions(-) create mode 100644 Content.Shared/GameObjects/Components/Weapons/Ranged/MagazineAutoEjectMessage.cs diff --git a/Content.Client/GameObjects/Components/Weapons/Ranged/Barrels/ClientMagazineBarrelComponent.cs b/Content.Client/GameObjects/Components/Weapons/Ranged/Barrels/ClientMagazineBarrelComponent.cs index 4a4ae191eb..adf93dc3ab 100644 --- a/Content.Client/GameObjects/Components/Weapons/Ranged/Barrels/ClientMagazineBarrelComponent.cs +++ b/Content.Client/GameObjects/Components/Weapons/Ranged/Barrels/ClientMagazineBarrelComponent.cs @@ -3,6 +3,7 @@ using Content.Client.Animations; using Content.Client.UserInterface.Stylesheets; using Content.Client.Utility; using Content.Shared.GameObjects; +using Content.Shared.GameObjects.Components.Weapons.Ranged; using Content.Shared.GameObjects.Components.Weapons.Ranged.Barrels; using Robust.Client.Animations; using Robust.Client.Graphics; @@ -112,10 +113,10 @@ namespace Content.Client.GameObjects.Components.Weapons.Ranged.Barrels switch (message) { - /* - case BmwComponentAutoEjectedMessage _: + + case MagazineAutoEjectMessage _: _statusControl?.PlayAlarmAnimation(); - return;*/ + return; } } diff --git a/Content.Server/GameObjects/Components/Weapon/Ranged/Barrels/ServerMagazineBarrelComponent.cs b/Content.Server/GameObjects/Components/Weapon/Ranged/Barrels/ServerMagazineBarrelComponent.cs index 5bfc0ede89..a38b47f002 100644 --- a/Content.Server/GameObjects/Components/Weapon/Ranged/Barrels/ServerMagazineBarrelComponent.cs +++ b/Content.Server/GameObjects/Components/Weapon/Ranged/Barrels/ServerMagazineBarrelComponent.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using Content.Server.GameObjects.Components.Weapon.Ranged.Ammunition; using Content.Server.GameObjects.EntitySystems; using Content.Shared.GameObjects; +using Content.Shared.GameObjects.Components.Weapons.Ranged; using Content.Shared.GameObjects.Components.Weapons.Ranged.Barrels; using Content.Shared.Interfaces; using Robust.Server.GameObjects; @@ -217,6 +218,7 @@ namespace Content.Server.GameObjects.Components.Weapon.Ranged.Barrels } _magazineContainer.Remove(magazine); + SendNetworkMessage(new MagazineAutoEjectMessage()); } if (nextRound == null && !BoltOpen) diff --git a/Content.Shared/GameObjects/Components/Weapons/Ranged/MagazineAutoEjectMessage.cs b/Content.Shared/GameObjects/Components/Weapons/Ranged/MagazineAutoEjectMessage.cs new file mode 100644 index 0000000000..fe8f2e183c --- /dev/null +++ b/Content.Shared/GameObjects/Components/Weapons/Ranged/MagazineAutoEjectMessage.cs @@ -0,0 +1,12 @@ +using System; +using Robust.Shared.GameObjects; +using Robust.Shared.Serialization; + +namespace Content.Shared.GameObjects.Components.Weapons.Ranged +{ + /// + /// This is sent if the MagazineBarrel AutoEjects the magazine + /// + [Serializable, NetSerializable] + public sealed class MagazineAutoEjectMessage : ComponentMessage {} +} \ No newline at end of file From 6fe7d11d54dfde4a736007a485649e98cb83b711 Mon Sep 17 00:00:00 2001 From: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com> Date: Mon, 22 Jun 2020 23:19:01 +1000 Subject: [PATCH 06/25] Fix battery barrel low energy ratio exception (#1187) Co-authored-by: Metal Gear Sloth --- .../Weapon/Ranged/Barrels/ServerBatteryBarrelComponent.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Content.Server/GameObjects/Components/Weapon/Ranged/Barrels/ServerBatteryBarrelComponent.cs b/Content.Server/GameObjects/Components/Weapon/Ranged/Barrels/ServerBatteryBarrelComponent.cs index e854ee8480..9d49d30257 100644 --- a/Content.Server/GameObjects/Components/Weapon/Ranged/Barrels/ServerBatteryBarrelComponent.cs +++ b/Content.Server/GameObjects/Components/Weapon/Ranged/Barrels/ServerBatteryBarrelComponent.cs @@ -170,7 +170,7 @@ namespace Content.Server.GameObjects.Components.Weapon.Ranged.Barrels { if (energyRatio < 1.0) { - var newDamages = new Dictionary(projectileComponent.Damages); + var newDamages = new Dictionary(projectileComponent.Damages.Count); foreach (var (damageType, damage) in projectileComponent.Damages) { newDamages.Add(damageType, (int) (damage * energyRatio)); From ff0f0821387e2815a8e6720c4e458cf9a6c82745 Mon Sep 17 00:00:00 2001 From: DrSmugleaf Date: Mon, 22 Jun 2020 18:54:56 +0200 Subject: [PATCH 07/25] Fix being able to use invalid verbs as a ghost (#1157) * Add CanInteract check to 18 verbs * Add more caninteract checks to verbs without it Storage toggle open, ammo box dump, bolt open and close, revolver spin and magazine open and close --- .../Components/Chemistry/SolutionComponent.cs | 60 +++++++++---------- .../Components/Fluids/CanSpillComponent.cs | 4 +- .../Interactable/HandheldLightComponent.cs | 6 ++ .../Items/Storage/EntityStorageComponent.cs | 13 +++- .../Components/Items/Storage/ItemComponent.cs | 4 +- .../Storage/SecureEntityStorageComponent.cs | 2 +- .../Medical/MedicalScannerComponent.cs | 12 ++++ .../Components/PDA/PDAComponent.cs | 6 ++ .../Chargers/PowerCellChargerComponent.cs | 12 ++++ .../WeaponCapacitorChargerComponent.cs | 12 ++++ .../Components/RotatableComponent.cs | 13 ++++ .../Weapon/Melee/StunbatonComponent.cs | 6 ++ .../Ranged/Ammunition/AmmoBoxComponent.cs | 22 ++++--- .../Barrels/BoltActionBarrelComponent.cs | 38 ++++++++---- .../Ranged/Barrels/RevolverBarrelComponent.cs | 6 ++ .../Barrels/ServerMagazineBarrelComponent.cs | 44 ++++++++++---- 16 files changed, 192 insertions(+), 68 deletions(-) diff --git a/Content.Server/GameObjects/Components/Chemistry/SolutionComponent.cs b/Content.Server/GameObjects/Components/Chemistry/SolutionComponent.cs index aa262e1b20..8d023d2580 100644 --- a/Content.Server/GameObjects/Components/Chemistry/SolutionComponent.cs +++ b/Content.Server/GameObjects/Components/Chemistry/SolutionComponent.cs @@ -219,23 +219,23 @@ namespace Content.Server.GameObjects.Components.Chemistry { protected override void GetData(IEntity user, SolutionComponent component, VerbData data) { - if (user.TryGetComponent(out var hands)) + if (!ActionBlockerSystem.CanInteract(user) || + !user.TryGetComponent(out var hands) || + hands.GetActiveHand == null || + !hands.GetActiveHand.Owner.TryGetComponent(out var solution)) { - if (hands.GetActiveHand != null) - { - if (hands.GetActiveHand.Owner.TryGetComponent(out var solution)) - { - if ((solution.Capabilities & SolutionCaps.PourOut) != 0 && - (component.Capabilities & SolutionCaps.PourIn) != 0) - { - var heldEntityName = hands.GetActiveHand.Owner?.Prototype?.Name ?? ""; - var myName = component.Owner.Prototype?.Name ?? ""; + data.Visibility = VerbVisibility.Invisible; + return; + } - data.Text= $"Transfer liquid from [{heldEntityName}] to [{myName}]."; - return; - } - } - } + if ((solution.Capabilities & SolutionCaps.PourOut) != 0 && + (component.Capabilities & SolutionCaps.PourIn) != 0) + { + var heldEntityName = hands.GetActiveHand.Owner?.Prototype?.Name ?? ""; + var myName = component.Owner.Prototype?.Name ?? ""; + + data.Text= $"Transfer liquid from [{heldEntityName}] to [{myName}]."; + return; } data.Visibility = VerbVisibility.Invisible; @@ -318,23 +318,23 @@ namespace Content.Server.GameObjects.Components.Chemistry { protected override void GetData(IEntity user, SolutionComponent component, VerbData data) { - if (user.TryGetComponent(out var hands)) + if (!ActionBlockerSystem.CanInteract(user) || + !user.TryGetComponent(out var hands) || + hands.GetActiveHand == null || + !hands.GetActiveHand.Owner.TryGetComponent(out var solution)) { - if (hands.GetActiveHand != null) - { - if (hands.GetActiveHand.Owner.TryGetComponent(out var solution)) - { - if ((solution.Capabilities & SolutionCaps.PourIn) != 0 && - (component.Capabilities & SolutionCaps.PourOut) != 0) - { - var heldEntityName = hands.GetActiveHand.Owner?.Prototype?.Name ?? ""; - var myName = component.Owner.Prototype?.Name ?? ""; + data.Visibility = VerbVisibility.Invisible; + return; + } - data.Text = $"Transfer liquid from [{myName}] to [{heldEntityName}]."; - return; - } - } - } + if ((solution.Capabilities & SolutionCaps.PourIn) != 0 && + (component.Capabilities & SolutionCaps.PourOut) != 0) + { + var heldEntityName = hands.GetActiveHand.Owner?.Prototype?.Name ?? ""; + var myName = component.Owner.Prototype?.Name ?? ""; + + data.Text = $"Transfer liquid from [{myName}] to [{heldEntityName}]."; + return; } data.Visibility = VerbVisibility.Invisible; diff --git a/Content.Server/GameObjects/Components/Fluids/CanSpillComponent.cs b/Content.Server/GameObjects/Components/Fluids/CanSpillComponent.cs index 8d9d2e4ce5..2c4cfc80f3 100644 --- a/Content.Server/GameObjects/Components/Fluids/CanSpillComponent.cs +++ b/Content.Server/GameObjects/Components/Fluids/CanSpillComponent.cs @@ -1,5 +1,6 @@ using System; using Content.Server.GameObjects.Components.Chemistry; +using Content.Server.GameObjects.EntitySystems; using Content.Shared.Chemistry; using Content.Shared.GameObjects; using Robust.Shared.GameObjects; @@ -21,7 +22,8 @@ namespace Content.Server.GameObjects.Components.Fluids { protected override void GetData(IEntity user, CanSpillComponent component, VerbData data) { - if (!component.Owner.TryGetComponent(out SolutionComponent solutionComponent)) + if (!ActionBlockerSystem.CanInteract(user) || + !component.Owner.TryGetComponent(out SolutionComponent solutionComponent)) { data.Visibility = VerbVisibility.Invisible; return; diff --git a/Content.Server/GameObjects/Components/Interactable/HandheldLightComponent.cs b/Content.Server/GameObjects/Components/Interactable/HandheldLightComponent.cs index 71d920d5fb..2e58ab6b6c 100644 --- a/Content.Server/GameObjects/Components/Interactable/HandheldLightComponent.cs +++ b/Content.Server/GameObjects/Components/Interactable/HandheldLightComponent.cs @@ -240,6 +240,12 @@ namespace Content.Server.GameObjects.Components.Interactable { protected override void GetData(IEntity user, HandheldLightComponent component, VerbData data) { + if (!ActionBlockerSystem.CanInteract(user)) + { + data.Visibility = VerbVisibility.Invisible; + return; + } + if (component.Cell == null) { data.Text = "Eject cell (cell missing)"; diff --git a/Content.Server/GameObjects/Components/Items/Storage/EntityStorageComponent.cs b/Content.Server/GameObjects/Components/Items/Storage/EntityStorageComponent.cs index 0b94299c7c..e3a7bab178 100644 --- a/Content.Server/GameObjects/Components/Items/Storage/EntityStorageComponent.cs +++ b/Content.Server/GameObjects/Components/Items/Storage/EntityStorageComponent.cs @@ -338,8 +338,13 @@ namespace Content.Server.GameObjects.Components { protected override void GetData(IEntity user, EntityStorageComponent component, VerbData data) { - component.OpenVerbGetData(user, component, data); + if (!ActionBlockerSystem.CanInteract(user)) + { + data.Visibility = VerbVisibility.Invisible; + return; + } + component.OpenVerbGetData(user, component, data); } /// @@ -351,6 +356,12 @@ namespace Content.Server.GameObjects.Components protected virtual void OpenVerbGetData(IEntity user, EntityStorageComponent component, VerbData data) { + if (!ActionBlockerSystem.CanInteract(user)) + { + data.Visibility = VerbVisibility.Invisible; + return; + } + if (IsWeldedShut) { data.Visibility = VerbVisibility.Disabled; diff --git a/Content.Server/GameObjects/Components/Items/Storage/ItemComponent.cs b/Content.Server/GameObjects/Components/Items/Storage/ItemComponent.cs index 9e71faa71e..0e34998d11 100644 --- a/Content.Server/GameObjects/Components/Items/Storage/ItemComponent.cs +++ b/Content.Server/GameObjects/Components/Items/Storage/ItemComponent.cs @@ -116,7 +116,9 @@ namespace Content.Server.GameObjects { protected override void GetData(IEntity user, ItemComponent component, VerbData data) { - if (ContainerHelpers.IsInContainer(component.Owner) || !component.CanPickup(user)) + if (!ActionBlockerSystem.CanInteract(user) || + ContainerHelpers.IsInContainer(component.Owner) || + !component.CanPickup(user)) { data.Visibility = VerbVisibility.Invisible; return; diff --git a/Content.Server/GameObjects/Components/Items/Storage/SecureEntityStorageComponent.cs b/Content.Server/GameObjects/Components/Items/Storage/SecureEntityStorageComponent.cs index 34ab66e526..d37f3b79c7 100644 --- a/Content.Server/GameObjects/Components/Items/Storage/SecureEntityStorageComponent.cs +++ b/Content.Server/GameObjects/Components/Items/Storage/SecureEntityStorageComponent.cs @@ -139,7 +139,7 @@ namespace Content.Server.GameObjects.Components.Items.Storage { protected override void GetData(IEntity user, SecureEntityStorageComponent component, VerbData data) { - if (component.Open) + if (!ActionBlockerSystem.CanInteract(user) || component.Open) { data.Visibility = VerbVisibility.Invisible; return; diff --git a/Content.Server/GameObjects/Components/Medical/MedicalScannerComponent.cs b/Content.Server/GameObjects/Components/Medical/MedicalScannerComponent.cs index d3ef519309..f309e1bce5 100644 --- a/Content.Server/GameObjects/Components/Medical/MedicalScannerComponent.cs +++ b/Content.Server/GameObjects/Components/Medical/MedicalScannerComponent.cs @@ -133,6 +133,12 @@ namespace Content.Server.GameObjects.Components.Medical { protected override void GetData(IEntity user, MedicalScannerComponent component, VerbData data) { + if (!ActionBlockerSystem.CanInteract(user)) + { + data.Visibility = VerbVisibility.Invisible; + return; + } + data.Text = "Enter"; data.Visibility = component.IsOccupied ? VerbVisibility.Invisible : VerbVisibility.Visible; } @@ -148,6 +154,12 @@ namespace Content.Server.GameObjects.Components.Medical { protected override void GetData(IEntity user, MedicalScannerComponent component, VerbData data) { + if (!ActionBlockerSystem.CanInteract(user)) + { + data.Visibility = VerbVisibility.Invisible; + return; + } + data.Text = "Eject"; data.Visibility = component.IsOccupied ? VerbVisibility.Visible : VerbVisibility.Invisible; } diff --git a/Content.Server/GameObjects/Components/PDA/PDAComponent.cs b/Content.Server/GameObjects/Components/PDA/PDAComponent.cs index f70cd43a9e..a6dd1deb05 100644 --- a/Content.Server/GameObjects/Components/PDA/PDAComponent.cs +++ b/Content.Server/GameObjects/Components/PDA/PDAComponent.cs @@ -250,6 +250,12 @@ namespace Content.Server.GameObjects.Components.PDA { protected override void GetData(IEntity user, PDAComponent component, VerbData data) { + if (!ActionBlockerSystem.CanInteract(user)) + { + data.Visibility = VerbVisibility.Invisible; + return; + } + data.Text = Loc.GetString("Eject ID"); data.Visibility = component.IdSlotEmpty ? VerbVisibility.Invisible : VerbVisibility.Visible; } diff --git a/Content.Server/GameObjects/Components/Power/Chargers/PowerCellChargerComponent.cs b/Content.Server/GameObjects/Components/Power/Chargers/PowerCellChargerComponent.cs index 526bff9b45..f904673e37 100644 --- a/Content.Server/GameObjects/Components/Power/Chargers/PowerCellChargerComponent.cs +++ b/Content.Server/GameObjects/Components/Power/Chargers/PowerCellChargerComponent.cs @@ -61,6 +61,12 @@ namespace Content.Server.GameObjects.Components.Power.Chargers { protected override void GetData(IEntity user, PowerCellChargerComponent component, VerbData data) { + if (!ActionBlockerSystem.CanInteract(user)) + { + data.Visibility = VerbVisibility.Invisible; + return; + } + if (!user.TryGetComponent(out HandsComponent handsComponent)) { data.Visibility = VerbVisibility.Invisible; @@ -99,6 +105,12 @@ namespace Content.Server.GameObjects.Components.Power.Chargers { protected override void GetData(IEntity user, PowerCellChargerComponent component, VerbData data) { + if (!ActionBlockerSystem.CanInteract(user)) + { + data.Visibility = VerbVisibility.Invisible; + return; + } + if (component._container.ContainedEntity == null) { data.Text = "Eject"; diff --git a/Content.Server/GameObjects/Components/Power/Chargers/WeaponCapacitorChargerComponent.cs b/Content.Server/GameObjects/Components/Power/Chargers/WeaponCapacitorChargerComponent.cs index a6530f5daf..2bb1bee4d5 100644 --- a/Content.Server/GameObjects/Components/Power/Chargers/WeaponCapacitorChargerComponent.cs +++ b/Content.Server/GameObjects/Components/Power/Chargers/WeaponCapacitorChargerComponent.cs @@ -46,6 +46,12 @@ namespace Content.Server.GameObjects.Components.Power.Chargers { protected override void GetData(IEntity user, WeaponCapacitorChargerComponent component, VerbData data) { + if (!ActionBlockerSystem.CanInteract(user)) + { + data.Visibility = VerbVisibility.Invisible; + return; + } + if (!user.TryGetComponent(out HandsComponent handsComponent)) { data.Visibility = VerbVisibility.Invisible; @@ -89,6 +95,12 @@ namespace Content.Server.GameObjects.Components.Power.Chargers { protected override void GetData(IEntity user, WeaponCapacitorChargerComponent component, VerbData data) { + if (!ActionBlockerSystem.CanInteract(user)) + { + data.Visibility = VerbVisibility.Invisible; + return; + } + if (component._container.ContainedEntity == null) { data.Visibility = VerbVisibility.Disabled; diff --git a/Content.Server/GameObjects/Components/RotatableComponent.cs b/Content.Server/GameObjects/Components/RotatableComponent.cs index 01eba427dc..bd45b22e98 100644 --- a/Content.Server/GameObjects/Components/RotatableComponent.cs +++ b/Content.Server/GameObjects/Components/RotatableComponent.cs @@ -1,3 +1,4 @@ +using Content.Server.GameObjects.EntitySystems; using Content.Server.Interfaces; using Content.Shared.GameObjects; using Robust.Server.GameObjects; @@ -37,6 +38,12 @@ namespace Content.Server.GameObjects.Components { protected override void GetData(IEntity user, RotatableComponent component, VerbData data) { + if (!ActionBlockerSystem.CanInteract(user)) + { + data.Visibility = VerbVisibility.Invisible; + return; + } + data.CategoryData = VerbCategories.Rotate; data.Text = "Rotate clockwise"; data.IconTexture = "/Textures/UserInterface/VerbIcons/rotate_cw.svg.96dpi.png"; @@ -53,6 +60,12 @@ namespace Content.Server.GameObjects.Components { protected override void GetData(IEntity user, RotatableComponent component, VerbData data) { + if (!ActionBlockerSystem.CanInteract(user)) + { + data.Visibility = VerbVisibility.Invisible; + return; + } + data.CategoryData = VerbCategories.Rotate; data.Text = "Rotate counter-clockwise"; data.IconTexture = "/Textures/UserInterface/VerbIcons/rotate_ccw.svg.96dpi.png"; diff --git a/Content.Server/GameObjects/Components/Weapon/Melee/StunbatonComponent.cs b/Content.Server/GameObjects/Components/Weapon/Melee/StunbatonComponent.cs index 2c9985e99b..907854dd89 100644 --- a/Content.Server/GameObjects/Components/Weapon/Melee/StunbatonComponent.cs +++ b/Content.Server/GameObjects/Components/Weapon/Melee/StunbatonComponent.cs @@ -252,6 +252,12 @@ namespace Content.Server.GameObjects.Components.Weapon.Melee { protected override void GetData(IEntity user, StunbatonComponent component, VerbData data) { + if (!ActionBlockerSystem.CanInteract(user)) + { + data.Visibility = VerbVisibility.Invisible; + return; + } + if (component.Cell == null) { data.Text = "Eject cell (cell missing)"; diff --git a/Content.Server/GameObjects/Components/Weapon/Ranged/Ammunition/AmmoBoxComponent.cs b/Content.Server/GameObjects/Components/Weapon/Ranged/Ammunition/AmmoBoxComponent.cs index 5918dae974..40d48ee25b 100644 --- a/Content.Server/GameObjects/Components/Weapon/Ranged/Ammunition/AmmoBoxComponent.cs +++ b/Content.Server/GameObjects/Components/Weapon/Ranged/Ammunition/AmmoBoxComponent.cs @@ -63,9 +63,9 @@ namespace Content.Server.GameObjects.Components.Weapon.Ranged.Ammunition _ammoContainer.Insert(entity); } } - + } - + void IMapInit.MapInit() { _unspawnedCount += _capacity; @@ -117,7 +117,7 @@ namespace Content.Server.GameObjects.Components.Weapon.Ranged.Ammunition Owner.PopupMessage(user, Loc.GetString("No room")); return false; } - + _spawnedAmmo.Push(entity); _ammoContainer.Insert(entity); UpdateAppearance(); @@ -136,7 +136,7 @@ namespace Content.Server.GameObjects.Components.Weapon.Ranged.Ammunition for (var i = 0; i < Math.Max(10, rangedMagazine.ShotsLeft); i++) { var ammo = rangedMagazine.TakeAmmo(); - + if (!TryInsertAmmo(eventArgs.User, ammo)) { rangedMagazine.TryInsertAmmo(eventArgs.User, ammo); @@ -146,7 +146,7 @@ namespace Content.Server.GameObjects.Components.Weapon.Ranged.Ammunition return true; } - + return false; } @@ -175,7 +175,7 @@ namespace Content.Server.GameObjects.Components.Weapon.Ranged.Ammunition { var ejectCount = Math.Min(count, Capacity); var ejectAmmo = new List(ejectCount); - + for (var i = 0; i < Math.Min(count, Capacity); i++) { var ammo = TakeAmmo(); @@ -200,13 +200,19 @@ namespace Content.Server.GameObjects.Components.Weapon.Ranged.Ammunition { return TryUse(eventArgs.User); } - + // So if you have 200 rounds in a box and that suddenly creates 200 entities you're not having a fun time [Verb] private sealed class DumpVerb : Verb { protected override void GetData(IEntity user, AmmoBoxComponent component, VerbData data) { + if (!ActionBlockerSystem.CanInteract(user)) + { + data.Visibility = VerbVisibility.Invisible; + return; + } + data.Text = Loc.GetString("Dump 10"); data.Visibility = component.AmmoLeft > 0 ? VerbVisibility.Visible : VerbVisibility.Disabled; } @@ -217,4 +223,4 @@ namespace Content.Server.GameObjects.Components.Weapon.Ranged.Ammunition } } } -} \ No newline at end of file +} diff --git a/Content.Server/GameObjects/Components/Weapon/Ranged/Barrels/BoltActionBarrelComponent.cs b/Content.Server/GameObjects/Components/Weapon/Ranged/Barrels/BoltActionBarrelComponent.cs index 5045361a7e..a5bfbbe7a3 100644 --- a/Content.Server/GameObjects/Components/Weapon/Ranged/Barrels/BoltActionBarrelComponent.cs +++ b/Content.Server/GameObjects/Components/Weapon/Ranged/Barrels/BoltActionBarrelComponent.cs @@ -28,7 +28,7 @@ namespace Content.Server.GameObjects.Components.Weapon.Ranged.Barrels { // Originally I had this logic shared with PumpBarrel and used a couple of variables to control things // but it felt a lot messier to play around with, especially when adding verbs - + public override string Name => "BoltActionBarrel"; public override int ShotsLeft @@ -62,7 +62,7 @@ namespace Content.Server.GameObjects.Components.Weapon.Ranged.Barrels } var soundSystem = EntitySystem.Get(); - + if (value) { if (_soundBoltOpen != null) @@ -77,7 +77,7 @@ namespace Content.Server.GameObjects.Components.Weapon.Ranged.Barrels soundSystem.PlayAtCoords(_soundBoltClosed, Owner.Transform.GridPosition, AudioParams.Default.WithVolume(-2)); } } - + _boltOpen = value; UpdateAppearance(); } @@ -105,7 +105,7 @@ namespace Content.Server.GameObjects.Components.Weapon.Ranged.Barrels serializer.DataField(ref _soundBoltClosed, "soundBoltClosed", "/Audio/Guns/Bolt/rifle_bolt_closed.ogg"); serializer.DataField(ref _soundInsert, "soundInsert", "/Audio/Guns/MagIn/bullet_insert.ogg"); } - + void IMapInit.MapInit() { if (_fillPrototype != null) @@ -137,7 +137,7 @@ namespace Content.Server.GameObjects.Components.Weapon.Ranged.Barrels { _appearanceComponent = appearanceComponent; } - + _appearanceComponent?.SetData(MagazineBarrelVisuals.MagLoaded, true); UpdateAppearance(); } @@ -183,7 +183,7 @@ namespace Content.Server.GameObjects.Components.Weapon.Ranged.Barrels var ammoComponent = chamberedEntity.GetComponent(); if (!ammoComponent.Caseless) { - EjectCasing(chamberedEntity); + EjectCasing(chamberedEntity); } } @@ -216,7 +216,7 @@ namespace Content.Server.GameObjects.Components.Weapon.Ranged.Barrels EntitySystem.Get().PlayAtCoords(_soundCycle, Owner.Transform.GridPosition, AudioParams.Default.WithVolume(-2)); } } - + Dirty(); UpdateAppearance(); } @@ -264,9 +264,9 @@ namespace Content.Server.GameObjects.Components.Weapon.Ranged.Barrels UpdateAppearance(); return true; } - + Owner.PopupMessage(user, Loc.GetString("No room")); - + return false; } @@ -279,7 +279,7 @@ namespace Content.Server.GameObjects.Components.Weapon.Ranged.Barrels // Dirty(); return true; } - + Cycle(true); return true; } @@ -288,12 +288,18 @@ namespace Content.Server.GameObjects.Components.Weapon.Ranged.Barrels { return TryInsertBullet(eventArgs.User, eventArgs.Using); } - + [Verb] private sealed class OpenBoltVerb : Verb { protected override void GetData(IEntity user, BoltActionBarrelComponent component, VerbData data) { + if (!ActionBlockerSystem.CanInteract(user)) + { + data.Visibility = VerbVisibility.Invisible; + return; + } + data.Text = Loc.GetString("Open bolt"); data.Visibility = component.BoltOpen ? VerbVisibility.Disabled : VerbVisibility.Visible; } @@ -303,12 +309,18 @@ namespace Content.Server.GameObjects.Components.Weapon.Ranged.Barrels component.BoltOpen = true; } } - + [Verb] private sealed class CloseBoltVerb : Verb { protected override void GetData(IEntity user, BoltActionBarrelComponent component, VerbData data) { + if (!ActionBlockerSystem.CanInteract(user)) + { + data.Visibility = VerbVisibility.Invisible; + return; + } + data.Text = Loc.GetString("Close bolt"); data.Visibility = component.BoltOpen ? VerbVisibility.Visible : VerbVisibility.Disabled; } @@ -319,4 +331,4 @@ namespace Content.Server.GameObjects.Components.Weapon.Ranged.Barrels } } } -} \ No newline at end of file +} diff --git a/Content.Server/GameObjects/Components/Weapon/Ranged/Barrels/RevolverBarrelComponent.cs b/Content.Server/GameObjects/Components/Weapon/Ranged/Barrels/RevolverBarrelComponent.cs index f9caf303b6..d5f5540f28 100644 --- a/Content.Server/GameObjects/Components/Weapon/Ranged/Barrels/RevolverBarrelComponent.cs +++ b/Content.Server/GameObjects/Components/Weapon/Ranged/Barrels/RevolverBarrelComponent.cs @@ -221,6 +221,12 @@ namespace Content.Server.GameObjects.Components.Weapon.Ranged.Barrels { protected override void GetData(IEntity user, RevolverBarrelComponent component, VerbData data) { + if (!ActionBlockerSystem.CanInteract(user)) + { + data.Visibility = VerbVisibility.Invisible; + return; + } + data.Text = Loc.GetString("Spin"); if (component.Capacity <= 1) { diff --git a/Content.Server/GameObjects/Components/Weapon/Ranged/Barrels/ServerMagazineBarrelComponent.cs b/Content.Server/GameObjects/Components/Weapon/Ranged/Barrels/ServerMagazineBarrelComponent.cs index a38b47f002..d4863587a7 100644 --- a/Content.Server/GameObjects/Components/Weapon/Ranged/Barrels/ServerMagazineBarrelComponent.cs +++ b/Content.Server/GameObjects/Components/Weapon/Ranged/Barrels/ServerMagazineBarrelComponent.cs @@ -26,7 +26,7 @@ namespace Content.Server.GameObjects.Components.Weapon.Ranged.Barrels { public override string Name => "MagazineBarrel"; public override uint? NetID => ContentNetIDs.MAGAZINE_BARREL; - + private ContainerSlot _chamberContainer; [ViewVariables] public bool HasMagazine => _magazineContainer.ContainedEntity != null; private ContainerSlot _magazineContainer; @@ -118,11 +118,11 @@ namespace Content.Server.GameObjects.Components.Weapon.Ranged.Barrels { count = (rangedMagazineComponent.ShotsLeft, rangedMagazineComponent.Capacity); } - + return new MagazineBarrelComponentState( - _chamberContainer.ContainedEntity != null, - FireRateSelector, - count, + _chamberContainer.ContainedEntity != null, + FireRateSelector, + count, SoundGunshot); } @@ -134,7 +134,7 @@ namespace Content.Server.GameObjects.Components.Weapon.Ranged.Barrels { _appearanceComponent = appearanceComponent; } - + _chamberContainer = ContainerManagerComponent.Ensure($"{Name}-chamber", Owner); _magazineContainer = ContainerManagerComponent.Ensure($"{Name}-magazine", Owner); } @@ -194,7 +194,7 @@ namespace Content.Server.GameObjects.Components.Weapon.Ranged.Barrels var ammoComponent = chamberEntity.GetComponent(); if (!ammoComponent.Caseless) { - EjectCasing(chamberEntity); + EjectCasing(chamberEntity); } } @@ -207,7 +207,7 @@ namespace Content.Server.GameObjects.Components.Weapon.Ranged.Barrels // If you're really into gunporn you could put a sound here _chamberContainer.Insert(nextRound); } - + var soundSystem = EntitySystem.Get(); if (_autoEjectMag && magazine != null && magazine.GetComponent().ShotsLeft == 0) @@ -245,7 +245,7 @@ namespace Content.Server.GameObjects.Components.Weapon.Ranged.Barrels soundSystem.PlayAtCoords(_soundRack, Owner.Transform.GridPosition, AudioParams.Default.WithVolume(-2)); } } - + Dirty(); UpdateAppearance(); } @@ -310,7 +310,7 @@ namespace Content.Server.GameObjects.Components.Weapon.Ranged.Barrels { handsComponent.PutInHandOrDrop(mag.GetComponent()); } - + Dirty(); UpdateAppearance(); } @@ -385,12 +385,18 @@ namespace Content.Server.GameObjects.Components.Weapon.Ranged.Barrels return false; } - + [Verb] private sealed class EjectMagazineVerb : Verb { protected override void GetData(IEntity user, ServerMagazineBarrelComponent component, VerbData data) { + if (!ActionBlockerSystem.CanInteract(user)) + { + data.Visibility = VerbVisibility.Invisible; + return; + } + data.Text = Loc.GetString("Eject magazine"); if (component.MagNeedsOpenBolt) { @@ -408,12 +414,18 @@ namespace Content.Server.GameObjects.Components.Weapon.Ranged.Barrels component.RemoveMagazine(user); } } - + [Verb] private sealed class OpenBoltVerb : Verb { protected override void GetData(IEntity user, ServerMagazineBarrelComponent component, VerbData data) { + if (!ActionBlockerSystem.CanInteract(user)) + { + data.Visibility = VerbVisibility.Invisible; + return; + } + data.Text = Loc.GetString("Open bolt"); data.Visibility = component.BoltOpen ? VerbVisibility.Disabled : VerbVisibility.Visible; } @@ -423,12 +435,18 @@ namespace Content.Server.GameObjects.Components.Weapon.Ranged.Barrels component.ToggleBolt(); } } - + [Verb] private sealed class CloseBoltVerb : Verb { protected override void GetData(IEntity user, ServerMagazineBarrelComponent component, VerbData data) { + if (!ActionBlockerSystem.CanInteract(user)) + { + data.Visibility = VerbVisibility.Invisible; + return; + } + data.Text = Loc.GetString("Close bolt"); data.Visibility = component.BoltOpen ? VerbVisibility.Visible : VerbVisibility.Disabled; } From 805a5f16895292fe1fc85e2782082b108f7e7c3b Mon Sep 17 00:00:00 2001 From: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com> Date: Tue, 23 Jun 2020 02:55:50 +1000 Subject: [PATCH 08/25] Refactor pathfinding updates and add AccessReader support (#1183) There was some extra bloat in the path graph updates. Now the queue should also just run if it gets too big regardless. Un-anchored physics objects are no longer a hard fail for pathfinding. Add AccessReader support so open / close doors show up for pathfinding AI also ensure they call the operator's shutdown when they're shutdown so that should cancel the pathfinding job. I tried to split these into 2 commits but they were kinda coupled together Co-authored-by: Metal Gear Sloth --- .../AI/Operators/Movement/BaseMover.cs | 4 +- .../Actions/Combat/Melee/MeleeAttackEntity.cs | 10 +- .../AI/Utility/AiLogic/UtilityAI.cs | 3 + .../Access/AccessReaderChangeMessage.cs | 16 + .../Access/AccessReaderComponent.cs | 2 +- .../Components/Doors/ServerDoorComponent.cs | 3 + .../GraphUpdates/CollidableMove.cs | 14 - .../GraphUpdates/CollisionChange.cs | 16 - .../Pathfinding/GraphUpdates/GridRemoval.cs | 14 - .../GraphUpdates/IPathfindingGraphUpdate.cs | 7 - .../AI/Pathfinding/GraphUpdates/TileUpdate.cs | 14 - .../Pathfinders/AStarPathfindingJob.cs | 10 +- .../Pathfinders/JpsPathfindingJob.cs | 26 +- .../Pathfinders/PathfindingArgs.cs | 4 + .../{Utils.cs => PathfindingHelpers.cs} | 62 ++-- .../AI/Pathfinding/PathfindingNode.cs | 102 +++++-- .../AI/Pathfinding/PathfindingSystem.cs | 276 ++++++++++++------ 17 files changed, 362 insertions(+), 221 deletions(-) create mode 100644 Content.Server/GameObjects/Components/Access/AccessReaderChangeMessage.cs delete mode 100644 Content.Server/GameObjects/EntitySystems/AI/Pathfinding/GraphUpdates/CollidableMove.cs delete mode 100644 Content.Server/GameObjects/EntitySystems/AI/Pathfinding/GraphUpdates/CollisionChange.cs delete mode 100644 Content.Server/GameObjects/EntitySystems/AI/Pathfinding/GraphUpdates/GridRemoval.cs delete mode 100644 Content.Server/GameObjects/EntitySystems/AI/Pathfinding/GraphUpdates/IPathfindingGraphUpdate.cs delete mode 100644 Content.Server/GameObjects/EntitySystems/AI/Pathfinding/GraphUpdates/TileUpdate.cs rename Content.Server/GameObjects/EntitySystems/AI/Pathfinding/{Utils.cs => PathfindingHelpers.cs} (79%) diff --git a/Content.Server/AI/Operators/Movement/BaseMover.cs b/Content.Server/AI/Operators/Movement/BaseMover.cs index d17472378f..cbbd5acdae 100644 --- a/Content.Server/AI/Operators/Movement/BaseMover.cs +++ b/Content.Server/AI/Operators/Movement/BaseMover.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Threading; +using Content.Server.GameObjects.Components.Access; using Content.Server.GameObjects.Components.Movement; using Content.Server.GameObjects.EntitySystems; using Content.Server.GameObjects.EntitySystems.AI.Pathfinding; @@ -240,10 +241,11 @@ namespace Content.Server.AI.Operators.Movement var startGrid = _mapManager.GetGrid(Owner.Transform.GridID).GetTileRef(Owner.Transform.GridPosition); var endGrid = _mapManager.GetGrid(TargetGrid.GridID).GetTileRef(TargetGrid);; - // _routeCancelToken = new CancellationTokenSource(); + var access = AccessReader.FindAccessTags(Owner); RouteJob = _pathfinder.RequestPath(new PathfindingArgs( Owner.Uid, + access, collisionMask, startGrid, endGrid, diff --git a/Content.Server/AI/Utility/Actions/Combat/Melee/MeleeAttackEntity.cs b/Content.Server/AI/Utility/Actions/Combat/Melee/MeleeAttackEntity.cs index 081a569423..25f329fdc1 100644 --- a/Content.Server/AI/Utility/Actions/Combat/Melee/MeleeAttackEntity.cs +++ b/Content.Server/AI/Utility/Actions/Combat/Melee/MeleeAttackEntity.cs @@ -29,11 +29,17 @@ namespace Content.Server.AI.Utility.Actions.Combat.Melee public override void SetupOperators(Blackboard context) { - var moveOperator = new MoveToEntityOperator(Owner, _entity); var equipped = context.GetState().GetValue(); + MoveToEntityOperator moveOperator; if (equipped != null && equipped.TryGetComponent(out MeleeWeaponComponent meleeWeaponComponent)) { - moveOperator.DesiredRange = meleeWeaponComponent.Range - 0.01f; + moveOperator = new MoveToEntityOperator(Owner, _entity, meleeWeaponComponent.Range - 0.01f); + } + // I think it's possible for this to happen given planning is time-sliced? + // TODO: At this point we should abort + else + { + moveOperator = new MoveToEntityOperator(Owner, _entity); } ActionOperators = new Queue(new AiOperator[] diff --git a/Content.Server/AI/Utility/AiLogic/UtilityAI.cs b/Content.Server/AI/Utility/AiLogic/UtilityAI.cs index 82d076ba1a..e886d0ff61 100644 --- a/Content.Server/AI/Utility/AiLogic/UtilityAI.cs +++ b/Content.Server/AI/Utility/AiLogic/UtilityAI.cs @@ -126,6 +126,9 @@ namespace Content.Server.AI.Utility.AiLogic { damageableComponent.DamageThresholdPassed -= DeathHandle; } + + var currentOp = CurrentAction?.ActionOperators.Peek(); + currentOp?.Shutdown(Outcome.Failed); } private void DeathHandle(object sender, DamageThresholdPassedEventArgs eventArgs) diff --git a/Content.Server/GameObjects/Components/Access/AccessReaderChangeMessage.cs b/Content.Server/GameObjects/Components/Access/AccessReaderChangeMessage.cs new file mode 100644 index 0000000000..cc1ae73793 --- /dev/null +++ b/Content.Server/GameObjects/Components/Access/AccessReaderChangeMessage.cs @@ -0,0 +1,16 @@ +using Robust.Shared.GameObjects; + +namespace Content.Server.GameObjects.Components.Access +{ + public sealed class AccessReaderChangeMessage : EntitySystemMessage + { + public EntityUid Uid { get; } + public bool Enabled { get; } + + public AccessReaderChangeMessage(EntityUid uid, bool enabled) + { + Uid = uid; + Enabled = enabled; + } + } +} \ No newline at end of file diff --git a/Content.Server/GameObjects/Components/Access/AccessReaderComponent.cs b/Content.Server/GameObjects/Components/Access/AccessReaderComponent.cs index f9e6c07a9d..2a1d18ac41 100644 --- a/Content.Server/GameObjects/Components/Access/AccessReaderComponent.cs +++ b/Content.Server/GameObjects/Components/Access/AccessReaderComponent.cs @@ -69,7 +69,7 @@ namespace Content.Server.GameObjects.Components.Access } [CanBeNull] - private static ICollection FindAccessTags(IEntity entity) + public static ICollection FindAccessTags(IEntity entity) { if (entity.TryGetComponent(out IAccess accessComponent)) { diff --git a/Content.Server/GameObjects/Components/Doors/ServerDoorComponent.cs b/Content.Server/GameObjects/Components/Doors/ServerDoorComponent.cs index 68d0c9847a..5ace07e054 100644 --- a/Content.Server/GameObjects/Components/Doors/ServerDoorComponent.cs +++ b/Content.Server/GameObjects/Components/Doors/ServerDoorComponent.cs @@ -154,6 +154,8 @@ namespace Content.Server.GameObjects State = DoorState.Open; SetAppearance(DoorVisualState.Open); }, _cancellationTokenSource.Token); + + Owner.EntityManager.EventBus.RaiseEvent(EventSource.Local, new AccessReaderChangeMessage(Owner.Uid, false)); } public virtual bool CanClose() @@ -203,6 +205,7 @@ namespace Content.Server.GameObjects occluder.Enabled = true; } }, _cancellationTokenSource.Token); + Owner.EntityManager.EventBus.RaiseEvent(EventSource.Local, new AccessReaderChangeMessage(Owner.Uid, true)); return true; } diff --git a/Content.Server/GameObjects/EntitySystems/AI/Pathfinding/GraphUpdates/CollidableMove.cs b/Content.Server/GameObjects/EntitySystems/AI/Pathfinding/GraphUpdates/CollidableMove.cs deleted file mode 100644 index e5df90943d..0000000000 --- a/Content.Server/GameObjects/EntitySystems/AI/Pathfinding/GraphUpdates/CollidableMove.cs +++ /dev/null @@ -1,14 +0,0 @@ -using Robust.Shared.GameObjects.Components.Transform; - -namespace Content.Server.GameObjects.EntitySystems.AI.Pathfinding.GraphUpdates -{ - public struct CollidableMove : IPathfindingGraphUpdate - { - public MoveEvent MoveEvent { get; } - - public CollidableMove(MoveEvent moveEvent) - { - MoveEvent = moveEvent; - } - } -} diff --git a/Content.Server/GameObjects/EntitySystems/AI/Pathfinding/GraphUpdates/CollisionChange.cs b/Content.Server/GameObjects/EntitySystems/AI/Pathfinding/GraphUpdates/CollisionChange.cs deleted file mode 100644 index 0d7dde253a..0000000000 --- a/Content.Server/GameObjects/EntitySystems/AI/Pathfinding/GraphUpdates/CollisionChange.cs +++ /dev/null @@ -1,16 +0,0 @@ -using Robust.Shared.Interfaces.GameObjects; - -namespace Content.Server.GameObjects.EntitySystems.AI.Pathfinding.GraphUpdates -{ - public class CollisionChange : IPathfindingGraphUpdate - { - public IEntity Owner { get; } - public bool Value { get; } - - public CollisionChange(IEntity owner, bool value) - { - Owner = owner; - Value = value; - } - } -} diff --git a/Content.Server/GameObjects/EntitySystems/AI/Pathfinding/GraphUpdates/GridRemoval.cs b/Content.Server/GameObjects/EntitySystems/AI/Pathfinding/GraphUpdates/GridRemoval.cs deleted file mode 100644 index 30ee86f2aa..0000000000 --- a/Content.Server/GameObjects/EntitySystems/AI/Pathfinding/GraphUpdates/GridRemoval.cs +++ /dev/null @@ -1,14 +0,0 @@ -using Robust.Shared.Map; - -namespace Content.Server.GameObjects.EntitySystems.AI.Pathfinding.GraphUpdates -{ - public struct GridRemoval : IPathfindingGraphUpdate - { - public GridId GridId { get; } - - public GridRemoval(GridId gridId) - { - GridId = gridId; - } - } -} diff --git a/Content.Server/GameObjects/EntitySystems/AI/Pathfinding/GraphUpdates/IPathfindingGraphUpdate.cs b/Content.Server/GameObjects/EntitySystems/AI/Pathfinding/GraphUpdates/IPathfindingGraphUpdate.cs deleted file mode 100644 index 69aa5c1eac..0000000000 --- a/Content.Server/GameObjects/EntitySystems/AI/Pathfinding/GraphUpdates/IPathfindingGraphUpdate.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace Content.Server.GameObjects.EntitySystems.AI.Pathfinding.GraphUpdates -{ - public interface IPathfindingGraphUpdate - { - - } -} diff --git a/Content.Server/GameObjects/EntitySystems/AI/Pathfinding/GraphUpdates/TileUpdate.cs b/Content.Server/GameObjects/EntitySystems/AI/Pathfinding/GraphUpdates/TileUpdate.cs deleted file mode 100644 index 501e4dabb8..0000000000 --- a/Content.Server/GameObjects/EntitySystems/AI/Pathfinding/GraphUpdates/TileUpdate.cs +++ /dev/null @@ -1,14 +0,0 @@ -using Robust.Shared.Map; - -namespace Content.Server.GameObjects.EntitySystems.AI.Pathfinding.GraphUpdates -{ - public struct TileUpdate : IPathfindingGraphUpdate - { - public TileUpdate(TileRef tile) - { - Tile = tile; - } - - public TileRef Tile { get; } - } -} diff --git a/Content.Server/GameObjects/EntitySystems/AI/Pathfinding/Pathfinders/AStarPathfindingJob.cs b/Content.Server/GameObjects/EntitySystems/AI/Pathfinding/Pathfinders/AStarPathfindingJob.cs index 1ac13372ad..e69b9e06d8 100644 --- a/Content.Server/GameObjects/EntitySystems/AI/Pathfinding/Pathfinders/AStarPathfindingJob.cs +++ b/Content.Server/GameObjects/EntitySystems/AI/Pathfinding/Pathfinders/AStarPathfindingJob.cs @@ -41,7 +41,7 @@ namespace Content.Server.GameObjects.EntitySystems.AI.Pathfinding.Pathfinders } // If we couldn't get a nearby node that's good enough - if (!Utils.TryEndNode(ref _endNode, _pathfindingArgs)) + if (!PathfindingHelpers.TryEndNode(ref _endNode, _pathfindingArgs)) { return null; } @@ -88,9 +88,9 @@ namespace Content.Server.GameObjects.EntitySystems.AI.Pathfinding.Pathfinders } // If tile is untraversable it'll be null - var tileCost = Utils.GetTileCost(_pathfindingArgs, currentNode, nextNode); + var tileCost = PathfindingHelpers.GetTileCost(_pathfindingArgs, currentNode, nextNode); - if (tileCost == null || !Utils.DirectionTraversable(_pathfindingArgs.CollisionMask, currentNode, direction)) + if (tileCost == null || !PathfindingHelpers.DirectionTraversable(_pathfindingArgs.CollisionMask, _pathfindingArgs.Access, currentNode, direction)) { continue; } @@ -107,7 +107,7 @@ namespace Content.Server.GameObjects.EntitySystems.AI.Pathfinding.Pathfinders // pFactor is tie-breaker where the fscore is otherwise equal. // See http://theory.stanford.edu/~amitp/GameProgramming/Heuristics.html#breaking-ties // There's other ways to do it but future consideration - var fScore = gScores[nextNode] + Utils.OctileDistance(_endNode, nextNode) * (1.0f + 1.0f / 1000.0f); + var fScore = gScores[nextNode] + PathfindingHelpers.OctileDistance(_endNode, nextNode) * (1.0f + 1.0f / 1000.0f); openTiles.Add((fScore, nextNode)); } } @@ -117,7 +117,7 @@ namespace Content.Server.GameObjects.EntitySystems.AI.Pathfinding.Pathfinders return null; } - var route = Utils.ReconstructPath(cameFrom, currentNode); + var route = PathfindingHelpers.ReconstructPath(cameFrom, currentNode); if (route.Count == 1) { diff --git a/Content.Server/GameObjects/EntitySystems/AI/Pathfinding/Pathfinders/JpsPathfindingJob.cs b/Content.Server/GameObjects/EntitySystems/AI/Pathfinding/Pathfinders/JpsPathfindingJob.cs index 2b12b1b456..ffae0d7d89 100644 --- a/Content.Server/GameObjects/EntitySystems/AI/Pathfinding/Pathfinders/JpsPathfindingJob.cs +++ b/Content.Server/GameObjects/EntitySystems/AI/Pathfinding/Pathfinders/JpsPathfindingJob.cs @@ -41,7 +41,7 @@ namespace Content.Server.GameObjects.EntitySystems.AI.Pathfinding.Pathfinders } // If we couldn't get a nearby node that's good enough - if (!Utils.TryEndNode(ref _endNode, _pathfindingArgs)) + if (!PathfindingHelpers.TryEndNode(ref _endNode, _pathfindingArgs)) { return null; } @@ -89,7 +89,7 @@ namespace Content.Server.GameObjects.EntitySystems.AI.Pathfinding.Pathfinders jumpNodes.Add(jumpNode); #endif // GetJumpPoint should already check if we can traverse to the node - var tileCost = Utils.GetTileCost(_pathfindingArgs, currentNode, jumpNode); + var tileCost = PathfindingHelpers.GetTileCost(_pathfindingArgs, currentNode, jumpNode); if (tileCost == null) { @@ -108,7 +108,7 @@ namespace Content.Server.GameObjects.EntitySystems.AI.Pathfinding.Pathfinders // pFactor is tie-breaker where the fscore is otherwise equal. // See http://theory.stanford.edu/~amitp/GameProgramming/Heuristics.html#breaking-ties // There's other ways to do it but future consideration - var fScore = gScores[jumpNode] + Utils.OctileDistance(_endNode, jumpNode) * (1.0f + 1.0f / 1000.0f); + var fScore = gScores[jumpNode] + PathfindingHelpers.OctileDistance(_endNode, jumpNode) * (1.0f + 1.0f / 1000.0f); openTiles.Add((fScore, jumpNode)); } } @@ -119,7 +119,7 @@ namespace Content.Server.GameObjects.EntitySystems.AI.Pathfinding.Pathfinders return null; } - var route = Utils.ReconstructJumpPath(cameFrom, currentNode); + var route = PathfindingHelpers.ReconstructJumpPath(cameFrom, currentNode); if (route.Count == 1) { return null; @@ -161,7 +161,7 @@ namespace Content.Server.GameObjects.EntitySystems.AI.Pathfinding.Pathfinders // We'll do opposite DirectionTraversable just because of how the method's setup // Nodes should be 2-way anyway. if (nextNode == null || - Utils.GetTileCost(_pathfindingArgs, currentNode, nextNode) == null) + PathfindingHelpers.GetTileCost(_pathfindingArgs, currentNode, nextNode) == null) { return null; } @@ -312,14 +312,14 @@ namespace Content.Server.GameObjects.EntitySystems.AI.Pathfinding.Pathfinders throw new ArgumentOutOfRangeException(); } - if ((closedNeighborOne == null || Utils.GetTileCost(_pathfindingArgs, currentNode, closedNeighborOne) == null) - && openNeighborOne != null && Utils.GetTileCost(_pathfindingArgs, currentNode, openNeighborOne) != null) + if ((closedNeighborOne == null || PathfindingHelpers.GetTileCost(_pathfindingArgs, currentNode, closedNeighborOne) == null) + && openNeighborOne != null && PathfindingHelpers.GetTileCost(_pathfindingArgs, currentNode, openNeighborOne) != null) { return true; } - if ((closedNeighborTwo == null || Utils.GetTileCost(_pathfindingArgs, currentNode, closedNeighborTwo) == null) - && openNeighborTwo != null && Utils.GetTileCost(_pathfindingArgs, currentNode, openNeighborTwo) != null) + if ((closedNeighborTwo == null || PathfindingHelpers.GetTileCost(_pathfindingArgs, currentNode, closedNeighborTwo) == null) + && openNeighborTwo != null && PathfindingHelpers.GetTileCost(_pathfindingArgs, currentNode, openNeighborTwo) != null) { return true; } @@ -371,14 +371,14 @@ namespace Content.Server.GameObjects.EntitySystems.AI.Pathfinding.Pathfinders throw new ArgumentOutOfRangeException(); } - if ((closedNeighborOne == null || !Utils.Traversable(_pathfindingArgs.CollisionMask, closedNeighborOne.CollisionMask)) && - (openNeighborOne != null && Utils.Traversable(_pathfindingArgs.CollisionMask, openNeighborOne.CollisionMask))) + if ((closedNeighborOne == null || !PathfindingHelpers.Traversable(_pathfindingArgs.CollisionMask, _pathfindingArgs.Access, closedNeighborOne)) && + (openNeighborOne != null && PathfindingHelpers.Traversable(_pathfindingArgs.CollisionMask, _pathfindingArgs.Access, openNeighborOne))) { return true; } - if ((closedNeighborTwo == null || !Utils.Traversable(_pathfindingArgs.CollisionMask, closedNeighborTwo.CollisionMask)) && - (openNeighborTwo != null && Utils.Traversable(_pathfindingArgs.CollisionMask, openNeighborTwo.CollisionMask))) + if ((closedNeighborTwo == null || !PathfindingHelpers.Traversable(_pathfindingArgs.CollisionMask, _pathfindingArgs.Access, closedNeighborTwo)) && + (openNeighborTwo != null && PathfindingHelpers.Traversable(_pathfindingArgs.CollisionMask, _pathfindingArgs.Access, openNeighborTwo))) { return true; } diff --git a/Content.Server/GameObjects/EntitySystems/AI/Pathfinding/Pathfinders/PathfindingArgs.cs b/Content.Server/GameObjects/EntitySystems/AI/Pathfinding/Pathfinders/PathfindingArgs.cs index d2a01ea1ce..5b7e9ce3c6 100644 --- a/Content.Server/GameObjects/EntitySystems/AI/Pathfinding/Pathfinders/PathfindingArgs.cs +++ b/Content.Server/GameObjects/EntitySystems/AI/Pathfinding/Pathfinders/PathfindingArgs.cs @@ -1,3 +1,4 @@ +using System.Collections.Generic; using Robust.Shared.GameObjects; using Robust.Shared.Map; @@ -6,6 +7,7 @@ namespace Content.Server.GameObjects.EntitySystems.AI.Pathfinding.Pathfinders public struct PathfindingArgs { public EntityUid Uid { get; } + public ICollection Access { get; } public int CollisionMask { get; } public TileRef Start { get; } public TileRef End { get; } @@ -20,6 +22,7 @@ namespace Content.Server.GameObjects.EntitySystems.AI.Pathfinding.Pathfinders public PathfindingArgs( EntityUid entityUid, + ICollection access, int collisionMask, TileRef start, TileRef end, @@ -29,6 +32,7 @@ namespace Content.Server.GameObjects.EntitySystems.AI.Pathfinding.Pathfinders bool allowSpace = false) { Uid = entityUid; + Access = access; CollisionMask = collisionMask; Start = start; End = end; diff --git a/Content.Server/GameObjects/EntitySystems/AI/Pathfinding/Utils.cs b/Content.Server/GameObjects/EntitySystems/AI/Pathfinding/PathfindingHelpers.cs similarity index 79% rename from Content.Server/GameObjects/EntitySystems/AI/Pathfinding/Utils.cs rename to Content.Server/GameObjects/EntitySystems/AI/Pathfinding/PathfindingHelpers.cs index a72869db78..127c43a8d4 100644 --- a/Content.Server/GameObjects/EntitySystems/AI/Pathfinding/Utils.cs +++ b/Content.Server/GameObjects/EntitySystems/AI/Pathfinding/PathfindingHelpers.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using Content.Server.GameObjects.Components.Access; using Content.Server.GameObjects.EntitySystems.AI.Pathfinding.Pathfinders; using Content.Server.GameObjects.EntitySystems.Pathfinding; using Robust.Shared.Interfaces.GameObjects; @@ -10,19 +11,19 @@ using Robust.Shared.Maths; namespace Content.Server.GameObjects.EntitySystems.AI.Pathfinding { - public static class Utils + public static class PathfindingHelpers { public static bool TryEndNode(ref PathfindingNode endNode, PathfindingArgs pathfindingArgs) { - if (!Traversable(pathfindingArgs.CollisionMask, endNode.CollisionMask)) + if (!Traversable(pathfindingArgs.CollisionMask, pathfindingArgs.Access, endNode)) { if (pathfindingArgs.Proximity > 0.0f) { // TODO: Should make this account for proximities, // probably some kind of breadth-first search to find a valid one - foreach (var (direction, node) in endNode.Neighbors) + foreach (var (_, node) in endNode.Neighbors) { - if (Traversable(pathfindingArgs.CollisionMask, node.CollisionMask)) + if (Traversable(pathfindingArgs.CollisionMask, pathfindingArgs.Access, node)) { endNode = node; return true; @@ -36,7 +37,7 @@ namespace Content.Server.GameObjects.EntitySystems.AI.Pathfinding return true; } - public static bool DirectionTraversable(int collisionMask, PathfindingNode currentNode, Direction direction) + public static bool DirectionTraversable(int collisionMask, ICollection access, PathfindingNode currentNode, Direction direction) { // If it's a diagonal we need to check NSEW to see if we can get to it and stop corner cutting, NE needs N and E etc. // Given there's different collision layers stored for each node in the graph it's probably not worth it to cache this @@ -51,32 +52,32 @@ namespace Content.Server.GameObjects.EntitySystems.AI.Pathfinding { case Direction.NorthEast: if (northNeighbor == null || eastNeighbor == null) return false; - if (!Traversable(collisionMask, northNeighbor.CollisionMask) || - !Traversable(collisionMask, eastNeighbor.CollisionMask)) + if (!Traversable(collisionMask, access, northNeighbor) || + !Traversable(collisionMask, access, eastNeighbor)) { return false; } break; case Direction.NorthWest: if (northNeighbor == null || westNeighbor == null) return false; - if (!Traversable(collisionMask, northNeighbor.CollisionMask) || - !Traversable(collisionMask, westNeighbor.CollisionMask)) + if (!Traversable(collisionMask, access, northNeighbor) || + !Traversable(collisionMask, access, westNeighbor)) { return false; } break; case Direction.SouthWest: if (southNeighbor == null || westNeighbor == null) return false; - if (!Traversable(collisionMask, southNeighbor.CollisionMask) || - !Traversable(collisionMask, westNeighbor.CollisionMask)) + if (!Traversable(collisionMask, access, southNeighbor) || + !Traversable(collisionMask, access, westNeighbor)) { return false; } break; case Direction.SouthEast: if (southNeighbor == null || eastNeighbor == null) return false; - if (!Traversable(collisionMask, southNeighbor.CollisionMask) || - !Traversable(collisionMask, eastNeighbor.CollisionMask)) + if (!Traversable(collisionMask, access, southNeighbor) || + !Traversable(collisionMask, access, eastNeighbor)) { return false; } @@ -86,11 +87,24 @@ namespace Content.Server.GameObjects.EntitySystems.AI.Pathfinding return true; } - public static bool Traversable(int collisionMask, int nodeMask) + public static bool Traversable(int collisionMask, ICollection access, PathfindingNode node) { - return (collisionMask & nodeMask) == 0; - } + if ((collisionMask & node.BlockedCollisionMask) != 0) + { + return false; + } + foreach (var reader in node.AccessReaders) + { + if (!reader.IsAllowed(access)) + { + return false; + } + } + + return true; + } + public static Queue ReconstructPath(Dictionary cameFrom, PathfindingNode current) { var running = new Stack(); @@ -194,6 +208,20 @@ namespace Content.Server.GameObjects.EntitySystems.AI.Pathfinding return 1.4f * dstX + (dstY - dstX); } + + public static float OctileDistance(TileRef endTile, TileRef startTile) + { + // "Fast Euclidean" / octile. + // This implementation is written down in a few sources; it just saves doing sqrt. + int dstX = Math.Abs(startTile.X - endTile.X); + int dstY = Math.Abs(startTile.Y - endTile.Y); + if (dstX > dstY) + { + return 1.4f * dstY + (dstX - dstY); + } + + return 1.4f * dstX + (dstY - dstX); + } public static float ManhattanDistance(PathfindingNode endNode, PathfindingNode currentNode) { @@ -202,7 +230,7 @@ namespace Content.Server.GameObjects.EntitySystems.AI.Pathfinding public static float? GetTileCost(PathfindingArgs pathfindingArgs, PathfindingNode start, PathfindingNode end) { - if (!pathfindingArgs.NoClip && !Traversable(pathfindingArgs.CollisionMask, end.CollisionMask)) + if (!pathfindingArgs.NoClip && !Traversable(pathfindingArgs.CollisionMask, pathfindingArgs.Access, end)) { return null; } diff --git a/Content.Server/GameObjects/EntitySystems/AI/Pathfinding/PathfindingNode.cs b/Content.Server/GameObjects/EntitySystems/AI/Pathfinding/PathfindingNode.cs index b9b110a566..262631a4b3 100644 --- a/Content.Server/GameObjects/EntitySystems/AI/Pathfinding/PathfindingNode.cs +++ b/Content.Server/GameObjects/EntitySystems/AI/Pathfinding/PathfindingNode.cs @@ -1,6 +1,12 @@ using System; using System.Collections.Generic; +using Content.Server.GameObjects.Components.Access; +using Content.Server.GameObjects.Components.Doors; using Content.Server.GameObjects.EntitySystems.AI.Pathfinding; +using Robust.Server.GameObjects; +using Robust.Shared.GameObjects; +using Robust.Shared.GameObjects.Components; +using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.Map; using Robust.Shared.Maths; @@ -8,27 +14,34 @@ namespace Content.Server.GameObjects.EntitySystems.Pathfinding { public class PathfindingNode { - // TODO: Add access ID here public PathfindingChunk ParentChunk => _parentChunk; private readonly PathfindingChunk _parentChunk; - public TileRef TileRef { get; private set; } - public List CollisionLayers { get; } - public int CollisionMask { get; private set; } + public Dictionary Neighbors => _neighbors; private Dictionary _neighbors = new Dictionary(); + + public TileRef TileRef { get; private set; } + + /// + /// Whenever there's a change in the collision layers we update the mask as the graph has more reads than writes + /// + public int BlockedCollisionMask { get; private set; } + private readonly Dictionary _blockedCollidables = new Dictionary(0); - public PathfindingNode(PathfindingChunk parent, TileRef tileRef, List collisionLayers = null) + public IReadOnlyCollection PhysicsUids => _physicsUids; + private readonly HashSet _physicsUids = new HashSet(0); + + /// + /// The entities on this tile that require access to traverse + /// + /// We don't store the ICollection, at least for now, as we'd need to replicate the access code here + public IReadOnlyCollection AccessReaders => _accessReaders.Values; + private readonly Dictionary _accessReaders = new Dictionary(0); + + public PathfindingNode(PathfindingChunk parent, TileRef tileRef) { _parentChunk = parent; TileRef = tileRef; - if (collisionLayers == null) - { - CollisionLayers = new List(); - } - else - { - CollisionLayers = collisionLayers; - } GenerateMask(); } @@ -105,25 +118,70 @@ namespace Content.Server.GameObjects.EntitySystems.Pathfinding TileRef = newTile; } - public void AddCollisionLayer(int layer) + /// + /// Call if this entity is relevant for the pathfinder + /// + /// + /// TODO: These 2 methods currently don't account for a bunch of changes (e.g. airlock unpowered, wrenching, etc.) + public void AddEntity(IEntity entity) { - CollisionLayers.Add(layer); - GenerateMask(); + // If we're a door + if (entity.HasComponent() || entity.HasComponent()) + { + // If we need access to traverse this then add to readers, otherwise no point adding it (except for maybe tile costs in future) + // TODO: Check for powered I think (also need an event for when it's depowered + // AccessReader calls this whenever opening / closing but it can seem to get called multiple times + // Which may or may not be intended? + if (entity.TryGetComponent(out AccessReader accessReader) && !_accessReaders.ContainsKey(entity.Uid)) + { + _accessReaders.Add(entity.Uid, accessReader); + } + return; + } + + if (entity.TryGetComponent(out CollidableComponent collidableComponent)) + { + if (entity.TryGetComponent(out PhysicsComponent physicsComponent) && !physicsComponent.Anchored) + { + _physicsUids.Add(entity.Uid); + } + else + { + _blockedCollidables.TryAdd(entity.Uid, collidableComponent.CollisionLayer); + GenerateMask(); + } + } } - public void RemoveCollisionLayer(int layer) + public void RemoveEntity(IEntity entity) { - CollisionLayers.Remove(layer); - GenerateMask(); + if (_accessReaders.ContainsKey(entity.Uid)) + { + _accessReaders.Remove(entity.Uid); + return; + } + + if (entity.HasComponent()) + { + if (entity.TryGetComponent(out PhysicsComponent physicsComponent) && physicsComponent.Anchored) + { + _blockedCollidables.Remove(entity.Uid); + GenerateMask(); + } + else + { + _physicsUids.Remove(entity.Uid); + } + } } private void GenerateMask() { - CollisionMask = 0x0; + BlockedCollisionMask = 0x0; - foreach (var layer in CollisionLayers) + foreach (var layer in _blockedCollidables.Values) { - CollisionMask |= layer; + BlockedCollisionMask |= layer; } } } diff --git a/Content.Server/GameObjects/EntitySystems/AI/Pathfinding/PathfindingSystem.cs b/Content.Server/GameObjects/EntitySystems/AI/Pathfinding/PathfindingSystem.cs index 07c4273664..62a8479306 100644 --- a/Content.Server/GameObjects/EntitySystems/AI/Pathfinding/PathfindingSystem.cs +++ b/Content.Server/GameObjects/EntitySystems/AI/Pathfinding/PathfindingSystem.cs @@ -1,12 +1,12 @@ using System; using System.Collections.Generic; using System.Threading; -using Content.Server.GameObjects.Components.Doors; -using Content.Server.GameObjects.EntitySystems.AI.Pathfinding.GraphUpdates; +using Content.Server.GameObjects.Components.Access; using Content.Server.GameObjects.EntitySystems.AI.Pathfinding.Pathfinders; using Content.Server.GameObjects.EntitySystems.JobQueues; using Content.Server.GameObjects.EntitySystems.JobQueues.Queues; using Content.Server.GameObjects.EntitySystems.Pathfinding; +using Content.Shared.Physics; using Robust.Shared.GameObjects.Components; using Robust.Shared.GameObjects.Components.Transform; using Robust.Shared.GameObjects.Systems; @@ -14,6 +14,7 @@ using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.Interfaces.Map; using Robust.Shared.IoC; using Robust.Shared.Map; +using Robust.Shared.Utility; namespace Content.Server.GameObjects.EntitySystems.AI.Pathfinding { @@ -29,18 +30,30 @@ namespace Content.Server.GameObjects.EntitySystems.AI.Pathfinding public class PathfindingSystem : EntitySystem { #pragma warning disable 649 + [Dependency] private readonly IEntityManager _entitymanager; [Dependency] private readonly IMapManager _mapManager; #pragma warning restore 649 public IReadOnlyDictionary> Graph => _graph; private readonly Dictionary> _graph = new Dictionary>(); - // Every tick we queue up all the changes and do them at once - private readonly Queue _queuedGraphUpdates = new Queue(); + private readonly PathfindingJobQueue _pathfindingQueue = new PathfindingJobQueue(); + + // Queued pathfinding graph updates + private readonly Queue _collidableUpdateQueue = new Queue(); + private readonly Queue _moveUpdateQueue = new Queue(); + private readonly Queue _accessReaderUpdateQueue = new Queue(); + private readonly Queue _tileUpdateQueue = new Queue(); // Need to store previously known entity positions for collidables for when they move private readonly Dictionary _lastKnownPositions = new Dictionary(); + public const int TrackedCollisionLayers = (int) + (CollisionGroup.Impassable | + CollisionGroup.MobImpassable | + CollisionGroup.SmallImpassable | + CollisionGroup.VaultImpassable); + /// /// Ask for the pathfinder to gimme somethin /// @@ -68,51 +81,66 @@ namespace Content.Server.GameObjects.EntitySystems.AI.Pathfinding private void ProcessGraphUpdates() { - for (var i = 0; i < Math.Min(50, _queuedGraphUpdates.Count); i++) + var totalUpdates = 0; + + foreach (var update in _collidableUpdateQueue) { - var update = _queuedGraphUpdates.Dequeue(); - switch (update) + var entity = _entitymanager.GetEntity(update.Owner); + if (update.CanCollide) { - case CollidableMove move: - HandleCollidableMove(move); - break; - case CollisionChange change: - if (change.Value) - { - HandleCollidableAdd(change.Owner); - } - else - { - HandleCollidableRemove(change.Owner); - } - - break; - case GridRemoval removal: - HandleGridRemoval(removal); - break; - case TileUpdate tile: - HandleTileUpdate(tile); - break; - default: - throw new ArgumentOutOfRangeException(); + HandleCollidableAdd(entity); + } + else + { + HandleAccessRemove(entity); } - } - } - private void HandleGridRemoval(GridRemoval removal) - { - if (!_graph.ContainsKey(removal.GridId)) + totalUpdates++; + } + + _collidableUpdateQueue.Clear(); + + foreach (var update in _accessReaderUpdateQueue) { - throw new InvalidOperationException(); + var entity = _entitymanager.GetEntity(update.Uid); + if (update.Enabled) + { + HandleAccessAdd(entity); + } + else + { + HandleAccessRemove(entity); + } + + totalUpdates++; + } + + _accessReaderUpdateQueue.Clear(); + + foreach (var tile in _tileUpdateQueue) + { + HandleTileUpdate(tile); + totalUpdates++; + } + + _tileUpdateQueue.Clear(); + var moveUpdateCount = Math.Max(50 - totalUpdates, 0); + + // Other updates are high priority so for this we'll just defer it if there's a spike (explosion, etc.) + // If the move updates grow too large then we'll just do it + if (_moveUpdateQueue.Count > 100) + { + moveUpdateCount = _moveUpdateQueue.Count - 100; } - _graph.Remove(removal.GridId); - } - - private void HandleTileUpdate(TileUpdate tile) - { - var chunk = GetChunk(tile.Tile); - chunk.UpdateNode(tile.Tile); + moveUpdateCount = Math.Min(moveUpdateCount, _moveUpdateQueue.Count); + + for (var i = 0; i < moveUpdateCount; i++) + { + HandleCollidableMove(_moveUpdateQueue.Dequeue()); + } + + DebugTools.Assert(_moveUpdateQueue.Count < 1000); } public PathfindingChunk GetChunk(TileRef tile) @@ -132,7 +160,6 @@ namespace Content.Server.GameObjects.EntitySystems.AI.Pathfinding } var newChunk = CreateChunk(tile.GridIndex, mapIndices); - return newChunk; } @@ -179,13 +206,13 @@ namespace Content.Server.GameObjects.EntitySystems.AI.Pathfinding public override void Initialize() { - IoCManager.InjectDependencies(this); SubscribeLocalEvent(QueueCollisionEnabledEvent); SubscribeLocalEvent(QueueCollidableMove); + SubscribeLocalEvent(QueueAccessChangeEvent); // Handle all the base grid changes // Anything that affects traversal (i.e. collision layer) is handled separately. - _mapManager.OnGridRemoved += QueueGridRemoval; + _mapManager.OnGridRemoved += HandleGridRemoval; _mapManager.GridChanged += QueueGridChange; _mapManager.TileChanged += QueueTileChange; } @@ -193,32 +220,85 @@ namespace Content.Server.GameObjects.EntitySystems.AI.Pathfinding public override void Shutdown() { base.Shutdown(); - _mapManager.OnGridRemoved -= QueueGridRemoval; + UnsubscribeLocalEvent(); + UnsubscribeLocalEvent(); + UnsubscribeLocalEvent(); + + _mapManager.OnGridRemoved -= HandleGridRemoval; _mapManager.GridChanged -= QueueGridChange; _mapManager.TileChanged -= QueueTileChange; } + + private void HandleTileUpdate(TileRef tile) + { + var node = GetNode(tile); + node.UpdateTile(tile); + } public void ResettingCleanup() { - _queuedGraphUpdates.Clear(); + _graph.Clear(); + _collidableUpdateQueue.Clear(); + _moveUpdateQueue.Clear(); + _accessReaderUpdateQueue.Clear(); + _tileUpdateQueue.Clear(); + _lastKnownPositions.Clear(); } - private void QueueGridRemoval(GridId gridId) + private void HandleGridRemoval(GridId gridId) { - _queuedGraphUpdates.Enqueue(new GridRemoval(gridId)); + if (_graph.ContainsKey(gridId)) + { + _graph.Remove(gridId); + } } private void QueueGridChange(object sender, GridChangedEventArgs eventArgs) { foreach (var (position, _) in eventArgs.Modified) { - _queuedGraphUpdates.Enqueue(new TileUpdate(eventArgs.Grid.GetTileRef(position))); + _tileUpdateQueue.Enqueue(eventArgs.Grid.GetTileRef(position)); } } private void QueueTileChange(object sender, TileChangedEventArgs eventArgs) { - _queuedGraphUpdates.Enqueue(new TileUpdate(eventArgs.NewTile)); + _tileUpdateQueue.Enqueue(eventArgs.NewTile); + } + + private void QueueAccessChangeEvent(AccessReaderChangeMessage message) + { + _accessReaderUpdateQueue.Enqueue(message); + } + + private void HandleAccessAdd(IEntity entity) + { + if (entity.Deleted || !entity.HasComponent()) + { + return; + } + + var grid = _mapManager.GetGrid(entity.Transform.GridID); + var tileRef = grid.GetTileRef(entity.Transform.GridPosition); + + var chunk = GetChunk(tileRef); + var node = chunk.GetNode(tileRef); + node.AddEntity(entity); + } + + private void HandleAccessRemove(IEntity entity) + { + if (entity.Deleted || !entity.HasComponent()) + { + return; + } + + var grid = _mapManager.GetGrid(entity.Transform.GridID); + var tileRef = grid.GetTileRef(entity.Transform.GridPosition); + + var chunk = GetChunk(tileRef); + var node = chunk.GetNode(tileRef); + node.RemoveEntity(entity); } #region collidable @@ -228,25 +308,22 @@ namespace Content.Server.GameObjects.EntitySystems.AI.Pathfinding /// private void HandleCollidableAdd(IEntity entity) { - // It's a grid / gone / a door / we already have it (which probably shouldn't happen) if (entity.Prototype == null || entity.Deleted || - entity.HasComponent() || - entity.HasComponent() || - _lastKnownPositions.ContainsKey(entity)) + _lastKnownPositions.ContainsKey(entity) || + !entity.TryGetComponent(out CollidableComponent collidableComponent) || + !collidableComponent.CanCollide || + (TrackedCollisionLayers & collidableComponent.CollisionLayer) == 0) { return; } var grid = _mapManager.GetGrid(entity.Transform.GridID); var tileRef = grid.GetTileRef(entity.Transform.GridPosition); - - var collisionLayer = entity.GetComponent().CollisionLayer; - var chunk = GetChunk(tileRef); var node = chunk.GetNode(tileRef); - node.AddCollisionLayer(collisionLayer); + node.AddEntity(entity); _lastKnownPositions.Add(entity, tileRef); } @@ -258,46 +335,37 @@ namespace Content.Server.GameObjects.EntitySystems.AI.Pathfinding { if (entity.Prototype == null || entity.Deleted || - entity.HasComponent() || - entity.HasComponent() || - !_lastKnownPositions.ContainsKey(entity)) + !_lastKnownPositions.ContainsKey(entity) || + !entity.TryGetComponent(out CollidableComponent collidableComponent) || + !collidableComponent.CanCollide || + (TrackedCollisionLayers & collidableComponent.CollisionLayer) == 0) { return; } - _lastKnownPositions.Remove(entity); - var grid = _mapManager.GetGrid(entity.Transform.GridID); var tileRef = grid.GetTileRef(entity.Transform.GridPosition); - - if (!entity.TryGetComponent(out CollidableComponent collidableComponent)) - { - return; - } - - var collisionLayer = collidableComponent.CollisionLayer; - var chunk = GetChunk(tileRef); var node = chunk.GetNode(tileRef); - node.RemoveCollisionLayer(collisionLayer); + + node.RemoveEntity(entity); + _lastKnownPositions.Remove(entity); } private void QueueCollidableMove(MoveEvent moveEvent) { - _queuedGraphUpdates.Enqueue(new CollidableMove(moveEvent)); + _moveUpdateQueue.Enqueue(moveEvent); } - private void HandleCollidableMove(CollidableMove move) + private void HandleCollidableMove(MoveEvent moveEvent) { - if (!_lastKnownPositions.ContainsKey(move.MoveEvent.Sender)) + if (!_lastKnownPositions.ContainsKey(moveEvent.Sender)) { return; } // The pathfinding graph is tile-based so first we'll check if they're on a different tile and if we need to update. // If you get entities bigger than 1 tile wide you'll need some other system so god help you. - var moveEvent = move.MoveEvent; - if (moveEvent.Sender.Deleted) { HandleCollidableRemove(moveEvent.Sender); @@ -314,14 +382,12 @@ namespace Content.Server.GameObjects.EntitySystems.AI.Pathfinding _lastKnownPositions[moveEvent.Sender] = newTile; - if (!moveEvent.Sender.TryGetComponent(out CollidableComponent collidableComponent)) + if (!moveEvent.Sender.HasComponent()) { HandleCollidableRemove(moveEvent.Sender); return; } - var collisionLayer = collidableComponent.CollisionLayer; - var gridIds = new HashSet(2) {oldTile.GridIndex, newTile.GridIndex}; foreach (var gridId in gridIds) @@ -330,33 +396,53 @@ namespace Content.Server.GameObjects.EntitySystems.AI.Pathfinding { var oldChunk = GetChunk(oldTile); var oldNode = oldChunk.GetNode(oldTile); - oldNode.RemoveCollisionLayer(collisionLayer); + oldNode.RemoveEntity(moveEvent.Sender); } if (newTile.GridIndex == gridId) { var newChunk = GetChunk(newTile); var newNode = newChunk.GetNode(newTile); - newNode.RemoveCollisionLayer(collisionLayer); + newNode.AddEntity(moveEvent.Sender); } } } private void QueueCollisionEnabledEvent(CollisionChangeEvent collisionEvent) { - // TODO: Handle containers - var entityManager = IoCManager.Resolve(); - var entity = entityManager.GetEntity(collisionEvent.Owner); - switch (collisionEvent.CanCollide) - { - case true: - _queuedGraphUpdates.Enqueue(new CollisionChange(entity, true)); - break; - case false: - _queuedGraphUpdates.Enqueue(new CollisionChange(entity, false)); - break; - } + _collidableUpdateQueue.Enqueue(collisionEvent); } #endregion + + // TODO: Need to rethink the pathfinder utils (traversable etc.). Maybe just chuck them all in PathfindingSystem + // Otherwise you get the steerer using this and the pathfinders using a different traversable. + // Also look at increasing tile cost the more physics entities are on it + public bool CanTraverse(IEntity entity, GridCoordinates grid) + { + var tile = _mapManager.GetGrid(grid.GridID).GetTileRef(grid); + var node = GetNode(tile); + return CanTraverse(entity, node); + } + + public bool CanTraverse(IEntity entity, PathfindingNode node) + { + if (entity.TryGetComponent(out CollidableComponent collidableComponent) && + (collidableComponent.CollisionMask & node.BlockedCollisionMask) != 0) + { + return false; + } + + var access = AccessReader.FindAccessTags(entity); + + foreach (var reader in node.AccessReaders) + { + if (!reader.IsAllowed(access)) + { + return false; + } + } + + return true; + } } } From 5f457c95d08633059fcd83840b489cb352467098 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Aguilera=20Puerto?= Date: Mon, 22 Jun 2020 19:43:36 +0200 Subject: [PATCH 09/25] Regular human is no longer abstract... --- Resources/Prototypes/Entities/Mobs/human.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/Resources/Prototypes/Entities/Mobs/human.yml b/Resources/Prototypes/Entities/Mobs/human.yml index 5bb8d68aaf..0c565c66c1 100644 --- a/Resources/Prototypes/Entities/Mobs/human.yml +++ b/Resources/Prototypes/Entities/Mobs/human.yml @@ -139,7 +139,6 @@ save: false name: Urist McHands parent: BaseHumanMob_Content - abstract: true id: HumanMob_Content description: A miserable pile of secrets drawdepth: Mobs From afac9e63207b53ef7aa1aab383b364c29e652447 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Aguilera=20Puerto?= Date: Mon, 22 Jun 2020 19:45:32 +0200 Subject: [PATCH 10/25] Make character dummy actually abstract --- Resources/Prototypes/Entities/Mobs/human.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/Resources/Prototypes/Entities/Mobs/human.yml b/Resources/Prototypes/Entities/Mobs/human.yml index 0c565c66c1..e9da57750b 100644 --- a/Resources/Prototypes/Entities/Mobs/human.yml +++ b/Resources/Prototypes/Entities/Mobs/human.yml @@ -160,6 +160,7 @@ save: false name: Urist McHands id: HumanMob_Dummy + abstract: true description: A dummy human meant to be used in character setup components: - type: Hands From f9a60b37ea1ba152310addcf6f4b82bcd346f9b7 Mon Sep 17 00:00:00 2001 From: F77F <66768086+F77F@users.noreply.github.com> Date: Mon, 22 Jun 2020 14:43:20 -0500 Subject: [PATCH 11/25] Add ToggleOutline cvar and console command (#1185) Co-authored-by: scuffedjays --- .../Commands/ToggleOutlineCommand.cs | 24 +++++++++++++++++++ Content.Client/EntryPoint.cs | 4 ++++ Content.Client/State/GameScreenBase.cs | 12 ++++++++++ 3 files changed, 40 insertions(+) create mode 100644 Content.Client/Commands/ToggleOutlineCommand.cs diff --git a/Content.Client/Commands/ToggleOutlineCommand.cs b/Content.Client/Commands/ToggleOutlineCommand.cs new file mode 100644 index 0000000000..a96c9e40a5 --- /dev/null +++ b/Content.Client/Commands/ToggleOutlineCommand.cs @@ -0,0 +1,24 @@ +using Robust.Client.Interfaces.Console; +using Robust.Shared.Interfaces.Configuration; +using Robust.Shared.IoC; + +namespace Content.Client.Commands +{ + public class ToggleOutlineCommand : IConsoleCommand + { + public string Command => "toggleoutline"; + + public string Description => "Toggles outline drawing on entities."; + + public string Help => ""; + + public bool Execute(IDebugConsole console, params string[] args) + { + var _configurationManager = IoCManager.Resolve(); + var old = _configurationManager.GetCVar("outline.enabled"); + _configurationManager.SetCVar("outline.enabled", !old); + console.AddLine($"Draw outlines set to: {_configurationManager.GetCVar("outline.enabled")}"); + return false; + } + } +} diff --git a/Content.Client/EntryPoint.cs b/Content.Client/EntryPoint.cs index e6e5177867..9807f35a0a 100644 --- a/Content.Client/EntryPoint.cs +++ b/Content.Client/EntryPoint.cs @@ -24,6 +24,7 @@ using Robust.Client.Interfaces.Input; using Robust.Client.Interfaces.State; using Robust.Client.Player; using Robust.Shared.ContentPack; +using Robust.Shared.Interfaces.Configuration; using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.Interfaces.Map; using Robust.Shared.IoC; @@ -41,6 +42,7 @@ namespace Content.Client [Dependency] private readonly IEscapeMenuOwner _escapeMenuOwner; [Dependency] private readonly IGameController _gameController; [Dependency] private readonly IStateManager _stateManager; + [Dependency] private readonly IConfigurationManager _configurationManager; #pragma warning restore 649 public override void Init() @@ -223,6 +225,8 @@ namespace Content.Client { IoCManager.Resolve().CreateNewMapEntity(MapId.Nullspace); }; + + _configurationManager.RegisterCVar("outline.enabled", true); } /// diff --git a/Content.Client/State/GameScreenBase.cs b/Content.Client/State/GameScreenBase.cs index f0496f8663..f407af9fe1 100644 --- a/Content.Client/State/GameScreenBase.cs +++ b/Content.Client/State/GameScreenBase.cs @@ -12,6 +12,7 @@ using Robust.Client.Interfaces.UserInterface; using Robust.Client.Player; using Robust.Shared.GameObjects; using Robust.Shared.Input; +using Robust.Shared.Interfaces.Configuration; using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.Interfaces.Map; using Robust.Shared.Interfaces.Timing; @@ -36,6 +37,8 @@ namespace Content.Client.State [Dependency] private readonly IGameTiming _timing; [Dependency] private readonly IMapManager _mapManager; [Dependency] private readonly IUserInterfaceManager _userInterfaceManager; + + [Dependency] private readonly IConfigurationManager _configurationManager; #pragma warning restore 649 private IEntity _lastHoveredEntity; @@ -72,6 +75,15 @@ namespace Content.Client.State } InteractionOutlineComponent outline; + if(!_configurationManager.GetCVar("outline.enabled")) + { + if(entityToClick != null && entityToClick.TryGetComponent(out outline)) + { + outline.OnMouseLeave(); //Prevent outline remains from persisting post command. + } + return; + } + if (entityToClick == _lastHoveredEntity) { if (entityToClick != null && entityToClick.TryGetComponent(out outline)) From 5f9214e6606cc2b253234de3c5ee6151314467ac Mon Sep 17 00:00:00 2001 From: zamp Date: Mon, 22 Jun 2020 22:43:46 +0300 Subject: [PATCH 12/25] Fixed compiler warnings about unreachable code (#1188) --- Content.Client/Commands/DebugAiCommand.cs | 3 ++- Content.Client/Commands/DebugPathfindingCommand.cs | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Content.Client/Commands/DebugAiCommand.cs b/Content.Client/Commands/DebugAiCommand.cs index 1d463e3072..f5c3088215 100644 --- a/Content.Client/Commands/DebugAiCommand.cs +++ b/Content.Client/Commands/DebugAiCommand.cs @@ -54,8 +54,9 @@ namespace Content.Client.Commands } return !anyAction; -#endif +#else return true; +#endif } } } diff --git a/Content.Client/Commands/DebugPathfindingCommand.cs b/Content.Client/Commands/DebugPathfindingCommand.cs index 8549ed1929..adc4760767 100644 --- a/Content.Client/Commands/DebugPathfindingCommand.cs +++ b/Content.Client/Commands/DebugPathfindingCommand.cs @@ -55,8 +55,9 @@ namespace Content.Client.Commands } return !anyAction; -#endif +#else return true; +#endif } } } From 27aefeb35da622bb148ee79a665669f50076157e Mon Sep 17 00:00:00 2001 From: Tyler Young Date: Mon, 22 Jun 2020 21:02:50 -0400 Subject: [PATCH 13/25] fis crap w/ grids being deleted while component events still ref --- .../GameObjects/EntitySystems/IconSmoothSystem.cs | 5 ++--- .../GameObjects/EntitySystems/SubFloorHideSystem.cs | 6 +++++- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/Content.Client/GameObjects/EntitySystems/IconSmoothSystem.cs b/Content.Client/GameObjects/EntitySystems/IconSmoothSystem.cs index 9cd35a72f4..901178e9ec 100644 --- a/Content.Client/GameObjects/EntitySystems/IconSmoothSystem.cs +++ b/Content.Client/GameObjects/EntitySystems/IconSmoothSystem.cs @@ -79,10 +79,9 @@ namespace Content.Client.GameObjects.EntitySystems } } - if (ev.LastPosition.HasValue) + // Entity is no longer valid, update around the last position it was at. + if (ev.LastPosition.HasValue && _mapManager.TryGetGrid(ev.LastPosition.Value.grid, out var grid)) { - // Entity is no longer valid, update around the last position it was at. - var grid = _mapManager.GetGrid(ev.LastPosition.Value.grid); var pos = ev.LastPosition.Value.pos; AddValidEntities(grid.GetSnapGridCell(pos + new MapIndices(1, 0), ev.Offset)); diff --git a/Content.Client/GameObjects/EntitySystems/SubFloorHideSystem.cs b/Content.Client/GameObjects/EntitySystems/SubFloorHideSystem.cs index 0551de45de..9a51fb4d8e 100644 --- a/Content.Client/GameObjects/EntitySystems/SubFloorHideSystem.cs +++ b/Content.Client/GameObjects/EntitySystems/SubFloorHideSystem.cs @@ -60,7 +60,11 @@ namespace Content.Client.GameObjects.EntitySystems private void HandleDirtyEvent(SubFloorHideDirtyEvent ev) { - var grid = _mapManager.GetGrid(ev.Sender.Transform.GridID); + if (!_mapManager.TryGetGrid(ev.Sender.Transform.GridID, out var grid)) + { + return; + } + var indices = grid.WorldToTile(ev.Sender.Transform.WorldPosition); UpdateTile(grid, indices); } From 304ab3a056e38c8770c9775c843ab60e8018de0a Mon Sep 17 00:00:00 2001 From: Pieter-Jan Briers Date: Tue, 23 Jun 2020 13:39:29 +0200 Subject: [PATCH 14/25] Update submodule --- RobustToolbox | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RobustToolbox b/RobustToolbox index 7dd0a668d5..2558201ae4 160000 --- a/RobustToolbox +++ b/RobustToolbox @@ -1 +1 @@ -Subproject commit 7dd0a668d50c462456634bebced035be63225594 +Subproject commit 2558201ae44fcd53e4199cd190b2063257d4c79c From fe65d1fa85a9480efdefce160a02760837a22eb1 Mon Sep 17 00:00:00 2001 From: Swept Date: Tue, 23 Jun 2020 12:04:19 +0000 Subject: [PATCH 15/25] Weapon Tweaks (#1186) * RPG Tweaks * Decreased bulletbase bb --- Resources/Audio/Guns/Gunshots/rpgfire.ogg | Bin 0 -> 51440 bytes .../Entities/Weapons/Launchers/launchers.yml | 2 +- .../Weapons/Projectiles/projectiles.yml | 12 ++++++++---- .../Objects/Guns/Launchers/rocket.rsi/mag-1.png | Bin 0 -> 2496 bytes .../Objects/Guns/Launchers/rocket.rsi/meta.json | 10 +++++++++- .../rocket.rsi/rocket0-inhand-left.png | Bin 0 -> 814 bytes .../rocket.rsi/rocket0-inhand-right.png | Bin 0 -> 820 bytes .../Guns/Projectiles/rocket.rsi/frag.png | Bin 266 -> 329 bytes .../Guns/Projectiles/rocket.rsi/meta.json | 6 +++++- .../Guns/Projectiles/rocket.rsi/smallfrag.png | Bin 0 -> 266 bytes 10 files changed, 23 insertions(+), 7 deletions(-) create mode 100644 Resources/Audio/Guns/Gunshots/rpgfire.ogg create mode 100644 Resources/Textures/Objects/Guns/Launchers/rocket.rsi/mag-1.png create mode 100644 Resources/Textures/Objects/Guns/Launchers/rocket.rsi/rocket0-inhand-left.png create mode 100644 Resources/Textures/Objects/Guns/Launchers/rocket.rsi/rocket0-inhand-right.png create mode 100644 Resources/Textures/Objects/Guns/Projectiles/rocket.rsi/smallfrag.png diff --git a/Resources/Audio/Guns/Gunshots/rpgfire.ogg b/Resources/Audio/Guns/Gunshots/rpgfire.ogg new file mode 100644 index 0000000000000000000000000000000000000000..516618fe91fbfd345c555620f5dcb2c26b3e5b62 GIT binary patch literal 51440 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�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%0AT6fJNAuwq)C@WX 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 literal 0 HcmV?d00001 diff --git a/Resources/Prototypes/Entities/Weapons/Launchers/launchers.yml b/Resources/Prototypes/Entities/Weapons/Launchers/launchers.yml index 19fa48c80a..a7544c1923 100644 --- a/Resources/Prototypes/Entities/Weapons/Launchers/launchers.yml +++ b/Resources/Prototypes/Entities/Weapons/Launchers/launchers.yml @@ -73,7 +73,7 @@ fireRate: 0.5 capacity: 1 soundEmpty: /Audio/Guns/Empty/empty.ogg - soundGunshot: /Audio/Guns/Gunshots/bang.ogg + soundGunshot: /Audio/Guns/Gunshots/rpgfire.ogg soundInsert: /Audio/Guns/MagIn/batrifle_magin.ogg - type: Appearance visuals: diff --git a/Resources/Prototypes/Entities/Weapons/Projectiles/projectiles.yml b/Resources/Prototypes/Entities/Weapons/Projectiles/projectiles.yml index 5fff01fdec..0e89d4e0ad 100644 --- a/Resources/Prototypes/Entities/Weapons/Projectiles/projectiles.yml +++ b/Resources/Prototypes/Entities/Weapons/Projectiles/projectiles.yml @@ -18,7 +18,7 @@ hard: false shapes: - !type:PhysShapeAabb - bounds: "-0.2,-0.2,0.2,0.2" + bounds: "-0.1,-0.1,0.1,0.1" layer: [Clickable] mask: - Impassable @@ -130,10 +130,14 @@ - type: Projectile deleteOnCollide: false - type: Explosive - devastationRange: 3 - heavyImpactRange: 5 - lightImpactRange: 7 + devastationRange: 1 + heavyImpactRange: 2 + lightImpactRange: 4 flashRange: 10 + - type: PointLight + radius: 3.5 + color: orange + energy: 0.5 - type: entity id: BulletGrenadeBaton diff --git a/Resources/Textures/Objects/Guns/Launchers/rocket.rsi/mag-1.png b/Resources/Textures/Objects/Guns/Launchers/rocket.rsi/mag-1.png new file mode 100644 index 0000000000000000000000000000000000000000..7ef2a792053ee7983a1afcc041996a1485f81082 GIT binary patch literal 2496 zcmV;x2|xCUP) zaB^>EX>4U6ba`-PAZ2)IW&i+q+U-|alH)cE{pTri1QH8D9tYg2a)TT{kCN=R-P4|= zlgdYGp9fx1t;bUz5-efAQ+c(aT@ z!f^_^xs_kybgd_SS?9YNda@|dT{AseG;_50cs;~#tx?vRr*|$nAYA!!>gLKZ!^Vbi z^6^@ZTVw{@1>^oyd`k4#f!ctpEyRY0ng|hJNzzE3R+`7yQ-_H{lMEwKN5uD9VWUbN zU?c<{pR~vVa2Q;GN(XYh5xLuv4!w2jgR%n6BVi{c2m{8?pYXcy-OrPtwRW1P6w5tU zu#0xqz>JODzGD{vN$ZNK9`Q}#9OCP>fn^}5N0@jP18qi@qsf(4cIF2te0ft z5`Yjvx5AjjKpjHp{Hj7jkX!lBFvzTV>VdchoLapHX{7?mcShLX8ff_CEVS4a;UX5oyzj zZp?rfNdn@w5kNxI#w?a3LL0e_S**l?!CSCWH#j40#DJj8M7q))yAR~P#4RAYe-}6U z5prQe_irEWpU2j1I+_!l z={(Mz!RxoZ;b{WR)S$nG{eW`o&|n}G93*qA*rn#$J-6NseAE|wsH##^0uL?486)^h zJs%^Eqj*jpM!Y`^#4-^ckj(U`(7fPKnav}VRFNf#TOCue9i4&(?#_(JQY#F5r^a_r z(VIb!f)0iX=%x0iW6W;B$CfFO>7z{Gl%agKPTnvT9GPQ#)we5-PEGM>ML~2RAjJN* zJM8W0SP+D1pa(MaG0xUNv^Z#TL)4Ch7?6#wri0;V(X3-FVK-3FL}-IdFsg&fii5uf zx+3^uj-x^+^v?yhf*YyYZccODCzP)});XKG4UwEihHF{z5*l%`jGe_h2)DGjY9EU5 z5Ga>m$;^HL2S{>63?8=PG{D&pULK%&ux#Fq7A)%sug@vT4R7fng)ty&YM^tfqoBE* zdp?Pp%u48Canh3FxKg}xJk!Vs3?pyg&+IBPz}r&c5q!^v(HMufa9t)Y(k*vk#~40Dj3iwBAGW_8!r9!f7uWFlRYw;b|80=aDW(ETy` z^~;M5y%OG=b`pono5+PXp`4}peG&)i^>!Yk+j-@v@Q$oLbJb0{;YUE0cU7SFZ^6#; z(`f$`g`j9RM$AnHY(NEGTi(k)Uf=M647L;q32UGj4`7oF{1s_2@d7t}p^eIJ?0X~st?f%Ws^^ z4huXpYUDC=#8G0g+{JPivx=b-PZ7ryRik_%@3O*qi?dp*v-Umt3&TZiIm>mL!$@Kg zDWoAnMjchuU?EPcMv93H?I%3^LykX9E}2|aFmlXe11coP5B>+gyERLb6K+yC0R&!b z`(p$M?gFibZGRuzcIyQ2KLb}<$G_18W|AB1V+o0z2@=m-tON1J=5;*2OCy$gss+y z9{>OV24YJ`L;(K){{a7>y{D4^000SaNLh0L04^f{04^f|c%?sf00007bV*G`2jm40 z3ll7k;I4uI00HnxL_t(o!(%*f-~huw0w#t52BQubb-<_t2HXKG)G}y8XFr3Tts#oo zp~L4H0?G^Nc6wI5unPLZ&Pwis3`RF+ce(?SsL4Aw|4jf>(dgU3z z?X4>@f)E=xboe~OI}sHIb8}<3n4N#9? zz`&rd<-iD!f|DoDGQ7qTgt&tG^M`*p#N>GQ^$- z58fjZAxtr`j$mM5V0ioP1p@;E1B0-T1cQ=_8eIJJsY475ccAi6`t7gxP+2j!#nb06 zLqx&bcP|*GFPp_$mzFvfHn zEZGpInD^65l2gCBoFpXi9%f)r^$s7nf{1~EfnoX5gA;f}jvQv?v9P_&O$;Q7IT=l=zlp2aL7}M;$OC8~^~ABiVm-pcSA10000< KMNUMnLSTYSJeU&z literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Guns/Launchers/rocket.rsi/meta.json b/Resources/Textures/Objects/Guns/Launchers/rocket.rsi/meta.json index cbc9bce33c..69eaa07a35 100644 --- a/Resources/Textures/Objects/Guns/Launchers/rocket.rsi/meta.json +++ b/Resources/Textures/Objects/Guns/Launchers/rocket.rsi/meta.json @@ -19,6 +19,14 @@ "name": "mag-0", "directions": 1 }, + { + "name": "rocket0-inhand-left", + "directions": 4 + }, + { + "name": "rocket0-inhand-right", + "directions": 4 + }, { "name": "inhand-left", "directions": 4 @@ -28,4 +36,4 @@ "directions": 4 } ] -} \ No newline at end of file +} diff --git a/Resources/Textures/Objects/Guns/Launchers/rocket.rsi/rocket0-inhand-left.png b/Resources/Textures/Objects/Guns/Launchers/rocket.rsi/rocket0-inhand-left.png new file mode 100644 index 0000000000000000000000000000000000000000..aa36fdfe14626be38014c344ee2583b4da2e3808 GIT binary patch literal 814 zcmV+}1JV46P)1Rp#)Kjh>)a6T4CioWWwILdpC3YW@a~eA2`VE&F;MS&D*!L^PXTBhG7_nIj@v- z{SL!0R}!s!s7KQ?_q6Q~f*|qu1xlk_a(RDOijZ~6LJF`}eHTrP-;yG{eDOAu2!#_s zIlsB}S$zHVTU?Z5*yk?K~hC zU~y@-^nLf6{Cgs}b1DKtx0eX`9pgY;Jat`aTY;6w;H%e9rLmjgPMZkb@`K9o;>3BJ z=K^c%04!5+8z>PbA3T=%AxQ+~JbuSGjK_I}6d>;0*w}5E3udcxZ6e&SJZTGOe2+Vi z@%`oyQ>-k6kg@S3z^zbQtx3b-6a?95H52dUa;sTdn6E_`r*a6Q2&+7-_HJIgYQt1_ zZ-a1TYkR%teB*bgB9%iZ@%}cbL;Z25p6F|#`U7-Hsv-wL zJ@M=_`4liIp`S?sOsdG_0=Ot=rOnq5^c^CGC2>>Y*TX!hA?8YegZ-Z+-IBN|o&5ut z$D~;@2`f23rzCDlQvU!&3Ej$L5MhbWv&tj+eR=VHruLS!{sGJ}GCG*aR?-Mit1gtc z@j2!jX z|M=1K_#Nxt z=-ub9wA_1B$%Np?fcEUQ)Ke|gyh{sShM>NIuX zvFwN7B5jDDj*qL?A6DPf!ozv%#fA&AbwUT8p)1dX)BwGov-suCOZE57TUUb+p9gfX z33=1yIBDY1&re>wOe`MFzsxezC!m8{^5Vihx^VUco1k>57J#`^7eC*=uf$JG980D6 zIt^yY8^fRnx}Xm_^|gXBpw(*8(n?>wi4UXC<8k=N-UzEM+mY2Zs26pke%1nA06L+U zQKFONpT4Qd(@DsE-UJNky?B=DilV|`) zGIb6#ppFcFSfEa9ec9Y@O9Sf4;D-fvdl8%4m|)xxNi+C$BI;48q|qM6A!2or25GzfC?x*aJz4ca!XP^h#H;Lx#2vQbyvx2j|SayPxGx@QVgTwf=Z z3_xFML~eckG!~^HWp}=6lW-PP?86ypF4M}1rryA!&ETj((IX3e9_b?o8B@_#r1qp yveuKL*$kc;WP(Y2(eIam4G;uD5CmaFA)-Hyjl6hmXwVw~0000061{q0GQseuJixS%@-M_&tC>M$HBpY zWV4vajRBD5iW=q&3JQV@nTb*V$u)lFcJK z1gHf@9WdYyU?E3Sp2rsk9#v+BFA856Zi%si#daMO03|~DIDcT$4ju-@2Y(sv-{4`m zdHEe!?7@Q%j4q7;l~ zLy8=LTo(+81E>K;9Wb;VFkmGi3`{K*Vz_mVl_CdF6aqY|ZVYNhyaVR|Y5)m59WXF3004mrR(%}Ob>08~002ovPDHLkV1fx* BdQt!Y delta 239 zcmV7iaw;J~q5h$(^S{WJACr%S%&dKI}du-WHv-hWT;B z)7}4#?(9E!xZv|A>$W24PiGcraJ{>4aT3T^Ze!=aH#wKhm5+l%D?Q};)Z`g<^^%Vp zEE*ac8y`M<>Mrtf`3=S?EcT%?30cCP6YJcHq?d-TxA|TF=}BZ;b$OoQp4#tC2d|vz zQ`EdU{mB-GZOjP@#(Tf~|1$G#in>#mtb?Y+heZ`oH#b-_FzEibx87;+_8HJ~44$rj JF6*2UngHt3ZgT(t literal 0 HcmV?d00001 From ffc1319733e041e5ed627effdd1e98d44f559cd0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Aguilera=20Puerto?= Date: Tue, 23 Jun 2020 14:42:20 +0200 Subject: [PATCH 16/25] Add new weapon spawners for SSS --- .../Markers/gamemode_conditional_spawners.yml | 184 ++++++- Resources/Prototypes/Entities/Mobs/human.yml | 1 + Resources/Textures/Objects/markers.rsi/AI.png | Bin 421 -> 1038 bytes .../Objects/markers.rsi/Assistant.png | Bin 435 -> 840 bytes .../markers.rsi/Atmospheric Technician.png | Bin 551 -> 1071 bytes .../Objects/markers.rsi/Bartender.png | Bin 485 -> 942 bytes .../Textures/Objects/markers.rsi/Botanist.png | Bin 492 -> 927 bytes .../Textures/Objects/markers.rsi/Captain.png | Bin 540 -> 1028 bytes .../Objects/markers.rsi/Cargo Technician.png | Bin 470 -> 923 bytes .../Textures/Objects/markers.rsi/Chaplain.png | Bin 472 -> 902 bytes .../Textures/Objects/markers.rsi/Chemist.png | Bin 522 -> 1035 bytes .../Objects/markers.rsi/Chief Engineer.png | Bin 642 -> 1144 bytes .../markers.rsi/Chief Medical Officer.png | Bin 566 -> 1136 bytes .../Textures/Objects/markers.rsi/Clown.png | Bin 504 -> 921 bytes .../Textures/Objects/markers.rsi/Cook.png | Bin 566 -> 1006 bytes .../Textures/Objects/markers.rsi/Curator.png | Bin 483 -> 926 bytes .../Textures/Objects/markers.rsi/Cyborg.png | Bin 345 -> 736 bytes .../Objects/markers.rsi/Detective.png | Bin 522 -> 965 bytes .../Objects/markers.rsi/Geneticist.png | Bin 524 -> 1006 bytes .../Objects/markers.rsi/Head of Personnel.png | Bin 501 -> 945 bytes .../Objects/markers.rsi/Head of Security.png | Bin 518 -> 1020 bytes .../Textures/Objects/markers.rsi/Janitor.png | Bin 484 -> 905 bytes .../Textures/Objects/markers.rsi/Lawyer.png | Bin 504 -> 855 bytes .../Objects/markers.rsi/Medical Doctor.png | Bin 535 -> 1109 bytes .../Textures/Objects/markers.rsi/Mime.png | Bin 457 -> 764 bytes .../Objects/markers.rsi/Paramedic.png | Bin 542 -> 1143 bytes .../Textures/Objects/markers.rsi/Prisoner.png | Bin 409 -> 828 bytes .../Objects/markers.rsi/Psychologist.png | Bin 389 -> 720 bytes .../Objects/markers.rsi/Quartermaster.png | Bin 527 -> 1082 bytes .../Objects/markers.rsi/Research Director.png | Bin 529 -> 1046 bytes .../Objects/markers.rsi/Roboticist.png | Bin 541 -> 1050 bytes .../Objects/markers.rsi/Scientist.png | Bin 483 -> 982 bytes .../Objects/markers.rsi/Security Officer.png | Bin 519 -> 1001 bytes .../Objects/markers.rsi/Shaft Miner.png | Bin 432 -> 1027 bytes .../Objects/markers.rsi/Station Engineer.png | Bin 560 -> 1035 bytes .../Objects/markers.rsi/Virologist.png | Bin 516 -> 1055 bytes .../Textures/Objects/markers.rsi/Warden.png | Bin 544 -> 1079 bytes .../Objects/markers.rsi/cross_green.png | Bin 225 -> 309 bytes .../Objects/markers.rsi/cross_pink.png | Bin 223 -> 331 bytes .../Objects/markers.rsi/cross_red.png | Bin 223 -> 296 bytes .../Textures/Objects/markers.rsi/meta.json | 462 +++++++++++++++++- .../Objects/markers.rsi/observer_start.png | Bin 401 -> 603 bytes .../Objects/markers.rsi/spawner_grenade.png | Bin 0 -> 510 bytes .../Objects/markers.rsi/spawner_hitscan.png | Bin 0 -> 801 bytes .../Objects/markers.rsi/spawner_launcher.png | Bin 0 -> 709 bytes .../Objects/markers.rsi/spawner_melee.png | Bin 3793 -> 481 bytes .../Objects/markers.rsi/spawner_pistol.png | Bin 3954 -> 723 bytes .../Objects/markers.rsi/spawner_revolver.png | Bin 0 -> 703 bytes .../Objects/markers.rsi/spawner_rifle.png | Bin 4474 -> 813 bytes .../Objects/markers.rsi/spawner_shotgun.png | Bin 0 -> 604 bytes .../Objects/markers.rsi/spawner_smg.png | Bin 0 -> 724 bytes .../Objects/markers.rsi/spawner_sniper.png | Bin 0 -> 645 bytes 52 files changed, 637 insertions(+), 10 deletions(-) create mode 100644 Resources/Textures/Objects/markers.rsi/spawner_grenade.png create mode 100644 Resources/Textures/Objects/markers.rsi/spawner_hitscan.png create mode 100644 Resources/Textures/Objects/markers.rsi/spawner_launcher.png create mode 100644 Resources/Textures/Objects/markers.rsi/spawner_revolver.png create mode 100644 Resources/Textures/Objects/markers.rsi/spawner_shotgun.png create mode 100644 Resources/Textures/Objects/markers.rsi/spawner_smg.png create mode 100644 Resources/Textures/Objects/markers.rsi/spawner_sniper.png diff --git a/Resources/Prototypes/Entities/Markers/gamemode_conditional_spawners.yml b/Resources/Prototypes/Entities/Markers/gamemode_conditional_spawners.yml index 9b5f6757b8..3339833383 100644 --- a/Resources/Prototypes/Entities/Markers/gamemode_conditional_spawners.yml +++ b/Resources/Prototypes/Entities/Markers/gamemode_conditional_spawners.yml @@ -38,10 +38,9 @@ - RifleBlackAk - RifleCarbine - RifleDallas - - RifleIhHeavy - - RifleSolEot - - RifleSolPara - - RifleSts + - RifleSTS + - RifleVintorez + - RifleWintermute chance: 0.75 gameRules: - RuleSuspicion @@ -62,14 +61,16 @@ - type: ConditionalSpawner prototypes: - PistolClarissa - - PistolDeagle - - PistolDeckard + - PistolColt - PistolGiskard - - PistolGyro + - PistolHMPistol - PistolLamia - - PistolMakarov + - PistolMandella - PistolMk58 - - PistolOlivawCivil + - PistolMk58Wood + - PistolMolly + - PistolOlivaw + - PistolPaco chance: 0.75 gameRules: - RuleSuspicion @@ -94,6 +95,171 @@ - Spear - ToolboxEmergency - CrowbarRed + - Stunbaton + chance: 0.75 + gameRules: + - RuleSuspicion + +- type: entity + name: Suspicion Revolver Spawner + id: SuspicionRevolverSpawner + parent: BaseConditionalSpawner + components: + - type: Sprite + netsync: false + visible: false + sprite: Objects/markers.rsi + state: spawner_revolver + - type: Icon + sprite: Objects/markers.rsi + state: spawner_revolver + - type: ConditionalSpawner + prototypes: + - RevolverDeckard + - RevolverInspector + - RevolverMateba + chance: 0.75 + gameRules: + - RuleSuspicion + +- type: entity + name: Suspicion Shotgun Spawner + id: SuspicionShotgunSpawner + parent: BaseConditionalSpawner + components: + - type: Sprite + netsync: false + visible: false + sprite: Objects/markers.rsi + state: spawner_shotgun + - type: Icon + sprite: Objects/markers.rsi + state: spawner_shotgun + - type: ConditionalSpawner + prototypes: + - ShotgunBojevic + - ShotgunDB + - ShotgunBull + - ShotgunGladstone + - ShotgunRegulator + - ShotgunPump + - ShotgunSawn + chance: 0.75 + gameRules: + - RuleSuspicion + +- type: entity + name: Suspicion SMG Spawner + id: SuspicionSMGSpawner + parent: BaseConditionalSpawner + components: + - type: Sprite + netsync: false + visible: false + sprite: Objects/markers.rsi + state: spawner_smg + - type: Icon + sprite: Objects/markers.rsi + state: spawner_smg + - type: ConditionalSpawner + prototypes: + - SmgAtreides + - SmgC20r + - SmgDrozd + - SmgStraylight + - SmgWt550 + - SmgZoric + chance: 0.75 + gameRules: + - RuleSuspicion + +- type: entity + name: Suspicion Sniper Spawner + id: SuspicionSniperSpawner + parent: BaseConditionalSpawner + components: + - type: Sprite + netsync: false + visible: false + sprite: Objects/markers.rsi + state: spawner_sniper + - type: Icon + sprite: Objects/markers.rsi + state: spawner_sniper + - type: ConditionalSpawner + prototypes: + - SniperBoltGun + - SniperBoltGunWood + - SniperHeavy + chance: 0.75 + gameRules: + - RuleSuspicion + +- type: entity + name: Suspicion Hitscan Spawner + id: SuspicionHitscanSpawner + parent: BaseConditionalSpawner + components: + - type: Sprite + netsync: false + visible: false + sprite: Objects/markers.rsi + state: spawner_hitscan + - type: Icon + sprite: Objects/markers.rsi + state: spawner_hitscan + - type: ConditionalSpawner + prototypes: + - RedLaser + - RedHeavyLaser + - XrayLaser + - LaserGun + - LaserCannon + - XrayCannon + - TaserGun + chance: 0.75 + gameRules: + - RuleSuspicion + +- type: entity + name: Suspicion Launchers Spawner + id: SuspicionLaunchersSpawner + parent: BaseConditionalSpawner + components: + - type: Sprite + netsync: false + visible: false + sprite: Objects/markers.rsi + state: spawner_launcher + - type: Icon + sprite: Objects/markers.rsi + state: spawner_launcher + - type: ConditionalSpawner + prototypes: + - LauncherChinaLake + - LauncherRocket + chance: 0.75 + gameRules: + - RuleSuspicion + +- type: entity + name: Suspicion Grenades Spawner + id: SuspicionGrenadesSpawner + parent: BaseConditionalSpawner + components: + - type: Sprite + netsync: false + visible: false + sprite: Objects/markers.rsi + state: spawner_grenade + - type: Icon + sprite: Objects/markers.rsi + state: spawner_grenade + - type: ConditionalSpawner + prototypes: + - ExGrenade + - GrenadeFlashBang + - SyndieMiniBomb chance: 0.75 gameRules: - RuleSuspicion diff --git a/Resources/Prototypes/Entities/Mobs/human.yml b/Resources/Prototypes/Entities/Mobs/human.yml index e9da57750b..16676d1f5f 100644 --- a/Resources/Prototypes/Entities/Mobs/human.yml +++ b/Resources/Prototypes/Entities/Mobs/human.yml @@ -155,6 +155,7 @@ - type: CameraRecoil - type: Examiner - type: HumanInventoryController + - type: Item - type: entity save: false diff --git a/Resources/Textures/Objects/markers.rsi/AI.png b/Resources/Textures/Objects/markers.rsi/AI.png index 1e6533c229f9fcef8dbffbf6dfbf4726a77fd083..aa331c468b9e4a2a7c6c1a664cfff23a7a376a34 100644 GIT binary patch delta 1027 zcmV+e1pND@1C9ug8Gi-<0047(dh`GQ1Jy}HK~#90#g}hr6L%QLKM4`$y=h#s(i^z3 znq)G#k_IF+bJ!R2g`Gkf4*DYCkgbzZD85*!1ASp&EkoFZB4R^XM_)K}uov3Ah%ahf za|BVa2PFjUiwR8@x|*2k0sQ zA3(KQ?TYf=-d+O$z#Dt_(&P7cL~*@Vj2>-jjv1Ksc*n&byXMb?_ODivK{Ru!kB2g&m z!VrLRxs0Z1V(kTxWtltc`)oo?#-l-FE%`lS^t|e^t)0UvBOYn>-ktS*D2mbqP%f9* zxO>iaDU~o7&*lvwdaWTweY;^>TgP8@qp!t65~+mY0e>fL+&w3};F<%b;zCImLNBx{Rc;gg(U7j)Y;{Iaqf5l6h)!`zK747a{P0k${Vfi@*hO$*DXRlKAb=F~-&BOw7&*<%f?XID90* zxT^E^p?_oIzF7tCAvj@g#ZHPxB$jXH(St)`@7*C|uGgC1FLS;>xEq2)w)Lv2GV(zJ z0M$j04~!68`auVp?lO^Ev$`Ew&v$v@@8|aOb{;T7V0haLMhKi$01yaA$!79A-P~@; z_POaZ0L)FFX{nB>`mKuaE2tHA4KnSaS-3i0VrY_&cyJHxM~H6~_fZ2La_ ziH*;i%AChbKO3*?T7K;r4@KTRA3KtH3n`PPaL`-Kwgx{L_!D zs;X-zbd&W`A@Kg*%qBAzOe>czUM3KZ(tmJ-Ksd_M#mnL>o5_pJH)oTqF((|028W+k7C7ptU-=z26d4#4JZ$c3QMNyDt z*>=%n9vf)JFfp1Go-oHkdY;5+Qh4jFSA3c>ocyvZ3+sgk+L0Cc)ivD~%fx7sxeHfp zprD!YZkD$rR{)b!_7{w^m0ELMUHZ0#Uv-(k5J0K0va^p;$DRjhRI61KMd|3XT+=lB x*RWozb@a!?BmuzuQ|UBy|K~K9%XL#f{{WR|^S;p9133Ty002ovPDHLkV1ljw_}>5k delta 406 zcmV;H0crk@2&Ds%8Gi!+002a!ipBr{08UU$R7C&)00RR92nPohRd^L?nHF7z7Z(>L zZkH{6t1vJyJe0*xx%GF={(8>-d&BL4-T#K)|A^B4i;Ih==l`w14Z_00()0i6^7rcM z>i_@$Yo%tn0003JNklfqAH_Ait$gqIkM5QdisM)+AqdWvz`31Ok}DX1c>K&k;?eGs-lBd?720{{af1*_ui zCIksk2|ff^3AdmM*I*WW2z(%|rf}Wv1eL@*&k`*oQn4^XPzzZnxNk>^WE8ivg%v?E zkerbv(ONJS`+vvG+*oLofl4ievjs&BbmVl3a?Y&<5ThzgI>cD+p|TK(>L#fqd02>o zWkK^k;cW4_OH49NTEZWT%(CNCa!!))a-1uR&2o?(_LhKGvaIi~Y5gGUylY52Ydmt( zFxeg$@ZM_ys@D=aE!S(>UfXv+PVejW(EI+srxq(MVGj{2>i_@%07*qoM6N<$f-Lj9 A$^ZZW diff --git a/Resources/Textures/Objects/markers.rsi/Assistant.png b/Resources/Textures/Objects/markers.rsi/Assistant.png index 7588e08c7bbdc10985a857e6df848efaa94aac6c..139cba34f516d5af52005313d2694c6e1a9586ba 100644 GIT binary patch delta 828 zcmV-C1H=5Y1IPxD8Gi-<0047(dh`GQ0}n|=K~#90<(ExJ6k!<0e`7(xwl&m(M7vmr ziBJYl(WO(jZ4s8Jn4r`#Em0LF zb!6w>hQRodANN%diS_sqWJBP13v2-Ao(uu-{7OF?Qj12^NJNT2;Cx-aI|sP%bch35 z?K~_N?|)l}aVdJwR7i z7wzrs0Dnw9ye0|#5T{NYW4`1wJ3HGvfdC0T2Gshzudgp85jaPLmzuUEdxnG_qx|Nr zis{A#K79I2Ja&**uUF7@o$2XmeBY<7t&QQ~Vanw)en$rIs@id!@Y=R*9LLe>b$@=DKs|O2rJc3lx-Kfiryk0$<9Y=7 zFBXg8UOka0i2Okkpja&8IF43N;;$0;UHJD1{A|Rkj^3S!RD`>Y=4Qur0OgjMnw%7X z-m6#9bsd1Er6nzuN(n%^E zIyyf;KS@bRN=iykPft@*Q&m+}W-|b2XlQC`YJPrxmzS5Al$4qd0HF^6tPlXMk7cf` ztgx`Kvk(BYv$MjVam&fc)~|fo+1cZ|gzD(%|NsC0E{rMw0Dk}hbW%=J06^y0W&i*H z_(?=TR5;7E&|!0fAPfdzn2wscu2~wyHk8u-{~x*FuDe|YKW#6kUd(fdG3IZ>6MMhW zp9I0$nk)SS6 zz!7F72ZGhUz<(%&BqK;opdh%tsB?f7pzjdIy}XO=fE9s+2Aq8FuvAYOhT#`@)#@oB z$Dn_qz&Z#qhc!si5fR!K>tc#)kaF08gDbeVT}WvKOb7-`thHE*`Yc6As#AIZJp<7u zKpnxq0$Kny!BFPC-0GR$Y&U5VC#w`!B5s)?HO@S>i_$+_?!D*TbI$*qcYn_1!v7u8UX%s~UK2aX z8yZFp+cTta<3@#0RSk>9ge;rV@<>EuWhF^TNv>fMrp!mS!)7xR4#$Z^G{WHok%)$( z#3?DsO_Tgr2wc8=L|7~)A`y*1zXpJ+CIJZaYb-9t0kBw%#gz5wGiN5GnVBfVSE2y? z`pqK%6eUj87k~MT{iJ8ZD9lC<5A~`P7MRJ+F`-#X3G{0$sd41I1o5N>;nqEbOTb$H<rPFok{n_r@+`IQlx-(9me3Z3a zLj;;Wt`q>p>&u+&zMYm|I$cNTP!S&--$a&8h6rR`1Ap!|#N52Te(BW!Kb-rJ&(D|8 z<9tIsIss`L`2-jCz`^s`~R6U{mqd#y|J>kWp6)1|{hRqFQxZBA3 zF36lJmq+lt9dWJ^fX|vM0k}4PA9tffWjTzhM*#Tp)P!!-+Xu=lbhT!*pIsM}9YgBy zVEGdqHh+D*_ku*M_&eTdfJy%$0PYTe)Zu}$V_BJn3>iqJUh41w@a}`30dN+s;jqC> znDl(@)P3-K)4HOgm9B5${KegUWX!;w0dUK$T$pOZ=krO8Z~JiApzinxh0eFQ`27eD z8~h%ZpsQ87Fx7@zZspEE7U5?i5LDooA$_i{sec8RN6gRbHSqqLUT4yvJ`es@2`-PQ zuBqLow=V*d5A7r-%UFC|%B{XpngTrl$oV!zy`EW7FEKi;cR*91hg*H4EIuwJF?gNk%eeNLyaZbv=vjVszeSSrc^}I=kBcv?1cqvBoY*aL&$kKsIeq! zEPu)M;o1GwKs2F|Z#JREl1xm6S&M2s_-lcwr5JVfc}y+ESPZRE{ff+UW;1F`zl`L( zoQ%inj(t}VLWr$(7=g=Un1JCoVSfrEV<1VAG%~hV3;QH+Q26f=xciJN_F3{w zF!U%TG{@l3c2Q7aOSU;@m_XKj+IRD&0BCM$p{S?`fa&RJ$?0?ofaT?7e(dc9pz*|s zgYExruU7~m#6mDAhW&nFwOU2WvD4`kR;yJE`~6}e7!*PX(e3pf;EM=oZ*SkxU>;{@ fr?lI*Y;6AxB7e$W7`m{d00000NkvXXu0mjfkfH=S delta 537 zcmV+!0_Od%2&V*)8Gi!+002a!ipBr{0IN_;R7C&)001Wc09$zgZj%6lt^lR~2etqW z4GkR~9X2l?K0ZD_I{-^UEK@WhS~VM6O)*|K9AP{qWIG;aGXQ2kCuUJKX+9rnYHDsl zA#Ot_bwwj}Pz!foF?nPFetv#|WO2W_L~!yJi!xdr2B@XI+X diff --git a/Resources/Textures/Objects/markers.rsi/Bartender.png b/Resources/Textures/Objects/markers.rsi/Bartender.png index acf2e044e07a68d38b379c3463a6b1ccb14ac2d1..d0f4baaf2b7ec7881ede1b188ed433cd384b90e0 100644 GIT binary patch delta 931 zcmV;U16=&&1Fi><8Gi-<0047(dh`GQ19eG6K~#90)t5bJ8)q2De=@QqHIXIxTwJhR zw?@X-1T18*r!M`V)E+WuZN?UaF)on_-ns{IOBNXdZI=#RR4{l6{g^yhh9t^hE;tGj zl`SjvNhc+$BcDD(7k0Ra4JgJQAB%E}6NSHCfj{c6K@bLe9gY$n!qadMn`v&BD^ zD(?q;TyeXQ^9S6xedlsl!G9r)=(jo8yalmXOb^dS^y2Uo$JH0+uQ)tKcs8QPVlmq< zCd<^ZSWM67^R$|66h$HP_#yN2^X%^K5}u792m&tmAb*pSlWc5kSgvcy0ZEedWHJfB zQRxst5D3pkNF)+w^P|!s0Lf$$Ns=r((Gx(DBt0IFlgs4*n4X>nKoA7JU%iDO2wmg3 zT#k4=ZW+Ro1G!v|R4N6){{H^|YK-wzDrLf+8$gmIJsORg&Ea&Wq0mH^E)<$D9WWrG z(WoUCdVe~wy}b><+S-}}PG`Ea^QcR+v-8Mwz|a|a=K{!PvwRt7kj-Yh#*O>_rt>%D z*#`LfV=n+VBjao))=fJVML|&%YPBkgqVVTmzneLmiFN&EWV|c?ZDHwaIO;nsl+Wkc z+S=mt&%Q9PWgb5SU1!g6y7Wi=pEBz6^6c=rm4DK`pMhGv!SEFi$7+pEr^E8{GM@L` zh@Z^x)6YM$xVXr*>(^OYTB6hGaIDt4pnFBnH1FWns&JWfj~e%I5+^n z@AsSI^?DruRaH%0rBbo{a9RRbSXj`5!5}9mC&;o)sZ{EMP*s(&u`xtZWN2uJLZP6i z(`ic(mPEl|@XU9;UawQBR2*KfSNHkO{v0JM6bhDVzXD*^fAv1MnBM>Z002ovPDHLk FV1ju*%k=;N delta 470 zcmV;{0V)2j2jv5h8Gi!+002a!ipBr{0EbXaR7C&)000000RR6D4Gj?y5g8d792^`S z9UUPcA|xavC@3f@Dk>~2EH5rGF)=YUH8nOiHbOx}Nl8gcN=i&jOixcwQc_Y@M?hv} zVQ6S*YHDhQduNS}jhUI5q@<*(orA5dt+I=ExT=l1k$k|wz<Ey zs^8z==(U^w|Nk7#%hLb=00DGTPE!Ct=GbNc009h1L_t(I%carbZi65c1z;FDl`E{= z)voR6EL))<4X@xT(l)xC` zobm?a>f>8|bbqD@Jgp$iN4Y?LkLQ<)ztv-^Pgd+KTg|@VXp);s~2O{ z_fFKX`&u9kXh{Li?y8stX|Fj5z?GeU8%)!}*%17&w5{;taQ zE?5Q#M^xGNTO1UH+MZ@^*BxfnN++FlN2u*-20+(!!V%RLge8E=hCF#x=mRlgyZsJo zdz$%SMGmz+&A9yzI)X>gb)83rJ}MjXEJI`jQ1`^7{eMY605efrTk3K99qjKqjoa^_ zwWU7Ir~OGk>YkV-2uqD9kekcJQ*F38VDti4AeHo{@vLbYx~_BaR2zZSx%7<;S_!@Q z4pcVe$)Pj*=o{$;;N-DBVBCNqTwGL&Fq>;nU1Z_~!^TwjZK`{F?t^2-Wf=)yQZ0y%&W zMAI~5LhVXlc~k+a&@>Gnk43pK&Lr^iO95sy3FMpKy}M38q8sQo26~T!2wp{@BUVJd z`Tkdt52PIA7Z6Giih~l4sL~NDGP<7G{W@Yr5`T`ULUB+iG2Sl+@ug1g7pTNc4p1Bv z%I*rAC1pku!-|9QKc5WBT!Mcx+#5HWdDJemG!}g3$o9YCY_i3kZO9gY>McvHQte6^ zK%(22UrGRgqnASl#5_BCIb=IIWO*sAu5aP_zf-jTF{)HH zpMM+ABwIU>!ywQ8N^h|fV;^{Cw%r^CNiG$@)ks8Oit2;!ak*UP=s5q~S^+>Jk)ZX` z6jVp#_q}_wx*vX4=R+Y85g8pGmiy7DIGs-Mcsv5&@p#1Pbjtl`R7Qt~MMUI$C}g<< qS|V+1Y+Nv4Q&W?&*qoKvp8%^QY)cu)j15Wv0000001CCF(E-QAwn`CLoy;nGcjcUGXMZHX3RTf z5_`H95XvzCV5h@%VgMnUR~X|e0J0t;za-M9D#qz$^^##2kakZHS1;*$(HVzBUpUi= zzFUJ{n7GH{tuUfbfU_t;hi5pWp%mv8KxK(wnNSoE7gnh(psFzBeiq;;a2}8#LV#q! z2r=UZP!dVC0n`Fi7VP5}4#z&zPgC8tsBPs{ZvPrvyAkog$L THJ#?700000NkvXXu0mjfHJ!}Y diff --git a/Resources/Textures/Objects/markers.rsi/Captain.png b/Resources/Textures/Objects/markers.rsi/Captain.png index 6d832c820eb053ed8c06f79916929db7eaf80ac5..f32f53e4625bc7577f8bc0a5542757f5e9d534f8 100644 GIT binary patch delta 1017 zcmVU+0O-HZ}7uyv zZsF6}qEouU&`qym!j4T@2t|zuj+C(xL9mvt=pQ2#QV_z@ze?~#60OkIF!2YvsFYe` z4bEV?J1wHw4{*Hu!`1Qc_c!lcL%7oHkX`tOxsoV1%53zB{u8Fu9>1fi^ zN1l+&UM`={mk^1BWg6*dk~2Gt zJMY-R^`)Q5&B^AsKmO!I)B6BSOiUycGpRg{bTsMyf_wm~UTH~c;)Dn|yngL3F69B+ zJUvrC@crA*6Zz>E(|*t0S={$h2Q?)Hd?Oc^r$<@5IDfP~i_qcqOG3e5P=;a1bNr+- zi^}Bi`n7c7Lpi*DWfqmmbNr+X!%#37l!P2!YYWn{0%sl_;@!^-0HV<-%71Vz$lO;r zolXE=sQ8vQ$NZKR*nB7S)oC&BFsH9J1K@VM$vs$0UO^!Mc?E?;B2nCKHvp%vHnW&_ z7<_e>6o0V36)#-@z~yoQkeQuBdgKzB**P$})*l;Z74Zr9>O{`I4MFF=`2kNJ~qjtJh9iS{nI<2mW!K6{N;9Ha^)#Lqi60 z6D#a_WVLU8exA&{hsZ20<%?<9UtD^t|4Y*^+<*KY`My-no%@x>iA3nE!%VkLQij6g z>6+=b$uJBVh9QU7FNfE!zIL&&E|+NS5>nZI0aQLl-=kf8jW(-V^0Bad3qFp z#fw8Afz5_t80^`-n~y*J1gcuVSpuD<$!|zA-8O~C(Y>ujC@!Y5Yg2ABh)d^pnc9rbV(Z}rq%qtiSYQ4{9NKBqsS>D1< zEwgOfxn^Iwl5iCycP4Zeg0qn2!B=gucCtwNP|BtLzu*6J0^5ZDDS`E}Z!ry)(b$Mt z&rFd?s8gn`(Q@4+M?CX=K2j$|5gtG$7*V}_n)A> zwN;W7Sy<52Z?_}aHR3p1^Eze`c00000NkvXXu0mjf6LtpG delta 526 zcmV+p0`dKX2%H3v8Gi!+002a!ipBr{0HRP#R7C&)0000000930IBNh)j{sn}0AR!b z|NjFlLV#KtMo3Apk{1 zMM+0TPft%#Mgvn*Q&}wmTuw)5XlQU@1b%*gfPesxZ2*{*lz*+Qt*)%Bu$TbCor=n% zkITu))2RX1u9@Mspy9^}>gee0z^MGpv;V^Y|Nj90{|*2D|7m`S{r~^~0d!JMQvg8b z*k%9#0VqjCK~y-)wb0>CgD?~Y;FcB#%H6zO6{TV)n{;l#P}uvwn#G8TqvhXDAcWqJ z(@;YG$B@}Xk$;M!xp{1qiK987jPirXY~mps<0ixQzfqo&{p;#|xSo7_>}$IEq^tUI z?G;u1QCI7=|2Ot+>mP&E&{kE|f|lT#cN#?kEhGYU=M-DSB>*fDx2`$k95W$6bQyBa zT!5h#@?L&vWDa20EJzZQBo;Wtuw)xRfzU`Cpy(TdnSYcZWrn2bi%W3qn`qZiHJKKSXT@*1^OQyqh9nGU z0VC|nfLXx&plIxQ+q>}0%QDS#lILkzI_JCd>5y8G9!}?-3%vbgeEj7bSg0Fq2vQr( Q00000Ne4wvM6N<$g1-vsPXGV_ diff --git a/Resources/Textures/Objects/markers.rsi/Cargo Technician.png b/Resources/Textures/Objects/markers.rsi/Cargo Technician.png index 89cdc3bded015ec10bb02c575a7ac35c1cb4a19a..e162a24154c1c9354d568c6e2f9108745f77aaa0 100644 GIT binary patch delta 912 zcmV;B18@A+1Dgks8Gi-<0047(dh`GQ17b-;K~#90<(DyN8&?>|f2V6~NpMJY>VOgy z2@-MPLJQ8IOf4GXB{Zci8SEBXvT11-4K4||FD?mq2xM>|UK(mBhBPz<4=p5vi-uxS z+@aL?5Qf}|_>5^l@de4QtGo{44%tn7cS=Hr{Fi(B-o5Ypy?_7deLBJGE~S@6XRaKS zyJK^e)t++2UPSS|;z5c;?G;h`6ebT{@Z)0-F46v{Q$MN`ksa7w9ANU$1=PNtov_WxV`sIKzE zfqwz`>5B)U^M-byTrNw?ve>68=+*5Vb9!}~eQKv>Obwec0)P-gj*N_S#y67~`8axY zn@ew?SlbadO%q+$L%9&>z{bXg2ctm8fs3F034oE0`}cVcc=vhhg7n5- zleTSR+kf^m=a=qpGE_`NUKbi*_~@IQICccfS!eiYMb1>00JwX{<8bAZL=6~28Q08axc4FJos`0B&QfXeT`H8Ja3eEN+AQnI9U`oRA8Pco3w zu$=WUse=LBW(zHupk}X5Pt#~Lc=*U=Af+*o z(s=mD4Fm{mnX{KG5@7WF6~#Lh-5MPo^~XX8gb+&inxOoF4(v{n$z=So<2cOE&->sUg2yuD>Y4%_ZAl9`r4Y5Qp)R7Q=#98LXnP- mk3Tix#KeTM*Iby~{{g9mU?-d@of-fD00{s|MNUMnLSTYAf4xKi delta 455 zcmV;&0XY7f2i60S8Gi!+002a!ipBr{0De$RR7C&)000000RR6D4GkR~9V#j+GiJ;> zIyy;7NlHpeO^q5(kQz@seIKWWbEl`Ls(>J_i+HZAth$wez`(%5oQBKE$$!kGjn=a$*{+uA=;;6d z|0E}Q5C8xG0d!JMQvg8b*k%9#0R~A#K~y-)wUNLAz2Tu%r_1!Z78>15tx?Ts?N#y(}}UL$P0@jF2J zPURZwjaQyJ=!BuaHAC>!!2`zXiMDN{prSBWPuMV8gdKI@fOZUaDYy~3u2cMt!|2AP z;DTKtAT8r#Wu03H%vzd+;GFBZNbho*dU|y3XVNlz>Ok^Bp!{~_1mbpOpiylc=ih{3 xD9VzRWibrNe1E;13lfU+<+@J^Uy=Lk!4F0I9e;?a@G<}Z002ovPDHLkV1fu<&GP^N diff --git a/Resources/Textures/Objects/markers.rsi/Chaplain.png b/Resources/Textures/Objects/markers.rsi/Chaplain.png index 84223f74021e746054adb3f874fd6f075cad47a2..c293074cd4564d4c6f4d280a8733183cb14684bb 100644 GIT binary patch delta 890 zcmV-=1BLw91BM5X8Gi-<0047(dh`GQ15HUpK~#90?Uv7L+h!QYKawK_g~)_3v}(cl z5`i%E&|Y#+PQHcFoJVgah5iRiOa6m^8NHR=%ZM)}w*_B{SEvpy!O#%!$)4FlQ05v- zww@hYsg9Fc@{+O3zVINu@B94tzR&x-j|8{CPd_5Ju?JB9X@8JsyU6c^>8L7{y{y z`oA?%I%kX`p?~}S5`gaeOGc5Pbj}jJtUe)Q4FDV*9I(B;t!!AUqN_Pn1%h#eo>Peg zf@n;mcdks@WX(cq@c8}k@K69YtX0|i?%PD-)Zb*27GvfSOz+_6=!o_8bt&&YC5WO# z%DYc-T~{iVip;W~o4_Q>+48x#auTw6Uv$_N_ z)Bu3%x?&gx!{HEs#l^*II`P`_@-n{f(`vQu<`%fFEBSmr89R=H=XrSjcW9c1_PHTB zjsrj#hUD{kT-VKX8|H3Awr#VsvxC|BLQ2y#Y}=mKRXTxq_hA?^7!0ngO=e{hgTY{~ zETm>24u3v*rp;y((=>0?Z?#%VOd<;wW-V@RZem#$yZJhn9FbO0oQMV=XsP$B>>Dny69?-rG*?9L6CIEuVH2eV(99Z zlL~@>APAE2>FFtmaH1%bN+onPhpwu89F4QMPJbsbii8DK;jhsc$8lI&TLZwdtVHMe z=cnU1bl-H*RTW)T38HioGYK?$=Stk?8@+R-V%u_je4HG?a5&`Trkhe2hF6Mlo(>pe?nV>`_I)4E^Az9rGhewoBXF1apTK`kAX6ingzx*;<_3eo zwR4ZvofG)w)hhw`;qhZuR#uYve!maE#l;0bzkCTG-#>bEyPwf%yr@=1M5Nd4%G*Xm zOw*J?p&$T-LP1Q^l(&tB^txRU5qVLqX8twL#B^_O??#9F`}@kQwJg5>28+U^m_LA~ Qxc~qF07*qoM6N<$f@X}qF8}}l delta 457 zcmV;)0XF`I2iOCU8Gi!+002a!ipBr{0CiAIR7C&)0000004Dzc|NjjQ4I3L99UUDX zA0H$nBq%5-Dk>^5Eiy4NF*Y_fHx?2(785-f6+SXIKN%H68W%?#7*9`6RYW3HRaIzc zXliO|etv#`Y5;(MfQgBTl)tu?eE^u0l&-9-u&}Vp$;s;I=zsI`^Z)<|Q#wB~V8whWFmif!ZS;6Cx%V1wG3MTBq-%HAJ$P8nTfA zFp}zxhMqqeqkGVlQH1!`7-J$SHLb7#?fexS zz+$jl!6O_q{J;S{ZUrA~KMX0Q1Mh7e_}Z{_l)yQUB|?z1EJw_@-21W1ESS{)T*%A| z%``P_%i6Y?CbB=@u9qeY&EA~CrfhvX;^w5J&U3$?Fl{O`}nC(h>h|nSwwKQ%j zNRW<);CN{2I-;>zk-D?)uZPvujcIpA?WtcF-n{So{oeb|?|;u*7XI&04&&6?Uty=6UCrkEpLWk9YYo>5B9GHTjtN%&*MMZ8{cUI|BQ|Yhv;u z`H;!C@9`q}5PuW%wRU#ksB-(7tK`A#CU3euWF$*^JBzo(gLqe6_dYgf;dbW&7(VL(Jorn!PPPLa7GdPn0@;f<7@M;QpY`OQu{n$E#T!IUEjSin zI|9;%Fax{`t$}5}pR35PwFZ{i0+`9!DMR*CYbyeprhkbH=4z|`SqEETjn=?2ZkLif zJgm|FtRp9MP|!5Zb|DrOAcIKz{SFMnfI7erKA(@Ru*Q02HCtf~pU($=pbiYfp#6Ra zGKeh^MFo8Mrv`0M8>v08*4x{AfUAwvLfektQ3Yt4CRbWo7**rYw#P3mEdekxGEy)H zpbbXVIDc1KT5P4FXaweUokSvma(%C`LZJ|rWl>X8gJoHSLZQ69avdd+NHDMK#kK}) zbU`AK*qhAchBJWxX958}xps|j?%vIj_x9Fz{mRP9jwax{z8>E4dfCiuQ(s;tum-@? z3^aEY_*}+<-+SK0YJa0^Ik9rz{JD^ z<*EuIC_}rpC3syfHZ$9Hwk|FplNH=9g>-hCTbDWsejFtDRS%+j-GP7BFqDDH|D!^>mtPb4>vl{Va}tQ)l%3IJ&N*d=APGC^LmV8yPF_^KYdc8aR1gfCwPa@{dLK2B3pQ$8hQj~=nIvO-T!&+%Tx`?0^h^nLGk+wN7^{xM3W zQmCq$yOMVh-1+i(UC;BWRO-JG0I;yIP%sV*3@Bjl&Oa7(cXx}3h+!BKjYb6^8jXr! z7$PEh&IugXz~bVfBfc0Mr68S7Gdw(8zY@Io{Uh%5_lt;#nM}%)>1m0_VzPU%nM_JN7LzB_(_$u*A|i69zu$H( u*h;}4rb$;ged|>+Ami z|Nk=p|7HOHgaH4U0RR90wyCAh00001bW%=J06^y0W&i*ID@jB_R5;76lHGE`AP|K~ zX=6a6w6$4?+EB#=mn851c-`2a8=zM`49hU*n=`uujQy|lqQCqT`KLUg-?f&SY8KdN zDJ9h$z^k_xT7MPK1@LOOmD^p#b(RpTr002ovPDHLkV1oF^=X3x7 diff --git a/Resources/Textures/Objects/markers.rsi/Chief Engineer.png b/Resources/Textures/Objects/markers.rsi/Chief Engineer.png index aad16c9ba331b1a057ae1799d2c15a0e4bfef772..ec40156f1f56eedc067192e265ac9427e4e0eeb3 100644 GIT binary patch delta 1134 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 delta 552 zcmV+@0@wZU2(|=}8Gi!+002a!ipBr{0H{z*R7C&)000000RR6MJ4qQtR2mvh8yis@ z8&Vt`R2@%ZAzE-ET5u#{dMR;?EqIhKf1ERB%r%d&H#avrp2I+)#X=zfN`|XctIJhX zR9BO@SuFutH5*N=QX)8)6qq{{PPmIQo)M z-@KV@CbMUD7Js4tj_><_^=}H_7ed?+OJ6*h<1gnxuoT>!WiSf@zJJ~GU>1Zy$T>H4 z4nWAm&|H}7D^i*XB~flcP6|jVN&@Ococ#*)nmm)WhRP*Km5ktX1W9EB!V(NRA|;75 z;DlL%P>eutqgAxkfH1WI#z;ZaESd%s!q@`2C~^g~S${PisJsxl4S1m#YZl&}rwU%! zfQuX}&{~7SJI?c+C33SGqxYWY?WFlgOCTIGMjt3+hrS>B{@?)P1aoCSY=&N1;4zM= znLy)u*t~3p+6H6BT2B*ffIf70M8{6cX$R>5-2}RWtm|6ZOQJWE@8V9|rdfuvENxq7 q|E#Z<)FFWMa@A)Sc%Sm~{N@WD-6_+xWFHj(0000AygU8Ig-|xNmegA$l1AqTBDU(gRSKgBFe)P+~ z`s$eO8wfz$Xq@5>O!gcIKtIFxr+?fhJNd&$J#A!xIGVPYq}Glb-51Me0Ra?^J5ID# zcr!nUNsgo~hUi;6ZsfrI9)2lotwlg4=WS85)h-aBb2VEH0D{)}ms``*SiaxI%G=$y*Mw4=FpNHo7=jGo z5@jTke{&6hRjmQAHawWhNyYb5(PU?!6HRDHdAodn=fB{cd7CR&=V;Cp1Ao9HLp*k$X9DQkDd8M9XNmw+e%j)A ztCea%fWHd`><=dZII-3UbTcNQF8~2)77EfV6hy$7<2qRfQf3K`w^}rSorL@m@J8%; z6xaeL0D5HVzyOj?`_UHgu*1hfAO@6Ln=pM7zTYK(n4)tm1k^bPvg)7N9Pt{yngFs1 zynowq`ZI7Uarl@tpK*7ZzTF1xc(b=*AHxS4uLSjM!eq1+-&di`@`5s~=JwJZm)TlN ze18_$eHpN|mX&i2+>*y>e+jF!6alhICAhx-9{_;s@{{cg40Zw`W zSBV2TSS59&KR@49RaI@5uYLdkiHV7gTrrt5|D9(yqzDMDaXhd90I;yIxOhOs007JY znbrUR*38V|Yz^c90O=7C@_!if^Yi$MivIur{{S=pGc*4)nScM8GylN<|Nj90|Ns5X z&4&O000DGTPE!Ct=GbNc00ApWL_t(I%Z-u?Z-X!lgrTfu>0@pV+H`?F(nsL`|H9dT zrl~Q~P9jRU&xd1?W&hUYa!Gb?{%HJeG~bJKLf$ov@A}R+jULgk?-$*|Gtp>G2+(sv zFMxiJFW=wpw}0N#%smg8XQKChb`pn-_!2Zfsx6|mHex&Hn~3Z6ifD8K!IVrOmL@>+ zV>AUsg^3Yb04Hn$ixZRxM8FiA$SMqwMu3Y<8ODU+^bSA(35Wt90qAIHOvp<^_DCsE z*+S~`kG!yzO@Zo2FstR~a%DhOMM(=p=b^GMyjUzZQH7V zV+mB(E&;d+vFlOJL76om-mZ2#D07;SNppYH;OW3*bsev~BpBBF(-U~S2H^Doo~Qj9 f%EzbLzrFkb@PR1AbX+%P00000NkvXXu0mjfSAXJ> diff --git a/Resources/Textures/Objects/markers.rsi/Cook.png b/Resources/Textures/Objects/markers.rsi/Cook.png index cc778e79ab61fadbd86f6ccd292666044790a29b..f8eae67a886addb0d0a881b4c4da914e28633f7d 100644 GIT binary patch delta 995 zcmV<9104Le1nvir8Gi-<0047(dh`GQ1GPy+K~#90)t6sLTXz)4KfiR5DW;WK?NgRy z?G!8w_TpTvophZL84O$zI`@aZY4Q*X#?n1#^uaRv6p@gpmUSuYp$r`KVaDx2y@IP+ zJ4PT?$sb1vu@((J)#}+pm+L~Kxyfu{U$`88=iGCCU(UI|^M5-R{!a)7gA$9yL`3q+ zU@$1Jg+xA-y7?QWIK|`fQrz-F74!1sa7ZF=ZS8A+Z}S*uu3joCW>Fa^Gn;96TFLg# zbIxCB%dt(3{D#SFDkdBNhCL>SL-K5Un=-SR^Hpit=*OYwNF`K$+Q0nc2+qogGs5VpLXEaO$L;%E}5- z_hPS}z_ab`Ju)|MkX~EYpR$`bN+wWJ9{_mzxht=}ySrP0!Jy%zXea|NmrGzT3nzXV z<91s!06%=v%!%;NWbJ)@efs-{Lcry6iP!7R(b?az@qhKW2EbQg4ZHnq-R5vO@Or(5 zNf^q2-EPlWhr?kSmlgqZ`ES^4Hbjgi;XndCJw4Lf+Y7*tf6eInH|Nrf`2Bpaw8)6x z&(!rhy3Or&qm(jSiUSFlOeP!-2X42UKp>FwVR<~B90_oJ>JEWGK)Ky+Y&Kh=y$chV zoBN%nrhg{p=jUIt`ThPJnd3MAfDfC`u&}UTh{V2_o){C^dMu9~YBD`BCQheQCWk{Z zIULgGfb6=Vp+THZr%X?b$)ksw$kt<-o*4UYCCH+-rkdKC<0KLZTCR2h=ygB$?U$Up z)TXUS+nrfC-jCIF?jc7BI;n>lm{C^pV(%IQb`={+B5(#WJ8!gwma5|kN zPM^l!-cDm87#L6@ijO~P zrM|u%r4&A&PbsCStE;26wH1KD!NH>HUeZW*m?(N4h(@C?=`xuNnG)y1q6j3DNs`HA zL0vI0T(6(*-W7mvE?=gqstSPB)m3G+T3iKSV`GEwZ`}f*yzwpy)Xu~_8(?5w0ysTco=qoan8f+42;{r!0Z4h;>dgKS1({|%Vh+lJW< RiopN?002ovPDHLkV1jwq?PUM} delta 552 zcmV+@0@wZS2et%|8Gi!+002a!ipBr{0J>02R7C&)000000RR6D4GkR~9V#j+Ha9sp zH#IjmH#a#rI5;>-Nl8jdN@8MSXlQ6@X=!R|YHMj~YinzLfq;H~et&;|fPjF3e}I93 ze}RF4f`EgFh=`DokeHN|n3$NEnVF=dq@|^$rlh5(r>Cy0tbe+?y1j#-z`(%5hNQ&2 zvBrs~$Rsbwi>b@W$;`vJ+R??{-rnEc;NRch-{0Zj;Naxi&g$ss@aEY5{{H^||Nr#n z|NZ~}{{R2~|3-RKP5=M^0d!JMQvg8b*k%9#0V+vEK~y-)osw-&!ypt!scm(NI(+HX z>DEoxy35LBqJJA(mH+>@gf{bog(iAPE+3wghXf$x59G=;D-RpSk@rtflS|mU8pDkwHNSM6ET38w6HT%Bojzpt$tr3=!X0b@h(8X1-im z!Po+0H{~&y4Y1r-dnfFMoqV`9?u@Y++sQl?*M<>yhJUdIl(1b#I2jDcp@EX))3e_K zuO+9h0Wqaq*1RidnSNR$I*L-MWmnKO2bxkt({tcjcLc)u=-HHG6GhPsIQL!Uo%$-9 zPpQEF77sI3+CQy6o&v(?{suD0MgUphIbkse0`mose+$zov?IWUr5%2XB2E&LBymxA q^NHE6Vj(NUtF4*%gxiM0_QN*^wKD6j*iTmg0000K~#90<(E-tTV)i-e{pS^HQwCZv^v+3 zpSk_6PwlCvi5ucIf*?-b4V9Z}&BfnmYY3&5IuI}ld`xx^VitU)c zu&rJtm`a?kzEP>OHnNdl=TdhXhkZZkOt!53YIcn;7Teg!ubWOv)0w-KL?-tqiRBd@ z(^TxX25vTOA^m0Ua$CkKDl_{pafLSG=GVT5eTT7blPmizQ^N1v8yN@ z4i2@SCUE{o^p+>_csxa&PMZz0BusC?R4xZVBoe{z_tW&paTab(6vrcxNQs_V>_{M> zYI3x`zQn1q(w4P34z-^~`Th)@Hd{#qrgAxs*4LYgg6RlcURk!l=1QNqcAc(9JMA}K z!`L1p0)K{{S=3chm@5>@WNp^XGhn~NK{k~(ZC5pcp0_U0>22fAVw|2-THe3@Q_1*r zI?Xe{>%ZT{+oS<7F)}F4P6w?mk25uUo6B#!Q#%0z&8h-y*7^DP671Utz)6RL3v+WI z!mMR8^3BfYX;u~PEXK{auABqLWwVq@bE+Z64}T|5@IjNt*UueiI-SPn^Wi;qjPCAk zPBp|>`g=J&3<|(NhfA*dTP2`s5>Pey?4`p36rX_(mu$7EgsL)jpu;8o z&${?^InPs?wX6-#Bzf;f^53}&wnHL&Z#U+Jahu4&VdIJ z&wt!6+xtZJ9(L>f|AxSqw^L=Zn~5wp6WN*wm@b*muUrv;SNi*LI-LN_&(B-jZnprW zQYk(RhXFWq_H0eRY5#~&FeoA-@mNfzCnrTw6fq`tyWOHFicC*VN<0=55s^?ZX!?uD p6w{%hp=})w4-Z>*8Z+bjFVhrypvBp+dJF&n002ovPDHLkV1huC$vXf5 delta 468 zcmV;_0W1EV2jc^f8Gi!+002a!ipBr{0FY2jR7C&)0000004Dzc|NjjQ4HFYD9UUDa zB3>#gDlG>HI8=;1N~}O&phRY>Nl8gcN=i;mzfVt3RaI464-sV<8D=v8XlQ6_F%oSN z6MlYvf)o~!7a5U&hL%PfmX?;7l$4q$C#z2$uB@!Eu&}a=cYn53BD#@$#+!x9$;r%M zB+sIY+NzT1wVUeb==1gQ|NsB#YlGnc0004WQchC{F8xp)}&(6SP&NrK35aMr>`#kC=gzJh)k>_@D zg=_4a8ygXBy??R8d=znUIbDn{Vt0HNnK33SqF=G5%!k&o9%<+L9bs4yBlP{e?*W;D zJ!2`K7E3CTLxPwPR?qV#0a5_amI%w$%YwK>a;E?g2%AmC3@Ac?JYYWD0gZsRo%Wz& z38*`($G~*3bsOYNLT9=$FjgxBtPoz6Hf98b)J0000< KMNUMnLSTYxvdo77 diff --git a/Resources/Textures/Objects/markers.rsi/Cyborg.png b/Resources/Textures/Objects/markers.rsi/Cyborg.png index f406e6b663f5702110c68e4ee03a553d168fb55d..88113856650630e987b4f5dd7fd0440e5ff2ef0c 100644 GIT binary patch delta 723 zcmV;^0xbR60^kLZ8Gi-<0047(dh`GQ0;fqtK~#90?Uu1?+fWe3e+~8KAT*R93>|~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 FV1fy0QXl{T delta 329 zcmV-P0k;0&1=#|S8Gi!+002a!ipBr{069=hR7C&)04XUcD=RfEEiF1aI#W|qQ&VVF zQ&U-4ab{+KYHDh4Z;Wzsa(a4}fPjF9hliP&nWd$rva+(#+b$ab0004WQchC#uw3 zIimZ$_gY)e2pIra2H@^y?oI|6W@cCl5CLnE0R0w?21vvjeqDsAqF;LRC)T$ON)q0ge zy-AK4uB#h2wL)6OVRoQen{KbbQ_>EA*pi;_z~r$v?(F?wz5|m2;0{ojuK<%D8Gpv# bmXi4!w@(NIV$f!>00000NkvXXu0mjflJtr| diff --git a/Resources/Textures/Objects/markers.rsi/Detective.png b/Resources/Textures/Objects/markers.rsi/Detective.png index b91db06e1a4231ec70c89ddfe0530fa4d1fd52df..73d944a0a712a206741fe5acecbec56f155e4379 100644 GIT binary patch delta 954 zcmV;r14aCb1jPrC8Gi-<0047(dh`GQ1B^*TK~#90?Uzez8$}$(f9oVo(yWs@b=(pm z$2n}FigG9+AQjMBIdG^bQXwd+cvR{ES#aZs)J6&yPMi{{LW%?^7YnN@k8mIovLUJx zEU1zqtaz0u_Q6itsaGnCHA#Fk3Z*{M5}Dz z%=$wva}vPy7Dy`qaJBmttYrYTQoYdi4O(8IedtSi*89$*Vma z@p#CqJ=H>r2TNE)A`w>?lN5o8uqOIStIjx`En*l3nSY~R48tIuEjqrw(kc^SO`1eQ z0uy0PoC@|4@Od%)CYG=OFijIxRWVHy083byev^RD%c)?WGzlpM0zR+PPw%DyXm4+S zsI~2n#vh7+y?TJfl??ziO*=5ww%c*CDl}9e;PbM$vOzR%C;*0GIKJNAUZ-!{qj5u7 zT-lITp?@xcP(WpIWrI*aJ-s)9bGaM<(f9*ZbX^y# z_XFfACs^9dYA@ zx3ss{kU-sQQ`dEIw4=i*_V#OI%*`*6$z&K97=K`Nbd+Q=NhXsa6bkYBxo7$K^Y5t5 zNhA_==V*9u+tMcz3B^7Y>1+|dwGF_`_kTFC6Jd>L+)!$B8r7G6IBJh%I$LCXq)ck9 z%;_gOiT%_`tU`JRs2=Tq#id=(zFK zgMYLF(YT>>l=6&^lo?X*J>(lw?=e17rlXX1wg0XN*hsCFUD+GK)fU{{sc?6v($MAx z(h6LU#l+>QIZEX{ye%f)mg>i6_eF#IJr+CEuiAmQHa#tb5TdZPC6dd_Vr&p` zaaa)m7l#!wHi$?rFN?y~mJmXSYtz%xBr~M8AXg|bIXUT!pMUdewR3w4?ZOo_;H&w0 cH*0e6FLls_4*eGO80-T(jq delta 507 zcmVr z9ImXavW{!JySv53#mmXb)F=So-{0!!==k{f|NsAzK|LP;0004WQchC+5PD$jXp3naKI zibC;Jz=jKzRhbfe6ZOH3g3Tgak$Q|z?q2=U<@N*XBG%E24VrgmH}8Yh(v%J z@(IsAA#^v|!7cz}0DN~NIUKrSr|* zF(`E>f$bJ!48Dn8m4aUPenBV&XsM?GiR1*}F|d&^!sK=(5B!$=(fodjN;em-#x xL)kQ_Y06=U`UiVCmkub;7kh{S`=H zgr*V79zu67VuGGlY7fD-hdp({_0T=E1z~#9+v+SKdr+we?Wu=qn9G*z$s*Pqv=o*e zb^`fQ-mi=ttL;j(0Spp!X>m-v& zUJkg->3Obt~wsAI`I0L>juese-PmjNV7V9^sbK&`O06IH60ciGmO&=}R zFFpPOx4Y``oq7Fn0`}o)ti#h-55UAgic5h20DtrI^QGh>%>CplkFCekScmb)mYvX* zOR#_0q*gXi-1ljZ{a|j#o1LAk_x?=7U6}h$P~7)<`|f>Na2;>oy|*ReL};;o*`Izz zQAE=;`AbAHo14?dv#~%i;BUF$}}x0_9(x(sh&1<#MMZ0AP7}*<#1X z$6b`_|KDJEcvwV448xFUG%5hmXjBZt5D_ssCvdz5R#sLV@s;4H1bcgXOifK$xUH?N zW1JJ%-Y!}^ZccAUM+X4S=g+$`>9hbWEL<#@V!k=-(#Kgg((N|NsC0|19}tSpWb40d!JMQvg8b*k%9#0We8KK~y-)m6Gdn!XOYvNrD9% zy4p%>7A4pym<03wuUD{_KY%km-@s00&u|$+$p4^>K5j?oqy8#}J`iZksw~t~NO6z4 zX47j3tLuWH*?(k1m@aL>8rw8su%f`8thG<9Ak+k~i6D^dAt-QMhyEHlWG+ex-Z%tf zjlge6(yNO03gU<_cocALMY;rvHVU6nXa%NycM>2ve8Vo(lS>RVl7KjO*qsFsX;MK- z!omBk_rQsiiJ+%Jb1)u#1zZo4P6az~=lr&MuJ~YwRCchFmK+2M;8I(gKA6_wXg9y9 zs!GO>3{p8~cE&j+^RFe9ab^=nN!Tf6!U{&IT|tQa%z5_9sE8UDRr;g$<6Rhw!h7I* z%G3A#Jd=42HQPTd^Q8|$f0>s9{U%1@gzjJ=yd(QWF?|-@QA44&1aq_GjICt*{ z)BbFxH-Gsx7;!y2SE~YuSrQgg1OV>d(l)DAsa#FyZSLMO?W#ANJSz#8OBO-D5-ykU z=DP={rUT5S07wO$On;%k3n!q@4!cd*-X!(v-%NjJo`9)*Wg`)>DGJWOFf+e=#N~<4 z^t+nh)YpZUmVXTUHLn4nzSCrO^b!EGqnD`fG<$JlouNHBG=2;_DrBaFTl`#M& z(^CM1ue3zKK-kR@So`^zp~=+i9s38_?T3yZqm;i7-}opGt6S9kL0P*0WWwc!KYwQ> z_O%v;+~?r+YBn=L8F4yz$@LtCwF=XPLlAh1;eR0q0Oj(1ik`Rh@yYZQTup!oMMaDJ z$mtUd4>@>P-7@03dkX41O@;>S)YJw=tD8{sSG+%7BV>61wJM=d2=BxM;c%Fu)lE%p zw2|(Hu7XL;1O;IF@;A!9sxGt~J6`|_d8N(fumsxB@=^k{QmnN;H2CsqMNjpBUI$*E zSAX<&kLZm6{Cms{9=D?>a76eY5;!Q|J?g-8S-x-151|9YM<$a_3qW!<#<3yI?8|~E z=X{C)Y}ADhK1~DgPAq2rpR*Gdl1UK}sjRQd?bTKBA4i^Ue9otc|2T4cbyX_s>mnku zkW3n`hzzCRk4lBPxjDT*`Thm1QMia_>K_w4KsJ{%^GrJa0V{oHW;2$qz5oCK07*qo IM6N<$f*8QWy#N3J delta 486 zcmVpPgyMiXlQ796%~Gd zeuMx3mv2azl$4!xOQrw-sC-batgNqsRImU5vrSF6PENRpSbw`vP`*-9#F1Xav^C4g z$?5gee6^Yj1z|JUK+$N&HU0d!JMQvg8b*k%9#0U1d|K~y-)wbI*CgD?;V;H0%( z(`AjUAew4uAQWop`@fz^J=~CV#tVOjVKVzovMdPkmu$b1uOr1^R%|zjABdY9TQttO z=04wpS*`EZD}R%%cm4PnuDfOM>i$vK*SXm3RT5KkOIJ(P$|+32>=MdRih?qDu%F10Ks}vM3ZKb z0uaG2fL#Qz0A{o%^bn4anvEUJ5_qeT6v+pvt+z|yM_&_OgOT+Um^ko-F!5vnDJ8^( zNY9GmZwa|?34|yRZvqG-_*Z~efO!xn42dy+r)|r+7Ij^=ZL+?`Fcr@+fK cKabyh0(-p}s@Q02qW}N^07*qoM6N<$f=Zgpng9R* diff --git a/Resources/Textures/Objects/markers.rsi/Head of Security.png b/Resources/Textures/Objects/markers.rsi/Head of Security.png index 48fe1dec814839e5c0c6051a5b5ed0cd29cc443a..e13caa290acb870291a19a15d44e5f40e7e2751b 100644 GIT binary patch delta 1009 zcmV z85I*s!nUqnf(KcV`llc)tWZ685MejSo&*nq$D)VgZ4WDg6k+iX2tB2jWodF)deAQJ zngm)U3~5Z0NjhC(GHH_bd8jiscH7KE7r&SJz2E!2@B7a8y?=Rc;D3gzmqC8txG>}L z&UQ~6CfvPD9tlrb?Nl1^Z-h7!aCGugu}u2A8Q@96^FITKUPRa)U`}2tmI2TzKBL_;wGFqj~SLdJS%^yFr@?XCGIZwFHIHBqde&4uQntDaZvMdBIhzcFE}@N zmY;t4m94u=)Ej%;{os2B`}$d1TXVDr968W9*azVDwOb5(26Pyc&J^`^iaD#7k?NXvEurEi)1oMEEaRL2W$z* zEF&_R42q%vu-MMgGz{+i_BKt!V6mM8Kv5JjnGBg_Y>Vi+VPshrp-_m`n{^^rY5*99 zLDMi84Fsr^N}L%QVrXaxfYc8jF2&BVv9Up+Q0U5UdkJRd_bdlaf}$wQ%J>W?iNO)oS&TwThyU z&1PMirlIS4H)?wVG)=Q&(}9oP$v(2y?EmMu({Sn%ghC+>_V*d~cmRZ=D5$E+;x|tN ze=k8cny04k*t01LhVpX?mQqk#Z$_|@ccIorIBE+Z4>WbdW#yN|F#HFQBuTs&jS5MU zgd|DA%pJ`;<#fCR4^k;EL?Ruz3y}y9QfeuuRL%r=ya`}8m-_iEbIyVb?C$O|Ha3RO=L2AKb5rQLZtEOXNl8jd zN>5KuTpuJ{TU%XIM`&nhmL)!xdH|XxK%XiupeRGADn_oZ0DrP9O3bp4*RTNEzM164 zpzzVC{{S=p&RhT2HUHkT|Nj6sp=k900004WQchCfUM3dim_1v<}R(xpM;o$8hI zO)4kn)S#TBxY!%(6uzT!*6brWm@|<=jf&`OAO^Jk0aiyq$iu7p+Mpr=G_c=>X>|(# z7}49cVOrgcS=DfD;AEj*nLAK#CF#(>A2`Wv9RammTX3>pmR{Dfz6Z=0*@T9cbKXc} zVxLlKjo2b;E#v`m*ryGVo{b+@pzexiRu3L_#4(*70&Eg`bGc%002ovPDHLkV1n?`*t!4! diff --git a/Resources/Textures/Objects/markers.rsi/Janitor.png b/Resources/Textures/Objects/markers.rsi/Janitor.png index 6872e9340d144f6c4380de4b061fdb7c755f0381..7be84691d193320f8bf6a63587b71d06260c82c0 100644 GIT binary patch delta 893 zcmV-@1A_eI1BnNa8Gi-<0047(dh`GQ15imsK~#90?UylV8)p>9f2Vk{(76Kn1PTbt zQH4OkP%t&7t*C}TP>5?%Cxf~aFRhRVjo!>*)3HOr1{X|2Cs7&-Njiq2LJW0GD5NFf za>POr=v*lRNp?JF$m^ioQMImhQsQRmACB+cd*Aoo@7{f%IDf(adc#tNU8qjaiESU; zzddvw&#M+c?tTyrOl}uz|NOP%8~gBc;MF?euK3IqQK#ob4y(dv^o;8CoTxKb2JXZ_ zuRuY8Gb6OxZ5}Ue1Mqlhn^wCGXGXg5(*&>~YV`)*(NXUI`T+0fD7AWHsN#bIc)HUs zUt7fI^YV5yf`8BF{g?KDl3rKP2wInij;>3}`YUe`}2?t$vTQ>q6~kBzlj zEoTe_0)MX84Fr(in&iB zm11jai*mWl#KZ*4%gdBXCCcZ|6S;JWNF+k7{(p?179gkvsMVkK1?YQD@7}p703TeK zS9D#Mcs$+{&tx)=t?N3vt}B0C(=UJD4*WeyC=_yR%d#jIi_X1myD4mIs82G>val?R zOeW*l!)ho10K+fl;L_kIN4?ZV14qi;MXEegGg)Y~u(`f2A|kc@ zec9dF5mi;iE*uVrMO9VV-Pw`a{=SHaY_6}n{vvWky0WrzY{J#mRpq3Zo7{f_ll6fe TNMfF100000NkvXXu0mjfZTh=9 delta 469 zcmV;`0V@892jl~g8Gi!+002a!ipBr{0E$pdR7C&)000000A>IH|NjjQ4Gl9*4K`5@ zHc}2aR2>~1CMG5-Dk@1yNlHpePft%!9$i%+VpUaDXlQ6@DSB#ZYHuxoelwDOetv*} zfQ2`ii;IhqJ*SwIl$n{Cr$@l2r>Cv0t*)%Byu7@?z`(@3v46|S$;`vJ*R(p?(Z%H2 z&g$ss@aEY6^ydHn{~0tfi~s-t0d!JMQvg8b*k%9#0SHM%K~y-)z0tvPgCG`wkkTg*FXz zF(Eq%d_BI82M*yq)=OyCqZkhj$cT_{G6QY`7&+XghqP@wfnM|`fN6S&_09tC10Wo% z^L7rpAx;)$jM3pysh_1xxIpVgpu%_l z5^Q(7?R`sR6>{I=8HT*7vZ~65A=>Y+ms1`hKGtotnT_`3|1z03^WOW-o1K}!|1MWMPWPrhh<}B)(ZTg?#d7R)Z|Z}X zH3~M{DsNBQ5N@Z*0ZgNaX%rjwTsFh3QTT0T{waXs@sP`A@CW-EHq$8L5B6aiMHG+6 zX?|w_KfZqlAW}*){;-3iN`~==9Yjh=+qe@s+OwO_r$l|l3zf@e==64TY}cTpn2sv2 zFnIrq2aAr&Xn(m=2dJ(VfE|ad-)+iK1!A$70GhU--mi}@2|z3s6S}SwPuyr)buODB zp16Uo>y9Dh0JNyM^==aYq0&o&{ULzHu?zNx2$fy}aO>SB(4x{1tpT*Cz^663s;ZKG zlj6j_owin0Rm;bxNkhng1NrJ%Pp8xPgMF+}6uyq^W`BjE;1BkZPN!}2WVJYe78T&L z1yxm*(Np8NhYnW*3>{|l)VRF@`6S?zs)Bq4lJ{MJwNjtPxms(p*XGGe0wDkAA?;*) zezE`)$G20y9pQCiFB5kzHIAuIr>a z_FDtm$$x5cAxOEZmA`ua3ILa`U62XgdJBwM6Yr`{J{1g7$~MCOG@+ThgqJ;qh@U-O_4!)> zn|4G5tB0(9J`29!Fa0EA?nwYHPQI0j?d&zI?SC`*Y(1m(vG)cUb5BwUYy<>jAY>pM zy@qz>YiGVjP^vcbl`@rbSvpEv{|6RRrBX%+`3Lcz1I$+{OAOH1{{{M%1vi*q41|Er zB?I{F6>Hg?tlkkoPfw31ryl{(-Q5kqdtk$-X8;t7Md)AWD7iGi@bIt*1Om*>%`rVa zO++r2Ye3YK`~7}it=-Jlk8c6_dq8SZAP{J(t7)1P3I$hJSC{a5o3GuOnHj0rKLP9` VG(>nPy{G^H002ovPDHLkV1j1!m7o9s delta 489 zcmVM08C>c2G!mP)T_-CVzhb0F1W8m&Meh)a9z( z?!ujl%A=3hu9@w?sQCE!{LHid|NpOerr`hp00DGTPE!Ct=GbNc009$8L_t(I%dODe zR)a7M0N{3{8ar7v4xCP%KV2vlWbglU2DtEocDpe-Jsil_oDik{H^La_>W#!15dw45 zaFZ1+2X5rF*?$f^+(~k_gWMj2o9qw*z6Ip}f>|cuJlIQl%zds-Fm(V*3qW!$OFBYG z){$!dk*o<*0uacB)A1A>K>~mQpc>%_SQE%w0w{8b8qtwT0hocA0W3fqx;S^xj$${& zCFnaR*Nwi>uBy5v=!aO4BTeq1sH%PeRE%m>tX814hGMFU$z2vW4T<2r$}HO$Fy`8S zefk^#S;3Y6c)tJ+Zx_JpO9q$;82|i~0po_{_}wlE*4CD#DodLI_mA6+6<{~p^d4@< fSSvd{|33c$+&vvoX!en!00000NkvXXu0mjfY#YjS diff --git a/Resources/Textures/Objects/markers.rsi/Medical Doctor.png b/Resources/Textures/Objects/markers.rsi/Medical Doctor.png index f8fea3883817c3826b7f63265e03196006cd9692..3b2fad9f3f3ca74ce5ad5a6af3f1d516ce12f18a 100644 GIT binary patch delta 1099 zcmV-R1ho5?1l0(T8Gi-<0047(dh`GQ1RP03K~#90?UzqTn|Bz;Kd*Lnb+t}Oq{AVx zP&G~1tvhLRhzJRlF>yV#rw(=yWTy(A*0Req#lt|Gg0MnIJveblp+fO8H3#EG7YF$m#X9t%Tv$p1slwI~f`2Bw0Jiq7p=6Sxq-+%iC{CrE^M3-+F!dRsrZE7Xe*4M07on=E^5n@AejE3*liWA)(vo66_H^L&dT~0P zdBx1R1*)pb(&8cjdv*_{CB^1v&+Y+WX>k!%Rr3;JP6T{DpImY{0PuRf*lafT>>f^^ zDq_#>!Dh4J^?Cug2>cx_>$x4hI&C1)I&r)TBBu%%hQWfSy@vPp_P&NKXc~rL3@2*&;Xpu<`4`9&3XD1)YaEhS6|PUH*fO8g9iX;nr42V-d9;!c`^cXKYdU2 zhwrnolghZ~r>CZ9Y--}ll`8;LS*@t53LHK!)~1H2D1DE)7q7As$Vr6h^A1o{Tug)A z4#4E(Bvn=`h~RWOGkiC8Qn`fAPGEQMfYYan*ndgxGZPH*tFCjfzmL^o;ql|ghzP2t z@$={?Gr=HFn$@Tk_+> zhkvwqJhXT`oGUNqyF@|&!YeCa4-W~Utc#dMN#;wqa&|3 zqMV&aM@GytHa0c_P<8&i5|70MV0wDm^lfWzFZiF*8|{97zley$V=lp$Ix-@&Gcyv8#Y9Bpet&IH|Nl2PH$p-}Mt;&t zhO10WOjT4=RzyEnlek(n8(udYWIG;eYHDk1Yiv+OZb2b+MI(54czJnwdU|?&e0+X> zet>|0g@uKRii(YmjhK{_o0pfKo}R9(tgf!Eudc4Mv$Md!z<+kRH{{R2~|Nrinb%6i?00DGTPE!Ct=GbNc00A;dL_t(I%e~QS zZ-XEd24LLQn`2mk&dp=3;M#*1EdT%44PCY`P(SV^K+OAuoJ2zYJ87D(_j#VDtGy6n zMbKP4`IXa$fPaf+Jp^RSw{L#046*g~N{_%9V;t~NuOZ`{XQ1N(?iwKz8KAyHwC~Ve z-~}!YyO@Bkox#@(+AaiOT8XZN3`&QxHGu#n3A$?u<<%jPDg;szjn?k1MNOm(02PdC zR2FQ4nleE{z?nA2?vv+4GtOw_M^UNKIfq&vIH!j|P=7z#-ENX3In@564g`^vG3uy{ zISs=!45tWCMs57AhiNwrbpVc4rTh!3DyH4*ZYn}BXFiMNg%FTW*H@(KUA@duM?k-T z{!|x5QHMj4cb}glo~CKWk&L6iqy5>9x5k6!Ho9{Rd@T9B{_+hc7$t_El$@^s0000< LMNUMnLIPldQAhaK diff --git a/Resources/Textures/Objects/markers.rsi/Mime.png b/Resources/Textures/Objects/markers.rsi/Mime.png index 24419d8855d33df908d71f5d6c1ebebe4daca2f2..a051ff5117f1ac0d25f05ef58a7efa31bbcc37a8 100644 GIT binary patch delta 751 zcmVeo}K~#90)tA3(6JZ#~Kc^iHG+jE~Y6rQY z*c!1R<4bVppoT7jbaKg`AkCYC|3QU{gE&e>dd0ff;U?iMxMy*oH#ID;6?f#Uho0r!Y8GJlBktDP#Hgh*dTbD(M9 zJn*e+?G5m901~M)5J&zEcm*`O)^AhdB`f{<=UmzccUsQh0QZA{55Rkg55R*U;D^1$ zJ!W<6CMU&pP!I%?q{|QK7=s{?wYF~psWSj@#oG4#?cL6C=vZA{6@ax?F@W}bkmv^@ zagSLgNyN?vt$%-CCD_>5V1zXe>^mkVCfagf-!Z}(<#Ks=StyswGRDXrT|BCHj8)H-`6pkEU>}UfO3I!Qs z`fkcpJ>WPF)oK-hMx#NgRDw?qj`Ld@jRpYKY8A&xe}5w%OTb#IN~MBLod0Y#3qYk( zK~h^{eanuPUC%6}J_XiV2aYnZva-^Sv^xXwb7|3&z~9oDj69Y!c6}3=o|-}u#bOcP z_uF2Qk;f9l_k9(MMI| zE|=qL6o2(}-jl$=&!05Ef9Lbo7Eu&&czDQbW7yr@WoKuHTCIlXd1Pj0xL^!>dwWDt zL>PvQjg6%u&=bDzE0KQX^LfQ%d_i?dx6SDxcAg}Xl$LI&IFet&;|fB*o1fPjYp zRg3@tj{pFel$5Tltgx`Kv9YnWw6ws$z{tqR%gM>tv^v__+JES^o9gK3|Ns9B!@dsy z0004WQchCD~sXY4iKt(}U(U2ehu8Aegw%5|cdYnm7mWBx=Y5 zC&Qw3$qLM=SARnCBbbBhtE%eVAy+4d>&F$2(gcI701!(^jiK$S!JQ7#P;yWPlijNU zmN=ncVWwvPvKW}xiuj2vz6>S>AOaE-fpw2}3I1mALHr7sB{cDGz&)BE^9t~n;A`4h z*d5hATvmYb-k?U!u}OSMrG_G!I(J$42CxCZ{4bz~z%z1`zZ%A|C`(h8#W*JGN14xs k0>ycjV+wd)^7FXm6KACsLnfbjxc~qF07*qoM6N<$f^z!74*&oF diff --git a/Resources/Textures/Objects/markers.rsi/Paramedic.png b/Resources/Textures/Objects/markers.rsi/Paramedic.png index 786f1b5b93de4bac5e4291d5382b33372d4b9ac5..6e228574e6d2b442e8fd74fec1ff57a01f29bf65 100644 GIT binary patch delta 1133 zcmV-z1d{un1osG#8Gi-<0047(dh`GQ1U^YbK~#90)s|mKTW1)DpLEq}(WWMt*<_7o z&cafuv>Di~r3_jI#ke#>Bdd{oru;zV|)v@5!6*oPY0w|BL2YkZ?0nC@0*E z%(WEGc~d)zHLu(Owld8mXZGsQ8dSI$v6VsP4lRFM0p?e=d;B#dmf_xh%?vcCd;5{Z zvKC*TUyKaJCWf0e698+uX1w^fW@amc@t13{rr(OMTT};Nt>~NPiDf9iaSLmCe%`hN ztT&IphOc*mj3m#x=!ZB%e;6gDydzdt?*Re zb#_&}%b#-#yl1ZA)n7|kzU{{Rr1W|vbs(qoLWZhc6*TVKOVzFl(hHfblqns+TU*jcs3ZW7$0IE*EdW&Zc7M`jw_-6FX|h|X?Ck{L{ddw^ zg4k4wqR4s;4i1Xh>5`R+TVi&)WN>g$4%MN@6-C)T2t`rE>~x8$s-miD9z<(vYo2*7 z$Lw@%AB5TIlEa-nVs^U3=kw`CA|iM1-jzdjh_lTts;Y|5=acpM#ndmj1{6h+iID&^ zQxB*=cz=XYCd<2bUICX&ngy^5sS%4dLhG^_ICL( z5P#Tkk0=Omyz7GD{>^@UCC5xI(xZ>{_z&Y@rbqnx_)L2{f7G9VNKAkJ#=w988$xW_ zf#Y2l4DOGOI>hdM4n3BgRdKet_3?*Ic0NCKO3O1EnK{uR08eAF4eM`dH>{}MLv~hW zab=0@tV%`o9soYD+jVpIz%T4J8uRA241eIC$QUM*YkPfadXmMJCFZ6d8WvZUNKH=y z5R1ok^Xlqq9U>Nwza2m+%4Rb7&z57SakAmAfUgB$BrEXz-Cfc zXGkTJ0x&u{s^^|=Z!h_9T2R-#UJ(&VC6h8fHYUS?faHu*$)pSi0x~`}CaGjnL`1H6 zy+t2Jiuwx@sT6&EeR*?_r=|e#UcH((E>-^k4LTt~-j5^@00000NkvXXu0mjfm2oo9 delta 528 zcmV+r0`L9z2%ZFx8Gi!+002a!ipBr{0E$pdR7C&)000000RR6JDl-)o6&x-)Doa~2 z7yvR@Yd1GHN`|XdR8&`!xLY(2W-|b4YHE0RczJnweSCa=etv*}fQ^lfn3R;6nVFlH zm!zbmr>Cc`tgOJmz`-T}!kvo6#l^~_kITu)*RGk{ECAo%-+$q@pyA-)>gee0F97Yp zsPFIZ_Avnb%(MUh|C%?V5&!@I0d!JMQvg8b*k%9#0YXVcK~y-)jgaedgCG!vu@taL zldU$U8Y4EaQ4x6m*DIly9}zP>Gu-BUbJ$%%{;x^@T=bOot<^-wWs^kky3ShLbvG(W z+^k98h?OFu-+wvXtyLMK_ipd(S^$yOD5s2->y4`G=T%J)CLxV6avcC|lu|}NulXO^ zIumLXX`=GppQxiJ;eD0zDPkaAf{#cO1kGvV(Vqp!Cft_+NOSOw7o2m*DJ~+arXmo0 zK#mY!_bmVr=!FN5J;c}jn4OX!5CO9uq;hfz7$N!|A%A2yo%eqJaLEl?iZQG6`8OLxY{i7c*Z2;QK=#MGjJ?i)P(-$0zB;Q&z SXq^B600{s|MNUMnLSTaWq40?S diff --git a/Resources/Textures/Objects/markers.rsi/Prisoner.png b/Resources/Textures/Objects/markers.rsi/Prisoner.png index 352fae06687ec90f0897347b2bb11dc5e19d0fe2..35383af8cb4b8fdf7e86a45af8deb5ef0ec3c6be 100644 GIT binary patch delta 816 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 TOV$*;00000NkvXXu0mjfFbJMa diff --git a/Resources/Textures/Objects/markers.rsi/Quartermaster.png b/Resources/Textures/Objects/markers.rsi/Quartermaster.png index 538d063eac935e1e0ce42f26b034c41e81ce716f..ac2aafa5cdaaf423e8c31603fbf514e7d0c01f19 100644 GIT binary patch delta 1072 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 Ef?-?ez5oCK diff --git a/Resources/Textures/Objects/markers.rsi/Roboticist.png b/Resources/Textures/Objects/markers.rsi/Roboticist.png index bb9f014e9d9d514d16f67598eed367759916bf16..05384b4b763aaf30dcbf356de4dab3981ab393e5 100644 GIT binary patch delta 1040 zcmV+r1n>Ku1eyqt8Gi-<0047(dh`GQ1K~+TK~#90<(6MeTU8jqe-#^wT87Ye_|TxS zN_i@A+RQ(pQFvNFgPWPYh>Y!;1;k;1H2xumL_@Ailnit-6^$la;?iY4`7qyBBSn%e z5pEe7_hE5VFcI29sW;2#1907(S?}%S$uBuM=Y01&-}&8hzJKqW1OIn%6f@{3N911I z{6U6NoB+JW2Sxe1!|s63c}M=K%VThizMJ$`#1{22`XrCRPAd5mg9F*a0F2!8A$bf+ zaoS!9TPv_N`7#-Ea)7RE52ZNCW7u(L9{^yP3|-kC9)05~fLV8Cdu&e*aHrh?t(RV6 zC7tGEXC8o)oqu^&(rL2UwW0uQNA6LM$g>w;;I6VVQok)yz0=29F2{GFZ|UWuqB6m@ zoIiI~maitwa{k=eqB6j?bTBNcs!AXbkV_ZiW(foWqN=KNFl-ydau9YfEEjN@{XKiz z$Sbd~XK$OSyMPP35S9Q`Rh1Lc4Zv)FDT<=p@Lf?9W`Fxj0XQMusH$oiq9A~(s?yun zhpy|?vrZTn9*+k_QFwQL4nhX@y(^7PcUfNSN)7ELf+tww8x$YdO%~&KKk3 z0E{!m^;wcgB&e*cygh&?9;xNY-H$PMS*N+_ae2Kd1;8h7y~yGBPSMcN06_cxr>W); zuyIKFydEBU@B!jKP2L{BmiW9?o2?XgH-5~oOMm5z9eM_Uu^+z%prrL1ICBu6*MrYn z#oT4xitEAvE9o>l%FFp>W|orB`^0~ElX}+i;$qjQV@$oOP|Z41xY*VD8H-DAof|tkEIsa7CbB=JRM*Pkat{B(wJ4;NPE5z9^J|QqnRHw~rXYb; ziGN0;5)ReKjHXFAR3ouiOgcL|B^HZGI8$=X;(vqzovkZ{QWbk^u==$HmRaaLBU{1bew=Dnw^YimJ)T5)L4mJ+MqQzE_ z1cN~-FE7V1405>~$z;+I3CYelb->Y~##P*{!olf7R%jI(9a=GmV zh@Czy0B!BEp7*Vo$7#ogZC+t5-{{R2~^ydHn|7KykYXATM0d!JMQvg8b z*k%9#0VzpDK~y-)t=iy7}{-f9Y#x;~N zMulq%iPky+8tO45$uUU)`vsh_8*y|4@EN>)N5vK%VJm3o6VNqR&~#G(ZNsQ2;1vo% zS<_AgNQS7`7f|d4MNCcsV+hk>co+tX5n~getX7!541X{zC|264DKHv8<*U_dkz;N2 z6d0=rrs7>toGaf4R|=7gWLZYu^6|wJMp`15k`TiD|ALjWmG|x`17KN}(oK+MxeS0Y zKf6Eae3qhgHc!!?fy?*iPhCfGjN&+|Yj3~4oDPu#(cyGi`@r*8evfND0UBu`<=6IZ RCjbBd00>D%PDHLkV1hYY@kRgu diff --git a/Resources/Textures/Objects/markers.rsi/Scientist.png b/Resources/Textures/Objects/markers.rsi/Scientist.png index 8cd403488be501445682cb758463fbd584d6726c..ac4849ba6902cf35b3ae487c04d5ea5291afd422 100644 GIT binary patch delta 971 zcmV;+12p{O1J(zS8Gi-<0047(dh`GQ1D#1kK~#90?UqqUTW1uj>Q?wnO)Q1h}+bEr2poNw)2=_^4_#jvE;Ly@cGG8r(ya?{0_>!6jm4QgR zD5G8xT4O>gAv#QgoIa$vGs?X8X5IF(KZNgo|9sy$|D1FF;eW#a_>WOj&82~rSvku6 z@I`l3u|9Yo$xq_ntAKJ6SM$dV6b>rZYDL(uK;eM9s~g+=gWnaLxrRTg# zWytRC@$kka03P1BM0R(NSE&rwmY&-dV0&<4VNH~J2OrhdvYpxCOhY|??B_}EWa;P& z*p64#ZwK-YCHvQH~@xPM$Oyjq^Nd&79OJT8}uR_eIO zKDw^+B;X)K$dU+C0a-0eKX9x0>9Oyor>Bo`x0;{Q|L)%37NBXG-0bPWGvlHE5Wlsx z1;FU&XvH3&AMnh0xY^TVsTHObSWP5|$K&|%8`JIc`6w2PG&MC*EEe(ke8zb{{+f6^ z&T1lI7JnLm56uoNE-o6+B^T`Twb#q1UN7I>xx>#>QvgiyD`l6I?>U`LQvoMd;7S7w z_qK7n^*pigpXHo?_6&fIjt&6aielV}g*Ca|dY<9lHm)?7=C@`;x6^@A?*QQY#Fu>5 z(o#wmi6x!gY^0APK6y<(l1n5d!D|9=NVLqj4WqU*W@gFyiZ27{vO zx`>Fu*@5jD*x1;x#hbxa3krn-larGbTqct_#@T^oyF?=qqrC0y?EtvXo~=nGlL9b5 zKX07002ovPDHLkV1lO;9W@>6`YinzGczAkxdVYR>e$uvpfPjUCg^G%bjg5_x^wXG>l$ijTo}QkrtgNoC zuCueV!kvo5#Kg*@kITu)*4Nk9u9@B5-rwKf;kKaa=;-R}>woRQsQk>c{{R2~|NlL! z`bYo(00DGTPE!Ct=GbNc009#pRkbr z+z9rrhk+gEJF@~R#6Qzz{>nFuu6vJZ)Qv92=QLtf;3>H1!o<~gu$w+6#~Zuk5W+@| z6r6K`u$BX141W;`$_Cv4laVIesE}*8qCV0i9W`D-7aC~D!k7in>lS2B8g)-E)Ter~ zD}#&_sLwt1XN^LdwIHPc^nT|(f{=10aC8i4JoyHJUF5Y899Zjj%|in&tnZscWSP#< zrZY$`T{v^vnl(>N)5!c#Kq_lZYphkW{4J!)9n!1`txZxUbudb`6(RGzmf0_(5^7vj z?T6WqcVVmwuZgdv%rFe|Eao}YVt!cW%aDZOGB1ac@OI~?{PGD>EE%VU5Eiun0000< KMNUMnLSTX%;^Vjg diff --git a/Resources/Textures/Objects/markers.rsi/Security Officer.png b/Resources/Textures/Objects/markers.rsi/Security Officer.png index ad1e4189918a1fba1e8619ef050385edfb6f307d..8d5dcdc9e3a66d8cf039a8410d6c02db7a108105 100644 GIT binary patch delta 990 zcmV<410no}1nCEm8Gi-<0047(dh`GQ1F%U%K~#90<(5rP8&?#D9~-+hHdA5)85>gu zfgE8>647>ns#LJRjbPC%x?;=9KcZQ+tNei?!+vWa=Er* zdD=-nJw1)z?`LFWgq@uo48s5r?LfGlCLbCc1i&zi`s54^4ib;Yg;M~>71)3I5?$Bv z`Fu5-X_}Odj+};au6R5yqS2`MX}c)qfB3%P8I49oI~8!W1sAd`iwC#vGZ(RWaO*yn zWz~FN`h1Qc9Di*=E|+tK<%k%w_VIUh@_enxJ^3ca=_%)Sm5=xK_}Mhux($vLmLsBa zxFsrwTVir@QiSD*P?kfQvj*g2N zuZLC3=6`YFHJ1JEQqp>+G>27))3@p@o%TztFr+m(m1De9_alh!J{F8uCN6y?gf zilXqOkawlE3agggEHu!h0(++>s%h577iYk>Z9JYom)f@7;0H)+mFoi>3`ODmoUTBC zDRV^l{r(1s3oR`zF*Y`aqA2wB^$EYv$BC}v?tkcjLcV-|=LGBHu}8Fkfb8vx*_T*fd>VzC%!XJ@FYilQj&@9#4^JByk~Ff=!Z z*X!jVpT}SKscxn#4`C*gaT%tGVVYzz8CN6{;j_I1zOK4Cd9hCK@mp3_R@mI!WO;d+ zNPi@9X-zW#M}7MXc|c4DZ!qk3Gu+|kn_`*oZuYW!US+phC9PF>Qpo>1--5rB(`5fB zz~eV34bT4+;IFOLN$b59fYRi2H}hXxk|c@GCntp@NkWn&abc^sJB{hMcIz7(+)gAK zY_}5$);BhshH?fF3}gRg#EKUc36wbTiN!Jvr6VgMW;A5$n48vKHq)$ M07*qoM6N<$g0}wIH~;_u delta 504 zcmV4_K|nx82na?* zL`g?SNl8gcN=i>pPgGM-RaI44Sy@@Ams}qtTw7acXlQ9^X@72RZgX>UeJCuJmX@C? zE~w7lu-4_Z+v>qBFwDca+R?@2+RpIi*#GqAN3NXX00001bW%=J06^y0W&i*I97#k$ zR5;76(d|xyFcb#hVgbj_8R*%{Xq_ORl}+66{x8l#mY7J3e|(!jPTwb?4UGM7AdX{L z>znSqYuo~4(|>eLBb@@^kY(8c+#vjTGb>yHm-E;862j3Xg6r+`b`6g1YXsx?6u9de zD2gJ2+SOwUG!mp}7rQ|r^idC}25swKBg7T}TEyNaDB3A3+O{oFX$vrW0b(%)kt{-M zV(JbQBfS765kt&PpCd9d)31oV6bf?_50#L6u>i8F5OLBp^&UK|Dro^yoD?ch_;Q+t z#WjRrwK*wyo>xzUEu{N_hF+8FXH9_p0ZLY`g28~n4az$xU4TDx&bWCx!PL#l9-s4# u0UOSJd!HoR`4ihDv5LnjKI8NIXZsse+#JvV8Gi-<0047(dh`GQ1IkH6K~#90<(AJ&BWE1OKQV4HZro90l2Ods z*|2L_4HzLt7P^EM3}5LFu8;-Zl`nuv7#IxGw&v zPSePkWSmKd#EiP#=^@6&3du~`rH4M3WZud9KA$|__sjdj|9@Sc&Zdd>>k`bS zMtS_KK##ARk$=!NdVJkHepX;MHR^UL_W-l0xSfnksA`EPD<+ky#gi2iRV|T>OU$O? zu3OPDz{32Tos3H?XSNw0j&Se8`#kz_53#?O;o%6&nQfABiG}$&R}hW>7Ut*dL^8p0 zW}Eax2vseitSk|}@+V;qQPmRZi4e<~Z4$|ZD~PsT(0?@7G!=l|@(F=~0p!#IWilN1 z2M7#k?3Pae&@`1qG67&Oeg9M2P3b5BO;af-MdXM`EbOCZ7$_@C{Iped<+`+H%11EpkAKHYa3KbIIYi+Krhjg+DGqT}SmIUwDP3OgKT80hHxOVj z6yka`iWn3a8jf5@;ET_{2HWQOi&ey+!1ZX9!BB|aK%lL8+XR|A)HIGP3sbjP)qh0{ z3M_uL2*BjjB)PNSnYzXAg#uRv!I3$%Ng$iedX6lMBg-P2&3XW$xB3tV{Q!uAesXI$ z@PBw(&S@oAr`P1vq#YX%0-zOZn1{!RgMLC%BktV|o!naP-Q9>x-C}n`Z+t&ICbyRJ zn1{#b=B94BSQwN5q8HQ^B*9oXQ2gnie!f}`!5m9#zT$_W71a8WscGEZ(_Mw#CzKex@ zKoe@z-cj<7ThS4~O?lM*D18e6y=a_YKAPGspAZZC2ucGakyy^)7{YM^tLsISQsYQ& mocnLpyeDK{ZeJ=-JN*UysgEet2x|HO0000u$p!4245lY#N++Nf~q<3Ge@wGi=hN0ojkuh>JNN2at#1e`Cz?n|?x!<0YkZ=@UiI zL>EZuRa)u;`w>$-_LE1%{e6!o-ym}whoQb6fFncb5gfogaWfFOtv|rY=^*2So4NqxvMJLK{PMkm=%z}{x7O?FU5 z+xccIU|!eapsotnb#4ISpi$zgbWW;oSUc!x!bvHmbJ7Z279o}ed&SZynsnU*aGA8+ z(|7ng029CfGIjwV0SI~kkkosSYEzql5L|I^Awb)pxEe#5zqdaCqhAn(ACSeK00000 LNkvXXu0mjfou{aW diff --git a/Resources/Textures/Objects/markers.rsi/Station Engineer.png b/Resources/Textures/Objects/markers.rsi/Station Engineer.png index ee306c811dc589242795990a2b801f2b82a8d6ef..d561f3de462833bc11da7da914ab95b67852687a 100644 GIT binary patch delta 1024 zcmV+b1poW61d9le8Gi-<0047(dh`GQ1JX%EK~#90#g=VoTU8jxe|JsO+Ai(5BT~an z*R&RbY%O=R)~>5-{gmlm7|LWQj7@MDbY*l5oqjDAZ5ggZm?CVreo#?yx)DDNw`gTd zXe_i_pzF%+LR(ss(q5Npn)dkNdecO-y-5T9;qsj4Ja7N=Jb#Ciz&haDfmlyGz=m84 zyPODZ3S3UadWd9Az_-IFyvYI2JoPM_9H33*ryJIaUqOhW3gL1ho~SlDA%-f1b|tq? zTuRBIS9;Kv5}cfmWR)|g5$N#+JjqD_JjqG)_(CpevLj%g9w0WS zQ(R)*oJ_n@PD^%`q-;KpTGZUxO* zN-!9do=*l*WbhH9+}%ufRR~3f;9+=U07-L}vfOIKS;49VrhbF(e==l4(@y$Y5EHd3 z0Bu#7zE@?Hz7|A7)6R^zwP0J#SXbT2c5e;$Cx54j>Bgr%`~CA{jb>cYqEUeqoWV z?m}+LDtp9M+SO*ZJoYGq;W3~$cLFBlaz|>t5Q#HeW~1xqHeCEj*U@c&V0PXHB-vc< zKrVN1e{$MN>b38H9$&yw@(9s6olz}@{^v5k-kV07P2k&YN1IJB6V+*`E}_(BBl`F6 zLVr5xoCzE{-7Af16AXsOICQ#K0+|0}34rLsMc(~*mgvL9e~lT{CQ>nZ!;|$}goq(b z8N5JBH^00V{3rTaNEHrVKnNjL)-iv;BJQ9D*ggrGLNYou`Hkf00000FihAlRE&JnVFh%Kc|LssfS0Z5hAXOcz?Q;fW44Czh3~rpa8*5 z0K%6=!kmV}pa8^80LGnD%1{8znKR6!jn}j~*{+t^+1cW?0RMjg|Irx#(<1-w0RR90 z-9Xhb00001bW%=J06^y0W&i*IElET{R5;7E($QAJFbn|DDqC@^LQ#TXZMDpzLLJt@ zp#1-bneyV1wST;soUP4rPx3NC{zgGAM$yZ9mq?LicUhJe#cq!i_PZhtiV#Tq@C*kqBWr< zEz1%?C}Kf9_105LQ~!hV)*h|(>H?5N{wv5i=LDZT1$e$hu*`X?&-n?2InjPyuTCpg kbsZIR9vhOJ-t*tjKi5krU3lz{qyPW_07*qoM6N<$g50(4g8%>k diff --git a/Resources/Textures/Objects/markers.rsi/Virologist.png b/Resources/Textures/Objects/markers.rsi/Virologist.png index e0e611cbf1cd099dc989ae72b1a41f816eaa773a..002550aaec2b4697b37a44711e6abab7d85e1e8f 100644 GIT binary patch delta 1045 zcmV+w1nT>Q1fK|y8Gi-<0047(dh`GQ1LjFYK~#90#g^YoTXz`7Kk)~1g2BiY)LtaTGAuL- zlA{$gjrfbSoi*Bb7g}C?*YH zat5jbJ^_&ZLn4>E4F6XP6Id$B0N7E&rgEBAAY1&o^#TCTtrv(~?n3qt&87lODiDsx zrMA4B)E^UU?|-GJtEpynBZX!noP2zge}F8FeR7G-zMLk>A?F%DYK1V8~$s{ zkN9o=vaTkm4BIDfXpWNDf*%GQK+gaZ$*S2 z#O7}kRaJ!^WJwzldJt7r#pZ7ldXTpwnfnDIuLAB-q;I(oUDv5{`Dmz_#^G?FHmZCx z_%mvwio@Zcp=O#Ymk(Xn>09o@JzAI&c?sOvQ*pbYA>jI8*9Qj&b8Oi^q#@wK?asuV zn1HIPa(}b4lY34Lw;Ohu24G`j1AvK%i5z>EY20qO=hV2_*-0U-$g99&EJidMW&ZBF zjq!Lqq|<5Y>+4CU(|9}{ae9f(Gw?~HYr2QJ=f;$l-1-*$KN z)5C|E!r{#Q<8gMoJuiWORiO6p1>INA3H+&sJKoS6W%!NEVVhKY`Ti zzp$S9oUOeSie2H-kIh{ArI{O=le)S(+@rt`7U%)RuCTS2GDv?Cj1TlmR(?fMMAI~R z7JrM0rfK5!dIc~pMN#Dan0zSsxveOQIGs*zbaVij?U-OzW`)2%LXh=jvl8J;ojzmNYg(O=z znMjBh3d!S0M3RYwh=@EG8Y*}e3TnZ6GD&}be~$0Zg#`eHMn-aMv-lfP0M6qOQV!e- P00000NkvXXu0mjf^t%5s delta 501 zcmVIHfB*ph{}6mW5P(1s zgFz99L^GKHH#avzLPAVTOloRsYinzGczAkxdVYR>fPjF7g@uZWij9qpkI2ZFl$4&H zo~MR$uB@!CuCBV3fV;c9yx!ixz`(@B#LLOa%%qLh*VoyumVepfpsqJ%z&Q&cFwTpB zg}1m^5e%cV!GF4OC_iHuKgNNV`=lGku_Hyn&~;tsuyhQ{5rPYVoM!uY0Tu-yg9~Q* z0?u3<@DUG!pFv~>2w)MsN5DX&BhVW`MT^ha#%g>b&`3hXvBmZ%D3K-wQWBucvRxJm zM9Ku{U^P&);8Ic0Hs};M3*Il=>Y)PbYzkb^5~yed1#YRGO90V2zM3~rRaMFBO(s%# zZyMvhlKF2T)pbI=N}y57#0f^JrU0(_-t*b5lOk$bRq2P>O*b$V!As27mQUaJ^GxPB r)@*;j&Zjic-!}QyQO-N>E&T+^d2s!8d^SsaZp6`1<_!J&d} zdu0xQjjflq`D`V0^^FVJ-T1HmKXN<#y!f?k5w@T-`9xRWxJbmGiRa6UA`yQky86b2 z(&Q88S~!o3-UgBX>AEh8-_OElyIm6#6XLTkzdd2U`|$?^Z`~qflhbmrzTG2~CMW3^ zCj9aVms)%U-+%9$Dd_x^yg%F=JD+`^Z}$j&yGH=R=ktl*W+w{IdEbD`W$RPeQd-=F z3v=(Vlis6I@$l!+4`*I|g`MDVb4*IVFsX{)!|l32tFMW>Q*%_s@142zwh}Z=6Y+SQ zcT?M}4@ZbZBFxXv(|UiN?|sb#0s*4Y==pR&(=-u_#eYx~g-M4*>;3sc@kxh-qA0{- zF*HrHwFfK-7*pHC=;$b_s**?~0O)kN@OV6Qx?BJx5(!jQWps3uF}2OIh_dY(Q`^MN zZ>ErL-{GS}6M+8yesok0A1G!1Olk4 zN-mef?Q*f7%~DZW$**ST`}av?W& za8QoEya0fgJ3HhK4rp(0$23h0!@%KikW3~S92~?52DxlRKMTmC_((nv_woLtA6Yv* z;*H7*zU#iuoBASP?dTQ5)@=x|Iyk`9hmTo1JYqcltF(4_#MOt7Ssfg(OLaB@PUrD3 zdXUZ0?e&WX*<6YJTm`HTNAP$&ul0F69)H${Bj+ceV`K=^Gzrbjme}$L&CFt&rlsL? zX2`NEu3x(*WLXxnEQ`FY*lw58_8xe;vO-5NSYqo426?)&VwcLE07X#>tJ`>W^S$o9 zIL-`g#BoiG)a})0Sp|r69lGe_~bHY$ld; nIxWevENW|OPvj(%)`rpFZ~>^v2V-$000000NkvXXu0mjfQJoAO delta 530 zcmV+t0`2{`2%rRz8Gi!+002a!ipBr{0Gv=vR7C&)000000RR6D4Gj?y5fK#`85tQI z92^}N6CE8LASyj1BqS**DJm)|GeTiDHa0joI662uJr^83JUl)=K0iM{KumQ-MMXvk z2uVjrNl8gcN=i>pPgPY_TpuJ{TU%&oXliO|Zfz`(%4006-)Fv6UM%%qLX|3ui&zS*vp+t$?fre~}G0004WQchCa*vISbvmQvf*=J%UdmyV{)SfIy{UzyhrTrqdN}6aP()4=DuwFmCp z9LS6j0L9)f0AWlv2QuUnilXodQ*|ZTOZ1yCRaeTlWq*E2z`*lzo6mrv zm9s($>y(Uq2=YV-B7TqksL7kCuoi@@J+LNZ5%$w`Gqu>HX^^-dwLoM#|E|9Qf0onfH0kr~<7=H)`0001UdV2H#008_+L_t(|oXwY85`!QNMUQNWMRiSG6l-cf zbR1g~$b+HHr-XZtgCr6DG3t}oD$OD%)~OIZ%_1dIVHU(lvq*`JHU+|>S+v9~gjKTu zvVqc7zy8u)O;^v^-f|X$gP>woL%Nk1*Rih5*BBnCu;009zr- zH82&xT3)jaOa$=O_6&qNlzPi+6ha+JBjq&$(H}|!70wHx4yBp$>VY^#zagUL*RW`A s+J>yTRr4l(ZXcLn9@bp>bNcgm1D4ula5x1%dH?_b07*qoM6N<$g3b4OCIA2c delta 209 zcmdnW^pJ6aL_G^L0|P^2NcwRgB^2Nj;tHf0&M+|iXE2@#M8?KvjLSQwdIJR+OM?7@ z862M7NCR?eJzX3_G|uNvyvTb%fy2f3&Vo+n5@!1w4HgZZzt3Ol=s0nee@_K}hzDo5 z-6pRkSz_Kfd-yYa`hNweY(Hdd=PLN>{g)E!X^LLYR#@y@#S`$dOaBNXci{mi8-)&b zmYobX9hw0qaoqgf{_W?FzISd;;{HFYrk|0Wb@7qJ`>&b1GqkU+oRqW`rOiW diff --git a/Resources/Textures/Objects/markers.rsi/cross_pink.png b/Resources/Textures/Objects/markers.rsi/cross_pink.png index e9fa9fc5d3f95bfdc39b7e19cb2341fec4a08d98..d5476f99e6d92b432e8dc0d87eb423937b6c53e3 100644 GIT binary patch delta 316 zcmV-C0mJ^^0m}lA7=H)`0001UdV2H#009z7L_t(|oXwXz5`!=dL?5O|!%@n8!Cx448s0C4C{sB+}qSSl^ z;DNB1Cjl%FR&#*l!xCY5&{@p004fOV<|=?31YkB-18hM6X7eHd2?B>X2w%aTr3R3$ zz#H2tfUTF%J3F!fxzEr$J2nASLF61@B7inty#p)>P@3%?2yrPbjaMs#xRhGr)dC?d zrPg>Yg%FogPc^)jK)gl2A*|-h(r7l)0k64Mb0z*dP{Z7;x#!R6&+85pYVSnSsq3o% O00001 zi~s-t0d!JMQvg8b*k%9#0DDP9K~yNuZIRIpz#s@jbpyi&#tn=cm~PPhXK6$PPIktKZs4tI37bLe?SA3=*G~VUOW|kuAh)A$pQ3{B3#W&)BjW}Q< z9$>@+j9dU7#1tqRuZ4%jr^Dys_n|?tg?~-H$AE)^QR1-g^#L+5CEJ+$K1Kil002ov JPDHLkV1mq(QbYg% diff --git a/Resources/Textures/Objects/markers.rsi/cross_red.png b/Resources/Textures/Objects/markers.rsi/cross_red.png index 4ac7f06b2045da1222be5f2fc809c1385e73cddb..063f341d3630290c321e0a84bde3bff0cd58eb3b 100644 GIT binary patch delta 281 zcmV+!0p|YS0jL6y7=H)`0001UdV2H#008evL_t(|oXwY85`!QNMUPB(#Gc%fT~k?8 z`qAoOMP5n8%<$nDPVOW?0Pbir$W=_2a`eU`a!i+UT!)2-64RYIT8OA&x|Ab$wTNcs z46=Z{Kmjp#hj>u?J*X!e*c*_*4?{yMK})5MUdy-(o4BXC_Wo zK#d48|4PBDEtg`mn)iy(25(AFx*VWM`=J}&*8WujRd9<%SS&%!S@7A8fu1h<&<2mq zZz95u(RCJFbrh?En~NCQj)z`IhF;0c7f}OqiYLTd&Z4E(FsHK#R{gxhJiylpW|xT` f=9Q1r;r0g2{1P8i$`-@800000NkvXXu0mjfxlDn& delta 207 zcmZ3%bf0m8L_G^L0|P^2NcwRgB^2Nj;tHhG7#LDsF8oc;bYXe&ial-*yVjBx?b$jq zD_4YCZmZ&3q2KQ&uChHcyk?n#$-Sp1)21oC>hRbQ6Ufz3a@71$L$5`GvRuLu=AIY^ zxg#PPQtMmWk1jv_{L%M?jvHI+efJ%2Xl@F8wBh|%Mk7Pj+cSRKxdGk5;OXk;vd$@? F2>`1DPbB~V diff --git a/Resources/Textures/Objects/markers.rsi/meta.json b/Resources/Textures/Objects/markers.rsi/meta.json index 02df455363..7eb1bca74a 100644 --- a/Resources/Textures/Objects/markers.rsi/meta.json +++ b/Resources/Textures/Objects/markers.rsi/meta.json @@ -1 +1,461 @@ -{"version": 1, "size": {"x": 32, "y": 32}, "license": "CC-BY-SA-3.0", "copyright": "Taken from https://github.com/vgstation-coders/vgstation13/blob/e71d6c4fba5a51f99b81c295dcaec4fc2f58fb19/icons/mob/screen1.dmi", "states": [{"name": "cross_blue", "directions": 1, "delays": [[1.0]]}, {"name": "cross_green", "directions": 1, "delays": [[1.0]]}, {"name": "cross_red", "directions": 1, "delays": [[1.0]]}, {"name": "AI", "directions": 1, "delays": [[1.0]]}, {"name": "Assistant", "directions": 1, "delays": [[1.0]]}, {"name": "Atmospheric Technician", "directions": 1, "delays": [[1.0]]}, {"name": "Bartender", "directions": 1, "delays": [[1.0]]}, {"name": "Botanist", "directions": 1, "delays": [[1.0]]}, {"name": "Captain", "directions": 1, "delays": [[1.0]]}, {"name": "Cargo Technician", "directions": 1, "delays": [[1.0]]}, {"name": "Chaplain", "directions": 1, "delays": [[1.0]]}, {"name": "Chemist", "directions": 1, "delays": [[1.0]]}, {"name": "Chief Engineer", "directions": 1, "delays": [[1.0]]}, {"name": "Chief Medical Officer", "directions": 1, "delays": [[1.0]]}, {"name": "Clown", "directions": 1, "delays": [[1.0]]}, {"name": "Cook", "directions": 1, "delays": [[1.0]]}, {"name": "Curator", "directions": 1, "delays": [[1.0]]}, {"name": "Cyborg", "directions": 1, "delays": [[1.0]]}, {"name": "Detective", "directions": 1, "delays": [[1.0]]}, {"name": "Geneticist", "directions": 1, "delays": [[1.0]]}, {"name": "Head of Personnel", "directions": 1, "delays": [[1.0]]}, {"name": "Head of Security", "directions": 1, "delays": [[1.0]]}, {"name": "Janitor", "directions": 1, "delays": [[1.0]]}, {"name": "Lawyer", "directions": 1, "delays": [[1.0]]}, {"name": "Medical Doctor", "directions": 1, "delays": [[1.0]]}, {"name": "Mime", "directions": 1, "delays": [[1.0]]}, {"name": "Paramedic", "directions": 1, "delays": [[1.0]]}, {"name": "Prisoner", "directions": 1, "delays": [[1.0]]}, {"name": "Psychologist", "directions": 1, "delays": [[1.0]]}, {"name": "Quartermaster", "directions": 1, "delays": [[1.0]]}, {"name": "Research Director", "directions": 1, "delays": [[1.0]]}, {"name": "Roboticist", "directions": 1, "delays": [[1.0]]}, {"name": "Scientist", "directions": 1, "delays": [[1.0]]}, {"name": "Security Officer", "directions": 1, "delays": [[1.0]]}, {"name": "Shaft Miner", "directions": 1, "delays": [[1.0]]}, {"name": "Station Engineer", "directions": 1, "delays": [[1.0]]}, {"name": "Virologist", "directions": 1, "delays": [[1.0]]}, {"name": "Warden", "directions": 1, "delays": [[1.0]]}, {"name": "cross_pink", "directions": 1, "delays": [[1.0]]}, {"name": "observer_start", "directions": 1, "delays": [[1.0]]}, {"name": "spawner_melee", "directions": 1, "delays": [[1.0]]}, {"name": "spawner_rifle", "directions": 1, "delays": [[1.0]]}, {"name": "spawner_pistol", "directions": 1, "delays": [[1.0]]}]} +{ + "version": 1, + "size": { + "x": 32, + "y": 32 + }, + "license": "CC-BY-SA-3.0", + "copyright": "Taken from https://github.com/vgstation-coders/vgstation13/blob/e71d6c4fba5a51f99b81c295dcaec4fc2f58fb19/icons/mob/screen1.dmi", + "states": [ + { + "name": "AI", + "directions": 1, + "delays": [ + [ + 1.0 + ] + ] + }, + { + "name": "Assistant", + "directions": 1, + "delays": [ + [ + 1.0 + ] + ] + }, + { + "name": "Atmospheric Technician", + "directions": 1, + "delays": [ + [ + 1.0 + ] + ] + }, + { + "name": "Bartender", + "directions": 1, + "delays": [ + [ + 1.0 + ] + ] + }, + { + "name": "Botanist", + "directions": 1, + "delays": [ + [ + 1.0 + ] + ] + }, + { + "name": "Captain", + "directions": 1, + "delays": [ + [ + 1.0 + ] + ] + }, + { + "name": "Cargo Technician", + "directions": 1, + "delays": [ + [ + 1.0 + ] + ] + }, + { + "name": "Chaplain", + "directions": 1, + "delays": [ + [ + 1.0 + ] + ] + }, + { + "name": "Chemist", + "directions": 1, + "delays": [ + [ + 1.0 + ] + ] + }, + { + "name": "Chief Engineer", + "directions": 1, + "delays": [ + [ + 1.0 + ] + ] + }, + { + "name": "Chief Medical Officer", + "directions": 1, + "delays": [ + [ + 1.0 + ] + ] + }, + { + "name": "Clown", + "directions": 1, + "delays": [ + [ + 1.0 + ] + ] + }, + { + "name": "Cook", + "directions": 1, + "delays": [ + [ + 1.0 + ] + ] + }, + { + "name": "Curator", + "directions": 1, + "delays": [ + [ + 1.0 + ] + ] + }, + { + "name": "Cyborg", + "directions": 1, + "delays": [ + [ + 1.0 + ] + ] + }, + { + "name": "Detective", + "directions": 1, + "delays": [ + [ + 1.0 + ] + ] + }, + { + "name": "Geneticist", + "directions": 1, + "delays": [ + [ + 1.0 + ] + ] + }, + { + "name": "Head of Personnel", + "directions": 1, + "delays": [ + [ + 1.0 + ] + ] + }, + { + "name": "Head of Security", + "directions": 1, + "delays": [ + [ + 1.0 + ] + ] + }, + { + "name": "Janitor", + "directions": 1, + "delays": [ + [ + 1.0 + ] + ] + }, + { + "name": "Lawyer", + "directions": 1, + "delays": [ + [ + 1.0 + ] + ] + }, + { + "name": "Medical Doctor", + "directions": 1, + "delays": [ + [ + 1.0 + ] + ] + }, + { + "name": "Mime", + "directions": 1, + "delays": [ + [ + 1.0 + ] + ] + }, + { + "name": "Paramedic", + "directions": 1, + "delays": [ + [ + 1.0 + ] + ] + }, + { + "name": "Prisoner", + "directions": 1, + "delays": [ + [ + 1.0 + ] + ] + }, + { + "name": "Psychologist", + "directions": 1, + "delays": [ + [ + 1.0 + ] + ] + }, + { + "name": "Quartermaster", + "directions": 1, + "delays": [ + [ + 1.0 + ] + ] + }, + { + "name": "Research Director", + "directions": 1, + "delays": [ + [ + 1.0 + ] + ] + }, + { + "name": "Roboticist", + "directions": 1, + "delays": [ + [ + 1.0 + ] + ] + }, + { + "name": "Scientist", + "directions": 1, + "delays": [ + [ + 1.0 + ] + ] + }, + { + "name": "Security Officer", + "directions": 1, + "delays": [ + [ + 1.0 + ] + ] + }, + { + "name": "Shaft Miner", + "directions": 1, + "delays": [ + [ + 1.0 + ] + ] + }, + { + "name": "Station Engineer", + "directions": 1, + "delays": [ + [ + 1.0 + ] + ] + }, + { + "name": "Virologist", + "directions": 1, + "delays": [ + [ + 1.0 + ] + ] + }, + { + "name": "Warden", + "directions": 1, + "delays": [ + [ + 1.0 + ] + ] + }, + { + "name": "cross_blue", + "directions": 1, + "delays": [ + [ + 1.0 + ] + ] + }, + { + "name": "cross_green", + "directions": 1, + "delays": [ + [ + 1.0 + ] + ] + }, + { + "name": "cross_pink", + "directions": 1, + "delays": [ + [ + 1.0 + ] + ] + }, + { + "name": "cross_red", + "directions": 1, + "delays": [ + [ + 1.0 + ] + ] + }, + { + "name": "observer_start", + "directions": 1, + "delays": [ + [ + 1.0 + ] + ] + }, + { + "name": "spawner_grenade", + "directions": 1, + "delays": [ + [ + 1.0 + ] + ] + }, + { + "name": "spawner_hitscan", + "directions": 1, + "delays": [ + [ + 1.0 + ] + ] + }, + { + "name": "spawner_launcher", + "directions": 1, + "delays": [ + [ + 1.0 + ] + ] + }, + { + "name": "spawner_melee", + "directions": 1, + "delays": [ + [ + 1.0 + ] + ] + }, + { + "name": "spawner_pistol", + "directions": 1, + "delays": [ + [ + 1.0 + ] + ] + }, + { + "name": "spawner_revolver", + "directions": 1, + "delays": [ + [ + 1.0 + ] + ] + }, + { + "name": "spawner_rifle", + "directions": 1, + "delays": [ + [ + 1.0 + ] + ] + }, + { + "name": "spawner_shotgun", + "directions": 1, + "delays": [ + [ + 1.0 + ] + ] + }, + { + "name": "spawner_smg", + "directions": 1, + "delays": [ + [ + 1.0 + ] + ] + }, + { + "name": "spawner_sniper", + "directions": 1, + "delays": [ + [ + 1.0 + ] + ] + } + ] +} \ No newline at end of file diff --git a/Resources/Textures/Objects/markers.rsi/observer_start.png b/Resources/Textures/Objects/markers.rsi/observer_start.png index 8f965c975195bdb8fe2a6f28915871c60a7cec38..309baacb03fe45a58360396534308b815b919e6c 100644 GIT binary patch delta 589 zcmV-T0_O5n@MC6wcZeMS&3az(cUO2fzcd1|pmg zop_}E0>uHG4}Uw$^m6bWqL0X@M*zyQ9C)@+;%*0Ta`=%>iU$CI-u=Ik@{?281tP=_ zxCMTWiiZHCKrW?BLd0!|JK)!Q;Pbx#$hqP+g!l@GF+a~H1bRoSZ}+=|$MVbp7?ger z!u-7~OQe(ukY5U5CDv;?Z9?1!S1TAmTO8;YO}ktM5Pz6>o_-jBUQc}p?f3gpU-|Ud zJ1^qoLI68(>Q!vPhJG<)t(XTOQ~fn>H`dkFyU{8PH(-Q5&fO3WfcE@0L%aY{{Ra&02Vg@AfNy<{{TRs0A~M7OG}`jpvcI`+1c5Obdz%c z000AYQchC{#haC!OA*N zvY8X51%3xTN4A4oiO|P-dqOmn$7O>4=m?@28zVV%$6Whk%Aq~O(Pq$c2xqn&N8q+ z%*u$q$p#qCIq$P`vNN;rH!8LH+k9vEaadwH&lGM-#LI4nE@~wjR2U>=hhh0bH#I)loh$UxX{4V zdzAWDorP)71?p|GFNT9K=BA8Zuh->_bTtR43~beWHzNH?v@v&xj4|h{XmhBvAXI%j zWYaIF-rv2GGnY*tqgPSp2LKu%fWcr;1KLlw!GDmJ!3@(0$QZL^?11h5U!Xp8`uGWn$@sP zHOuxPh?W*KEX9GIuV1PF-Wzr{u%>o2^r(GT6B$=B+y>QsGiosZ?!n~fLrscP(FsmN zKLGI;52dF)me(Yl{>5ZJ;a6VG!i3cNiJA%Y1!@5N7P)E5DF6Tf07*qoM6N<$f=*%M A!TkK4<=#h&06w2w1F$ShIfP-TO#`=q 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 iubDR>Zu}3<81M(Y6#q$r);# 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 literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/markers.rsi/spawner_rifle.png b/Resources/Textures/Objects/markers.rsi/spawner_rifle.png index 0b1c3395955c1aa9c7df44ee7196fc030cfc623f..2dbb558c05ae31871167f9e8e63a65d6a736d923 100644 GIT binary patch delta 746 zcmV8FUcvHTEmYK+qW_~v3eK<$ysjRmA6KtKZ2sM%C~phlUV?I9Ll76AEN zk!<=WkT8>?)m*juLj_V6CIHj3Ndb_5O)p9w0ak|-E5Hh6-C*#jA3{I~%DO=;Zf2Bq zgN5i0VP(S}RZ?ZPLU+u30D8!#9gfFO?lC{N9;>skdAP+`f?j6c*5#FTv(4(00OGf11UNR8b%UcHUjgXu8=zA8>(~`GNpsdp1jO%LErcFn>wabrpsV+yRTLT)|N96+@Qan^o->b{Wx5Uq%iz^s01 zvXgD?nCxaZ`qg233O?gwWIV#$h zYaH$y_EhZc>Zpa+F2GYgO-JkJxe|;EB^dYfVsa5LrDuCBZ!qBOKTK)|oXe+~dw}2Z cKQMiW-@j6k4<$RS!vFvP07*qoM6N<$f_Rf?m;e9( delta 4435 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 Z;}5@5kq>xD@HYSe002ovPDHLkV1n7vaby4h diff --git a/Resources/Textures/Objects/markers.rsi/spawner_shotgun.png b/Resources/Textures/Objects/markers.rsi/spawner_shotgun.png new file mode 100644 index 0000000000000000000000000000000000000000..86092fefa5ca223666ba20b5a663850ccdf863c5 GIT binary patch literal 604 zcmV-i0;BzjP)SyoIK6Q;8x~B?5Isf&qzv(Q9@l{sb6UDzS9PMkGcU3Uug_ zST^UeiwmNlQ)3qq^_;QPNP`f&DGvVU;c zi`g?&09p+pKVu@q3R|1&0300l*xFpDwy_Gp>z8lhu`H-5#5u|K z#oG~oiq+Vx-}h7n9^WsegrlUW59;|1g8}}c3;s^Z#4s4J1pGWc0Y<4diiyMl7Lo!< zB$J}+Slj|!HR}ka;xgXf_xKKA-sI~MKw+Y-6;IgjdK2p|!!A(bue!g$0x?>HPvG@k zzzHM9TNGg5`5un#67C{({}k?&0X6e+zfvy58d%^vZm1gx0NCJI<2VSfZ2*}xai)QH zN1@BU9|o%zP&0S}6kt2loDh$R<=iHkW>q%L>eNoi^<$Ll=Q!5`Nv=n->v$-=+GF`C q30MDPGM$jiuURrdH!g!y1O5RPv(LRiBIEM_00007<2NNK1kAq%y*Xmu80pkm2N5V48`QVQJu?HB(^BFBHB$n< z3x6TT)-)W2j}T*P+8kBk6U5k>1CA*_ApTp^Plyw1`2lfijnfGDHjCp6X$wiAEhNQB zlV5cQNCyA`DafnxR{tQcQ^@gjARL(@rp*Jpz=kF93-tVFAP=Ms&2a(7gGj7g7cx0m zAkuPr0X;i9IeOD_@!jIp~KeWc*zeBh|m;kj(1N(V66162OnCCgY zVEWn5?O=mrh9y?kL`<7!ef6~oGPDM2l?G1}FZr^y3rLZAwM9&GPh?N%HYRoCUsCTE zV>gpzZgx>9lM{5>UGAz6Tr2uhuh40CQ6?t<=(M{IALIT^bedYFF?6)nm1VBGpk8fJ z&TkS_Li9RKhcH0qcn4I7vosWIKzSVp?aE+qv9uS^vs;0n5+WR#BB+FhgH`1A23|ai z(P?+N6^@cQ-XW-j$n1ZhSi0j{vF8jFOM4Dyxnh&zRq_cry+Aqt)0~BPc?oXF7or8b4yZD@N827%tV?p|gC()D=6JBo%`Tchub4A`68anK zTNM}jHgsaG%lJ}yzOUsj0q6f=G8k|npJw&|zwInEeXxI`OSpuP3WLf30000Vo7≈#A7mscL8Ubx)`-)7|&`efJK%dvG(YEJDOA3uua9 zMfk?F14V!$d}F!-(;^@dzA=Xa%Rz{^G-i+@#>NUl#Fa6w0uWdg#{mkwk1hi^i6-_9 zJTY>ABC6XvqEIXeHM=^JyihEOLb2rWNq!_$w|9h+OY!>U8#cDq9lzG-uva_e+0!+S zPns+*W}I)s?{1%xOYvxFK?0caBjEU?34pGjp*1=l|BTtgs8xsohW>t#B(JbnJM`fE zGJm4$XW;Tn0GnC)!alwFqDuhzWI_PkNj>Cu=K}yrwC}{lV-enc^X4kiKAIV!-t9>M za#9rl)6sj#@~jiLyqK{n5RXNezkl2L@b&v2Hj#y9Mo^-C40(l(t#!0U2BTIX9*cMg zpUe%*kD$3k>D{)ZW>7p3q7IWq^?)rX0favRi~bDW6OTtC9ABH0{4f7JKMB`=F&Rz> Date: Tue, 23 Jun 2020 05:53:38 -0700 Subject: [PATCH 17/25] Add fist graphic and change some punch settings --- .../Weapon/Melee/UnarmedCombatComponent.cs | 4 +--- Resources/Prototypes/Entities/Mobs/human.yml | 3 +++ .../Prototypes/MeleeWeaponAnimations/default.yml | 7 +++++++ .../Textures/Effects/weapons/arcs.rsi/fist.png | Bin 0 -> 190 bytes .../Textures/Effects/weapons/arcs.rsi/meta.json | 4 ++++ 5 files changed, 15 insertions(+), 3 deletions(-) create mode 100644 Resources/Textures/Effects/weapons/arcs.rsi/fist.png diff --git a/Content.Server/GameObjects/Components/Weapon/Melee/UnarmedCombatComponent.cs b/Content.Server/GameObjects/Components/Weapon/Melee/UnarmedCombatComponent.cs index 0cd7cb189c..9841f283a0 100644 --- a/Content.Server/GameObjects/Components/Weapon/Melee/UnarmedCombatComponent.cs +++ b/Content.Server/GameObjects/Components/Weapon/Melee/UnarmedCombatComponent.cs @@ -1,6 +1,4 @@ - -using Content.Server.GameObjects.EntitySystems; -using Robust.Shared.GameObjects; +using Robust.Shared.GameObjects; namespace Content.Server.GameObjects.Components.Weapon.Melee { diff --git a/Resources/Prototypes/Entities/Mobs/human.yml b/Resources/Prototypes/Entities/Mobs/human.yml index 629926bc51..ba2e459c0c 100644 --- a/Resources/Prototypes/Entities/Mobs/human.yml +++ b/Resources/Prototypes/Entities/Mobs/human.yml @@ -135,6 +135,9 @@ - type: Stunnable - type: AnimationPlayer - type: UnarmedCombat + range: 0.8 + arcwidth: 30 + arc: fist - type: entity save: false diff --git a/Resources/Prototypes/MeleeWeaponAnimations/default.yml b/Resources/Prototypes/MeleeWeaponAnimations/default.yml index c7fe845719..0259f33948 100644 --- a/Resources/Prototypes/MeleeWeaponAnimations/default.yml +++ b/Resources/Prototypes/MeleeWeaponAnimations/default.yml @@ -5,3 +5,10 @@ length: 0.1 color: 255,255,255,1020 colorDelta: 0,0,0,-5100 + +- type: MeleeWeaponAnimation + id: fist + state: fist + arcType: Poke + length: 0.15 + speed: 1 diff --git a/Resources/Textures/Effects/weapons/arcs.rsi/fist.png b/Resources/Textures/Effects/weapons/arcs.rsi/fist.png new file mode 100644 index 0000000000000000000000000000000000000000..337d57adc28b31a7e1d84c2eed5d212dedb6996c GIT binary patch literal 190 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz#^NA%Cx&(BWL^R}6`n4RArY-_ zCwp@pFyLVIeR Date: Tue, 23 Jun 2020 15:13:49 +0200 Subject: [PATCH 18/25] I'm sorry --- Resources/Prototypes/Entities/Mobs/human.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/Resources/Prototypes/Entities/Mobs/human.yml b/Resources/Prototypes/Entities/Mobs/human.yml index 16676d1f5f..e9da57750b 100644 --- a/Resources/Prototypes/Entities/Mobs/human.yml +++ b/Resources/Prototypes/Entities/Mobs/human.yml @@ -155,7 +155,6 @@ - type: CameraRecoil - type: Examiner - type: HumanInventoryController - - type: Item - type: entity save: false From 2fb2cea29f5b3f9f1fef2c10b1247bf838449d1a Mon Sep 17 00:00:00 2001 From: Pieter-Jan Briers Date: Tue, 23 Jun 2020 17:14:51 +0200 Subject: [PATCH 19/25] Fix macOS not exporting freetype --- Tools/package_release_build.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Tools/package_release_build.py b/Tools/package_release_build.py index 8400021f61..fae399325a 100755 --- a/Tools/package_release_build.py +++ b/Tools/package_release_build.py @@ -75,12 +75,13 @@ WINDOWS_NATIVES = { LINUX_NATIVES = { "libglfw.so.3", - "libswnfd.so" + "libswnfd.so", } MAC_NATIVES = { "libglfw.3.dylib", - "libswnfd.dylib" + "libswnfd.dylib", + "libfreetype.6.dylib" } SERVER_EXTRA_CONTENT_ASSEMBLIES = [ From ae541bbdabe0d43e8ec3402affb63d63f31e8ee1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Aguilera=20Puerto?= Date: Tue, 23 Jun 2020 18:35:48 +0200 Subject: [PATCH 20/25] Balance stunbaton. Now it has a different stun chance depending on whether the other mob is slowed down or not. --- .../Weapon/Melee/StunbatonComponent.cs | 20 ++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/Content.Server/GameObjects/Components/Weapon/Melee/StunbatonComponent.cs b/Content.Server/GameObjects/Components/Weapon/Melee/StunbatonComponent.cs index 907854dd89..15df71beab 100644 --- a/Content.Server/GameObjects/Components/Weapon/Melee/StunbatonComponent.cs +++ b/Content.Server/GameObjects/Components/Weapon/Melee/StunbatonComponent.cs @@ -39,7 +39,10 @@ namespace Content.Server.GameObjects.Components.Weapon.Melee [ViewVariables] private ContainerSlot _cellContainer; [ViewVariables(VVAccess.ReadWrite)] - private float _paralyzeChance = 0.25f; + private float _paralyzeChanceNoSlowdown = 0.35f; + + [ViewVariables(VVAccess.ReadWrite)] + private float _paralyzeChanceWithSlowdown = 0.85f; [ViewVariables(VVAccess.ReadWrite)] private float _paralyzeTime = 10f; @@ -75,7 +78,8 @@ namespace Content.Server.GameObjects.Components.Weapon.Melee { base.ExposeData(serializer); - serializer.DataField(ref _paralyzeChance, "paralyzeChance", 0.25f); + serializer.DataField(ref _paralyzeChanceNoSlowdown, "paralyzeChanceNoSlowdown", 0.35f); + serializer.DataField(ref _paralyzeChanceWithSlowdown, "paralyzeChanceWithSlowdown", 0.85f); serializer.DataField(ref _paralyzeTime, "paralyzeTime", 10f); serializer.DataField(ref _slowdownTime, "slowdownTime", 5f); } @@ -92,10 +96,16 @@ namespace Content.Server.GameObjects.Components.Weapon.Melee { if (!entity.TryGetComponent(out StunnableComponent stunnable)) continue; - if(_robustRandom.Prob(_paralyzeChance)) - stunnable.Paralyze(_paralyzeTime); + if(!stunnable.SlowedDown) + if(_robustRandom.Prob(_paralyzeChanceNoSlowdown)) + stunnable.Paralyze(_paralyzeTime); + else + stunnable.Slowdown(_slowdownTime); else - stunnable.Slowdown(_slowdownTime); + if(_robustRandom.Prob(_paralyzeChanceWithSlowdown)) + stunnable.Paralyze(_paralyzeTime); + else + stunnable.Slowdown(_slowdownTime); } cell.DeductCharge(EnergyPerUse); From 137d32e6aa45630548d473229f2c0320b7fd2af1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Aguilera=20Puerto?= <6766154+Zumorica@users.noreply.github.com> Date: Tue, 23 Jun 2020 20:24:25 +0200 Subject: [PATCH 21/25] Timed spawners (#1196) * "Spawner" is a word. * Timed Spawners. * Default interval is now 60s --- .../Markers/ConditionalSpawnerComponent.cs | 3 - .../Markers/TimedSpawnerComponent.cs | 89 +++++++++++++++++++ .../Entities/Markers/timed_spawners.yml | 42 +++++++++ SpaceStation14.sln.DotSettings | 4 +- 4 files changed, 133 insertions(+), 5 deletions(-) create mode 100644 Content.Server/GameObjects/Components/Markers/TimedSpawnerComponent.cs create mode 100644 Resources/Prototypes/Entities/Markers/timed_spawners.yml diff --git a/Content.Server/GameObjects/Components/Markers/ConditionalSpawnerComponent.cs b/Content.Server/GameObjects/Components/Markers/ConditionalSpawnerComponent.cs index a41c72b31d..53dfca85c1 100644 --- a/Content.Server/GameObjects/Components/Markers/ConditionalSpawnerComponent.cs +++ b/Content.Server/GameObjects/Components/Markers/ConditionalSpawnerComponent.cs @@ -2,18 +2,15 @@ using System; using System.Collections.Generic; using Content.Server.GameTicking; using Content.Server.Interfaces.GameTicking; -using NFluidsynth; using Robust.Server.Interfaces.GameObjects; using Robust.Shared.GameObjects; using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.Interfaces.Random; using Robust.Shared.Interfaces.Reflection; using Robust.Shared.IoC; -using Robust.Shared.Prototypes; using Robust.Shared.Random; using Robust.Shared.Serialization; using Robust.Shared.ViewVariables; -using SQLitePCL; using Logger = Robust.Shared.Log.Logger; namespace Content.Server.GameObjects.Components.Markers diff --git a/Content.Server/GameObjects/Components/Markers/TimedSpawnerComponent.cs b/Content.Server/GameObjects/Components/Markers/TimedSpawnerComponent.cs new file mode 100644 index 0000000000..96aa996204 --- /dev/null +++ b/Content.Server/GameObjects/Components/Markers/TimedSpawnerComponent.cs @@ -0,0 +1,89 @@ +using System; +using System.Collections.Generic; +using System.Threading; +using Robust.Shared.GameObjects; +using Robust.Shared.Interfaces.GameObjects; +using Robust.Shared.Interfaces.Random; +using Robust.Shared.IoC; +using Robust.Shared.Random; +using Robust.Shared.Serialization; +using Robust.Shared.ViewVariables; +using Timer = Robust.Shared.Timers.Timer; + +namespace Content.Server.GameObjects.Components.Markers +{ + [RegisterComponent] + public class TimedSpawnerComponent : Component + { +#pragma warning disable 649 + [Dependency] private IEntityManager _entityManager; + [Dependency] private IRobustRandom _robustRandom; +#pragma warning restore 649 + + public override string Name => "TimedSpawner"; + + [ViewVariables(VVAccess.ReadWrite)] + public List Prototypes { get; set; } = new List(); + + [ViewVariables(VVAccess.ReadWrite)] + public float Chance { get; set; } = 1.0f; + + [ViewVariables(VVAccess.ReadWrite)] + public int IntervalSeconds { get; set; } = 60; + + [ViewVariables(VVAccess.ReadWrite)] + public int MinimumEntitiesSpawned { get; set; } = 1; + + [ViewVariables(VVAccess.ReadWrite)] + public int MaximumEntitiesSpawned { get; set; } = 1; + + private CancellationTokenSource TokenSource; + + public override void Initialize() + { + base.Initialize(); + SetupTimer(); + } + + protected override void Shutdown() + { + base.Shutdown(); + TokenSource.Cancel(); + } + + public override void ExposeData(ObjectSerializer serializer) + { + base.ExposeData(serializer); + + serializer.DataField(this, x => Prototypes, "prototypes", new List()); + serializer.DataField(this, x => Chance, "chance", 1.0f); + serializer.DataField(this, x => IntervalSeconds, "intervalSeconds", 60); + serializer.DataField(this, x => MinimumEntitiesSpawned, "minimumEntitiesSpawned", 1); + serializer.DataField(this, x => MaximumEntitiesSpawned, "maximumEntitiesSpawned", 1); + + if(MinimumEntitiesSpawned > MaximumEntitiesSpawned) + throw new ArgumentException("MaximumEntitiesSpawned can't be lower than MinimumEntitiesSpawned!"); + } + + private void SetupTimer() + { + TokenSource?.Cancel(); + TokenSource = new CancellationTokenSource(); + Timer.SpawnRepeating(TimeSpan.FromSeconds(IntervalSeconds), OnTimerFired, TokenSource.Token); + } + + private void OnTimerFired() + { + if (!_robustRandom.Prob(Chance)) + return; + + var number = _robustRandom.Next(MinimumEntitiesSpawned, MaximumEntitiesSpawned); + + for (int i = 0; i < number; i++) + { + var entity = _robustRandom.Pick(Prototypes); + _entityManager.SpawnEntity(entity, Owner.Transform.GridPosition); + } + } + } +} diff --git a/Resources/Prototypes/Entities/Markers/timed_spawners.yml b/Resources/Prototypes/Entities/Markers/timed_spawners.yml new file mode 100644 index 0000000000..4bc96baeed --- /dev/null +++ b/Resources/Prototypes/Entities/Markers/timed_spawners.yml @@ -0,0 +1,42 @@ +- type: entity + name: base timed spawner + id: BaseTimedSpawner + abstract: true + components: + - type: Sprite + netsync: false + visible: false + sprite: Objects/markers.rsi + state: cross_blue + - type: Icon + sprite: Objects/markers.rsi + state: cross_blue + - type: Marker + - type: Clickable + - type: InteractionOutline + - type: Collidable + - type: TimedSpawner + placement: + mode: AlignTileAny + +- type: entity + name: AI Timed Spawner + id: AITimedSpawner + parent: BaseTimedSpawner + components: + - type: Sprite + netsync: false + visible: false + sprite: Objects/markers.rsi + state: spawner_rifle + - type: Icon + sprite: Objects/markers.rsi + state: spawner_rifle + - type: TimedSpawner + prototypes: + - HumanMob_Spirate + - HumanMob_Civilian + chance: 0.75 + intervalSeconds: 60 + minimumEntitiesSpawned: 1 + maximumEntitiesSpawned: 5 diff --git a/SpaceStation14.sln.DotSettings b/SpaceStation14.sln.DotSettings index 5e9ee1ab64..39b7cb2137 100644 --- a/SpaceStation14.sln.DotSettings +++ b/SpaceStation14.sln.DotSettings @@ -57,9 +57,9 @@ True True True + True True True True True - True - True + \ No newline at end of file From 7089b607388d9188b584dad5ad693af705a3e9bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Aguilera=20Puerto?= Date: Tue, 23 Jun 2020 21:05:25 +0200 Subject: [PATCH 22/25] Rejuvenate now resets stuns. Fixes #1198 --- .../GameObjects/Components/Mobs/StunnableComponent.cs | 11 +++++++++++ Content.Server/GlobalVerbs/RejuvenateVerb.cs | 5 +++++ 2 files changed, 16 insertions(+) diff --git a/Content.Server/GameObjects/Components/Mobs/StunnableComponent.cs b/Content.Server/GameObjects/Components/Mobs/StunnableComponent.cs index 8948752b88..fbbd165230 100644 --- a/Content.Server/GameObjects/Components/Mobs/StunnableComponent.cs +++ b/Content.Server/GameObjects/Components/Mobs/StunnableComponent.cs @@ -192,6 +192,17 @@ namespace Content.Server.GameObjects.Components.Mobs _statusRemoveCancellation = new CancellationTokenSource(); } + public void ResetStuns() + { + _stunnedTimer = 0f; + _slowdownTimer = 0f; + + if (KnockedDown) + StandingStateHelper.Standing(Owner); + + _knockdownTimer = 0f; + } + public void Update(float delta) { if (Stunned) diff --git a/Content.Server/GlobalVerbs/RejuvenateVerb.cs b/Content.Server/GlobalVerbs/RejuvenateVerb.cs index cf141019b6..3c2c69da6f 100644 --- a/Content.Server/GlobalVerbs/RejuvenateVerb.cs +++ b/Content.Server/GlobalVerbs/RejuvenateVerb.cs @@ -1,4 +1,5 @@ using Content.Server.GameObjects; +using Content.Server.GameObjects.Components.Mobs; using Content.Server.GameObjects.Components.Nutrition; using Content.Shared.GameObjects; using Robust.Server.Console; @@ -62,6 +63,10 @@ namespace Content.Server.GlobalVerbs { thirst.ResetThirst(); } + if (target.TryGetComponent(out StunnableComponent stun)) + { + stun.ResetStuns(); + } } } } From 78085855dbd18e593424bfa6e7c84313eda4c6eb Mon Sep 17 00:00:00 2001 From: DrSmugleaf Date: Tue, 23 Jun 2020 21:30:37 +0200 Subject: [PATCH 23/25] Fix a late joining client not knowing if the lobby has been paused (#1199) * Fix client not knowing that the lobby is paused when joining after the pause Also fixes a client thinking that a lobby is paused when joining a new one after leaving a previously paused one * Add server announcement to delaying and pausing round start --- Content.Client/GameTicking/ClientGameTicker.cs | 1 + Content.Server/GameTicking/GameTicker.cs | 7 +++++++ Content.Shared/SharedGameTicker.cs | 3 +++ 3 files changed, 11 insertions(+) diff --git a/Content.Client/GameTicking/ClientGameTicker.cs b/Content.Client/GameTicking/ClientGameTicker.cs index 194f600657..a80f606215 100644 --- a/Content.Client/GameTicking/ClientGameTicker.cs +++ b/Content.Client/GameTicking/ClientGameTicker.cs @@ -55,6 +55,7 @@ namespace Content.Client.GameTicking StartTime = message.StartTime; IsGameStarted = message.IsRoundStarted; AreWeReady = message.YouAreReady; + Paused = message.Paused; LobbyStatusUpdated?.Invoke(); } diff --git a/Content.Server/GameTicking/GameTicker.cs b/Content.Server/GameTicking/GameTicker.cs index 93581796ac..51b0136957 100644 --- a/Content.Server/GameTicking/GameTicker.cs +++ b/Content.Server/GameTicking/GameTicker.cs @@ -437,6 +437,8 @@ namespace Content.Server.GameTicking lobbyCountdownMessage.Paused = Paused; _netManager.ServerSendToAll(lobbyCountdownMessage); + _chatManager.DispatchServerAnnouncement($"Round start has been delayed for {time.TotalSeconds} seconds."); + return true; } @@ -463,6 +465,10 @@ namespace Content.Server.GameTicking lobbyCountdownMessage.Paused = Paused; _netManager.ServerSendToAll(lobbyCountdownMessage); + _chatManager.DispatchServerAnnouncement(Paused + ? "Round start has been paused." + : "Round start countdown is now resumed."); + return true; } @@ -838,6 +844,7 @@ namespace Content.Server.GameTicking msg.IsRoundStarted = RunLevel != GameRunLevel.PreRoundLobby; msg.StartTime = _roundStartTimeUtc; msg.YouAreReady = ready; + msg.Paused = Paused; return msg; } diff --git a/Content.Shared/SharedGameTicker.cs b/Content.Shared/SharedGameTicker.cs index c4dd450c8b..2fea6dd16b 100644 --- a/Content.Shared/SharedGameTicker.cs +++ b/Content.Shared/SharedGameTicker.cs @@ -66,6 +66,7 @@ namespace Content.Shared public bool YouAreReady { get; set; } // UTC. public DateTime StartTime { get; set; } + public bool Paused { get; set; } public override void ReadFromBuffer(NetIncomingMessage buffer) { @@ -78,6 +79,7 @@ namespace Content.Shared YouAreReady = buffer.ReadBoolean(); StartTime = new DateTime(buffer.ReadInt64(), DateTimeKind.Utc); + Paused = buffer.ReadBoolean(); } public override void WriteToBuffer(NetOutgoingMessage buffer) @@ -91,6 +93,7 @@ namespace Content.Shared buffer.Write(YouAreReady); buffer.Write(StartTime.Ticks); + buffer.Write(Paused); } } From 73d4f3165aa15ddebba75b99f59663bf001f8e1d Mon Sep 17 00:00:00 2001 From: Pieter-Jan Briers Date: Wed, 24 Jun 2020 12:01:20 +0200 Subject: [PATCH 24/25] Update submodule --- RobustToolbox | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RobustToolbox b/RobustToolbox index 2558201ae4..4650dc2c49 160000 --- a/RobustToolbox +++ b/RobustToolbox @@ -1 +1 @@ -Subproject commit 2558201ae44fcd53e4199cd190b2063257d4c79c +Subproject commit 4650dc2c49888593c63b4a3871d99845fb7acc7a From 3a862643ac46baba03bd1efce92cc0a54bf1bc56 Mon Sep 17 00:00:00 2001 From: Pieter-Jan Briers Date: Wed, 24 Jun 2020 12:11:33 +0200 Subject: [PATCH 25/25] Fix exception when re-entering body. --- Content.Client/EntryPoint.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Content.Client/EntryPoint.cs b/Content.Client/EntryPoint.cs index 9807f35a0a..d939d9cbce 100644 --- a/Content.Client/EntryPoint.cs +++ b/Content.Client/EntryPoint.cs @@ -253,7 +253,10 @@ namespace Content.Client /// public static void DetachPlayerFromEntity(EntityDetachedEventArgs eventArgs) { - eventArgs.OldEntity.RemoveComponent(); + if (!eventArgs.OldEntity.Deleted) + { + eventArgs.OldEntity.RemoveComponent(); + } } public override void PostInit()