From 81c7a03c97419dac672e1dfa0453912fb2e88254 Mon Sep 17 00:00:00 2001 From: Rane <60792108+Elijahrane@users.noreply.github.com> Date: Thu, 10 Feb 2022 17:15:06 -0500 Subject: [PATCH] Drones (#6448) --- Content.Client/Entry/IgnoredComponents.cs | 1 + .../Actions/Actions/DisarmAction.cs | 8 +- .../Actions/Events/DisarmAttemptEvent.cs | 15 ++ .../Drone/Components/DroneComponent.cs | 17 +++ Content.Server/Drone/DroneSystem.cs | 132 +++++++++++++++++ .../Drone/Components/DroneToolComponent.cs | 8 ++ Content.Shared/Drone/SharedDroneSystem.cs | 22 +++ Resources/Locale/en-US/drone/drone-system.ftl | 3 + Resources/Prototypes/Body/Parts/silicon.yml | 50 +++++++ Resources/Prototypes/Body/Presets/drone.yml | 10 ++ Resources/Prototypes/Body/Templates/drone.yml | 11 ++ .../Catalog/Research/technologies.yml | 1 + .../Entities/Markers/Spawners/mobs.yml | 15 ++ .../Entities/Mobs/Player/silicon.yml | 135 ++++++++++++++++++ .../Entities/Structures/Machines/lathe.yml | 1 + Resources/Prototypes/Recipes/Lathes/misc.yml | 14 +- Resources/Prototypes/accents.yml | 8 ++ .../Textures/Mobs/Silicon/drone.rsi/drone.png | Bin 0 -> 2855 bytes .../Mobs/Silicon/drone.rsi/l_hand.png | Bin 0 -> 654 bytes .../Textures/Mobs/Silicon/drone.rsi/meta.json | 53 +++++++ .../Mobs/Silicon/drone.rsi/r_hand.png | Bin 0 -> 5373 bytes .../Textures/Mobs/Silicon/drone.rsi/shell.png | Bin 0 -> 942 bytes 22 files changed, 502 insertions(+), 2 deletions(-) create mode 100644 Content.Server/Actions/Events/DisarmAttemptEvent.cs create mode 100644 Content.Server/Drone/Components/DroneComponent.cs create mode 100644 Content.Server/Drone/DroneSystem.cs create mode 100644 Content.Shared/Drone/Components/DroneToolComponent.cs create mode 100644 Content.Shared/Drone/SharedDroneSystem.cs create mode 100644 Resources/Locale/en-US/drone/drone-system.ftl create mode 100644 Resources/Prototypes/Body/Parts/silicon.yml create mode 100644 Resources/Prototypes/Body/Presets/drone.yml create mode 100644 Resources/Prototypes/Body/Templates/drone.yml create mode 100644 Resources/Prototypes/Entities/Mobs/Player/silicon.yml create mode 100644 Resources/Textures/Mobs/Silicon/drone.rsi/drone.png create mode 100644 Resources/Textures/Mobs/Silicon/drone.rsi/l_hand.png create mode 100644 Resources/Textures/Mobs/Silicon/drone.rsi/meta.json create mode 100644 Resources/Textures/Mobs/Silicon/drone.rsi/r_hand.png create mode 100644 Resources/Textures/Mobs/Silicon/drone.rsi/shell.png diff --git a/Content.Client/Entry/IgnoredComponents.cs b/Content.Client/Entry/IgnoredComponents.cs index 4e8ae5f97f..11f96b3c48 100644 --- a/Content.Client/Entry/IgnoredComponents.cs +++ b/Content.Client/Entry/IgnoredComponents.cs @@ -56,6 +56,7 @@ namespace Content.Client.Entry "Electrified", "Electrocution", "Paper", + "Drone", "Bloodstream", "TransformableContainer", "Mind", diff --git a/Content.Server/Actions/Actions/DisarmAction.cs b/Content.Server/Actions/Actions/DisarmAction.cs index 7e9ac324a6..07d2e69af5 100644 --- a/Content.Server/Actions/Actions/DisarmAction.cs +++ b/Content.Server/Actions/Actions/DisarmAction.cs @@ -1,6 +1,7 @@ using System; using System.Linq; using Content.Server.Act; +using Content.Server.Actions.Events; using Content.Server.Administration.Logs; using Content.Server.Interaction; using Content.Server.Popups; @@ -44,11 +45,16 @@ namespace Content.Server.Actions.Actions [ViewVariables] [DataField("disarmSuccessSound")] private SoundSpecifier DisarmSuccessSound { get; } = new SoundPathSpecifier("/Audio/Effects/thudswoosh.ogg"); - public void DoTargetEntityAction(TargetEntityActionEventArgs args) { var entMan = IoCManager.Resolve(); var disarmedActs = entMan.GetComponents(args.Target).ToArray(); + var attemptEvent = new DisarmAttemptEvent(args.Target, args.Performer); + + entMan.EventBus.RaiseLocalEvent(args.Target, attemptEvent); + + if (attemptEvent.Cancelled) + return; if (!args.Performer.InRangeUnobstructed(args.Target)) return; diff --git a/Content.Server/Actions/Events/DisarmAttemptEvent.cs b/Content.Server/Actions/Events/DisarmAttemptEvent.cs new file mode 100644 index 0000000000..2a5d167209 --- /dev/null +++ b/Content.Server/Actions/Events/DisarmAttemptEvent.cs @@ -0,0 +1,15 @@ +using Robust.Shared.GameObjects; + +namespace Content.Server.Actions.Events +{ + public class DisarmAttemptEvent : CancellableEntityEventArgs + { + public readonly EntityUid TargetUid; + public readonly EntityUid DisarmerUid; + public DisarmAttemptEvent(EntityUid targetUid, EntityUid disarmerUid) + { + TargetUid = targetUid; + DisarmerUid = disarmerUid; + } + } +} diff --git a/Content.Server/Drone/Components/DroneComponent.cs b/Content.Server/Drone/Components/DroneComponent.cs new file mode 100644 index 0000000000..785552a4d6 --- /dev/null +++ b/Content.Server/Drone/Components/DroneComponent.cs @@ -0,0 +1,17 @@ +using System.Collections.Generic; +using Content.Server.Storage; +using Robust.Shared.Analyzers; +using Robust.Shared.GameObjects; +using Robust.Shared.Serialization.Manager.Attributes; + + +namespace Content.Server.Drone.Components +{ + [RegisterComponent] + public sealed class DroneComponent : Component + { + [DataField("tools")] public List Tools = new(); + public List ToolUids = new(); + public bool AlreadyAwoken = false; + } +} diff --git a/Content.Server/Drone/DroneSystem.cs b/Content.Server/Drone/DroneSystem.cs new file mode 100644 index 0000000000..9db870f0a9 --- /dev/null +++ b/Content.Server/Drone/DroneSystem.cs @@ -0,0 +1,132 @@ +using Content.Shared.Drone; +using Content.Server.Drone.Components; +using Content.Shared.Drone.Components; +using Content.Shared.Interaction.Events; +using Content.Shared.Inventory.Events; +using Content.Shared.MobState.Components; +using Content.Shared.MobState; +using Content.Shared.DragDrop; +using Content.Shared.Examine; +using Content.Server.Popups; +using Content.Server.Mind.Components; +using Content.Server.Ghost.Roles.Components; +using Content.Server.Hands.Components; +using Content.Shared.Body.Components; +using Content.Server.Actions.Events; +using Robust.Shared.IoC; +using Robust.Shared.GameObjects; +using Robust.Shared.Localization; +using Robust.Shared.Player; +using Content.Shared.Tag; + +namespace Content.Server.Drone +{ + public class DroneSystem : SharedDroneSystem + { + [Dependency] private readonly PopupSystem _popupSystem = default!; + public override void Initialize() + { + base.Initialize(); + SubscribeLocalEvent(OnMobStateChanged); + SubscribeLocalEvent(OnDisarmAttempt); + SubscribeLocalEvent(OnDropAttempt); + SubscribeLocalEvent(OnExamined); + SubscribeLocalEvent(OnMindAdded); + SubscribeLocalEvent(OnMindRemoved); + } + + private void OnExamined(EntityUid uid, DroneComponent component, ExaminedEvent args) + { + if (args.IsInDetailsRange) + { + if (TryComp(uid, out var mind) && mind.HasMind) + { + args.PushMarkup(Loc.GetString("drone-active")); + } + else + { + args.PushMarkup(Loc.GetString("drone-dormant")); + } + } + } + + private void OnMobStateChanged(EntityUid uid, DroneComponent drone, MobStateChangedEvent args) + { + if (args.Component.IsDead()) + { + var body = Comp(uid); //There's no way something can have a mobstate but not a body... + + foreach (var item in drone.ToolUids) + { + EntityManager.DeleteEntity(item); + } + body.Gib(); + EntityManager.DeleteEntity(uid); + } + } + + private void OnDisarmAttempt(EntityUid uid, DroneComponent drone, DisarmAttemptEvent args) + { + TryComp(args.TargetUid, out var hands); + var item = hands?.GetActiveHandItem; + if (TryComp(item?.Owner, out var itemInHand)) + { + args.Cancel(); + } + } + + private void OnMindAdded(EntityUid uid, DroneComponent drone, MindAddedMessage args) + { + TryComp(uid, out var tagComp); + UpdateDroneAppearance(uid, DroneStatus.On); + tagComp?.AddTag("DoorBumpOpener"); + _popupSystem.PopupEntity(Loc.GetString("drone-activated"), uid, Filter.Pvs(uid)); + + if (drone.AlreadyAwoken == false) + { + var spawnCoord = Transform(uid).Coordinates; + + if (drone.Tools.Count == 0) return; + + if (TryComp(uid, out var hands) && hands.Count >= drone.Tools.Count) + { + foreach (var entry in drone.Tools) + { + var item = EntityManager.SpawnEntity(entry.PrototypeId, spawnCoord); + AddComp(item); + hands.PutInHand(item); + drone.ToolUids.Add(item); + } + } + + drone.AlreadyAwoken = true; + } + } + + private void OnMindRemoved(EntityUid uid, DroneComponent drone, MindRemovedMessage args) + { + TryComp(uid, out var tagComp); + UpdateDroneAppearance(uid, DroneStatus.Off); + tagComp?.RemoveTag("DoorBumpOpener"); + EnsureComp(uid); + } + + private void OnDropAttempt(EntityUid uid, DroneComponent drone, DropAttemptEvent args) + { + TryComp(uid, out var hands); + var item = hands?.GetActiveHandItem; + if (TryComp(item?.Owner, out var itemInHand)) + { + args.Cancel(); + } + } + + private void UpdateDroneAppearance(EntityUid uid, DroneStatus status) + { + if (TryComp(uid, out var appearance)) + { + appearance.SetData(DroneVisuals.Status, status); + } + } + } +} diff --git a/Content.Shared/Drone/Components/DroneToolComponent.cs b/Content.Shared/Drone/Components/DroneToolComponent.cs new file mode 100644 index 0000000000..f25955e827 --- /dev/null +++ b/Content.Shared/Drone/Components/DroneToolComponent.cs @@ -0,0 +1,8 @@ +using Robust.Shared.GameObjects; +using Robust.Shared.Analyzers; + +namespace Content.Shared.Drone.Components +{ + [RegisterComponent] + public sealed class DroneToolComponent : Component {} +} diff --git a/Content.Shared/Drone/SharedDroneSystem.cs b/Content.Shared/Drone/SharedDroneSystem.cs new file mode 100644 index 0000000000..e29534d3f3 --- /dev/null +++ b/Content.Shared/Drone/SharedDroneSystem.cs @@ -0,0 +1,22 @@ +using System; +using Robust.Shared.GameObjects; +using Robust.Shared.Serialization; + +namespace Content.Shared.Drone +{ + public abstract class SharedDroneSystem : EntitySystem + { + [Serializable, NetSerializable] + public enum DroneVisuals : byte + { + Status + } + + [Serializable, NetSerializable] + public enum DroneStatus : byte + { + Off, + On + } + } +} diff --git a/Resources/Locale/en-US/drone/drone-system.ftl b/Resources/Locale/en-US/drone/drone-system.ftl new file mode 100644 index 0000000000..68000da268 --- /dev/null +++ b/Resources/Locale/en-US/drone/drone-system.ftl @@ -0,0 +1,3 @@ +drone-active = A maintenance drone. It seems totally unconcerned with you. +drone-dormant = A dormant maintenance drone. Who knows when it will wake up? +drone-activated = The drone whirrs to life! diff --git a/Resources/Prototypes/Body/Parts/silicon.yml b/Resources/Prototypes/Body/Parts/silicon.yml new file mode 100644 index 0000000000..1a0b6be4f4 --- /dev/null +++ b/Resources/Prototypes/Body/Parts/silicon.yml @@ -0,0 +1,50 @@ +- type: entity + id: PartSilicon + parent: BaseItem + name: "silicon body part" + abstract: true + components: + - type: Damageable + damageContainer: Inorganic + +- type: entity + id: LeftHandDrone + name: "left drone hand" + parent: PartSilicon + components: + - type: Sprite + netsync: false + sprite: Mobs/Silicon/drone.rsi + state: "l_hand" + - type: Icon + sprite: Mobs/Silicon/drone.rsi + state: "l_hand" + - type: BodyPart + partType: Hand + size: 3 + compatibility: Biological ##Does this do anything? Revisit when surgery is in + symmetry: Left + - type: Tag + tags: + - Trash + +- type: entity + id: RightHandDrone + name: "right drone hand" + parent: PartSilicon + components: + - type: Sprite + netsync: false + sprite: Mobs/Silicon/drone.rsi + state: "r_hand" + - type: Icon + sprite: Mobs/Silicon/drone.rsi + state: "r_hand" + - type: BodyPart + partType: Hand + size: 3 + compatibility: Biological + symmetry: Right + - type: Tag + tags: + - Trash diff --git a/Resources/Prototypes/Body/Presets/drone.yml b/Resources/Prototypes/Body/Presets/drone.yml new file mode 100644 index 0000000000..08eb753086 --- /dev/null +++ b/Resources/Prototypes/Body/Presets/drone.yml @@ -0,0 +1,10 @@ +- type: bodyPreset + name: "drone" + id: DronePreset + partIDs: + hand 1: LeftHandDrone + hand 2: LeftHandDrone + hand 3: LeftHandDrone + hand 4: RightHandDrone + hand 5: RightHandDrone + hand 6: RightHandDrone diff --git a/Resources/Prototypes/Body/Templates/drone.yml b/Resources/Prototypes/Body/Templates/drone.yml new file mode 100644 index 0000000000..046b79764c --- /dev/null +++ b/Resources/Prototypes/Body/Templates/drone.yml @@ -0,0 +1,11 @@ +- type: bodyTemplate + id: DroneTemplate + name: "drone" + centerSlot: "torso" + slots: + hand 1: hand + hand 2: hand + hand 3: hand + hand 4: hand + hand 5: hand + hand 6: hand diff --git a/Resources/Prototypes/Catalog/Research/technologies.yml b/Resources/Prototypes/Catalog/Research/technologies.yml index 61ab251acf..b102f5acbe 100644 --- a/Resources/Prototypes/Catalog/Research/technologies.yml +++ b/Resources/Prototypes/Catalog/Research/technologies.yml @@ -277,6 +277,7 @@ - IndustrialEngineering unlockedRecipes: - ShuttleConsoleCircuitboard + - Drone # Electromagnetic Theory Technology Tree diff --git a/Resources/Prototypes/Entities/Markers/Spawners/mobs.yml b/Resources/Prototypes/Entities/Markers/Spawners/mobs.yml index 71de4ea02b..16a6b09661 100644 --- a/Resources/Prototypes/Entities/Markers/Spawners/mobs.yml +++ b/Resources/Prototypes/Entities/Markers/Spawners/mobs.yml @@ -44,3 +44,18 @@ prototypes: - MobCorgi - MobCorgiOld + +## Player-controlled + +- type: entity + name: Drone Spawner + id: SpawnMobDrone + parent: MarkerBase + components: + - type: Sprite + layers: + - state: green + - texture: Mobs/Silicon/drone.rsi/shell.png + - type: ConditionalSpawner + prototypes: + - Drone diff --git a/Resources/Prototypes/Entities/Mobs/Player/silicon.yml b/Resources/Prototypes/Entities/Mobs/Player/silicon.yml new file mode 100644 index 0000000000..7fb997aa71 --- /dev/null +++ b/Resources/Prototypes/Entities/Mobs/Player/silicon.yml @@ -0,0 +1,135 @@ +- type: entity + save: false + abstract: true + id: PlayerSiliconBase #for player controlled silicons + components: + - type: Reactive + groups: + Acidic: [Touch] + - type: Input + context: "human" + - type: MovedByPressure + - type: DamageOnHighSpeedImpact + damage: + types: + Blunt: 5 + soundHit: + path: /Audio/Effects/hit_kick.ogg + - type: Clickable + - type: Damageable + damageContainer: Inorganic + - type: InteractionOutline + - type: Fixtures + fixtures: + - shape: + # Circles, cuz rotation of rectangles looks very bad + !type:PhysShapeCircle + radius: 0.35 + mass: 20 + mask: + - Impassable + - MobImpassable + - VaultImpassable + - SmallImpassable + layer: + - Opaque + - type: MovementSpeedModifier + baseWalkSpeed : 4 + baseSprintSpeed : 3 + - type: Sprite + noRot: true + drawdepth: Mobs + - type: Physics + bodyType: KinematicController + - type: Hands + - type: Body + template: DroneTemplate + preset: DronePreset + - type: DoAfter + - type: Pullable + - type: Examiner + - type: Puller + - type: Recyclable + safe: false + - type: StandingState + - type: Alerts + +- type: entity + name: drone + id: Drone + parent: PlayerSiliconBase + components: + - type: Drone + tools: + - id: PowerDrill + - id: JawsOfLife + - id: WelderExperimental + - type: GhostTakeoverAvailable + makeSentient: true + name: Maintenance Drone + description: Maintain the station. Ignore organics. + rules: | + You are bound by these laws both in-game and out-of-character: + 1. You may not involve yourself in the matters of another being, even if such matters conflict with Law Two or Law Three, unless the other being is another Drone. + 2. You may not harm any being, regardless of intent or circumstance. + 3. Your goals are to build, maintain, repair, improve, and power to the best of your abilities, You must never actively work against these goals. + - type: MovementSpeedModifier + baseWalkSpeed : 6 + baseSprintSpeed : 6 + - type: MobState + thresholds: + 0: !type:NormalMobState {} + 70: !type:DeadMobState {} + - type: Sprite + drawdepth: Mobs + netsync: false + layers: + - state: shell + sprite: Mobs/Silicon/drone.rsi + - type: Fixtures + fixtures: + - shape: + !type:PhysShapeCircle + radius: 0.25 + mass: 5 + mask: + - VaultImpassable + layer: + - Opaque + - type: Tag + - type: Access + tags: + - Maintenance + - Cargo + # - Quartermaster + - Engineering + - ChiefEngineer + - Medical + - ChiefMedicalOfficer + - Research + - ResearchDirector + - Security + - Service + - Captain + - Command + - External + - HeadOfSecurity + - HeadOfPersonnel + - Bar + - Hydroponics + - Kitchen + - Janitor + - Theatre + - type: Appearance + visuals: + - type: GenericEnumVisualizer + key: enum.DroneVisuals.Status + layer: 0 + states: + enum.DroneStatus.Off: shell + enum.DroneStatus.On: drone + - type: ReplacementAccent + accent: silicon + - type: Repairable + fuelcost: 15 + doAfterDelay: 8 diff --git a/Resources/Prototypes/Entities/Structures/Machines/lathe.yml b/Resources/Prototypes/Entities/Structures/Machines/lathe.yml index 10b3e6f005..8641dd800c 100644 --- a/Resources/Prototypes/Entities/Structures/Machines/lathe.yml +++ b/Resources/Prototypes/Entities/Structures/Machines/lathe.yml @@ -160,6 +160,7 @@ - Dropper - Syringe - PillCanister + - Drone - Flash - Handcuffs - Stunbaton diff --git a/Resources/Prototypes/Recipes/Lathes/misc.yml b/Resources/Prototypes/Recipes/Lathes/misc.yml index 13616025b8..3601fb520f 100644 --- a/Resources/Prototypes/Recipes/Lathes/misc.yml +++ b/Resources/Prototypes/Recipes/Lathes/misc.yml @@ -71,9 +71,21 @@ materials: Wood: 100 +- type: latheRecipe + id: Drone + icon: + sprite: Mobs/Silicon/drone.rsi + state: shell + result: Drone + completetime: 1500 + materials: + Steel: 500 + Glass: 500 + Plastic: 500 + - type: latheRecipe id: SynthesizerInstrument - icon: + icon: sprite: Objects/Fun/Instruments/h_synthesizer.rsi state: icon result: SynthesizerInstrument diff --git a/Resources/Prototypes/accents.yml b/Resources/Prototypes/accents.yml index decc7210b7..54e9a3a7a2 100644 --- a/Resources/Prototypes/accents.yml +++ b/Resources/Prototypes/accents.yml @@ -30,3 +30,11 @@ - Mmfph! - Mmmf mrrfff! - Mmmf mnnf! + +- type: accent + id: silicon + words: + - Beep. + - Boop. + - Whirr. + - Beep-boop. diff --git a/Resources/Textures/Mobs/Silicon/drone.rsi/drone.png b/Resources/Textures/Mobs/Silicon/drone.rsi/drone.png new file mode 100644 index 0000000000000000000000000000000000000000..531a2aaa8ed7ecb058554a32321ef9256a56a8d9 GIT binary patch literal 2855 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 literal 0 HcmV?d00001 diff --git a/Resources/Textures/Mobs/Silicon/drone.rsi/l_hand.png b/Resources/Textures/Mobs/Silicon/drone.rsi/l_hand.png new file mode 100644 index 0000000000000000000000000000000000000000..272f4a066465599e2e86fea27c5568ae78b04545 GIT binary patch literal 654 zcmV;90&)F`P)EX>4Tx04R}tkv&MmKpe$iQ>8^J4i*$~$WWauh>AFB6^c+H)C#RSm|Xe=O&XFE z7e~Rh;NZt%)xpJCR|i)?5c~jfbaGO3krMxx6k5c1aNLh~_a1le0HIM~n$%wfUwLgV@{G%@Eu?G2=MhT&a?c_{W*Hoyv2ZkNIc67(3QNPu~_V2rGr_?)QG2uW2&Z8zL51; z<-EmNtJGNQp8SQ8yuPx`b(+ISVi8M_AVNV6WmI4zPODCeg*5FaeEdVMUm}-6t}+-o z7Epx-+4Y0}!S8OZ!sLXP6iEQxFOKsu0)%#fX5DeVj~%CZ0tBCdE4}TnHh`H=((7$4 zb_Dco0~gnAP1yr3cYwhsLpEhs3epq`1>pURz9|Rv-vT{rUT>{^oIU^<>MC^u92^3p zMao|Hd3U(8w|~#H`uhRNFmhx3{23Sk000JJOGiWi{{a60|De66lK=n!32;bRa{vGe z!~g&a!~te)g46&200(qQO+^Rh0s|KY2Eyza_W%F@j7da6RCwC$+A#{nAPfM|(i7xv zIYRCa-oQT=9ukhaFViH1dF~IU{I93@bV_dqnK}F8uR800000001!0SO0m-?h4HO%6@9{jD3VHCSX+4hwlfp o);@3g$bEz@Ct!u#008Xf2P{NA<;_V#TL1t607*qoM6N<$g2KWWC;$Ke literal 0 HcmV?d00001 diff --git a/Resources/Textures/Mobs/Silicon/drone.rsi/meta.json b/Resources/Textures/Mobs/Silicon/drone.rsi/meta.json new file mode 100644 index 0000000000..46a79f9ae7 --- /dev/null +++ b/Resources/Textures/Mobs/Silicon/drone.rsi/meta.json @@ -0,0 +1,53 @@ +{ + "version": 1, + "size": { + "x": 32, + "y": 32 + }, + "license": "CC-BY-SA-3.0", + "copyright": "Taken from tgstation at https://github.com/tgstation/tgstation/commit/40d89d11ea4a5cb81d61dc1018b46f4e7d32c62a", + "states": [ + { + "name": "drone", + "directions": 4, + "delays": [ + [ + 0.2, + 0.2, + 0.2 + ], + [ + 0.2, + 0.2, + 0.2 + ], + [ + 0.2, + 0.2, + 0.2 + ], + [ + 0.2, + 0.2, + 0.2 + ] + ] + }, + { + "name": "shell", + "delays": [ + [ + 1 + ] + ] + }, + { + "name": "l_hand", + "directions": 4 + }, + { + "name": "r_hand", + "directions": 4 + } + ] +} diff --git a/Resources/Textures/Mobs/Silicon/drone.rsi/r_hand.png b/Resources/Textures/Mobs/Silicon/drone.rsi/r_hand.png new file mode 100644 index 0000000000000000000000000000000000000000..4a18493138cc9ae617653e61c10d3aefa8174c90 GIT binary patch literal 5373 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