From dc77c399b9d9fdf5ee8e84bcbbf64de2c99e0432 Mon Sep 17 00:00:00 2001 From: SoulSloth <67545203+SoulSloth@users.noreply.github.com> Date: Wed, 19 Aug 2020 10:23:20 -0400 Subject: [PATCH] Add 'Scan DNA' function to medical scanner (#1783) * Add art assets for cloning * Added a 'Scan DNA' button to the medical scanner * Made the UI update unconditional for the medical scanner until checks for power changes are in place * Update Medical scanner to reflect powered status and fix #1774 * added a 'scan dna' button the the medical scanner that will add the contained bodies Uid to a list in CloningSystem, fixed an issue with the menu not populating if the scanner starts in an unpowered state * Add disabling logic to 'Scan DNA' button on medical scanner * Removed un-used libraries * changed scan dna button to Scan and Save DNA --- .../MedicalScannerBoundUserInterface.cs | 1 + .../MedicalScanner/MedicalScannerWindow.cs | 29 +++++- .../Medical/MedicalScannerComponent.cs | 51 +++++++--- .../EntitySystems/CloningSystem.cs | 24 +++++ .../EntitySystems/MedicalScannerSystem.cs | 1 + .../Medical/SharedMedicalScannerComponent.cs | 24 ++++- .../Specific/Medical/Cloning.rsi/meta.json | 88 ++++++++++++++++++ .../Specific/Medical/Cloning.rsi/pod_0.png | Bin 0 -> 1319 bytes .../Specific/Medical/Cloning.rsi/scanner.png | Bin 0 -> 1938 bytes .../Cloning.rsi/scanner_maintenance.png | Bin 0 -> 1782 bytes .../Medical/Cloning.rsi/scanner_occupied.png | Bin 0 -> 4782 bytes .../Medical/Cloning.rsi/scanner_open.png | Bin 0 -> 1910 bytes .../Cloning.rsi/scanner_open_maintenance.png | Bin 0 -> 1750 bytes .../Cloning.rsi/scanner_open_unpowered.png | Bin 0 -> 1664 bytes .../Medical/Cloning.rsi/scanner_unpowered.png | Bin 0 -> 1652 bytes 15 files changed, 201 insertions(+), 17 deletions(-) create mode 100644 Content.Server/GameObjects/EntitySystems/CloningSystem.cs create mode 100644 Resources/Textures/Objects/Specific/Medical/Cloning.rsi/meta.json create mode 100644 Resources/Textures/Objects/Specific/Medical/Cloning.rsi/pod_0.png create mode 100644 Resources/Textures/Objects/Specific/Medical/Cloning.rsi/scanner.png create mode 100644 Resources/Textures/Objects/Specific/Medical/Cloning.rsi/scanner_maintenance.png create mode 100644 Resources/Textures/Objects/Specific/Medical/Cloning.rsi/scanner_occupied.png create mode 100644 Resources/Textures/Objects/Specific/Medical/Cloning.rsi/scanner_open.png create mode 100644 Resources/Textures/Objects/Specific/Medical/Cloning.rsi/scanner_open_maintenance.png create mode 100644 Resources/Textures/Objects/Specific/Medical/Cloning.rsi/scanner_open_unpowered.png create mode 100644 Resources/Textures/Objects/Specific/Medical/Cloning.rsi/scanner_unpowered.png diff --git a/Content.Client/GameObjects/Components/MedicalScanner/MedicalScannerBoundUserInterface.cs b/Content.Client/GameObjects/Components/MedicalScanner/MedicalScannerBoundUserInterface.cs index 4b2fa2a1fc..2280406c5b 100644 --- a/Content.Client/GameObjects/Components/MedicalScanner/MedicalScannerBoundUserInterface.cs +++ b/Content.Client/GameObjects/Components/MedicalScanner/MedicalScannerBoundUserInterface.cs @@ -22,6 +22,7 @@ namespace Content.Client.GameObjects.Components.MedicalScanner Title = Owner.Owner.Name, }; _window.OnClose += Close; + _window.ScanButton.OnPressed += _ => SendMessage(new UiButtonPressedMessage(UiButton.ScanDNA)); _window.OpenCentered(); } diff --git a/Content.Client/GameObjects/Components/MedicalScanner/MedicalScannerWindow.cs b/Content.Client/GameObjects/Components/MedicalScanner/MedicalScannerWindow.cs index 61adc113f2..4668854fbf 100644 --- a/Content.Client/GameObjects/Components/MedicalScanner/MedicalScannerWindow.cs +++ b/Content.Client/GameObjects/Components/MedicalScanner/MedicalScannerWindow.cs @@ -12,18 +12,38 @@ namespace Content.Client.GameObjects.Components.MedicalScanner { public class MedicalScannerWindow : SS14Window { + public readonly Button ScanButton; + private readonly Label _diagnostics; protected override Vector2? CustomSize => (485, 90); + public MedicalScannerWindow() + { + Contents.AddChild(new VBoxContainer + { + Children = + { + (ScanButton = new Button + { + Text = "Scan and Save DNA" + }), + (_diagnostics = new Label + { + Text = "" + }) + } + }); + } + public void Populate(MedicalScannerBoundUserInterfaceState state) { - Contents.RemoveAllChildren(); var text = new StringBuilder(); if (!state.Entity.HasValue || !state.HasDamage() || !IoCManager.Resolve().TryGetEntity(state.Entity.Value, out var entity)) { - text.Append(Loc.GetString("No patient data.")); + _diagnostics.Text = Loc.GetString("No patient data."); + ScanButton.Disabled = true; } else { @@ -45,9 +65,10 @@ namespace Content.Client.GameObjects.Components.MedicalScanner text.Append("\n"); } - } - Contents.AddChild(new Label() {Text = text.ToString()}); + _diagnostics.Text = text.ToString(); + ScanButton.Disabled = state.IsScanned; + } } } } diff --git a/Content.Server/GameObjects/Components/Medical/MedicalScannerComponent.cs b/Content.Server/GameObjects/Components/Medical/MedicalScannerComponent.cs index 4e36ffed71..d50513e374 100644 --- a/Content.Server/GameObjects/Components/Medical/MedicalScannerComponent.cs +++ b/Content.Server/GameObjects/Components/Medical/MedicalScannerComponent.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using Content.Server.GameObjects.Components.Power.ApcNetComponents; +using Content.Server.GameObjects.EntitySystems; using Content.Shared.GameObjects.Components.Damage; using Content.Shared.GameObjects.Components.Medical; using Content.Shared.GameObjects.EntitySystems; @@ -38,9 +39,14 @@ namespace Content.Server.GameObjects.Components.Medical _appearance = Owner.GetComponent(); _userInterface = Owner.GetComponent() .GetBoundUserInterface(MedicalScannerUiKey.Key); + _userInterface.OnReceiveMessage += OnUiReceiveMessage; _bodyContainer = ContainerManagerComponent.Ensure($"{Name}-bodyContainer", Owner); _powerReceiver = Owner.GetComponent(); + //TODO: write this so that it checks for a change in power events and acts accordingly. + var newState = GetUserInterfaceState(); + _userInterface.SetState(newState); + UpdateUserInterface(); } @@ -48,7 +54,8 @@ namespace Content.Server.GameObjects.Components.Medical new MedicalScannerBoundUserInterfaceState( null, new Dictionary(), - new Dictionary()); + new Dictionary(), + false); private MedicalScannerBoundUserInterfaceState GetUserInterfaceState() { @@ -68,7 +75,7 @@ namespace Content.Server.GameObjects.Components.Medical var classes = new Dictionary(damageable.DamageClasses); var types = new Dictionary(damageable.DamageTypes); - return new MedicalScannerBoundUserInterfaceState(body.Uid, classes, types); + return new MedicalScannerBoundUserInterfaceState(body.Uid, classes, types, CloningSystem.HasUid(body.Uid)); } private void UpdateUserInterface() @@ -92,12 +99,18 @@ namespace Content.Server.GameObjects.Components.Medical default: throw new ArgumentException(nameof(damageState)); } } + private MedicalScannerStatus GetStatus() { - var body = _bodyContainer.ContainedEntity; - return body == null - ? MedicalScannerStatus.Open - : GetStatusFromDamageState(body.GetComponent().CurrentDamageState); + if (Powered) + { + var body = _bodyContainer.ContainedEntity; + return body == null + ? MedicalScannerStatus.Open + : GetStatusFromDamageState(body.GetComponent().CurrentDamageState); + } + + return MedicalScannerStatus.Off; } private void UpdateAppearance() @@ -178,14 +191,28 @@ namespace Content.Server.GameObjects.Components.Medical public void Update(float frameTime) { - if (_bodyContainer.ContainedEntity == null) - { - // There's no need to update if there's no one inside - return; - } - UpdateUserInterface(); UpdateAppearance(); } + + private void OnUiReceiveMessage(ServerBoundUserInterfaceMessage obj) + { + if (!(obj.Message is UiButtonPressedMessage message)) + { + return; + } + + switch (message.Button) + { + case UiButton.ScanDNA: + if (_bodyContainer.ContainedEntity != null) + { + CloningSystem.AddToScannedUids(_bodyContainer.ContainedEntity.Uid); + } + break; + default: + throw new ArgumentOutOfRangeException(); + } + } } } diff --git a/Content.Server/GameObjects/EntitySystems/CloningSystem.cs b/Content.Server/GameObjects/EntitySystems/CloningSystem.cs new file mode 100644 index 0000000000..469c0f6157 --- /dev/null +++ b/Content.Server/GameObjects/EntitySystems/CloningSystem.cs @@ -0,0 +1,24 @@ +using System.Collections.Generic; +using Robust.Shared.GameObjects; +using Robust.Shared.GameObjects.Systems; + +namespace Content.Server.GameObjects.EntitySystems +{ + internal sealed class CloningSystem : EntitySystem + { + public static List scannedUids = new List(); + + public static void AddToScannedUids(EntityUid uid) + { + if (!scannedUids.Contains(uid)) + { + scannedUids.Add(uid); + } + } + + public static bool HasUid(EntityUid uid) + { + return scannedUids.Contains(uid); + } + } +} diff --git a/Content.Server/GameObjects/EntitySystems/MedicalScannerSystem.cs b/Content.Server/GameObjects/EntitySystems/MedicalScannerSystem.cs index 3180063247..01d1cd20ac 100644 --- a/Content.Server/GameObjects/EntitySystems/MedicalScannerSystem.cs +++ b/Content.Server/GameObjects/EntitySystems/MedicalScannerSystem.cs @@ -7,6 +7,7 @@ namespace Content.Server.GameObjects.EntitySystems [UsedImplicitly] internal sealed class MedicalScannerSystem : EntitySystem { + public override void Update(float frameTime) { foreach (var comp in ComponentManager.EntityQuery()) diff --git a/Content.Shared/GameObjects/Components/Medical/SharedMedicalScannerComponent.cs b/Content.Shared/GameObjects/Components/Medical/SharedMedicalScannerComponent.cs index 8573a50c63..10262d1fd2 100644 --- a/Content.Shared/GameObjects/Components/Medical/SharedMedicalScannerComponent.cs +++ b/Content.Shared/GameObjects/Components/Medical/SharedMedicalScannerComponent.cs @@ -17,15 +17,18 @@ namespace Content.Shared.GameObjects.Components.Medical public readonly EntityUid? Entity; public readonly Dictionary DamageClasses; public readonly Dictionary DamageTypes; + public readonly bool IsScanned; public MedicalScannerBoundUserInterfaceState( EntityUid? entity, Dictionary damageClasses, - Dictionary damageTypes) + Dictionary damageTypes, + bool isScanned) { Entity = entity; DamageClasses = damageClasses; DamageTypes = damageTypes; + IsScanned = isScanned; } public bool HasDamage() @@ -56,5 +59,24 @@ namespace Content.Shared.GameObjects.Components.Medical Green, Yellow, } + + [Serializable, NetSerializable] + public enum UiButton + { + ScanDNA, + } + + [Serializable, NetSerializable] + public class UiButtonPressedMessage : BoundUserInterfaceMessage + { + public readonly UiButton Button; + + public UiButtonPressedMessage(UiButton button) + { + Button = button; + } + } + + } } diff --git a/Resources/Textures/Objects/Specific/Medical/Cloning.rsi/meta.json b/Resources/Textures/Objects/Specific/Medical/Cloning.rsi/meta.json new file mode 100644 index 0000000000..36d0f22970 --- /dev/null +++ b/Resources/Textures/Objects/Specific/Medical/Cloning.rsi/meta.json @@ -0,0 +1,88 @@ +{ + "version": 1, + "license": "CC BY-SA 3.0", + "copyright": "Taken from https://github.com/tgstation/tgstation at commit 9bebd81ae0b0a7f952b59886a765c681205de31f", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "pod_0", + "directions": 1, + "delays": [ + [ + 1.0 + ] + ] + }, + { + "name": "scanner", + "directions": 1, + "delays": [ + [ + 0.2, + 0.2 + ] + ] + }, + { + "name": "scanner_maintenance", + "directions": 1, + "delays": [ + [ + 1.0 + ] + ] + }, + { + "name": "scanner_occupied", + "directions": 1, + "delays": [ + [ + 0.1, + 0.1, + 0.1, + 0.1 + ] + ] + }, + { + "name": "scanner_open", + "directions": 1, + "delays": [ + [ + 0.2, + 0.2 + ] + ] + }, + { + "name": "scanner_open_maintenance", + "directions": 1, + "delays": [ + [ + 1.0 + ] + ] + }, + { + "name": "scanner_open_unpowered", + "directions": 1, + "delays": [ + [ + 1.0 + ] + ] + }, + { + "name": "scanner_unpowered", + "directions": 1, + "delays": [ + [ + 1.0 + ] + ] + } + ] +} diff --git a/Resources/Textures/Objects/Specific/Medical/Cloning.rsi/pod_0.png b/Resources/Textures/Objects/Specific/Medical/Cloning.rsi/pod_0.png new file mode 100644 index 0000000000000000000000000000000000000000..13d289fd6cc923117d0ff7e9e6e78dc6fa29f990 GIT binary patch literal 1319 zcmV+?1=#wDP)kdTld!5zkG*y4t*8g!ux zT_8I#0gVD7DMZ>LrBCqz0)37%(|O#PxsUIDF79+{Tj*SpCVGk6Wg2o13a!jt69B7h7E z5eQ)K{=@R8b6+re?-4sY+W>G}!L`02as`u6C`7y=%9fV(#Ofj(J#r*4L`{G>@mphm zup!Z05qEj6B|&Rq4Oe?75T3{Qw95E&isv`C(iCstVYwm@Kp+Q-Wt+)ln(G6jtZj_*=feqpywO)_I29KgMfIIF%_8ZXi4fij z0+cKOhR1&6L4Aw|6O-igd88)+fsh`WZXl(^c5HG56IZOL17-52iGd(rFiFkka2!N!Ln_N<2ZPpBosF06Qpmq^dwSBJkO(S+kpTAmB14&CEN8EXeyor+j1)6AW;yGi>4V> z7lKA02a1-BW7~+z86aG@Dh}Xzz5|M)peP!`leliMDF_5mFiTjjTRDV$F;!J7-3OZP zm&0#LpQ=zS1_B6F0@wBJ)-?@04>8yMYK31>7UjE?=Ss8^0CvSrR|s6s!?qoN3IIjb z0MHEGcLfFM3CiWt$^nFQ6&m7fNHn7BI+kr$#6U_9JrqJy^-2RuK*21pumjOZn1I{|7rn>!=^$YX5l=o4!!0$Jp#urgy+wSTq^Tt~T*tC8vr+N zjj5rYW%m!%vah_hk1dI32pI;c%q-J?r|G?MV_whD+0?d`STu$ntw&1G41>bdy_$PJ z7GUF!SEXh7Z?j}FMKYP9dCwknO=EmINj6tlvc|DW5RKt^0_jN}j12(ulN1hz_^bcQ zl5#8nm`i@|=t)M$Mwp(S;^6)_u^pGwpPZ@YHLYvKFbpD*NW}qz#&xYc{B>x4uexUe z$e8!p*t!`ZG_1=0|L%(gM2T&?<*5@Na{KlzCMPE;ni&8rtH6PSN3pCj;c$e{&z}Y0 zH7PM%n-t|~hIa0~$3vM80ZD0-OY#OJyST+d9tmav^MK}~DpU)8rhp{b-4IBMGFn50+#Eq?5VEYpR9v5>^AH37erAyz@ z)%7|TFJ7R%y_3<=VcOd}863JpJRWDDzlYB4I~X49Cs&z-T4Naa^JTF+Pm1Q|Mv}>N dP2vAd`~xa+a~}W~hi(7>002ovPDHLkV1hLkWOV=l literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Specific/Medical/Cloning.rsi/scanner.png b/Resources/Textures/Objects/Specific/Medical/Cloning.rsi/scanner.png new file mode 100644 index 0000000000000000000000000000000000000000..01b9c37f9e8b00fda6750dd0c4ed6d440969650e GIT binary patch literal 1938 zcmV;D2W|L?P)?6C~HM^LaY{JqdCT(pDg&G5jptVq{LMyE`5Y#9>P>f&v zprRkF2!5z2HAN`6R7#~%iERi}X`0YB4>xJjytA3v_wGFJ+`vCC$B2p>>6_Cqh@rp&X zQdQ-(Qb?sRrt;hC|Nh7A;O{8EdH^<2e}oqxm&@T7i{&h(6{!;1qm~rW zN};E&V!H0Swca(DUuk|z@GpOM0LO7~T#z0(Zut3ymo5U(yD-T19lHRKQW69{Mk#z5 zl=A>&5MZ>TH175?)P)Q0Rhxek_*Du#`ne%yCTDS?4vur(K%9t!>&6&+^&*@?^!5#! z%_Cd+>))Sew&2kjcX{pfS$wVe^ACO&*7^F^NW@~a$6b0lI@sLT%l_TpuHE@2@vB@w zN{P}MTUT153?#U*io72^`wRfbl9ODWo#Tmnw=h1DWY06d)e|{(96G;w?pCPLi3%)Fu z+y1eBj!eyv%;Xs9t=nY7`PPk%N~s6}Ne~2>rCBiAAeS{*l9Q<^-nej?;kDh2Pb4{f z=?Yk)0uJ!@M2ZLQ>ScCuk%I5n?Np=r)h-Z7w9+V{Q1be+5d=XwxRj)r%aO?!@ZvF! zUQ6-6nRz^|m@aq#bjMv>%SH%+l#=OemfX^}6$hZf{3;6oFvg&bL1~TBnji=&lqtz< z!DGtv2t1DyscAeVnabucQetG7_LRiaiu2Pm6tp3AlL2TnzlIA)gb-+@!!=ZeGog(^ z-k`*sSHxbN#|VM16;ru9MoRob0l!cPmB{DGESX&(CCN;#Zs!}#uNef5F$f`0QeiuG z87zZJ6P(UwNh`QGJBwd zZ+@0(B)_H$2vNQM)>3No$@2hAuU-Yl;6|d@SS;o;2q4kghKV=?#^7tiz<=MtzsWM# zXnx%opjViQ)oa$8haY)@Y%WJ21LUD3+&6+JeN?eXRD_0=Ef%mv3_IGw!i%qN6)`gZQx+9D3aZj`(G)*>)CmW^!;+Gv!~*v8=4 z4nhdlcdY@SCtBO+n#H$D@X|fofy48x?&_%d95_4=z`CK02B0MtBe8Tw?{00yI1acj zmg_<^3N0-d$DupX3P8-Z>5NxfKr{JH3BGUt?s8@cw30mZ&=>gEt1sfl<3yY&5!WT| zROF>JtC7Q%6eI}swbO^@s1#wss0n$33r_U+%zw)LT(96e{)_vr7cpwGVa z8-~^;0oecMZ|P-_7RSbQEIQp7LI`?VTA0e^DQ&%k5cIURAcSC*W7F0WCl;x8foAe+ zI^-|LzE^YPhp1k;qOll`yjxUxkKihZgLQ2WYr~gu=q!e zD->AUyN=1!<(hDSuC6|cev!LBv58{QBavt)n@uy7y2kwc3?uj4Usb12$dJ5tg-m*m zj*d>W5f~F5ax&?;3QK4PzhWz#&u0M`-Lj+Ny?JCSt!*6u*p|R7{de=d0sw2edH_fz zFIPQ_3*nmHzN!mt>fiG>gI^I5GU+)0W@l0r@ATp#f$x#aECBHCyR$VrP;d5bMVi6? YKME-2{eM@NKL7v#07*qoM6N<$f+N+!;s5{u literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Specific/Medical/Cloning.rsi/scanner_maintenance.png b/Resources/Textures/Objects/Specific/Medical/Cloning.rsi/scanner_maintenance.png new file mode 100644 index 0000000000000000000000000000000000000000..b659cb7f35c244a5481737196924d6888fced1a2 GIT binary patch literal 1782 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 IM6N<$g2$F^TL1t6 literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Specific/Medical/Cloning.rsi/scanner_open.png b/Resources/Textures/Objects/Specific/Medical/Cloning.rsi/scanner_open.png new file mode 100644 index 0000000000000000000000000000000000000000..4af3b016115cdbbb9d2363751afdb1c8e6e8cb78 GIT binary patch literal 1910 zcmV-+2Z{KJP)Bd~={ zsZhkMRFFah-j_n)2!ZR?{`T&_-@Fz4ZRH0Yuz|)No`zDXgjK2dMM4Tvr;gIye;1A= zupJ9A+Yu=Qa$*cOcE`<)uF3q`@SBBy^$Q6!O+z!lF+nrDpI?1_1c3PTDz45@B)Fpr^BwjlFU9@A_{2 z!MBJXSOSjYAf!ZbSjIg>i`_R zmclBPaLh8l`TKspcK2rjV{a9|t_VsY5Kags)L5XS;V|!Byv(7G&hy-tb})1`$$_DB z6s2I=a{TwUeQE_qC(u7jw~ePS0x;RN1T8bgz>0N56gVuI^Cz&ROX9!Bv2L&pHk;ot0%RR1 zK-bdc?gI}#O0iVJc5IwONyPFVPFx)ZU>TmrtAE?w-AupsmappT`v(Brg|5QQw~}k?&^0>S+lijzz{_@OGinrAz3I7?Tov+i@?a29}-eRsM5ZIKA=Muau-9^6ENv<`)^=TqA4v#+W-D< ziL;6}O~uecbQ=+0Yyb+m*#X45P&7}DmS`#+ZBZh6a0#@MUw1+NYVhfL#q<%}xx$f1 zP3{h$V@VePGxN$K;V?$H@j1YVMgX&^{1Cvm?)?eJF1Q@K;OWrd!4QK7Lu_56uyu{X z;6ZO)Ro}Tc{uKbEs$m!g!{cdw`SfnT(LydeHw(bt=YGM-)Wm`VukznJ?cLR@+^;{- z$31sy{PC^1=(yc{4WL-a@$lv+kU}tc@=xsjw&#c+|5@?B18nWs0l-YjyHiJWFLNt( zjSJZv`<{IUE=|_}&UHx6PNdOw9b3x4Y}MmG_6K<72P)gYbD81Y@bd2eA77cj{cPL5 z6UT9Q_LGrmAV^_}mWe-2Hi`Dn8Po(&;4Y`v({p*i3X$yZ`qT&XZ`kCQNg+5hbduAj-fua-rUT34D;ZCX)`bJaV!c$X3TxMGpi(huZ(mHY zm}eq&jchi}rn~M5)G3z>B(Gheke{Nnvm5CuxUP4}DdeYWBB2%hnxpW{Oc8*A&D(1} zH*VU(qK-}g)R2NZo2#=-FX6Z})&oE)IU0C!)1DYDUJ^sPjr07i;MXWZA@5~WGU-&! wXFiw1woFQeX#hU_FjIE`jb`s=tQGwK0eA#*E6!n-IRF3v07*qoM6N<$g0pJA4FCWD literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Specific/Medical/Cloning.rsi/scanner_open_maintenance.png b/Resources/Textures/Objects/Specific/Medical/Cloning.rsi/scanner_open_maintenance.png new file mode 100644 index 0000000000000000000000000000000000000000..513eb24d71fac5d24083355b81a86f45d1b3965f GIT binary patch literal 1750 zcmV;{1}XW8P)`BYZSQ)$U*6f7d++dLykn1d zosu4Dw7d7tz3+S8d(OFMHSW@q-96sjuDO#LA7{~bzjq7($EhKN#FZ|UQW?8eLrK~2 zzLF9lC7u_ad-tDzZ9-r#clK}*DwPUOtriSPCCOa5Kxf~*2uI=y2f0i{Nr{@9!b{xK zbUUpX_}4z4!Y~XB3xo}ZD-Yzx7p6 zw{Cq%COx4w5P0MZy<}%|7*PYmSP{rD4J<3h>9@yW1TER!ZoUwYRgcJISe|-wD8>Nel=fkV>Je@JR?)fE5dk{ov%w z09;DXGL>84@%#5PJe}srmw&D#)6;psHzCT>GS3xNZ?Kb_$-_aw;`3RE2@G}m|p zu0TnJ)Fe`@q>bykL2%WrR;f^0s$$1u49#TFO_QnIVpFw*5X_g$RI2u!2>^JWhw?n6 zQb7Gk8uL3>wVAVRcH1_?xkYxh#@W>x5504vTm@ikK1)@3WIl?35CTopP*Md&MGA@X zJj5Cj3w8~?kjG1OuzQ2Wi4!N#bU)d&& zr1CRimCcvS6eWz$=Q#1oD*>=(g#G%>OUHxnr8URclz_IXJT#NOZbip0JZgEJ$(ZJUM4-E-SIkBQms2TJbVcN zyJoXgDx&R3q4oCSjgO;4Z~=L#6fEQz8NQ5em<{_h4Z^w#tDn`DUzpXdU%M25r;a>^ z7Fh|rW??(7EH`sj-83k0CYveqDSiB^*-;+xjY?-_NLF7b9n%^_kPj? zXoUv-g2g7XfY#fKRw`oZI$f596$>{t2EegXN4amOUwnpc zdK`P?*A1X2-+YPQ?S5rD_1>>Y(nE`(V;K=TtymCj0HwmR1Bnha!w<(zhE7{coR}Ft zf~HyU^V82Z^}LtH3K@;XLcJqE+olcxmR60$qEW2qI(6WQ2Y<-WO^>0QejJ`0fuRxb zM&QWc3mh4I0U&ti!Q__#P`ZI-S&YtR`PsA2gcJx=0FJ--Q!Z!bnmT0wluHF3-Tx#? zN={$?Z7})7w|(GOe|MbU?}hu?4*8x{{5w5n`kk{f4Q}QOoOu2@xV0DpxZb9?HkZXT zO?=1wL&(VW>4P$0|WbsZ)gqv zk`0~z51%^lK*JixakzTrefswH2V+V~MusnQ^~!r%h``q5c4jk^O~C;YiEe66ja|F< zQmfgtwr-?cE;5&yA)n9EfA6Oo)>Nw{(lfUy6&Gl4??ibTp66e3rQ$-k6fZ560T|dn z82a4Te}D~b?EvTz4R5(ubZo!j+??nFAd{YKcnXVtFmBwGKzWT>6pDya(eG$-*-YrO sSSa8+HkHyM03UpiYpT$l)LYN~2ddpSeQimav;Y7A07*qoM6N<$f_lVGJpcdz literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Specific/Medical/Cloning.rsi/scanner_open_unpowered.png b/Resources/Textures/Objects/Specific/Medical/Cloning.rsi/scanner_open_unpowered.png new file mode 100644 index 0000000000000000000000000000000000000000..206e0c02aca134280fd9a43e1f81805bd58cacec GIT binary patch literal 1664 zcmV-`27md9P)A6O6~}+?Yy9n*jO~nLf*n;Pbs8%}KBPn@1WFqfS`|brr8GAf4Z{Cb&-p9R{#hZDa=Xp+*a-^#_@4kD^ z|J?um-*fM1Jf=+^m{E`G^C&YviPMjMd>H`Ga|r^0FMJwKotEn&h3FYCg&+_DrQ+ZI z`j=M|5}4xAGgQ!MH1J$E>Jm~=So#-Zv&RWMfggB?b|O*;mq%RXTJTlSd2swDk+gdL(_T%)om%$WO<{+?e!wx$RFcj zxysFl1zJk79qjlX9?P;~J5-u32h;HwJq$=G34}xl5wW0@LIl0ZJg{qgu(`!ldX$Id zDj$`~pc4ZJ_;0z&;eBc9&27B4KK5il2pKW}$S&H25RtMw=DRK}*Tc6g?pAGd)1X}U z6WJ0{;b{S*-9U{DG1+IaaP=yh7Otvhgij?T7cM-D6NC&_nrQ2` zgLY<*z7uwLGXAc3dum`;jcg|q&)#SkDor=gG#$NO4?kqHC>^v)HGH>r3Yx#Gz9c7* z0G@P0JUcQ4BU4+t>e2pcJR&AYQS-haa0jn}NN^ z-08L^cbJI=7c^V3<}dBJe2|R`))P9>*rDY{9g(58%6{Uph~3(umi3(H)B2{R(u(v1U|`Kuiw-e?C-BhX-U092^Oo*37#bN&Y)f|<08AfxQUUat7X6k*EtzkL+;A}VCg!;srXr8cEB%RxfFGFfcCPdpMHUb*M5(cN@3_G zh7|_Y_U}jE*kEWhO+RUB)gs!&1X{C+q3euV7M2;`cqYK*E0=g87gnE@qT=!oe%S+h z<&~c?F;)fOHw(XDk{MElhGl3Br_9*eJ9Z`d-4W)XuG8O_!ZM9m+{8NY^I!iYapn^V zCDJr43_TunB)t!St!lAroQY+`$3a^I-+%F^tP~Y1#ZZS&LF{^mvQ+jiolOn|y$^U@c8h!ld~{o_}O0|8DS4EOMMBh-jx8W_5c zGIffLZNB&7^PE3=F6Q&wcNbW%IT(gXASJpU-vwIt_M1O(YdHk3c>B=8{Axa zM~fwpo1CUtSWN^67#}}?>$!a9@KId1#qjVb^?Hqs!WxxIiMiuvdVHEqhxN7lIJGjF z%otK>C>0)ZPOTg-#oOEAg(83ATKQw8At_qP%mdK7zm+5Z3nyb83G`EeEi0000< KMNUMnLSTYH3KfX} literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Specific/Medical/Cloning.rsi/scanner_unpowered.png b/Resources/Textures/Objects/Specific/Medical/Cloning.rsi/scanner_unpowered.png new file mode 100644 index 0000000000000000000000000000000000000000..4d0705aac0731debfd943acfaba62f97cb534dcd GIT binary patch literal 1652 zcmV-)28;QLP)93lX(4rp^YBdKj6LtUk8=)-J2Rf^xeiMCq@%h1&iP*d z?{SU=Pe^m~i}p!n9!JiH5&F(|F9Hw*K2f9zbx6C}qUZY z2NrmIgcjQEHi7RCS=wkStN-A@(hEd^CX51f-w~rV=D}TTX(3geNHe~&Ttq2_bisrm z-FW+NZ$AWJ&MtEH+$#V?QA8L9Sgi@7aL5CQ!VqgTgSgd*sav<+r?Polj5%?rC9;O=zkd^e+R_oSuFHh$ zQka_LBQrDH_|@g1aR9j&60J4HTCBBu_+|{gl~+Fnz{XCUzpmfr#KJ74i3!S|`y_`x zaf*-49%QLFgN{NX-^YXjFMsVz2_30LXpO;Wfe_;bHA}7$R-ZS`SgM)}o_vXYSS;y#MeK3)2Pe)pqz` zs|J#Uae)8Sb~yUfG_7ujpkE*RBA~U25dh2x>{{z#We+IyeR_UC=(^n6sdKm4CbWh| z5Eo;?b8&@42++pR?Dg>bd;2;NhfM6i00CnX&J3s(gfzmCxiH{fD{@HKyM98)z6c=V6i6k}eZzY@q1o%vHSn;}q85gjesnqrb`M1nMmsPu0YJ|r(>R6z zkQh&C&=08FFE(p5SPK?x6oC*iio=52ZRv22zH|rn8OD3(yy_1sA=TgjL{Z;=0Z{~6 zC-jAT=1Y1CL<%p(sn6yYAiuzs?G3ONPdP{g9lwVFGMOwWMFd3FvSKC)s%`%LKOGp< zKi_AbhC$MmGv0K_Pat`XX5tUNLT`+=9-c6=qc>2S<^|Fp+!Bfo56cB(C5@{`lcu8wfQX+(4HlG7v z+DXPN2gV2Qyw#g+rt*`iYxQOufWt?gvj7>#CEJgvkjY?`0@p>lZd{OF%qwK#6uDB8 z^Sp!u&cOJ^OBaUBfua5ArI%jg^6!3$>v<^Ypj;1E1xUxi3W2Z|3Gug7xJsdKyfmI<2blVjmb-Z zZ+_wXtXD1T)!6fAX2sYVptD}Jy!hM~0kA^hdM=fElliGBijx^UDJf+$l(O-6aWcbv zAHR3vPZmlD!wmUpqD)Qp-a|xNB zzjc|-MiZqRB4dy;*#%;>{m!0yg(!;n^_4fqjDP0Dc^dUPckkRB@?QV?1-2(N^`1}8 zb2%br#^kKETo1PJjlnt&Gq<<+^Phe@oP@)q&do2{V@qYCFeDg#P>fKo+h%KPlVeL| z%H@+xOy!3ElD+-bo18lR@iCbo2)MTTPnM1^4|zswZmhk_wbj3igafm4hpARJQjG(Y zO7r-E&$CC5