From 6c2b2a8a4ab7c7b0c5e18d796ccd94d09b087509 Mon Sep 17 00:00:00 2001 From: Raphael Bertoche Date: Wed, 27 Nov 2024 12:19:19 -0300 Subject: [PATCH 01/35] Fixes Make Cultist Admin Verb to Act on Target Not Self (#1289) There's a small error on the admin verb for blood cultists which made the verb only work on self. This fixes it. --- Content.Server/Administration/Systems/AdminVerbSystem.Antags.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Content.Server/Administration/Systems/AdminVerbSystem.Antags.cs b/Content.Server/Administration/Systems/AdminVerbSystem.Antags.cs index d9d7943c45c..d23fa930701 100644 --- a/Content.Server/Administration/Systems/AdminVerbSystem.Antags.cs +++ b/Content.Server/Administration/Systems/AdminVerbSystem.Antags.cs @@ -146,7 +146,7 @@ private void AddAntagVerbs(GetVerbsEvent args) Icon = new SpriteSpecifier.Rsi(new("/Textures/Objects/Weapons/Melee/cult_dagger.rsi"), "icon"), Act = () => { - _antag.ForceMakeAntag(player, DefaultBloodCultRule); + _antag.ForceMakeAntag(targetPlayer, DefaultBloodCultRule); }, Impact = LogImpact.High, Message = Loc.GetString("admin-verb-make-blood-cultist"), From f133b9b7cf175815a3c6de59d541e12f0fc60790 Mon Sep 17 00:00:00 2001 From: sleepyyapril <123355664+sleepyyapril@users.noreply.github.com> Date: Wed, 27 Nov 2024 11:19:32 -0400 Subject: [PATCH 02/35] IPC Instrument Menu Fix (#1287) # Description Fixes IPCs being unable to use the midi menu. --- # Changelog :cl: - fix: Fixed IPCs being unable to use the midi menu. --- Resources/Prototypes/Entities/Mobs/Player/silicon_base.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Resources/Prototypes/Entities/Mobs/Player/silicon_base.yml b/Resources/Prototypes/Entities/Mobs/Player/silicon_base.yml index 6ca0435b35e..7a8332b6618 100644 --- a/Resources/Prototypes/Entities/Mobs/Player/silicon_base.yml +++ b/Resources/Prototypes/Entities/Mobs/Player/silicon_base.yml @@ -207,6 +207,9 @@ type: HumanoidMarkingModifierBoundUserInterface enum.StrippingUiKey.Key: type: StrippableBoundUserInterface + enum.InstrumentUiKey.Key: + type: InstrumentBoundUserInterface + requireInputValidation: false enum.RadialSelectorUiKey.Key: type: RadialSelectorMenuBUI enum.ListViewSelectorUiKey.Key: From 92a6e099fca1581ea8a0cfd16bf7f13ae8d1108a Mon Sep 17 00:00:00 2001 From: SimpleStation Changelogs Date: Wed, 27 Nov 2024 15:20:19 +0000 Subject: [PATCH 03/35] Automatic Changelog Update (#1287) --- Resources/Changelog/Changelog.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 831ff4d0705..99ac41739b6 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -8157,3 +8157,10 @@ Entries: id: 6541 time: '2024-11-25T05:43:25.0000000+00:00' url: https://github.com/Simple-Station/Einstein-Engines/pull/1164 +- author: sleepyyapril + changes: + - type: Fix + message: Fixed IPCs being unable to use the midi menu. + id: 6542 + time: '2024-11-27T15:19:32.0000000+00:00' + url: https://github.com/Simple-Station/Einstein-Engines/pull/1287 From b0407604ced2859ccbdc417345dadc29656f71f0 Mon Sep 17 00:00:00 2001 From: sleepyyapril <123355664+sleepyyapril@users.noreply.github.com> Date: Fri, 29 Nov 2024 11:26:27 -0400 Subject: [PATCH 04/35] Fix Bug with Opening Storage Containers (#1292) # Description Fixes the bug with opening storage containers while there's already one opened. --- # Changelog :cl: - fix: Fixed the bug with opening storage containers while there's already one open. --- Content.Client/Storage/StorageBoundUserInterface.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/Content.Client/Storage/StorageBoundUserInterface.cs b/Content.Client/Storage/StorageBoundUserInterface.cs index 899df30f7fc..7c53f45e8a8 100644 --- a/Content.Client/Storage/StorageBoundUserInterface.cs +++ b/Content.Client/Storage/StorageBoundUserInterface.cs @@ -9,6 +9,7 @@ public sealed class StorageBoundUserInterface : BoundUserInterface { [Dependency] private readonly IEntityManager _entManager = default!; + [Obsolete] public override bool DeferredClose => false; private readonly StorageSystem _storage; public StorageBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey) From 9a40c3783eb0d0e622badc2febcaf0794f6f8ddd Mon Sep 17 00:00:00 2001 From: SimpleStation Changelogs Date: Fri, 29 Nov 2024 15:26:55 +0000 Subject: [PATCH 05/35] Automatic Changelog Update (#1292) --- Resources/Changelog/Changelog.yml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 99ac41739b6..933a3d61a0f 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -8164,3 +8164,12 @@ Entries: id: 6542 time: '2024-11-27T15:19:32.0000000+00:00' url: https://github.com/Simple-Station/Einstein-Engines/pull/1287 +- author: sleepyyapril + changes: + - type: Fix + message: >- + Fixed the bug with opening storage containers while there's already one + open. + id: 6543 + time: '2024-11-29T15:26:27.0000000+00:00' + url: https://github.com/Simple-Station/Einstein-Engines/pull/1292 From 327247585612d9d65e20b8b856864701ceb1c933 Mon Sep 17 00:00:00 2001 From: DocNITE Date: Fri, 29 Nov 2024 18:28:29 +0300 Subject: [PATCH 06/35] Change Target Doll Icon For Ashen Theme (#1282) # Description ![target_doll](https://github.com/user-attachments/assets/1fdcd665-251f-4a3f-b80e-e11b77f13eef) --- .../Textures/Interface/Ashen/target_doll.png | Bin 422 -> 716 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/Resources/Textures/Interface/Ashen/target_doll.png b/Resources/Textures/Interface/Ashen/target_doll.png index e8eb2f52717b08c7124e99ddf4e2196a958b9362..91af9d84ac146cbe8c27ddc5af5d137ced4e8c28 100644 GIT binary patch delta 703 zcmV;w0zmzy1Iz`G8Gi-<0047(dh`GQ0+UHZK~z|UVmhKua5GC~Y(` zx|M~kFTkr%S@|Bk0Ih`;8jUt~&}gBhKM{-tG5R&`hMz?juebV6LRfZZ_MF|F836d- zAw?e=jmAS&)juUXpU;@j=Zu#%TCLVYQ55*TkIiQDcA{>#%YWMA@mPqwTCGA=Rh&*I zESF0O0DgGn!{LxQnWmYVh!6t9Fk*d<jYDQ5UEIC8vgi!QdsiWm&O%UJ(=po&g1K7d+1c z05qG;*q!#jLw}N^kYNYYG*i3aI1Uzz1tX)Y_dE}a#Ue8fc)Lj<0YINelqBS`C#-g=>>X2=GipQSxZ?PbL%A?sPin zbUGi25E8&ky(nQ6)J{}HW)Sko-$gnd7fDHB0Th;H!GCq#Oc9>v!F64h8KQV8fUcgB z20;MVbz$3f%+9uLxUP#J2$&erT@c!VXpUDZ74-Z4*m%F+XIVjOg(!rNfFdjXvijda zC<|!06#*e6m%Z=~@Fq>h0=3h1UHIMbR)FVu&~=@AuE|&cz}^+Qt_ulxc?2}@Xb_4- zb<*co0)L_tCXp<~B0e7p$U^k%DXT1tAa@!@k@wB_6#@JGK3D(O1$?^@#RP<5_|YVJ zkmO(j=qJ`+ilB3Anidz}`#uy!VFS0@E#=Is0aG_2R_*iLl2T~=bFxZm%rt?PQM1oM8^qB!K!=~My|Kd0?>`%x;DQjX69&MYt z)wZd}trQ!s&sT$b>LCE{KtEMA80+@kvf#aktb(=1m}by%{|d2)_ltv<66-+--=Us| zM`dtqCqnpP0C{3?OXu87=t4>fBbo?RKq8_9wD^<2H55Xx<3Ol2R^fzD z_Ni@CXDo!$fqz^bl+h3~0i}H8T=sKDX$U?EdG?W(P0}VjAg!8)cZ@$o{WHe@4;JDYwh;J`J_`T<002ovPDHLkV1n}5 BtlR(q From d4879f9129ae484f24f57eb642cc7d600f2323e0 Mon Sep 17 00:00:00 2001 From: Tmanzxd <164098915+Tmanzxd@users.noreply.github.com> Date: Fri, 29 Nov 2024 09:29:47 -0600 Subject: [PATCH 07/35] Fix Applicable Medication Stack Bug (#1278) ## About the PR - Fixed a bug where applicable medication stacks would revert back to 10 after 1 use. ## Why / Balance - Did you know maxstacks were stored in a separate YML? Me neither, until now. **Changelog** :cl: - fix: Fixed a bug where applicable medication stacks would revert back to 10 after 1 use from full. Signed-off-by: Tmanzxd <164098915+Tmanzxd@users.noreply.github.com> --- Resources/Prototypes/Stacks/medical_stacks.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Resources/Prototypes/Stacks/medical_stacks.yml b/Resources/Prototypes/Stacks/medical_stacks.yml index 9d2b77ec933..8a10e72d9a2 100644 --- a/Resources/Prototypes/Stacks/medical_stacks.yml +++ b/Resources/Prototypes/Stacks/medical_stacks.yml @@ -11,7 +11,7 @@ name: aloe cream icon: { sprite: "/Textures/Objects/Specific/Hydroponics/aloe.rsi", state: cream } spawn: AloeCream - maxCount: 10 + maxCount: 15 #Changed to 15 due to shitmed changes itemSize: 1 - type: stack @@ -19,7 +19,7 @@ name: gauze icon: { sprite: "/Textures/Objects/Specific/Medical/medical.rsi", state: gauze } spawn: Gauze - maxCount: 10 + maxCount: 15 #Changed to 15 due to shitmed changes itemSize: 1 - type: stack @@ -27,7 +27,7 @@ name: brutepack icon: { sprite: "/Textures/Objects/Specific/Medical/medical.rsi", state: gauze } spawn: Brutepack - maxCount: 10 + maxCount: 15 #Changed to 15 due to shitmed changes itemSize: 1 - type: stack @@ -35,7 +35,7 @@ name: bloodpack icon: { sprite: "/Textures/Objects/Specific/Medical/medical.rsi", state: bloodpack } spawn: Bloodpack - maxCount: 10 + maxCount: 15 #Changed to 15 due to shitmed changes itemSize: 1 - type: stack @@ -43,7 +43,7 @@ name: medicated-suture icon: {sprite: "/Textures/Objects/Specific/Medical/medical.rsi", state: medicated-suture } spawn: MedicatedSuture - maxCount: 10 + maxCount: 15 #Changed to 15 due to shitmed changes itemSize: 1 - type: stack @@ -51,7 +51,7 @@ name: regenerative-mesh icon: {sprite: "/Textures/Objects/Specific/Medical/medical.rsi", state: regenerative-mesh} spawn: RegenerativeMesh - maxCount: 10 + maxCount: 15 #Changed to 15 due to shitmed changes itemSize: 1 From 8d485e8c0d4e3932835aeed210388e85988a0213 Mon Sep 17 00:00:00 2001 From: SimpleStation Changelogs Date: Fri, 29 Nov 2024 15:30:14 +0000 Subject: [PATCH 08/35] Automatic Changelog Update (#1278) --- Resources/Changelog/Changelog.yml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 933a3d61a0f..0f9e1278c85 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -8173,3 +8173,12 @@ Entries: id: 6543 time: '2024-11-29T15:26:27.0000000+00:00' url: https://github.com/Simple-Station/Einstein-Engines/pull/1292 +- author: Tmanzxd + changes: + - type: Fix + message: >- + Fixed a bug where applicable medication stacks would revert back to 10 + after 1 use from full. + id: 6544 + time: '2024-11-29T15:29:47.0000000+00:00' + url: https://github.com/Simple-Station/Einstein-Engines/pull/1278 From 1a9763528a9b15f11f474a2fa7ecfdde98aa9a15 Mon Sep 17 00:00:00 2001 From: Skubman Date: Sat, 30 Nov 2024 06:58:56 +0800 Subject: [PATCH 09/35] Re-Enable Language Color and Font (#1294) # Description Re-enables language font and colors showing up in chat messages. The language font/colors were bugged after adding language names in chat (https://github.com/Simple-Station/Einstein-Engines/pull/1165) I also overhauled the format for chat messages to be more aesthetically pleasing, and made sure chat bubbles use the language color/font. ## Media **Nekomimetic** ![image](https://github.com/user-attachments/assets/4cb88d7b-7466-42ed-bf2d-b68c68edb62c) ![image](https://github.com/user-attachments/assets/adec7fd7-0a84-4e21-9eff-c1a387e2d529) **Bubblish** ![image](https://github.com/user-attachments/assets/c49f5573-ac96-4375-a584-e8b2cc6f5fee) ![image](https://github.com/user-attachments/assets/c739c249-9d1e-453e-9e92-3f7ef24a4d61) **Tau-Ceti Basic (Default Language)** ![image](https://github.com/user-attachments/assets/e6660039-ac2f-449b-96e0-44e0142d3715) ![image](https://github.com/user-attachments/assets/2baec2ca-975d-4111-85b0-3b2056fdd7f7) **Rootspeak** ![image](https://github.com/user-attachments/assets/99d94f8d-9a1c-4be9-8c98-b42c9c7cffd7) ![image](https://github.com/user-attachments/assets/c20b4621-1ca7-42f5-a22a-82c9a4d1dddf) ## Changelog :cl: Skubman - fix: Language colors and fonts will show up in text messages again, both on in-person messages and on the radio. - tweak: The text on chat bubbles now uses the color and font of the language being spoken. - tweak: The language prefix before the name on chat messages now uses the language's color. --- Content.Server/Chat/Systems/ChatSystem.cs | 2 +- Content.Server/Radio/EntitySystems/RadioSystem.cs | 4 +++- .../Locale/en-US/chat/managers/chat-manager.ftl | 13 +++++++++---- .../Locale/en-US/headset/headset-component.ftl | 4 ++-- 4 files changed, 15 insertions(+), 8 deletions(-) diff --git a/Content.Server/Chat/Systems/ChatSystem.cs b/Content.Server/Chat/Systems/ChatSystem.cs index 5ba5845f087..db52e247298 100644 --- a/Content.Server/Chat/Systems/ChatSystem.cs +++ b/Content.Server/Chat/Systems/ChatSystem.cs @@ -880,7 +880,7 @@ public string WrapMessage(LocId wrapId, InGameICChatType chatType, EntityUid sou if (language.SpeechOverride.Color is { } colorOverride) color = Color.InterpolateBetween(color, colorOverride, colorOverride.A); var languageDisplay = language.IsVisibleLanguage - ? $"{language.ChatName} | " + ? Loc.GetString("chat-manager-language-prefix", ("language", language.ChatName)) : ""; return Loc.GetString(wrapId, diff --git a/Content.Server/Radio/EntitySystems/RadioSystem.cs b/Content.Server/Radio/EntitySystems/RadioSystem.cs index 71fb4ff5020..66dadc85b5d 100644 --- a/Content.Server/Radio/EntitySystems/RadioSystem.cs +++ b/Content.Server/Radio/EntitySystems/RadioSystem.cs @@ -167,12 +167,14 @@ private string WrapRadioMessage(EntityUid source, RadioChannelPrototype channel, if (language.SpeechOverride.Color is { } colorOverride) languageColor = Color.InterpolateBetween(languageColor, colorOverride, colorOverride.A); var languageDisplay = language.IsVisibleLanguage - ? $"{language.ChatName} | " + ? Loc.GetString("chat-manager-language-prefix", ("language", language.ChatName)) : ""; + var messageColor = language.IsVisibleLanguage ? languageColor : channel.Color; return Loc.GetString(speech.Bold ? "chat-radio-message-wrap-bold" : "chat-radio-message-wrap", ("color", channel.Color), ("languageColor", languageColor), + ("messageColor", messageColor), ("fontType", language.SpeechOverride.FontId ?? speech.FontId), ("fontSize", language.SpeechOverride.FontSize ?? speech.FontSize), ("verb", Loc.GetString(_random.Pick(speech.SpeechVerbStrings))), diff --git a/Resources/Locale/en-US/chat/managers/chat-manager.ftl b/Resources/Locale/en-US/chat/managers/chat-manager.ftl index 8a61f8d5da5..7f224256854 100644 --- a/Resources/Locale/en-US/chat/managers/chat-manager.ftl +++ b/Resources/Locale/en-US/chat/managers/chat-manager.ftl @@ -18,14 +18,19 @@ chat-manager-no-radio-key = No radio key specified! chat-manager-no-such-channel = There is no channel with key '{$key}'! chat-manager-whisper-headset-on-message = You can't whisper on the radio! +chat-manager-language-prefix = ({ $language }){" "} + chat-manager-server-wrap-message = [bold]{$message}[/bold] chat-manager-sender-announcement-wrap-message = [font size=14][bold]{$sender} Announcement:[/font][font size=12] {$message}[/bold][/font] -chat-manager-entity-say-wrap-message = [BubbleHeader][bold][Name]{ $language }{ $entityName }[/Name][/bold][/BubbleHeader] { $verb }, [font={ $fontType } size={ $fontSize } ]"[BubbleContent]{ $message }[/BubbleContent]"[/font] -chat-manager-entity-say-bold-wrap-message = [BubbleHeader][bold][Name]{ $language }{ $entityName }[/Name][/bold][/BubbleHeader] { $verb }, [font={ $fontType } size={ $fontSize }]"[BubbleContent][bold]{ $message }[/bold][/BubbleContent]"[/font] -chat-manager-entity-whisper-wrap-message = [font size=11][italic][BubbleHeader][Name]{ $language }{ $entityName }[/Name][/BubbleHeader] whispers,"[BubbleContent]{ $message }[/BubbleContent]"[/italic][/font] -chat-manager-entity-whisper-unknown-wrap-message = [font size=11][italic][BubbleHeader]Someone[/BubbleHeader] whispers, "[BubbleContent][font="{$fontType}"][color={$color}]{$message}[/color][/font][/BubbleContent]"[/italic][/font] +# For the message in double quotes, the font/color/bold/italic elements are repeated twice, outside the double quotes and inside. +# The outside elements are for formatting the double quotes, and the inside elements are for formatting the text in speech bubbles ([BubbleContent]). +chat-manager-entity-say-wrap-message = [BubbleHeader][Name][font size=11][color={$color}][bold]{$language}[/bold][/color][/font][bold]{$entityName}[/bold][/Name][/BubbleHeader] {$verb}, [font="{$fontType}" size={$fontSize} ][color={$color}]"[BubbleContent][font="{$fontType}" size={$fontSize}][color={$color}]{$message}[/color][/font][/BubbleContent]"[/color][/font] +chat-manager-entity-say-bold-wrap-message = [BubbleHeader][Name][font size=11][color={$color}][bold]{$language}[/bold][/color][/font][bold]{$entityName}[/bold][/Name][/BubbleHeader] {$verb}, [font="{$fontType}" size={$fontSize} ][color={$color}][bold]"[BubbleContent][font="{$fontType}" size={$fontSize}][color={$color}][bold]{$message}[/bold][/color][/font][/BubbleContent]"[/bold][/color][/font] + +chat-manager-entity-whisper-wrap-message = [BubbleHeader][Name][font size=10][color={$color}][bold]{$language}[/bold][/color][/font][font size=11][italic]{$entityName}[/Name][/BubbleHeader] whispers, [font="{$fontType}"][color={$color}][italic]"[BubbleContent][font="{$fontType}"][color={$color}][italic]{$message}[/italic][/color][/font][/BubbleContent]"[/italic][/color][/font][/italic][/font] +chat-manager-entity-whisper-unknown-wrap-message = [BubbleHeader][font size=10][color={$color}][bold]{$language}[/bold][/color][/font][font size=11][italic]Someone[/BubbleHeader] whispers, [font="{$fontType}"][color={$color}][italic]"[BubbleContent][font="{$fontType}"][color={$color}][italic]{$message}[/italic][/color][/font][/BubbleContent]"[/italic][/color][/font][/italic][/font] # THE() is not used here because the entity and its name can technically be disconnected if a nameOverride is passed... chat-manager-entity-me-wrap-message = [italic]{ PROPER($entity) -> diff --git a/Resources/Locale/en-US/headset/headset-component.ftl b/Resources/Locale/en-US/headset/headset-component.ftl index 3f89dde13ab..8d759e237a8 100644 --- a/Resources/Locale/en-US/headset/headset-component.ftl +++ b/Resources/Locale/en-US/headset/headset-component.ftl @@ -1,6 +1,6 @@ # Chat window radio wrap (prefix and postfix) -chat-radio-message-wrap = [color={ $color }]{ $channel } [bold]{ $language }{ $name }[/bold] { $verb }, [font={ $fontType } size={ $fontSize }]"{ $message }"[/font][/color] -chat-radio-message-wrap-bold = [color={ $color }]{ $channel } [bold]{ $language }{ $name }[/bold] { $verb }, [font={ $fontType } size={ $fontSize }][bold]"{ $message }"[/bold][/font][/color] +chat-radio-message-wrap = [color={$color}]{$channel} [font size=11][color={$languageColor}][bold]{$language}[/bold][/color][/font][bold]{$name}[/bold] {$verb}, [font="{$fontType}" size={$fontSize}][color={$messageColor}]"{$message}"[/color][/font][/color] +chat-radio-message-wrap-bold = [color={$color}]{$channel} [font size=11][color={$languageColor}][bold]{$language}[/bold][/color][/font][bold]{$name}[/bold] {$verb}, [font="{$fontType}" size={$fontSize}][color={$messageColor}][bold]"{$message}"[/bold][/color][/font][/color] examine-headset-default-channel = Use {$prefix} for the default channel ([color={$color}]{$channel}[/color]). From 7d802e35dc45c37016681c3a009bdaebe2707178 Mon Sep 17 00:00:00 2001 From: SimpleStation Changelogs Date: Fri, 29 Nov 2024 22:59:21 +0000 Subject: [PATCH 10/35] Automatic Changelog Update (#1294) --- Resources/Changelog/Changelog.yml | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 0f9e1278c85..99725a56a49 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -8182,3 +8182,20 @@ Entries: id: 6544 time: '2024-11-29T15:29:47.0000000+00:00' url: https://github.com/Simple-Station/Einstein-Engines/pull/1278 +- author: Skubman + changes: + - type: Fix + message: >- + Language colors and fonts will show up in text messages again, both on + in-person messages and on the radio. + - type: Tweak + message: >- + The text on chat bubbles now uses the color and font of the language + being spoken. + - type: Tweak + message: >- + The language prefix before the name on chat messages now uses the + language's color. + id: 6545 + time: '2024-11-29T22:58:56.0000000+00:00' + url: https://github.com/Simple-Station/Einstein-Engines/pull/1294 From 2eafa0d47e7b9a3270ae797f82dd7b1772dffb15 Mon Sep 17 00:00:00 2001 From: gluesniffler <159397573+gluesniffler@users.noreply.github.com> Date: Sat, 30 Nov 2024 12:06:55 -0400 Subject: [PATCH 11/35] Shitmed Update 2 - [Insert Snarky Remark] (#1271) # Description ![image](https://github.com/user-attachments/assets/b10f1e33-94fb-4ded-a644-b9945b58dbc5) Honey wake up, another shitmed PR with 5 features and a trillion bugs! I love bloat. --- # Known Bugs - A lot of shit with changelings lol - Markings suddenly disappear from your entity apparently at random. Wizden exclusive issue as of now. - Fire heretics explode when ascending due to part damage shitcode (sorry) - Some exceptions/null point references at round end, tentatively related to salvage corpses. - Slots having wonky behavior due to not being networked. More of a broad issue with how I implemented them initially. - Arachne are FUCKED with surgery, I was incredibly tempted to set them to roundstart: false, but I'll try to hotfix it this week. --- # Changelog :cl: Mocho, Deltanedas - add: Ported Ghetto Surgery from Deltanedas! - add: Ported fishops organs from Deltanedas! - add: Added different step durations to each surgery step. - add: Added a T2 research for advanced surgical tools - add: Added a T3 research for an omnitool for surgery. - add: Added Surgical and Advanced Surgical modules for Mediborgs - add: Mediborgs can now perform surgery! - add: Added lobotomies as an operation. Godspeed you psychopaths. - add: Added cybernetic arms, legs and eyes. - add: Added EMP weaknesses to all cybernetic parts (the day of reckoning will come for IPCs soon) - add: Losing your eyes now blinds you. - fix: Fixed a few species that did not inherit from BasePart's, thus taking damage types they shouldn't on their limbs. - fix: Fixed harpy lungs not being usable in surgeries. - fix: Fixed biosynthetic and other printable parts not allowing you to attach body parts to them. - fix: Fixed fire being able to destroy your chest. - fix: Fixed entities being able to take over your body by just inserting a brain or another head on top of you. - fix: Fixed some shitcode that didnt let rejuvenate or godmode work properly. - fix: Fixed bionic arm, and cybernetic eyes traits not working properly due to shitty networking. - tweak: Increased tend wounds's speed by double, and bumped up the values on its calculations. DEATH TO TOPICALS, LEAVE THOSE TO TIDERS. - tweak: Beheading an entity now doesnt let it move, speak, and forces it to the ground immediately (literally 1984!!11!!) - tweak: Changed sprites on most surgical tools to now use /tg/ sprites. - tweak: Unbound shitmed targeting doll keybinds by default (did you know we have those). --------- Signed-off-by: gluesniffler <159397573+gluesniffler@users.noreply.github.com> Co-authored-by: FoxxoTrystan <45297731+FoxxoTrystan@users.noreply.github.com> Co-authored-by: goet <6637097+goet@users.noreply.github.com> Co-authored-by: Saphire Lattice --- .../Options/UI/Tabs/KeyRebindTab.xaml.cs | 4 + Content.Client/Smoking/MatchstickSystem.cs | 5 + .../Speech/Components/OhioAccentComponent.cs | 6 + Content.Client/Targeting/TargetingSystem.cs | 16 +- .../Body/Components/BrainComponent.cs | 5 + Content.Server/Body/Systems/BodySystem.cs | 10 + Content.Server/Body/Systems/BrainSystem.cs | 51 ++- .../Body/Systems/DebrainedSystem.cs | 62 +++ Content.Server/Body/Systems/EyesSystem.cs | 87 ++++ .../Cybernetics/CyberneticsSystem.cs | 54 +++ .../Thresholds/Behaviors/BurnBodyBehavior.cs | 16 +- .../Light/Components/MatchstickComponent.cs | 29 -- .../Light/EntitySystems/MatchboxSystem.cs | 1 + .../Light/EntitySystems/MatchstickSystem.cs | 18 +- .../Medical/Surgery/SurgerySystem.cs | 6 +- .../Speech/Components/OhioAccentComponent.cs | 8 + .../Speech/EntitySystems/OhioAccentSystem.cs | 46 ++ Content.Shared/Body/Organ/OrganComponent.cs | 32 +- Content.Shared/Body/Organ/OrganEvents.cs | 12 + Content.Shared/Body/Part/BodyPartComponent.cs | 37 +- Content.Shared/Body/Part/BodyPartEvents.cs | 2 + .../Body/Systems/SharedBodySystem.Body.cs | 22 +- .../Body/Systems/SharedBodySystem.Organs.cs | 62 +++ .../SharedBodySystem.PartAppearance.cs | 8 +- .../Body/Systems/SharedBodySystem.Parts.cs | 42 +- .../Systems/SharedBodySystem.Targeting.cs | 5 +- .../Body/Systems/SharedBodySystem.cs | 2 + .../BodyEffects/BodyPartEffectComponent.cs | 26 ++ .../BodyEffects/BodyPartEffectSystem.cs | 95 ++++ .../BodyEffects/OrganEffectComponent.cs | 27 ++ .../BodyEffects/OrganEffectSystem.cs | 109 +++++ .../GenerateChildPartComponent.cs | 18 + .../GenerateChildPartSystem.cs | 65 +++ .../Cybernetics/CyberneticsComponent.cs | 16 + .../Damage/Systems/DamageableSystem.cs | 36 +- .../Damage/Systems/SharedGodmodeSystem.cs | 13 +- .../Eye/Blinding/Systems/BlindableSystem.cs | 11 + Content.Shared/Input/ContentKeyFunctions.cs | 5 +- .../SurgeryComponentConditionComponent.cs | 16 + .../Surgery/SharedSurgerySystem.Steps.cs | 96 +++- .../Medical/Surgery/SharedSurgerySystem.cs | 18 +- .../Steps/SurgeryCanPerformStepEvent.cs | 4 +- .../Surgery/Steps/SurgeryStepComponent.cs | 6 + .../Medical/Surgery/Tools/BoneGelComponent.cs | 5 +- .../Medical/Surgery/Tools/BoneSawComponent.cs | 4 +- .../Surgery/Tools/BoneSetterComponent.cs | 8 +- .../Medical/Surgery/Tools/CauteryComponent.cs | 4 +- .../Medical/Surgery/Tools/DrillComponent.cs | 12 + .../Surgery/Tools/HemostatComponent.cs | 4 +- .../Surgery/Tools/ISurgeryToolComponent.cs | 9 +- .../Surgery/Tools/RetractorComponent.cs | 4 +- .../Medical/Surgery/Tools/ScalpelComponent.cs | 4 +- .../Surgery/Tools/SurgeryToolComponent.cs | 9 +- .../Surgery/Tools/SurgeryToolExamineSystem.cs | 65 +++ .../Tools/SurgeryToolsConditionsSystem.cs | 57 +++ .../Surgery/Tools/SurgicalDrillComponent.cs | 10 - .../Medical/Surgery/Tools/TendingComponent.cs | 15 + .../Surgery/Tools/TweezersComponent.cs | 15 + .../Overlays/ShowHealthBarsComponent.cs | 4 +- .../Overlays/ShowHealthIconsComponent.cs | 4 +- .../Prying/Components/PryingComponent.cs | 6 +- .../Smoking/Components/MatchstickComponent.cs | 28 ++ .../Smoking/Systems/SharedMatchstickSystem.cs | 16 + .../Standing/SharedLayingDownSystem.cs | 6 +- Resources/Locale/en-US/accent/ohio.ftl | 421 ++++++++++++++++++ .../en-US/medical/surgery/surgery-tools.ftl | 9 + .../Locale/en-US/research/technologies.ftl | 4 +- Resources/Maps/glacier.yml | 8 + .../Prototypes/Body/Organs/Animal/animal.yml | 18 + .../Prototypes/Body/Organs/cybernetic.yml | 51 +++ Resources/Prototypes/Body/Organs/generic.yml | 23 + Resources/Prototypes/Body/Parts/animal.yml | 40 +- .../Prototypes/Body/Parts/cybernetic.yml | 169 +++++++ Resources/Prototypes/Body/Parts/generic.yml | 103 +++++ Resources/Prototypes/Body/Parts/silicon.yml | 22 +- .../Body/Prototypes/Animal/animal.yml | 2 +- .../Body/Prototypes/Animal/carp.yml | 17 + .../Prototypes/DeltaV/Body/Organs/harpy.yml | 2 + .../DeltaV/Body/Parts/vulpkanin.yml | 2 +- .../DeltaV/Body/Prototypes/harpy.yml | 1 + .../DeltaV/Body/Prototypes/vulpkanin.yml | 1 + .../Entities/Mobs/Cyborgs/borg_chassis.yml | 1 + .../Prototypes/Entities/Mobs/NPCs/carp.yml | 7 + .../Entities/Objects/Materials/shards.yml | 7 + .../Entities/Objects/Misc/paper.yml | 7 + .../Entities/Objects/Misc/utensils.yml | 11 + .../Objects/Specific/Hydroponics/tools.yml | 14 + .../Objects/Specific/Medical/surgery.yml | 276 +++++++----- .../Specific/Robotics/borg_modules.yml | 35 ++ .../Entities/Objects/Tools/lighters.yml | 7 + .../Entities/Objects/Tools/matches.yml | 7 + .../Entities/Objects/Tools/tools.yml | 26 ++ .../Entities/Objects/Tools/welders.yml | 7 + .../Weapons/Guns/Battery/battery_guns.yml | 10 + .../Objects/Weapons/Melee/armblade.yml | 7 + .../Objects/Weapons/Melee/chainsaw.yml | 7 + .../Objects/Weapons/Melee/e_sword.yml | 11 + .../Objects/Weapons/Melee/fireaxe.yml | 7 + .../Entities/Objects/Weapons/Melee/knife.yml | 7 + .../Entities/Structures/Machines/lathe.yml | 17 + .../Prototypes/Entities/Surgery/surgeries.yml | 53 +++ .../Entities/Surgery/surgery_steps.yml | 104 ++++- .../Entities/Body/Parts/spider.yml | 2 +- .../Entities/Body/Prototypes/arachne.yml | 1 + .../Entities/Body/Prototypes/felinid.yml | 1 + .../Prototypes/Recipes/Lathes/medical.yml | 49 ++ .../Prototypes/Recipes/Lathes/robotics.yml | 80 ++++ .../Prototypes/Recipes/Lathes/security.yml | 12 + .../Prototypes/Research/civilianservices.yml | 42 +- Resources/Prototypes/Species/arachne.yml | 2 +- Resources/Prototypes/Species/cybernetic.yml | 47 ++ .../Aliens/Carps/carp_parts.rsi/meta.json | 17 + .../Mobs/Aliens/Carps/carp_parts.rsi/tail.png | Bin 0 -> 244 bytes .../Aliens/Carps/carp_parts.rsi/torso.png | Bin 0 -> 479 bytes .../bishop/bishop_main.rsi/l_arm-combined.png | Bin 0 -> 388 bytes .../bishop/bishop_main.rsi/l_leg-combined.png | Bin 0 -> 523 bytes .../bishop/bishop_main.rsi/meta.json | 18 +- .../bishop/bishop_main.rsi/r_arm-combined.png | Bin 0 -> 401 bytes .../bishop/bishop_main.rsi/r_leg-combined.png | Bin 0 -> 525 bytes .../Mobs/Species/IPC/organs.rsi/eyes.png | Bin 0 -> 1047 bytes .../Mobs/Species/IPC/organs.rsi/meta.json | 3 + .../adv-retractor.rsi/adv-retractor-on.png | Bin 0 -> 220 bytes .../adv-retractor.rsi/adv-retractor.png | Bin 0 -> 254 bytes .../adv-retractor.rsi/inhand-left-on.png | Bin 0 -> 397 bytes .../Surgery/adv-retractor.rsi/inhand-left.png | Bin 0 -> 400 bytes .../adv-retractor.rsi/inhand-right-on.png | Bin 0 -> 421 bytes .../adv-retractor.rsi/inhand-right.png | Bin 0 -> 405 bytes .../Surgery/adv-retractor.rsi/meta.json | 33 ++ .../Medical/Surgery/bone-gel.rsi/bone-gel.png | Bin 0 -> 258 bytes .../Surgery/bone-gel.rsi/inhand-left.png | Bin 0 -> 418 bytes .../Surgery/bone-gel.rsi/inhand-right.png | Bin 0 -> 431 bytes .../Medical/Surgery/bone-gel.rsi/meta.json | 22 + .../Medical/Surgery/bone_gel.rsi/bone-gel.png | Bin 432 -> 0 bytes .../Surgery/bone_gel.rsi/bone-gel_0.png | Bin 391 -> 0 bytes .../Surgery/bone_gel.rsi/bone-gel_25.png | Bin 444 -> 0 bytes .../Surgery/bone_gel.rsi/bone-gel_50.png | Bin 456 -> 0 bytes .../Surgery/bone_gel.rsi/bone-gel_75.png | Bin 444 -> 0 bytes .../Medical/Surgery/bone_gel.rsi/meta.json | 29 -- .../bone_gel.rsi/predator_bone-gel.png | Bin 585 -> 0 bytes .../Surgery/bonesetter.rsi/bonesetter.png | Bin 581 -> 287 bytes .../Surgery/bonesetter.rsi/inhand-left.png | Bin 0 -> 486 bytes .../Surgery/bonesetter.rsi/inhand-right.png | Bin 0 -> 474 bytes .../Medical/Surgery/bonesetter.rsi/meta.json | 35 +- .../bonesetter.rsi/predator_bonesetter.png | Bin 489 -> 0 bytes .../Medical/Surgery/cautery.rsi/cautery.png | Bin 181 -> 238 bytes .../Surgery/cautery.rsi/inhand-left.png | Bin 372 -> 420 bytes .../Surgery/cautery.rsi/inhand-right.png | Bin 374 -> 430 bytes .../Medical/Surgery/cautery.rsi/meta.json | 2 +- .../Surgery/circular-saw.rsi/circular-saw.png | Bin 0 -> 273 bytes .../Surgery/circular-saw.rsi/inhand-left.png | Bin 0 -> 666 bytes .../Surgery/circular-saw.rsi/inhand-right.png | Bin 0 -> 668 bytes .../Surgery/circular-saw.rsi/meta.json | 22 + .../Medical/Surgery/drapes.rsi/drapes.png | Bin 0 -> 228 bytes .../Surgery/drapes.rsi/inhand-left.png | Bin 0 -> 460 bytes .../Surgery/drapes.rsi/inhand-right.png | Bin 0 -> 462 bytes .../Medical/Surgery/drapes.rsi/meta.json | 22 + .../Specific/Medical/Surgery/drill.rsi/0.png | Bin 240 -> 0 bytes .../Medical/Surgery/drill.rsi/100.png | Bin 108 -> 0 bytes .../Specific/Medical/Surgery/drill.rsi/25.png | Bin 108 -> 0 bytes .../Specific/Medical/Surgery/drill.rsi/50.png | Bin 108 -> 0 bytes .../Specific/Medical/Surgery/drill.rsi/75.png | Bin 108 -> 0 bytes .../Medical/Surgery/drill.rsi/drill.png | Bin 238 -> 702 bytes .../Medical/Surgery/drill.rsi/inhand-left.png | Bin 514 -> 685 bytes .../Surgery/drill.rsi/inhand-right.png | Bin 517 -> 689 bytes .../Medical/Surgery/drill.rsi/meta.json | 23 +- .../Surgery/e-cautery.rsi/e-cautery-on.png | Bin 0 -> 234 bytes .../Surgery/e-cautery.rsi/e-cautery.png | Bin 0 -> 244 bytes .../Surgery/e-cautery.rsi/inhand-left-on.png | Bin 0 -> 481 bytes .../Surgery/e-cautery.rsi/inhand-left.png | Bin 0 -> 462 bytes .../Surgery/e-cautery.rsi/inhand-right-on.png | Bin 0 -> 496 bytes .../Surgery/e-cautery.rsi/inhand-right.png | Bin 0 -> 475 bytes .../Medical/Surgery/e-cautery.rsi/meta.json | 33 ++ .../Surgery/e-scalpel.rsi/e-scalpel-on.png | Bin 0 -> 537 bytes .../Surgery/e-scalpel.rsi/e-scalpel.png | Bin 0 -> 218 bytes .../Surgery/e-scalpel.rsi/inhand-left-on.png | Bin 0 -> 503 bytes .../Surgery/e-scalpel.rsi/inhand-left.png | Bin 0 -> 487 bytes .../Surgery/e-scalpel.rsi/inhand-right-on.png | Bin 0 -> 505 bytes .../Surgery/e-scalpel.rsi/inhand-right.png | Bin 0 -> 480 bytes .../Medical/Surgery/e-scalpel.rsi/meta.json | 39 ++ .../Medical/Surgery/hemostat.rsi/hemostat.png | Bin 0 -> 261 bytes .../Surgery/hemostat.rsi/inhand-left.png | Bin 0 -> 374 bytes .../Surgery/hemostat.rsi/inhand-right.png | Bin 0 -> 385 bytes .../Medical/Surgery/hemostat.rsi/meta.json | 22 + .../{scalpel.rsi => oldscalpel.rsi}/0.png | Bin .../{scalpel.rsi => oldscalpel.rsi}/100.png | Bin .../{scalpel.rsi => oldscalpel.rsi}/25.png | Bin .../{scalpel.rsi => oldscalpel.rsi}/50.png | Bin .../{scalpel.rsi => oldscalpel.rsi}/75.png | Bin .../advanced-inhand-left.png | Bin .../advanced-inhand-right.png | Bin .../advanced.png | Bin .../Surgery/oldscalpel.rsi/inhand-left.png | Bin 0 -> 250 bytes .../Surgery/oldscalpel.rsi/inhand-right.png | Bin 0 -> 242 bytes .../laser-inhand-left.png | Bin .../laser-inhand-right.png | Bin .../{scalpel.rsi => oldscalpel.rsi}/laser.png | Bin .../Medical/Surgery/oldscalpel.rsi/meta.json | 76 ++++ .../Surgery/oldscalpel.rsi/scalpel.png | Bin 0 -> 166 bytes .../shiv-inhand-left.png | Bin .../shiv-inhand-right.png | Bin .../{scalpel.rsi => oldscalpel.rsi}/shiv.png | Bin .../Surgery/omnimed.rsi/inhand-left.png | Bin 0 -> 593 bytes .../Surgery/omnimed.rsi/inhand-right.png | Bin 0 -> 585 bytes .../Medical/Surgery/omnimed.rsi/meta.json | 22 + .../Medical/Surgery/omnimed.rsi/omnimed.png | Bin 0 -> 271 bytes .../Surgery/retractor.rsi/inhand-left.png | Bin 0 -> 480 bytes .../Surgery/retractor.rsi/inhand-right.png | Bin 0 -> 486 bytes .../Medical/Surgery/retractor.rsi/meta.json | 22 + .../Surgery/retractor.rsi/retractor.png | Bin 0 -> 304 bytes .../Surgery/scalpel.rsi/inhand-left.png | Bin 250 -> 424 bytes .../Surgery/scalpel.rsi/inhand-right.png | Bin 242 -> 433 bytes .../Medical/Surgery/scalpel.rsi/meta.json | 56 +-- .../Medical/Surgery/scalpel.rsi/scalpel.png | Bin 166 -> 194 bytes .../scissors.rsi/hemostat-inhand-left.png | Bin 332 -> 0 bytes .../scissors.rsi/hemostat-inhand-right.png | Bin 337 -> 0 bytes .../Medical/Surgery/scissors.rsi/hemostat.png | Bin 201 -> 0 bytes .../Surgery/scissors.rsi/inhand-left.png | Bin 356 -> 0 bytes .../Surgery/scissors.rsi/inhand-right.png | Bin 361 -> 0 bytes .../Medical/Surgery/scissors.rsi/meta.json | 44 -- .../Surgery/scissors.rsi/retractor.png | Bin 219 -> 0 bytes .../scissors.rsi/setter-inhand-left.png | Bin 340 -> 0 bytes .../scissors.rsi/setter-inhand-right.png | Bin 347 -> 0 bytes .../Medical/Surgery/scissors.rsi/setter.png | Bin 200 -> 0 bytes .../borgmodule.rsi/icon-advanced-surgery.png | Bin 0 -> 254 bytes .../Robotics/borgmodule.rsi/icon-surgery.png | Bin 0 -> 258 bytes .../Robotics/borgmodule.rsi/meta.json | 6 + Resources/keybinds.yml | 25 -- 227 files changed, 3351 insertions(+), 475 deletions(-) create mode 100644 Content.Client/Smoking/MatchstickSystem.cs create mode 100644 Content.Client/Speech/Components/OhioAccentComponent.cs create mode 100644 Content.Server/Body/Systems/DebrainedSystem.cs create mode 100644 Content.Server/Body/Systems/EyesSystem.cs create mode 100644 Content.Server/Cybernetics/CyberneticsSystem.cs delete mode 100644 Content.Server/Light/Components/MatchstickComponent.cs create mode 100644 Content.Server/Speech/Components/OhioAccentComponent.cs create mode 100644 Content.Server/Speech/EntitySystems/OhioAccentSystem.cs create mode 100644 Content.Shared/Body/Organ/OrganEvents.cs create mode 100644 Content.Shared/BodyEffects/BodyPartEffectComponent.cs create mode 100644 Content.Shared/BodyEffects/BodyPartEffectSystem.cs create mode 100644 Content.Shared/BodyEffects/OrganEffectComponent.cs create mode 100644 Content.Shared/BodyEffects/OrganEffectSystem.cs create mode 100644 Content.Shared/BodyEffects/Subsystems/GenerateChildPart/GenerateChildPartComponent.cs create mode 100644 Content.Shared/BodyEffects/Subsystems/GenerateChildPart/GenerateChildPartSystem.cs create mode 100644 Content.Shared/Cybernetics/CyberneticsComponent.cs create mode 100644 Content.Shared/Medical/Surgery/Conditions/SurgeryComponentConditionComponent.cs create mode 100644 Content.Shared/Medical/Surgery/Tools/DrillComponent.cs create mode 100644 Content.Shared/Medical/Surgery/Tools/SurgeryToolExamineSystem.cs create mode 100644 Content.Shared/Medical/Surgery/Tools/SurgeryToolsConditionsSystem.cs delete mode 100644 Content.Shared/Medical/Surgery/Tools/SurgicalDrillComponent.cs create mode 100644 Content.Shared/Medical/Surgery/Tools/TendingComponent.cs create mode 100644 Content.Shared/Medical/Surgery/Tools/TweezersComponent.cs create mode 100644 Content.Shared/Smoking/Components/MatchstickComponent.cs create mode 100644 Content.Shared/Smoking/Systems/SharedMatchstickSystem.cs create mode 100644 Resources/Locale/en-US/accent/ohio.ftl create mode 100644 Resources/Locale/en-US/medical/surgery/surgery-tools.ftl create mode 100644 Resources/Prototypes/Body/Organs/cybernetic.yml create mode 100644 Resources/Prototypes/Body/Organs/generic.yml create mode 100644 Resources/Prototypes/Body/Parts/cybernetic.yml create mode 100644 Resources/Prototypes/Body/Parts/generic.yml create mode 100644 Resources/Prototypes/Body/Prototypes/Animal/carp.yml create mode 100644 Resources/Prototypes/Species/cybernetic.yml create mode 100644 Resources/Textures/Mobs/Aliens/Carps/carp_parts.rsi/meta.json create mode 100644 Resources/Textures/Mobs/Aliens/Carps/carp_parts.rsi/tail.png create mode 100644 Resources/Textures/Mobs/Aliens/Carps/carp_parts.rsi/torso.png create mode 100644 Resources/Textures/Mobs/Customization/cyberlimbs/bishop/bishop_main.rsi/l_arm-combined.png create mode 100644 Resources/Textures/Mobs/Customization/cyberlimbs/bishop/bishop_main.rsi/l_leg-combined.png create mode 100644 Resources/Textures/Mobs/Customization/cyberlimbs/bishop/bishop_main.rsi/r_arm-combined.png create mode 100644 Resources/Textures/Mobs/Customization/cyberlimbs/bishop/bishop_main.rsi/r_leg-combined.png create mode 100644 Resources/Textures/Mobs/Species/IPC/organs.rsi/eyes.png create mode 100644 Resources/Textures/Objects/Specific/Medical/Surgery/adv-retractor.rsi/adv-retractor-on.png create mode 100644 Resources/Textures/Objects/Specific/Medical/Surgery/adv-retractor.rsi/adv-retractor.png create mode 100644 Resources/Textures/Objects/Specific/Medical/Surgery/adv-retractor.rsi/inhand-left-on.png create mode 100644 Resources/Textures/Objects/Specific/Medical/Surgery/adv-retractor.rsi/inhand-left.png create mode 100644 Resources/Textures/Objects/Specific/Medical/Surgery/adv-retractor.rsi/inhand-right-on.png create mode 100644 Resources/Textures/Objects/Specific/Medical/Surgery/adv-retractor.rsi/inhand-right.png create mode 100644 Resources/Textures/Objects/Specific/Medical/Surgery/adv-retractor.rsi/meta.json create mode 100644 Resources/Textures/Objects/Specific/Medical/Surgery/bone-gel.rsi/bone-gel.png create mode 100644 Resources/Textures/Objects/Specific/Medical/Surgery/bone-gel.rsi/inhand-left.png create mode 100644 Resources/Textures/Objects/Specific/Medical/Surgery/bone-gel.rsi/inhand-right.png create mode 100644 Resources/Textures/Objects/Specific/Medical/Surgery/bone-gel.rsi/meta.json delete mode 100644 Resources/Textures/Objects/Specific/Medical/Surgery/bone_gel.rsi/bone-gel.png delete mode 100644 Resources/Textures/Objects/Specific/Medical/Surgery/bone_gel.rsi/bone-gel_0.png delete mode 100644 Resources/Textures/Objects/Specific/Medical/Surgery/bone_gel.rsi/bone-gel_25.png delete mode 100644 Resources/Textures/Objects/Specific/Medical/Surgery/bone_gel.rsi/bone-gel_50.png delete mode 100644 Resources/Textures/Objects/Specific/Medical/Surgery/bone_gel.rsi/bone-gel_75.png delete mode 100644 Resources/Textures/Objects/Specific/Medical/Surgery/bone_gel.rsi/meta.json delete mode 100644 Resources/Textures/Objects/Specific/Medical/Surgery/bone_gel.rsi/predator_bone-gel.png create mode 100644 Resources/Textures/Objects/Specific/Medical/Surgery/bonesetter.rsi/inhand-left.png create mode 100644 Resources/Textures/Objects/Specific/Medical/Surgery/bonesetter.rsi/inhand-right.png delete mode 100644 Resources/Textures/Objects/Specific/Medical/Surgery/bonesetter.rsi/predator_bonesetter.png create mode 100644 Resources/Textures/Objects/Specific/Medical/Surgery/circular-saw.rsi/circular-saw.png create mode 100644 Resources/Textures/Objects/Specific/Medical/Surgery/circular-saw.rsi/inhand-left.png create mode 100644 Resources/Textures/Objects/Specific/Medical/Surgery/circular-saw.rsi/inhand-right.png create mode 100644 Resources/Textures/Objects/Specific/Medical/Surgery/circular-saw.rsi/meta.json create mode 100644 Resources/Textures/Objects/Specific/Medical/Surgery/drapes.rsi/drapes.png create mode 100644 Resources/Textures/Objects/Specific/Medical/Surgery/drapes.rsi/inhand-left.png create mode 100644 Resources/Textures/Objects/Specific/Medical/Surgery/drapes.rsi/inhand-right.png create mode 100644 Resources/Textures/Objects/Specific/Medical/Surgery/drapes.rsi/meta.json delete mode 100644 Resources/Textures/Objects/Specific/Medical/Surgery/drill.rsi/0.png delete mode 100644 Resources/Textures/Objects/Specific/Medical/Surgery/drill.rsi/100.png delete mode 100644 Resources/Textures/Objects/Specific/Medical/Surgery/drill.rsi/25.png delete mode 100644 Resources/Textures/Objects/Specific/Medical/Surgery/drill.rsi/50.png delete mode 100644 Resources/Textures/Objects/Specific/Medical/Surgery/drill.rsi/75.png create mode 100644 Resources/Textures/Objects/Specific/Medical/Surgery/e-cautery.rsi/e-cautery-on.png create mode 100644 Resources/Textures/Objects/Specific/Medical/Surgery/e-cautery.rsi/e-cautery.png create mode 100644 Resources/Textures/Objects/Specific/Medical/Surgery/e-cautery.rsi/inhand-left-on.png create mode 100644 Resources/Textures/Objects/Specific/Medical/Surgery/e-cautery.rsi/inhand-left.png create mode 100644 Resources/Textures/Objects/Specific/Medical/Surgery/e-cautery.rsi/inhand-right-on.png create mode 100644 Resources/Textures/Objects/Specific/Medical/Surgery/e-cautery.rsi/inhand-right.png create mode 100644 Resources/Textures/Objects/Specific/Medical/Surgery/e-cautery.rsi/meta.json create mode 100644 Resources/Textures/Objects/Specific/Medical/Surgery/e-scalpel.rsi/e-scalpel-on.png create mode 100644 Resources/Textures/Objects/Specific/Medical/Surgery/e-scalpel.rsi/e-scalpel.png create mode 100644 Resources/Textures/Objects/Specific/Medical/Surgery/e-scalpel.rsi/inhand-left-on.png create mode 100644 Resources/Textures/Objects/Specific/Medical/Surgery/e-scalpel.rsi/inhand-left.png create mode 100644 Resources/Textures/Objects/Specific/Medical/Surgery/e-scalpel.rsi/inhand-right-on.png create mode 100644 Resources/Textures/Objects/Specific/Medical/Surgery/e-scalpel.rsi/inhand-right.png create mode 100644 Resources/Textures/Objects/Specific/Medical/Surgery/e-scalpel.rsi/meta.json create mode 100644 Resources/Textures/Objects/Specific/Medical/Surgery/hemostat.rsi/hemostat.png create mode 100644 Resources/Textures/Objects/Specific/Medical/Surgery/hemostat.rsi/inhand-left.png create mode 100644 Resources/Textures/Objects/Specific/Medical/Surgery/hemostat.rsi/inhand-right.png create mode 100644 Resources/Textures/Objects/Specific/Medical/Surgery/hemostat.rsi/meta.json rename Resources/Textures/Objects/Specific/Medical/Surgery/{scalpel.rsi => oldscalpel.rsi}/0.png (100%) rename Resources/Textures/Objects/Specific/Medical/Surgery/{scalpel.rsi => oldscalpel.rsi}/100.png (100%) rename Resources/Textures/Objects/Specific/Medical/Surgery/{scalpel.rsi => oldscalpel.rsi}/25.png (100%) rename Resources/Textures/Objects/Specific/Medical/Surgery/{scalpel.rsi => oldscalpel.rsi}/50.png (100%) rename Resources/Textures/Objects/Specific/Medical/Surgery/{scalpel.rsi => oldscalpel.rsi}/75.png (100%) rename Resources/Textures/Objects/Specific/Medical/Surgery/{scalpel.rsi => oldscalpel.rsi}/advanced-inhand-left.png (100%) rename Resources/Textures/Objects/Specific/Medical/Surgery/{scalpel.rsi => oldscalpel.rsi}/advanced-inhand-right.png (100%) rename Resources/Textures/Objects/Specific/Medical/Surgery/{scalpel.rsi => oldscalpel.rsi}/advanced.png (100%) create mode 100644 Resources/Textures/Objects/Specific/Medical/Surgery/oldscalpel.rsi/inhand-left.png create mode 100644 Resources/Textures/Objects/Specific/Medical/Surgery/oldscalpel.rsi/inhand-right.png rename Resources/Textures/Objects/Specific/Medical/Surgery/{scalpel.rsi => oldscalpel.rsi}/laser-inhand-left.png (100%) rename Resources/Textures/Objects/Specific/Medical/Surgery/{scalpel.rsi => oldscalpel.rsi}/laser-inhand-right.png (100%) rename Resources/Textures/Objects/Specific/Medical/Surgery/{scalpel.rsi => oldscalpel.rsi}/laser.png (100%) create mode 100644 Resources/Textures/Objects/Specific/Medical/Surgery/oldscalpel.rsi/meta.json create mode 100644 Resources/Textures/Objects/Specific/Medical/Surgery/oldscalpel.rsi/scalpel.png rename Resources/Textures/Objects/Specific/Medical/Surgery/{scalpel.rsi => oldscalpel.rsi}/shiv-inhand-left.png (100%) rename Resources/Textures/Objects/Specific/Medical/Surgery/{scalpel.rsi => oldscalpel.rsi}/shiv-inhand-right.png (100%) rename Resources/Textures/Objects/Specific/Medical/Surgery/{scalpel.rsi => oldscalpel.rsi}/shiv.png (100%) create mode 100644 Resources/Textures/Objects/Specific/Medical/Surgery/omnimed.rsi/inhand-left.png create mode 100644 Resources/Textures/Objects/Specific/Medical/Surgery/omnimed.rsi/inhand-right.png create mode 100644 Resources/Textures/Objects/Specific/Medical/Surgery/omnimed.rsi/meta.json create mode 100644 Resources/Textures/Objects/Specific/Medical/Surgery/omnimed.rsi/omnimed.png create mode 100644 Resources/Textures/Objects/Specific/Medical/Surgery/retractor.rsi/inhand-left.png create mode 100644 Resources/Textures/Objects/Specific/Medical/Surgery/retractor.rsi/inhand-right.png create mode 100644 Resources/Textures/Objects/Specific/Medical/Surgery/retractor.rsi/meta.json create mode 100644 Resources/Textures/Objects/Specific/Medical/Surgery/retractor.rsi/retractor.png delete mode 100644 Resources/Textures/Objects/Specific/Medical/Surgery/scissors.rsi/hemostat-inhand-left.png delete mode 100644 Resources/Textures/Objects/Specific/Medical/Surgery/scissors.rsi/hemostat-inhand-right.png delete mode 100644 Resources/Textures/Objects/Specific/Medical/Surgery/scissors.rsi/hemostat.png delete mode 100644 Resources/Textures/Objects/Specific/Medical/Surgery/scissors.rsi/inhand-left.png delete mode 100644 Resources/Textures/Objects/Specific/Medical/Surgery/scissors.rsi/inhand-right.png delete mode 100644 Resources/Textures/Objects/Specific/Medical/Surgery/scissors.rsi/meta.json delete mode 100644 Resources/Textures/Objects/Specific/Medical/Surgery/scissors.rsi/retractor.png delete mode 100644 Resources/Textures/Objects/Specific/Medical/Surgery/scissors.rsi/setter-inhand-left.png delete mode 100644 Resources/Textures/Objects/Specific/Medical/Surgery/scissors.rsi/setter-inhand-right.png delete mode 100644 Resources/Textures/Objects/Specific/Medical/Surgery/scissors.rsi/setter.png create mode 100644 Resources/Textures/Objects/Specific/Robotics/borgmodule.rsi/icon-advanced-surgery.png create mode 100644 Resources/Textures/Objects/Specific/Robotics/borgmodule.rsi/icon-surgery.png diff --git a/Content.Client/Options/UI/Tabs/KeyRebindTab.xaml.cs b/Content.Client/Options/UI/Tabs/KeyRebindTab.xaml.cs index c89659c3ab5..21d9ae45607 100644 --- a/Content.Client/Options/UI/Tabs/KeyRebindTab.xaml.cs +++ b/Content.Client/Options/UI/Tabs/KeyRebindTab.xaml.cs @@ -256,9 +256,13 @@ void AddCheckBox(string checkBoxName, bool currentState, Action HandleTargetChange(session, TargetBodyPart.Torso))) .Bind(ContentKeyFunctions.TargetLeftArm, InputCmdHandler.FromDelegate((session) => HandleTargetChange(session, TargetBodyPart.LeftArm))) -/* .Bind(ContentKeyFunctions.TargetLeftHand, - InputCmdHandler.FromDelegate((session) => HandleTargetChange(session, TargetBodyPart.LeftHand))) SOON :TM: */ + .Bind(ContentKeyFunctions.TargetLeftHand, + InputCmdHandler.FromDelegate((session) => HandleTargetChange(session, TargetBodyPart.LeftHand))) .Bind(ContentKeyFunctions.TargetRightArm, InputCmdHandler.FromDelegate((session) => HandleTargetChange(session, TargetBodyPart.RightArm))) -/* .Bind(ContentKeyFunctions.TargetRightHand, - InputCmdHandler.FromDelegate((session) => HandleTargetChange(session, TargetBodyPart.RightHand)))*/ + .Bind(ContentKeyFunctions.TargetRightHand, + InputCmdHandler.FromDelegate((session) => HandleTargetChange(session, TargetBodyPart.RightHand))) .Bind(ContentKeyFunctions.TargetLeftLeg, InputCmdHandler.FromDelegate((session) => HandleTargetChange(session, TargetBodyPart.LeftLeg))) -/* .Bind(ContentKeyFunctions.TargetLeftFoot, - InputCmdHandler.FromDelegate((session) => HandleTargetChange(session, TargetBodyPart.LeftFoot)))*/ + .Bind(ContentKeyFunctions.TargetLeftFoot, + InputCmdHandler.FromDelegate((session) => HandleTargetChange(session, TargetBodyPart.LeftFoot))) .Bind(ContentKeyFunctions.TargetRightLeg, InputCmdHandler.FromDelegate((session) => HandleTargetChange(session, TargetBodyPart.RightLeg))) -/* .Bind(ContentKeyFunctions.TargetRightFoot, - InputCmdHandler.FromDelegate((session) => HandleTargetChange(session, TargetBodyPart.RightFoot)))*/ + .Bind(ContentKeyFunctions.TargetRightFoot, + InputCmdHandler.FromDelegate((session) => HandleTargetChange(session, TargetBodyPart.RightFoot))) .Register(); } diff --git a/Content.Server/Body/Components/BrainComponent.cs b/Content.Server/Body/Components/BrainComponent.cs index 004ff24eaff..1a0ebc5f2a7 100644 --- a/Content.Server/Body/Components/BrainComponent.cs +++ b/Content.Server/Body/Components/BrainComponent.cs @@ -5,5 +5,10 @@ namespace Content.Server.Body.Components [RegisterComponent, Access(typeof(BrainSystem))] public sealed partial class BrainComponent : Component { + /// + /// Is this brain currently controlling the entity? + /// + [DataField] + public bool Active = true; } } diff --git a/Content.Server/Body/Systems/BodySystem.cs b/Content.Server/Body/Systems/BodySystem.cs index 3dca4b81fe1..2584e4daa2d 100644 --- a/Content.Server/Body/Systems/BodySystem.cs +++ b/Content.Server/Body/Systems/BodySystem.cs @@ -168,6 +168,16 @@ public override HashSet GibPart( return gibs; } + public override bool BurnPart(EntityUid partId, BodyPartComponent? part = null) + { + if (!Resolve(partId, ref part, logMissing: false) + || TerminatingOrDeleted(partId) + || EntityManager.IsQueuedForDeletion(partId)) + return false; + + return base.BurnPart(partId, part); + } + protected override void ApplyPartMarkings(EntityUid target, BodyPartAppearanceComponent component) { return; diff --git a/Content.Server/Body/Systems/BrainSystem.cs b/Content.Server/Body/Systems/BrainSystem.cs index 6f6e7eda430..8338bc0f85b 100644 --- a/Content.Server/Body/Systems/BrainSystem.cs +++ b/Content.Server/Body/Systems/BrainSystem.cs @@ -2,9 +2,11 @@ using Content.Server.Ghost.Components; using Content.Shared.Body.Components; using Content.Shared.Body.Systems; +using Content.Shared.Body.Systems; using Content.Shared.Body.Events; using Content.Shared.Body.Organ; using Content.Server.DelayedDeath; +using Content.Server.DelayedDeath; using Content.Shared.Mind; using Content.Shared.Mind.Components; using Content.Shared.Pointing; @@ -25,29 +27,33 @@ public override void Initialize() SubscribeLocalEvent(OnPointAttempt); } - private void HandleRemoval(EntityUid uid, BrainComponent _, ref OrganRemovedFromBodyEvent args) + private void HandleRemoval(EntityUid uid, BrainComponent brain, ref OrganRemovedFromBodyEvent args) { if (TerminatingOrDeleted(uid) || TerminatingOrDeleted(args.OldBody)) return; + brain.Active = false; // Prevents revival, should kill the user within a given timespan too. - EnsureComp(args.OldBody); - EnsureComp(args.OldBody); - HandleMind(uid, args.OldBody); + if (!CheckOtherBrains(args.OldBody)) + { + EnsureComp(args.OldBody); + HandleMind(uid, args.OldBody); + } } - private void HandleAddition(EntityUid uid, BrainComponent _, ref OrganAddedToBodyEvent args) + private void HandleAddition(EntityUid uid, BrainComponent brain, ref OrganAddedToBodyEvent args) { if (TerminatingOrDeleted(uid) || TerminatingOrDeleted(args.Body)) return; - RemComp(args.Body); - if (_bodySystem.TryGetBodyOrganComponents(args.Body, out var _)) - RemComp(args.Body); - HandleMind(args.Body, uid); + if (!CheckOtherBrains(args.Body)) + { + RemComp(args.Body); + HandleMind(args.Body, uid, brain); + } } - private void HandleMind(EntityUid newEntity, EntityUid oldEntity) + private void HandleMind(EntityUid newEntity, EntityUid oldEntity, BrainComponent? brain = null) { if (TerminatingOrDeleted(newEntity) || TerminatingOrDeleted(oldEntity)) return; @@ -63,11 +69,36 @@ private void HandleMind(EntityUid newEntity, EntityUid oldEntity) return; _mindSystem.TransferTo(mindId, newEntity, mind: mind); + if (brain != null) + brain.Active = true; } private void OnPointAttempt(Entity ent, ref PointAttemptEvent args) { args.Cancel(); } + + private bool CheckOtherBrains(EntityUid entity) + { + var hasOtherBrains = false; + if (TryComp(entity, out var body)) + { + if (TryComp(entity, out var bodyBrain)) + hasOtherBrains = true; + else + { + foreach (var (organ, _) in _bodySystem.GetBodyOrgans(entity, body)) + { + if (TryComp(organ, out var brain) && brain.Active) + { + hasOtherBrains = true; + break; + } + } + } + } + + return hasOtherBrains; + } } } diff --git a/Content.Server/Body/Systems/DebrainedSystem.cs b/Content.Server/Body/Systems/DebrainedSystem.cs new file mode 100644 index 00000000000..6f1f2c1ff62 --- /dev/null +++ b/Content.Server/Body/Systems/DebrainedSystem.cs @@ -0,0 +1,62 @@ +using Content.Shared.Body.Systems; +using Content.Shared.Body.Organ; +using Content.Server.DelayedDeath; +using Content.Shared.Mind; +using Content.Server.Popups; +using Content.Shared.Speech; +using Content.Shared.Standing; +using Content.Shared.Stunnable; + +namespace Content.Server.Body.Systems; + +/// +/// This system handles behavior on entities when they lose their head or their brains are removed. +/// MindComponent fuckery should still be mainly handled on BrainSystem as usual. +/// +public sealed class DebrainedSystem : EntitySystem +{ + [Dependency] private readonly SharedBodySystem _bodySystem = default!; + [Dependency] private readonly PopupSystem _popupSystem = default!; + [Dependency] private readonly StandingStateSystem _standingSystem = default!; + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnComponentInit); + SubscribeLocalEvent(OnComponentRemove); + SubscribeLocalEvent(OnSpeakAttempt); + SubscribeLocalEvent(OnStandAttempt); + } + + private void OnComponentInit(EntityUid uid, DebrainedComponent _, ComponentInit args) + { + if (TerminatingOrDeleted(uid)) + return; + + EnsureComp(uid); + EnsureComp(uid); + _standingSystem.Down(uid); + } + + private void OnComponentRemove(EntityUid uid, DebrainedComponent _, ComponentRemove args) + { + if (TerminatingOrDeleted(uid)) + return; + + RemComp(uid); + RemComp(uid); + if (_bodySystem.TryGetBodyOrganComponents(uid, out var _)) + RemComp(uid); + } + + private void OnSpeakAttempt(EntityUid uid, DebrainedComponent _, SpeakAttemptEvent args) + { + _popupSystem.PopupEntity(Loc.GetString("speech-muted"), uid, uid); + args.Cancel(); + } + + private void OnStandAttempt(EntityUid uid, DebrainedComponent _, StandAttemptEvent args) + { + args.Cancel(); + } +} diff --git a/Content.Server/Body/Systems/EyesSystem.cs b/Content.Server/Body/Systems/EyesSystem.cs new file mode 100644 index 00000000000..b59b278711a --- /dev/null +++ b/Content.Server/Body/Systems/EyesSystem.cs @@ -0,0 +1,87 @@ +using Content.Server.Body.Components; +using Content.Shared.Body.Components; +using Content.Shared.Body.Events; +using Content.Shared.Body.Organ; +using Content.Shared.Eye.Blinding.Components; +using Content.Shared.Eye.Blinding.Systems; + +namespace Content.Server.Body.Systems +{ + public sealed class EyesSystem : EntitySystem + { + [Dependency] private readonly IEntityManager _entityManager = default!; + [Dependency] private readonly BlindableSystem _blindableSystem = default!; + [Dependency] private readonly BodySystem _bodySystem = default!; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnOrganEnabled); + SubscribeLocalEvent(OnOrganDisabled); + } + + private void HandleSight(EntityUid newEntity, EntityUid oldEntity) + { + if (TerminatingOrDeleted(newEntity) || TerminatingOrDeleted(oldEntity)) + return; + + BlindableComponent? newSight; + BlindableComponent? oldSight; + //transfer existing component to organ + if (!TryComp(newEntity, out newSight)) + newSight = EnsureComp(newEntity); + + if (!TryComp(oldEntity, out oldSight)) + oldSight = EnsureComp(oldEntity); + + //give new sight all values of old sight + _blindableSystem.TransferBlindness(newSight, oldSight, newEntity); + + var hasOtherEyes = false; + //check for other eye components on owning body and owning body organs (if old entity has a body) + if (TryComp(oldEntity, out var body)) + { + if (TryComp(oldEntity, out var bodyEyes)) //some bodies see through their skin!!! (slimes) + hasOtherEyes = true; + else + { + foreach (var (organ, _) in _bodySystem.GetBodyOrgans(oldEntity, body)) + { + if (TryComp(organ, out var eyes)) + { + hasOtherEyes = true; + break; + } + } + //TODO (MS14): Should we do this for body parts too? might be a little overpowered but could be funny/interesting + } + } + + //if there are no existing eye components for the old entity - set old sight to be blind otherwise leave it as is + if (!hasOtherEyes && !TryComp(oldEntity, out var self)) + _blindableSystem.AdjustEyeDamage((oldEntity, oldSight), oldSight.MaxDamage); + + } + + private void OnOrganEnabled(EntityUid uid, EyesComponent component, OrganEnabledEvent args) + { + if (TerminatingOrDeleted(uid) + || args.Organ.Comp.Body is not { Valid: true } body) + return; + + RemComp(body); + HandleSight(uid, body); + } + + private void OnOrganDisabled(EntityUid uid, EyesComponent component, OrganDisabledEvent args) + { + if (TerminatingOrDeleted(uid) + || args.Organ.Comp.Body is not { Valid: true } body) + return; + + EnsureComp(body); + HandleSight(body, uid); + } + } +} diff --git a/Content.Server/Cybernetics/CyberneticsSystem.cs b/Content.Server/Cybernetics/CyberneticsSystem.cs new file mode 100644 index 00000000000..744e0e77caa --- /dev/null +++ b/Content.Server/Cybernetics/CyberneticsSystem.cs @@ -0,0 +1,54 @@ +using Content.Server.Emp; +using Content.Server.Body.Systems; +using Content.Shared.Body.Part; +using Content.Shared.Body.Organ; +using Content.Shared.Cybernetics; + +namespace Content.Server.Cybernetics; + +internal sealed class CyberneticsSystem : EntitySystem +{ + public override void Initialize() + { + SubscribeLocalEvent(OnEmpPulse); + SubscribeLocalEvent(OnEmpDisabledRemoved); + } + private void OnEmpPulse(Entity cyberEnt, ref EmpPulseEvent ev) + { + if (!cyberEnt.Comp.Disabled) + { + ev.Affected = true; + ev.Disabled = true; + cyberEnt.Comp.Disabled = true; + + if (HasComp(cyberEnt)) + { + var disableEvent = new OrganEnableChangedEvent(false); + RaiseLocalEvent(cyberEnt, ref disableEvent); + } + else if (HasComp(cyberEnt)) + { + var disableEvent = new BodyPartEnableChangedEvent(false); + RaiseLocalEvent(cyberEnt, ref disableEvent); + } + } + } + + private void OnEmpDisabledRemoved(Entity cyberEnt, ref EmpDisabledRemoved ev) + { + if (cyberEnt.Comp.Disabled) + { + cyberEnt.Comp.Disabled = false; + if (HasComp(cyberEnt)) + { + var enableEvent = new OrganEnableChangedEvent(true); + RaiseLocalEvent(cyberEnt, ref enableEvent); + } + else if (HasComp(cyberEnt)) + { + var enableEvent = new BodyPartEnableChangedEvent(true); + RaiseLocalEvent(cyberEnt, ref enableEvent); + } + } + } +} diff --git a/Content.Server/Destructible/Thresholds/Behaviors/BurnBodyBehavior.cs b/Content.Server/Destructible/Thresholds/Behaviors/BurnBodyBehavior.cs index f0499dc6a2d..7e70493c918 100644 --- a/Content.Server/Destructible/Thresholds/Behaviors/BurnBodyBehavior.cs +++ b/Content.Server/Destructible/Thresholds/Behaviors/BurnBodyBehavior.cs @@ -1,4 +1,5 @@ using Content.Shared.Body.Components; +using Content.Shared.Body.Part; using Content.Shared.Inventory; using Content.Shared.Popups; using JetBrains.Annotations; @@ -17,6 +18,7 @@ public void Execute(EntityUid bodyId, DestructibleSystem system, EntityUid? caus var inventorySystem = system.EntityManager.System(); var sharedPopupSystem = system.EntityManager.System(); + if (system.EntityManager.TryGetComponent(bodyId, out var comp)) { foreach (var item in inventorySystem.GetHandOrInventoryEntities(bodyId)) @@ -25,8 +27,16 @@ public void Execute(EntityUid bodyId, DestructibleSystem system, EntityUid? caus } } - sharedPopupSystem.PopupCoordinates(Loc.GetString("bodyburn-text-others", ("name", bodyId)), transformSystem.GetMoverCoordinates(bodyId), PopupType.LargeCaution); - - system.EntityManager.QueueDeleteEntity(bodyId); + if (system.EntityManager.TryGetComponent(bodyId, out var bodyPart)) + { + if (bodyPart.CanSever + && system.BodySystem.BurnPart(bodyId, bodyPart)) + sharedPopupSystem.PopupCoordinates(Loc.GetString("bodyburn-text-others", ("name", bodyId)), transformSystem.GetMoverCoordinates(bodyId), PopupType.LargeCaution); + } + else + { + sharedPopupSystem.PopupCoordinates(Loc.GetString("bodyburn-text-others", ("name", bodyId)), transformSystem.GetMoverCoordinates(bodyId), PopupType.LargeCaution); + system.EntityManager.QueueDeleteEntity(bodyId); + } } } diff --git a/Content.Server/Light/Components/MatchstickComponent.cs b/Content.Server/Light/Components/MatchstickComponent.cs deleted file mode 100644 index 3c47f4c18b3..00000000000 --- a/Content.Server/Light/Components/MatchstickComponent.cs +++ /dev/null @@ -1,29 +0,0 @@ -using Content.Server.Light.EntitySystems; -using Content.Shared.Smoking; -using Robust.Shared.Audio; - -namespace Content.Server.Light.Components -{ - [RegisterComponent] - [Access(typeof(MatchstickSystem))] - public sealed partial class MatchstickComponent : Component - { - /// - /// Current state to matchstick. Can be Unlit, Lit or Burnt. - /// - [DataField("state")] - public SmokableState CurrentState = SmokableState.Unlit; - - /// - /// How long will matchstick last in seconds. - /// - [ViewVariables(VVAccess.ReadOnly)] - [DataField("duration")] - public int Duration = 10; - - /// - /// Sound played when you ignite the matchstick. - /// - [DataField("igniteSound", required: true)] public SoundSpecifier IgniteSound = default!; - } -} diff --git a/Content.Server/Light/EntitySystems/MatchboxSystem.cs b/Content.Server/Light/EntitySystems/MatchboxSystem.cs index 9a73e44f878..e4925c610dd 100644 --- a/Content.Server/Light/EntitySystems/MatchboxSystem.cs +++ b/Content.Server/Light/EntitySystems/MatchboxSystem.cs @@ -2,6 +2,7 @@ using Content.Server.Storage.EntitySystems; using Content.Shared.Interaction; using Content.Shared.Smoking; +using Content.Shared.Smoking.Components; namespace Content.Server.Light.EntitySystems { diff --git a/Content.Server/Light/EntitySystems/MatchstickSystem.cs b/Content.Server/Light/EntitySystems/MatchstickSystem.cs index 96e4695784d..6748fa9ce66 100644 --- a/Content.Server/Light/EntitySystems/MatchstickSystem.cs +++ b/Content.Server/Light/EntitySystems/MatchstickSystem.cs @@ -1,9 +1,10 @@ using Content.Server.Atmos.EntitySystems; -using Content.Server.Light.Components; using Content.Shared.Audio; using Content.Shared.Interaction; using Content.Shared.Item; using Content.Shared.Smoking; +using Content.Shared.Smoking.Components; +using Content.Shared.Smoking.Systems; using Content.Shared.Temperature; using Robust.Server.GameObjects; using Robust.Shared.Audio; @@ -12,7 +13,7 @@ namespace Content.Server.Light.EntitySystems { - public sealed class MatchstickSystem : EntitySystem + public sealed class MatchstickSystem : SharedMatchstickSystem { [Dependency] private readonly AtmosphereSystem _atmosphereSystem = default!; [Dependency] private readonly SharedAppearanceSystem _appearance = default!; @@ -84,18 +85,21 @@ public void Ignite(Entity matchstick, EntityUid user) _audio.PlayPvs(component.IgniteSound, matchstick, AudioParams.Default.WithVariation(0.125f).WithVolume(-0.125f)); // Change state - SetState(matchstick, component, SmokableState.Lit); + SetState((matchstick, component), SmokableState.Lit); _litMatches.Add(matchstick); matchstick.Owner.SpawnTimer(component.Duration * 1000, delegate { - SetState(matchstick, component, SmokableState.Burnt); + SetState((matchstick, component), SmokableState.Burnt); _litMatches.Remove(matchstick); }); } - private void SetState(EntityUid uid, MatchstickComponent component, SmokableState value) + public override bool SetState(Entity ent, SmokableState value) { - component.CurrentState = value; + if (!base.SetState(ent, value)) + return false; + + var (uid, component) = ent; if (_lights.TryGetLight(uid, out var pointLightComponent)) { @@ -119,6 +123,8 @@ private void SetState(EntityUid uid, MatchstickComponent component, SmokableStat { _appearance.SetData(uid, SmokingVisuals.Smoking, component.CurrentState, appearance); } + + return true; } } } diff --git a/Content.Server/Medical/Surgery/SurgerySystem.cs b/Content.Server/Medical/Surgery/SurgerySystem.cs index c5c99ac6f89..8d666d178ad 100644 --- a/Content.Server/Medical/Surgery/SurgerySystem.cs +++ b/Content.Server/Medical/Surgery/SurgerySystem.cs @@ -134,12 +134,14 @@ private void OnSurgeryStepDamage(Entity ent, ref Surgery private void OnSurgerySpecialDamageChange(Entity ent, ref SurgeryStepDamageChangeEvent args) { + // Im killing this shit soon as well. if (ent.Comp.DamageType == "Rot") _rot.ReduceAccumulator(args.Body, TimeSpan.FromSeconds(2147483648)); // BEHOLD, SHITCODE THAT I JUST COPY PASTED. I'll redo it at some point, pinky swear :) - else if (ent.Comp.DamageType == "Eye" + + /*else if (ent.Comp.DamageType == "Eye" && TryComp(ent, out BlindableComponent? blindComp) && blindComp.EyeDamage > 0) - _blindableSystem.AdjustEyeDamage((args.Body, blindComp), -blindComp!.EyeDamage); + _blindableSystem.AdjustEyeDamage((args.Body, blindComp), -blindComp!.EyeDamage);*/ } private void OnSurgeryDamageChange(Entity ent, ref SurgeryStepDamageChangeEvent args) diff --git a/Content.Server/Speech/Components/OhioAccentComponent.cs b/Content.Server/Speech/Components/OhioAccentComponent.cs new file mode 100644 index 00000000000..101208bfef5 --- /dev/null +++ b/Content.Server/Speech/Components/OhioAccentComponent.cs @@ -0,0 +1,8 @@ +using Content.Server.Speech.EntitySystems; + +namespace Content.Server.Speech.Components; + +[RegisterComponent] +[Access(typeof(OhioAccentSystem))] +public sealed partial class OhioAccentComponent : Component +{ } \ No newline at end of file diff --git a/Content.Server/Speech/EntitySystems/OhioAccentSystem.cs b/Content.Server/Speech/EntitySystems/OhioAccentSystem.cs new file mode 100644 index 00000000000..3c424b6586b --- /dev/null +++ b/Content.Server/Speech/EntitySystems/OhioAccentSystem.cs @@ -0,0 +1,46 @@ +using System.Text.RegularExpressions; +using Content.Server.Speech.Components; +using Robust.Shared.Random; + +namespace Content.Server.Speech.EntitySystems; + +public sealed class OhioAccentSystem : EntitySystem +{ + [Dependency] private readonly IRobustRandom _random = default!; + [Dependency] private readonly ReplacementAccentSystem _replacement = default!; + + public override void Initialize() + { + base.Initialize(); + SubscribeLocalEvent(OnAccent); + } + + private void OnAccent(EntityUid uid, OhioAccentComponent component, AccentGetEvent args) + { + var message = args.Message; + + message = _replacement.ApplyReplacements(message, "ohio"); + + // Prefix + if (_random.Prob(0.15f)) + { + var pick = _random.Next(1, 3); + + // Reverse sanitize capital + message = message[0].ToString().ToLower() + message.Remove(0, 1); + message = Loc.GetString($"accent-ohio-prefix-{pick}") + " " + message; + } + + // Sanitize capital again, in case we substituted a word that should be capitalized + message = message[0].ToString().ToUpper() + message.Remove(0, 1); + + // Suffixes + if (_random.Prob(0.3f)) + { + var pick = _random.Next(1, 8); + message += Loc.GetString($"accent-ohio-suffix-{pick}"); + } + + args.Message = message; + } +}; \ No newline at end of file diff --git a/Content.Shared/Body/Organ/OrganComponent.cs b/Content.Shared/Body/Organ/OrganComponent.cs index e964a2f47ac..310a3f04a88 100644 --- a/Content.Shared/Body/Organ/OrganComponent.cs +++ b/Content.Shared/Body/Organ/OrganComponent.cs @@ -2,6 +2,7 @@ using Robust.Shared.Containers; using Robust.Shared.GameStates; using Content.Shared.Medical.Surgery.Tools; +using Robust.Shared.Prototypes; namespace Content.Shared.Body.Organ; @@ -27,15 +28,42 @@ public sealed partial class OrganComponent : Component, ISurgeryToolComponent /// without referencing the prototype or hardcoding. /// - [DataField] + [DataField, AlwaysPushInheritance] public string SlotId = ""; - [DataField] + [DataField, AlwaysPushInheritance] public string ToolName { get; set; } = "An organ"; + [DataField, AlwaysPushInheritance] + public float Speed { get; set; } = 1f; + /// /// If true, the organ will not heal an entity when transplanted into them. /// [DataField, AutoNetworkedField] public bool? Used { get; set; } + + /// + /// When attached, the organ will ensure these components on the entity, and delete them on removal. + /// + [DataField] + public ComponentRegistry? OnAdd; + + /// + /// When removed, the organ will ensure these components on the entity, and add them on removal. + /// + [DataField] + public ComponentRegistry? OnRemove; + + /// + /// Is this organ working or not? + /// + [DataField, AutoNetworkedField] + public bool Enabled = true; + + /// + /// Can this organ be enabled or disabled? Used mostly for prop, damaged or useless organs. + /// + [DataField] + public bool CanEnable = true; } diff --git a/Content.Shared/Body/Organ/OrganEvents.cs b/Content.Shared/Body/Organ/OrganEvents.cs new file mode 100644 index 00000000000..b94df359d4c --- /dev/null +++ b/Content.Shared/Body/Organ/OrganEvents.cs @@ -0,0 +1,12 @@ +namespace Content.Shared.Body.Organ; + +public readonly record struct OrganComponentsModifyEvent(EntityUid Body, bool Add); + +[ByRefEvent] +public readonly record struct OrganEnableChangedEvent(bool Enabled); + +[ByRefEvent] +public readonly record struct OrganEnabledEvent(Entity Organ); + +[ByRefEvent] +public readonly record struct OrganDisabledEvent(Entity Organ); diff --git a/Content.Shared/Body/Part/BodyPartComponent.cs b/Content.Shared/Body/Part/BodyPartComponent.cs index 2a93f6aed25..85fa74c1f78 100644 --- a/Content.Shared/Body/Part/BodyPartComponent.cs +++ b/Content.Shared/Body/Part/BodyPartComponent.cs @@ -7,6 +7,7 @@ using Content.Shared.Targeting; using Robust.Shared.Containers; using Robust.Shared.GameStates; +using Robust.Shared.Prototypes; using Robust.Shared.Serialization; namespace Content.Shared.Body.Part; @@ -28,7 +29,7 @@ public sealed partial class BodyPartComponent : Component, ISurgeryToolComponent [DataField, AutoNetworkedField] public BodyPartSlot? ParentSlot; - [DataField, AutoNetworkedField] + [DataField, AutoNetworkedField, AlwaysPushInheritance] public BodyPartType PartType = BodyPartType.Other; // TODO BODY Replace with a simulation of organs @@ -47,12 +48,15 @@ public sealed partial class BodyPartComponent : Component, ISurgeryToolComponent public FixedPoint2 VitalDamage = 100; - [DataField, AutoNetworkedField] + [DataField, AutoNetworkedField, AlwaysPushInheritance] public BodyPartSymmetry Symmetry = BodyPartSymmetry.None; - [DataField] + [DataField, AlwaysPushInheritance] public string ToolName { get; set; } = "A body part"; + [DataField, AlwaysPushInheritance] + public float Speed { get; set; } = 1f; + [DataField, AutoNetworkedField] public bool? Used { get; set; } = null; @@ -74,6 +78,12 @@ public sealed partial class BodyPartComponent : Component, ISurgeryToolComponent [DataField] public float MinIntegrity; + /// + /// Whether this body part can be severed or not + /// + [DataField, AutoNetworkedField] + public bool CanSever = true; + /// /// Whether this body part is enabled or not. /// @@ -86,6 +96,12 @@ public sealed partial class BodyPartComponent : Component, ISurgeryToolComponent [DataField] public bool CanEnable = true; + /// + /// Whether this body part can attach children or not. + /// + [DataField] + public bool CanAttachChildren = true; + /// /// How long it takes to run another self heal tick on the body part. /// @@ -115,7 +131,6 @@ public sealed partial class BodyPartComponent : Component, ISurgeryToolComponent [DataField, AutoNetworkedField] public ItemSlot ItemInsertionSlot = new(); - /// /// Current species. Dictates things like body part sprites. /// @@ -132,7 +147,7 @@ public sealed partial class BodyPartComponent : Component, ISurgeryToolComponent /// /// The ID of the base layer for this body part. /// - [DataField, AutoNetworkedField] + [DataField, AutoNetworkedField, AlwaysPushInheritance] public string? BaseLayerId; /// @@ -152,6 +167,18 @@ public sealed partial class BodyPartComponent : Component, ISurgeryToolComponent { TargetIntegrity.Healthy, 10 }, }; + /// + /// When attached, the part will ensure these components on the entity, and delete them on removal. + /// + [DataField, AlwaysPushInheritance] + public ComponentRegistry? OnAdd; + + /// + /// When removed, the part will ensure these components on the entity, and add them on removal. + /// + [DataField, AlwaysPushInheritance] + public ComponentRegistry? OnRemove; + /// /// These are only for VV/Debug do not use these for gameplay/systems /// diff --git a/Content.Shared/Body/Part/BodyPartEvents.cs b/Content.Shared/Body/Part/BodyPartEvents.cs index 9872b092002..8246a9b0043 100644 --- a/Content.Shared/Body/Part/BodyPartEvents.cs +++ b/Content.Shared/Body/Part/BodyPartEvents.cs @@ -25,3 +25,5 @@ namespace Content.Shared.Body.Part; [ByRefEvent] public readonly record struct BodyPartDisabledEvent(Entity Part); + +public readonly record struct BodyPartComponentsModifyEvent(EntityUid Body, bool Add); diff --git a/Content.Shared/Body/Systems/SharedBodySystem.Body.cs b/Content.Shared/Body/Systems/SharedBodySystem.Body.cs index 78e24b12c36..a56504b5f0d 100644 --- a/Content.Shared/Body/Systems/SharedBodySystem.Body.cs +++ b/Content.Shared/Body/Systems/SharedBodySystem.Body.cs @@ -372,7 +372,7 @@ public virtual HashSet GibPart( if (part.Body is { } bodyEnt) { - if (IsPartRoot(bodyEnt, partId, part: part)) + if (IsPartRoot(bodyEnt, partId, part: part) || !part.CanSever) return gibs; ChangeSlotState((partId, part), true); @@ -405,6 +405,26 @@ public virtual HashSet GibPart( return gibs; } + public virtual bool BurnPart(EntityUid partId, + BodyPartComponent? part = null) + { + if (!Resolve(partId, ref part, logMissing: false)) + return false; + + if (part.Body is { } bodyEnt) + { + if (IsPartRoot(bodyEnt, partId, part: part)) + return false; + + ChangeSlotState((partId, part), true); + RemovePartChildren((partId, part), bodyEnt); + QueueDel(partId); + return true; + } + + return false; + } + private void OnProfileLoadFinished(EntityUid uid, BodyComponent component, ProfileLoadFinishedEvent args) { if (!HasComp(uid) diff --git a/Content.Shared/Body/Systems/SharedBodySystem.Organs.cs b/Content.Shared/Body/Systems/SharedBodySystem.Organs.cs index 92b67cca173..9c9fdc57276 100644 --- a/Content.Shared/Body/Systems/SharedBodySystem.Organs.cs +++ b/Content.Shared/Body/Systems/SharedBodySystem.Organs.cs @@ -3,6 +3,7 @@ using Content.Shared.Body.Events; using Content.Shared.Body.Organ; using Content.Shared.Body.Part; +using Content.Shared.BodyEffects; using Content.Shared.Damage; using Robust.Shared.Containers; @@ -10,6 +11,18 @@ namespace Content.Shared.Body.Systems; public partial class SharedBodySystem { + private void InitializeOrgans() + { + SubscribeLocalEvent(OnMapInit); + SubscribeLocalEvent(OnOrganEnableChanged); + } + + private void OnMapInit(Entity ent, ref MapInitEvent args) + { + if (ent.Comp.OnAdd is not null || ent.Comp.OnRemove is not null) + EnsureComp(ent); + } + private void AddOrgan( Entity organEnt, EntityUid bodyUid, @@ -24,6 +37,8 @@ private void AddOrgan( organEnt.Comp.OriginalBody = organEnt.Comp.Body; var addedInBodyEv = new OrganAddedToBodyEvent(bodyUid, parentPartUid); RaiseLocalEvent(organEnt, ref addedInBodyEv); + var organEnabledEv = new OrganEnableChangedEvent(true); + RaiseLocalEvent(organEnt, ref organEnabledEv); } Dirty(organEnt, organEnt.Comp); @@ -36,6 +51,9 @@ private void RemoveOrgan(Entity organEnt, EntityUid parentPartUi if (organEnt.Comp.Body is { Valid: true } bodyUid) { + organEnt.Comp.OriginalBody = organEnt.Comp.Body; + var organDisabledEv = new OrganEnableChangedEvent(false); + RaiseLocalEvent(organEnt, ref organDisabledEv); var removedInBodyEv = new OrganRemovedFromBodyEvent(bodyUid, parentPartUid); RaiseLocalEvent(organEnt, ref removedInBodyEv); } @@ -229,4 +247,48 @@ public bool TrySetOrganUsed(EntityUid organId, bool used, OrganComponent? organ Dirty(organId, organ); return true; } + + private void OnOrganEnableChanged(Entity organEnt, ref OrganEnableChangedEvent args) + { + if (!organEnt.Comp.CanEnable && args.Enabled) + return; + + organEnt.Comp.Enabled = args.Enabled; + + if (args.Enabled) + EnableOrgan(organEnt); + else + DisableOrgan(organEnt); + + if (organEnt.Comp.Body is { Valid: true } bodyEnt) + RaiseLocalEvent(organEnt, new OrganComponentsModifyEvent(bodyEnt, args.Enabled)); + + Dirty(organEnt, organEnt.Comp); + } + + private void EnableOrgan(Entity organEnt) + { + if (!TryComp(organEnt.Comp.Body, out BodyComponent? body)) + return; + + // I hate having to hardcode these checks so much. + if (HasComp(organEnt)) + { + var ev = new OrganEnabledEvent(organEnt); + RaiseLocalEvent(organEnt, ref ev); + } + } + + private void DisableOrgan(Entity organEnt) + { + if (!TryComp(organEnt.Comp.Body, out BodyComponent? body)) + return; + + // I hate having to hardcode these checks so much. + if (HasComp(organEnt)) + { + var ev = new OrganDisabledEvent(organEnt); + RaiseLocalEvent(organEnt, ref ev); + } + } } diff --git a/Content.Shared/Body/Systems/SharedBodySystem.PartAppearance.cs b/Content.Shared/Body/Systems/SharedBodySystem.PartAppearance.cs index 1a8f91acad2..347ec487aba 100644 --- a/Content.Shared/Body/Systems/SharedBodySystem.PartAppearance.cs +++ b/Content.Shared/Body/Systems/SharedBodySystem.PartAppearance.cs @@ -20,8 +20,8 @@ private void InitializePartAppearances() SubscribeLocalEvent(OnPartAppearanceStartup); SubscribeLocalEvent(HandleState); - SubscribeLocalEvent(OnPartAttachedToBody); - SubscribeLocalEvent(OnPartDroppedFromBody); + SubscribeLocalEvent(OnPartAttachedToBody); + SubscribeLocalEvent(OnPartDroppedFromBody); } private void OnPartAppearanceStartup(EntityUid uid, BodyPartAppearanceComponent component, ComponentStartup args) @@ -130,7 +130,7 @@ public void ModifyMarkings(EntityUid uid, private void HandleState(EntityUid uid, BodyPartAppearanceComponent component, ref AfterAutoHandleStateEvent args) => ApplyPartMarkings(uid, component); - private void OnPartAttachedToBody(EntityUid uid, BodyComponent component, ref BodyPartAttachedEvent args) + private void OnPartAttachedToBody(EntityUid uid, BodyComponent component, ref BodyPartAddedEvent args) { if (!TryComp(args.Part, out BodyPartAppearanceComponent? partAppearance) || !TryComp(uid, out HumanoidAppearanceComponent? bodyAppearance)) @@ -142,7 +142,7 @@ private void OnPartAttachedToBody(EntityUid uid, BodyComponent component, ref Bo UpdateAppearance(uid, partAppearance); } - private void OnPartDroppedFromBody(EntityUid uid, BodyComponent component, ref BodyPartDroppedEvent args) + private void OnPartDroppedFromBody(EntityUid uid, BodyComponent component, ref BodyPartRemovedEvent args) { if (TerminatingOrDeleted(uid) || TerminatingOrDeleted(args.Part) diff --git a/Content.Shared/Body/Systems/SharedBodySystem.Parts.cs b/Content.Shared/Body/Systems/SharedBodySystem.Parts.cs index 2c6d128f63a..dc088542279 100644 --- a/Content.Shared/Body/Systems/SharedBodySystem.Parts.cs +++ b/Content.Shared/Body/Systems/SharedBodySystem.Parts.cs @@ -2,6 +2,7 @@ using Content.Shared.Body.Events; using Content.Shared.Body.Organ; using Content.Shared.Body.Part; +using Content.Shared.BodyEffects; using Content.Shared.Damage; using Content.Shared.Damage.Prototypes; using Content.Shared.Humanoid; @@ -43,6 +44,14 @@ private void OnMapInit(Entity ent, ref MapInitEvent args) _slots.AddItemSlot(ent, ent.Comp.ContainerName, ent.Comp.ItemInsertionSlot); Dirty(ent, ent.Comp); } + + if (ent.Comp.OnAdd is not null || ent.Comp.OnRemove is not null) + EnsureComp(ent); + + foreach (var connection in ent.Comp.Children.Keys) + { + Containers.EnsureContainer(ent, GetPartSlotContainerId(connection)); + } } private void OnBodyPartRemove(Entity ent, ref ComponentRemove args) @@ -143,6 +152,9 @@ protected virtual void AddPart( Dirty(partEnt, partEnt.Comp); partEnt.Comp.Body = bodyEnt; + if (partEnt.Comp.Enabled && partEnt.Comp.Body is { Valid: true } body) + RaiseLocalEvent(partEnt, new BodyPartComponentsModifyEvent(body, true)); + var ev = new BodyPartAddedEvent(slotId, partEnt); RaiseLocalEvent(bodyEnt, ref ev); AddLeg(partEnt, bodyEnt); @@ -158,6 +170,10 @@ protected virtual void RemovePart( partEnt.Comp.ParentSlot = null; partEnt.Comp.OriginalBody = partEnt.Comp.Body; + + if (partEnt.Comp.Body is { Valid: true } body) + RaiseLocalEvent(partEnt, new BodyPartComponentsModifyEvent(body, false)); + var ev = new BodyPartRemovedEvent(slotId, partEnt); RaiseLocalEvent(bodyEnt, ref ev); RemoveLeg(partEnt, bodyEnt); @@ -268,12 +284,21 @@ private void OnPartEnableChanged(Entity partEnt, ref BodyPart return; partEnt.Comp.Enabled = args.Enabled; - Dirty(partEnt, partEnt.Comp); if (args.Enabled) + { EnablePart(partEnt); + if (partEnt.Comp.Body is { Valid: true } bodyEnt) + RaiseLocalEvent(partEnt, new BodyPartComponentsModifyEvent(bodyEnt, true)); + } else + { DisablePart(partEnt); + if (partEnt.Comp.Body is { Valid: true } bodyEnt) + RaiseLocalEvent(partEnt, new BodyPartComponentsModifyEvent(bodyEnt, false)); + } + + Dirty(partEnt, partEnt.Comp); } private void EnablePart(Entity partEnt) { @@ -309,12 +334,13 @@ private void EnablePart(Entity partEnt) public void ChangeSlotState(Entity partEnt, bool disable) { if (partEnt.Comp.Body is not null + && TryComp(partEnt.Comp.Body, out var inventory) && GetBodyPartCount(partEnt.Comp.Body.Value, partEnt.Comp.PartType) == 1 && TryGetPartSlotContainerName(partEnt.Comp.PartType, out var containerNames)) { foreach (var containerName in containerNames) { - _inventorySystem.SetSlotStatus(partEnt.Comp.Body.Value, containerName, disable); + _inventorySystem.SetSlotStatus(partEnt.Comp.Body.Value, containerName, disable, inventory); var ev = new RefreshInventorySlotsEvent(containerName); RaiseLocalEvent(partEnt.Comp.Body.Value, ev); } @@ -1023,8 +1049,8 @@ private bool TryGetPartSlotContainerName(BodyPartType partType, out HashSet new() { "gloves" }, - BodyPartType.Leg => new() { "shoes" }, + BodyPartType.Hand => new() { "gloves" }, + BodyPartType.Foot => new() { "shoes" }, BodyPartType.Head => new() { "eyes", "ears", "head", "mask" }, _ => new() }; @@ -1045,5 +1071,13 @@ public int GetBodyPartCount(EntityUid bodyId, BodyPartType partType, BodyCompone return count; } + public string GetSlotFromBodyPart(BodyPartComponent part) + { + if (part.Symmetry != BodyPartSymmetry.None) + return $"{part.Symmetry.ToString().ToLower()} {part.PartType.ToString().ToLower()}"; + else + return part.PartType.ToString().ToLower(); + } + #endregion } diff --git a/Content.Shared/Body/Systems/SharedBodySystem.Targeting.cs b/Content.Shared/Body/Systems/SharedBodySystem.Targeting.cs index 45495896bcb..09c3c5fa52d 100644 --- a/Content.Shared/Body/Systems/SharedBodySystem.Targeting.cs +++ b/Content.Shared/Body/Systems/SharedBodySystem.Targeting.cs @@ -62,7 +62,7 @@ public IntegrityJob(SharedBodySystem self, Entity ent, double private void InitializeIntegrityQueue() { _queryTargeting = GetEntityQuery(); - SubscribeLocalEvent(OnBeforeDamageChanged); + SubscribeLocalEvent(OnTryChangePartDamage); SubscribeLocalEvent(OnBodyDamageModify); SubscribeLocalEvent(OnPartDamageModify); SubscribeLocalEvent(OnDamageChanged); @@ -104,7 +104,7 @@ public override void Update(float frameTime) } } - private void OnBeforeDamageChanged(Entity ent, ref BeforeDamageChangedEvent args) + private void OnTryChangePartDamage(Entity ent, ref TryChangePartDamageEvent args) { // If our target has a TargetingComponent, that means they will take limb damage // And if their attacker also has one, then we use that part. @@ -221,6 +221,7 @@ private void OnDamageChanged(Entity partEnt, ref DamageChange var delta = args.DamageDelta; if (args.CanSever + && partEnt.Comp.CanSever && partIdSlot is not null && delta != null && !HasComp(partEnt) diff --git a/Content.Shared/Body/Systems/SharedBodySystem.cs b/Content.Shared/Body/Systems/SharedBodySystem.cs index 013e302633b..966d2fa95b3 100644 --- a/Content.Shared/Body/Systems/SharedBodySystem.cs +++ b/Content.Shared/Body/Systems/SharedBodySystem.cs @@ -1,5 +1,6 @@ using Content.Shared.Damage; using Content.Shared.Movement.Systems; +using Content.Shared.Body.Part; using Content.Shared.Standing; using Robust.Shared.Containers; using Robust.Shared.Prototypes; @@ -42,6 +43,7 @@ public override void Initialize() InitializeBody(); InitializeParts(); + InitializeOrgans(); // To try and mitigate the server load due to integrity checks, we set up a Job Queue. InitializeIntegrityQueue(); InitializePartAppearances(); diff --git a/Content.Shared/BodyEffects/BodyPartEffectComponent.cs b/Content.Shared/BodyEffects/BodyPartEffectComponent.cs new file mode 100644 index 00000000000..72269be1f22 --- /dev/null +++ b/Content.Shared/BodyEffects/BodyPartEffectComponent.cs @@ -0,0 +1,26 @@ +using Robust.Shared.GameStates; +using Robust.Shared.Prototypes; +using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom; + +namespace Content.Shared.BodyEffects; + +[RegisterComponent, NetworkedComponent] +[AutoGenerateComponentPause] +public sealed partial class BodyPartEffectComponent : Component +{ + /// + /// The components that are active on the part and will be refreshed every 5s + /// + [DataField] + public ComponentRegistry Active = new(); + + /// + /// How long to wait between each refresh. + /// Effects can only last at most this long once the organ is removed. + /// + [DataField] + public TimeSpan Delay = TimeSpan.FromSeconds(5); + + [DataField(customTypeSerializer: typeof(TimeOffsetSerializer)), AutoPausedField] + public TimeSpan NextUpdate = TimeSpan.Zero; +} diff --git a/Content.Shared/BodyEffects/BodyPartEffectSystem.cs b/Content.Shared/BodyEffects/BodyPartEffectSystem.cs new file mode 100644 index 00000000000..c814f6dd3b9 --- /dev/null +++ b/Content.Shared/BodyEffects/BodyPartEffectSystem.cs @@ -0,0 +1,95 @@ +using Content.Shared.Body.Part; +using Robust.Shared.Prototypes; +using Robust.Shared.Serialization.Manager; +using Robust.Shared.Timing; +using System.Linq; + +namespace Content.Shared.BodyEffects; +public partial class BodyPartEffectSystem : EntitySystem +{ + [Dependency] private readonly IComponentFactory _compFactory = default!; + [Dependency] private readonly ISerializationManager _serManager = default!; + [Dependency] private readonly IGameTiming _gameTiming = default!; + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnPartComponentsModify); + } + + // While I would love to kill this function, problem is that if we happen to have two parts that add the same + // effect, removing one will remove both of them, since we cant tell what the source of a Component is. + public override void Update(float frameTime) + { + base.Update(frameTime); + + var query = EntityQueryEnumerator(); + var now = _gameTiming.CurTime; + while (query.MoveNext(out var uid, out var comp, out var part)) + { + if (now < comp.NextUpdate || !comp.Active.Any() || part.Body is not { } body) + continue; + + comp.NextUpdate = now + comp.Delay; + AddComponents(body, uid, comp.Active); + } + } + + private void OnPartComponentsModify(Entity partEnt, + ref BodyPartComponentsModifyEvent ev) + { + if (partEnt.Comp.OnAdd != null) + { + if (ev.Add) + AddComponents(ev.Body, partEnt, partEnt.Comp.OnAdd); + else + RemoveComponents(ev.Body, partEnt, partEnt.Comp.OnAdd); + } + + if (partEnt.Comp.OnRemove != null) + { + if (ev.Add) + AddComponents(ev.Body, partEnt, partEnt.Comp.OnRemove); + else + RemoveComponents(ev.Body, partEnt, partEnt.Comp.OnRemove); + } + + Dirty(partEnt, partEnt.Comp); + } + + private void AddComponents(EntityUid body, + EntityUid part, + ComponentRegistry reg, + BodyPartEffectComponent? effectComp = null) + { + if (!Resolve(part, ref effectComp, logMissing: false)) + return; + + foreach (var (key, comp) in reg) + { + var compType = comp.Component.GetType(); + if (HasComp(body, compType)) + continue; + + var newComp = (Component) _serManager.CreateCopy(comp.Component, notNullableOverride: true); + EntityManager.AddComponent(body, newComp, true); + + effectComp.Active[key] = comp; + } + } + + private void RemoveComponents(EntityUid body, + EntityUid part, + ComponentRegistry reg, + BodyPartEffectComponent? effectComp = null) + { + if (!Resolve(part, ref effectComp, logMissing: false)) + return; + + foreach (var (key, comp) in reg) + { + RemComp(body, comp.Component.GetType()); + effectComp.Active.Remove(key); + } + } +} diff --git a/Content.Shared/BodyEffects/OrganEffectComponent.cs b/Content.Shared/BodyEffects/OrganEffectComponent.cs new file mode 100644 index 00000000000..ee6990b2c5e --- /dev/null +++ b/Content.Shared/BodyEffects/OrganEffectComponent.cs @@ -0,0 +1,27 @@ +// We keep this clone of the other component since I don't know yet if I'll need organ specific functions in the future. +using Robust.Shared.GameStates; +using Robust.Shared.Prototypes; +using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom; + +namespace Content.Shared.BodyEffects; + +[RegisterComponent, NetworkedComponent] +[AutoGenerateComponentPause] +public sealed partial class OrganEffectComponent : Component +{ + /// + /// The components that are active on the part and will be refreshed every 5s + /// + [DataField] + public ComponentRegistry Active = new(); + + /// + /// How long to wait between each refresh. + /// Effects can only last at most this long once the organ is removed. + /// + [DataField] + public TimeSpan Delay = TimeSpan.FromSeconds(5); + + [DataField(customTypeSerializer: typeof(TimeOffsetSerializer)), AutoPausedField] + public TimeSpan NextUpdate = TimeSpan.Zero; +} diff --git a/Content.Shared/BodyEffects/OrganEffectSystem.cs b/Content.Shared/BodyEffects/OrganEffectSystem.cs new file mode 100644 index 00000000000..679d9ddef08 --- /dev/null +++ b/Content.Shared/BodyEffects/OrganEffectSystem.cs @@ -0,0 +1,109 @@ +// We keep this clone of the other system since I don't know yet if I'll need organ specific functions in the future. +// will delete or refactor as time goes on. +using Content.Shared.Body.Organ; +using Robust.Shared.Prototypes; +using Robust.Shared.Serialization.Manager; +using Robust.Shared.Timing; +using System.Linq; +using Robust.Shared.Network; + + +namespace Content.Shared.BodyEffects; +public partial class OrganEffectSystem : EntitySystem +{ + [Dependency] private readonly IComponentFactory _compFactory = default!; + [Dependency] private readonly ISerializationManager _serManager = default!; + [Dependency] private readonly IGameTiming _gameTiming = default!; + [Dependency] private readonly INetManager _net = default!; + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnOrganComponentsModify); + } + + // While I would love to kill this function, problem is that if we happen to have two parts that add the same + // effect, removing one will remove both of them, since we cant tell what the source of a Component is. + public override void Update(float frameTime) + { + base.Update(frameTime); + + if (!_net.IsServer) // TODO: Kill this once I figure out whats breaking the Diagnostic Cybernetics. + return; + + var query = EntityQueryEnumerator(); + var now = _gameTiming.CurTime; + while (query.MoveNext(out var uid, out var comp, out var part)) + { + if (now < comp.NextUpdate || !comp.Active.Any() || part.Body is not { } body) + continue; + + comp.NextUpdate = now + comp.Delay; + AddComponents(body, uid, comp.Active); + } + } + + private void OnOrganComponentsModify(Entity organEnt, + ref OrganComponentsModifyEvent ev) + { + if (!_net.IsServer) // TODO: Kill this once I figure out whats breaking the Diagnostic Cybernetics. + return; + + if (organEnt.Comp.OnAdd != null) + { + if (ev.Add) + AddComponents(ev.Body, organEnt, organEnt.Comp.OnAdd); + else + RemoveComponents(ev.Body, organEnt, organEnt.Comp.OnAdd); + } + + if (organEnt.Comp.OnRemove != null) + { + if (ev.Add) + AddComponents(ev.Body, organEnt, organEnt.Comp.OnRemove); + else + RemoveComponents(ev.Body, organEnt, organEnt.Comp.OnRemove); + } + } + + private void AddComponents(EntityUid body, + EntityUid part, + ComponentRegistry reg, + OrganEffectComponent? effectComp = null) + { + if (!Resolve(part, ref effectComp, logMissing: false)) + return; + + foreach (var (key, comp) in reg) + { + var compType = comp.Component.GetType(); + if (HasComp(body, compType)) + continue; + + var newComp = (Component) _serManager.CreateCopy(comp.Component, notNullableOverride: true); + newComp.Owner = body; + EntityManager.AddComponent(body, newComp, true); + effectComp.Active[key] = comp; + if (newComp.NetSyncEnabled) + { + Dirty(body, newComp); + Dirty(part, effectComp); + } + } + } + + private void RemoveComponents(EntityUid body, + EntityUid part, + ComponentRegistry reg, + OrganEffectComponent? effectComp = null) + { + if (!Resolve(part, ref effectComp, logMissing: false)) + return; + + foreach (var (key, comp) in reg) + { + RemComp(body, comp.Component.GetType()); + effectComp.Active.Remove(key); + } + } +} diff --git a/Content.Shared/BodyEffects/Subsystems/GenerateChildPart/GenerateChildPartComponent.cs b/Content.Shared/BodyEffects/Subsystems/GenerateChildPart/GenerateChildPartComponent.cs new file mode 100644 index 00000000000..289c4c47492 --- /dev/null +++ b/Content.Shared/BodyEffects/Subsystems/GenerateChildPart/GenerateChildPartComponent.cs @@ -0,0 +1,18 @@ +using Robust.Shared.GameStates; +using Robust.Shared.Prototypes; + +namespace Content.Shared.BodyEffects.Subsystems; + +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +public sealed partial class GenerateChildPartComponent : Component +{ + + [DataField(required: true)] + public EntProtoId Id = ""; + + [DataField, AutoNetworkedField] + public EntityUid? ChildPart; + + [DataField] + public bool Destroyed = false; +} diff --git a/Content.Shared/BodyEffects/Subsystems/GenerateChildPart/GenerateChildPartSystem.cs b/Content.Shared/BodyEffects/Subsystems/GenerateChildPart/GenerateChildPartSystem.cs new file mode 100644 index 00000000000..74455802f96 --- /dev/null +++ b/Content.Shared/BodyEffects/Subsystems/GenerateChildPart/GenerateChildPartSystem.cs @@ -0,0 +1,65 @@ +using Content.Shared.Body.Part; +using Content.Shared.Body.Systems; +using Content.Shared.Body.Events; +using Robust.Shared.Map; +using Robust.Shared.Timing; +using Robust.Shared.Network; +using System.Numerics; + +namespace Content.Shared.BodyEffects.Subsystems; + +public sealed class GenerateChildPartSystem : EntitySystem +{ + [Dependency] private readonly SharedBodySystem _bodySystem = default!; + [Dependency] private readonly IGameTiming _timing = default!; + [Dependency] private readonly INetManager _net = default!; + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnPartComponentsModify); + } + + private void OnPartComponentsModify(EntityUid uid, GenerateChildPartComponent component, ref BodyPartComponentsModifyEvent args) + { + if (args.Add) + CreatePart(uid, component); + //else + //DeletePart(uid, component); + } + + private void CreatePart(EntityUid uid, GenerateChildPartComponent component) + { + if (!TryComp(uid, out BodyPartComponent? partComp) + || partComp.Body is null) + return; + + if (_net.IsServer) + { + var childPart = Spawn(component.Id, new EntityCoordinates(partComp.Body.Value, Vector2.Zero)); + + if (!TryComp(childPart, out BodyPartComponent? childPartComp)) + return; + + var slotName = _bodySystem.GetSlotFromBodyPart(childPartComp); + _bodySystem.TryCreatePartSlot(uid, slotName, childPartComp.PartType, out var _); + _bodySystem.AttachPart(uid, slotName, childPart, partComp, childPartComp); + component.ChildPart = childPart; + Dirty(childPart, childPartComp); + } + + _bodySystem.ChangeSlotState((uid, partComp), false); + } + + private void DeletePart(EntityUid uid, GenerateChildPartComponent component) + { + if (!TryComp(uid, out BodyPartComponent? partComp)) + return; + + _bodySystem.ChangeSlotState((uid, partComp), true); + var ev = new BodyPartDroppedEvent((uid, partComp)); + RaiseLocalEvent(uid, ref ev); + QueueDel(uid); + } +} + diff --git a/Content.Shared/Cybernetics/CyberneticsComponent.cs b/Content.Shared/Cybernetics/CyberneticsComponent.cs new file mode 100644 index 00000000000..36c9754cce6 --- /dev/null +++ b/Content.Shared/Cybernetics/CyberneticsComponent.cs @@ -0,0 +1,16 @@ +using Robust.Shared.GameStates; + +namespace Content.Shared.Cybernetics; + +/// +/// Component for cybernetic implants that can be installed in entities +/// +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +public sealed partial class CyberneticsComponent : Component { + + /// + /// Is the cybernetic implant disabled by EMPs, etc? + /// + [DataField, AutoNetworkedField] + public bool Disabled = false; +} diff --git a/Content.Shared/Damage/Systems/DamageableSystem.cs b/Content.Shared/Damage/Systems/DamageableSystem.cs index 5a3ff778574..4e42fc5d251 100644 --- a/Content.Shared/Damage/Systems/DamageableSystem.cs +++ b/Content.Shared/Damage/Systems/DamageableSystem.cs @@ -145,10 +145,16 @@ public void DamageChanged(EntityUid uid, DamageableComponent component, DamageSp return damage; } - var before = new BeforeDamageChangedEvent(damage, origin, targetPart, canSever ?? true, canEvade ?? false, partMultiplier ?? 1.00f); + var before = new BeforeDamageChangedEvent(damage, origin, targetPart); RaiseLocalEvent(uid.Value, ref before); - if (before.Cancelled || before.Evaded) + if (before.Cancelled) + return null; + + var partDamage = new TryChangePartDamageEvent(damage, origin, targetPart, canSever ?? true, canEvade ?? false, partMultiplier ?? 1.00f); + RaiseLocalEvent(uid.Value, ref partDamage); + + if (partDamage.Evaded || partDamage.Cancelled) return null; // Apply resistances @@ -228,6 +234,17 @@ public void SetAllDamage(EntityUid uid, DamageableComponent component, FixedPoin // Setting damage does not count as 'dealing' damage, even if it is set to a larger value, so we pass an // empty damage delta. DamageChanged(uid, component, new DamageSpecifier()); + + // Shitmed Start + if (HasComp(uid)) + foreach (var (part, _) in _body.GetBodyChildren(uid)) + { + if (!TryComp(part, out DamageableComponent? damageComp)) + continue; + + SetAllDamage(part, damageComp, newValue); + } + // Shitmed End } public void SetDamageModifierSetId(EntityUid uid, string damageModifierSetId, DamageableComponent? comp = null) @@ -271,11 +288,6 @@ private void OnRejuvenate(EntityUid uid, DamageableComponent component, Rejuvena TryComp(uid, out var thresholds); _mobThreshold.SetAllowRevives(uid, true, thresholds); // do this so that the state changes when we set the damage SetAllDamage(uid, component, 0); - // Shitmed Start - if (HasComp(uid)) - foreach (var part in _body.GetBodyChildren(uid)) - RaiseLocalEvent(part.Id, new RejuvenateEvent()); - // Shitmed End _mobThreshold.SetAllowRevives(uid, false, thresholds); } @@ -306,6 +318,16 @@ private void DamageableHandleState(EntityUid uid, DamageableComponent component, /// [ByRefEvent] public record struct BeforeDamageChangedEvent( + DamageSpecifier Damage, + EntityUid? Origin = null, + TargetBodyPart? TargetPart = null, + bool Cancelled = false); + + /// + /// Raised on parts before damage is done so we can cancel the damage if they evade. + /// + [ByRefEvent] + public record struct TryChangePartDamageEvent( DamageSpecifier Damage, EntityUid? Origin = null, TargetBodyPart? TargetPart = null, diff --git a/Content.Shared/Damage/Systems/SharedGodmodeSystem.cs b/Content.Shared/Damage/Systems/SharedGodmodeSystem.cs index d904c211eea..ab46684a6f7 100644 --- a/Content.Shared/Damage/Systems/SharedGodmodeSystem.cs +++ b/Content.Shared/Damage/Systems/SharedGodmodeSystem.cs @@ -2,13 +2,15 @@ using Content.Shared.Rejuvenate; using Content.Shared.Slippery; using Content.Shared.StatusEffect; +using Content.Shared.Body.Systems; +using Content.Shared.Targeting; namespace Content.Shared.Damage.Systems; public abstract class SharedGodmodeSystem : EntitySystem { [Dependency] private readonly DamageableSystem _damageable = default!; - + [Dependency] private readonly SharedBodySystem _bodySystem = default!; public override void Initialize() { base.Initialize(); @@ -49,7 +51,12 @@ public virtual void EnableGodmode(EntityUid uid, GodmodeComponent? godmode = nul } // Rejuv to cover other stuff + RaiseLocalEvent(uid, new RejuvenateEvent()); + foreach (var (id, _) in _bodySystem.GetBodyChildren(uid)) + { + EnableGodmode(id); + } } public virtual void DisableGodmode(EntityUid uid, GodmodeComponent? godmode = null) @@ -63,6 +70,10 @@ public virtual void DisableGodmode(EntityUid uid, GodmodeComponent? godmode = nu } RemComp(uid); + foreach (var (id, _) in _bodySystem.GetBodyChildren(uid)) + { + DisableGodmode(id); + } } /// diff --git a/Content.Shared/Eye/Blinding/Systems/BlindableSystem.cs b/Content.Shared/Eye/Blinding/Systems/BlindableSystem.cs index 24eed3adcf5..57d087125d2 100644 --- a/Content.Shared/Eye/Blinding/Systems/BlindableSystem.cs +++ b/Content.Shared/Eye/Blinding/Systems/BlindableSystem.cs @@ -87,6 +87,17 @@ public void SetMinDamage(Entity blindable, int amount) blindable.Comp.MinDamage = amount; UpdateEyeDamage(blindable, false); } + + public void TransferBlindness(BlindableComponent newSight, BlindableComponent oldSight, EntityUid newEntity) + { + newSight.IsBlind = oldSight.IsBlind; + newSight.EyeDamage = oldSight.EyeDamage; + newSight.LightSetup = oldSight.LightSetup; + newSight.GraceFrame = oldSight.GraceFrame; + newSight.MinDamage = oldSight.MinDamage; + newSight.MaxDamage = oldSight.MaxDamage; + UpdateEyeDamage((newEntity, newSight), true); + } } /// diff --git a/Content.Shared/Input/ContentKeyFunctions.cs b/Content.Shared/Input/ContentKeyFunctions.cs index 699acc87ad3..2727a400a40 100644 --- a/Content.Shared/Input/ContentKeyFunctions.cs +++ b/Content.Shared/Input/ContentKeyFunctions.cs @@ -64,10 +64,13 @@ public static class ContentKeyFunctions public static readonly BoundKeyFunction TargetHead = "TargetHead"; public static readonly BoundKeyFunction TargetTorso = "TargetTorso"; public static readonly BoundKeyFunction TargetLeftArm = "TargetLeftArm"; + public static readonly BoundKeyFunction TargetLeftHand = "TargetLeftHand"; public static readonly BoundKeyFunction TargetRightArm = "TargetRightArm"; + public static readonly BoundKeyFunction TargetRightHand = "TargetRightHand"; public static readonly BoundKeyFunction TargetLeftLeg = "TargetLeftLeg"; + public static readonly BoundKeyFunction TargetLeftFoot = "TargetLeftFoot"; public static readonly BoundKeyFunction TargetRightLeg = "TargetRightLeg"; - + public static readonly BoundKeyFunction TargetRightFoot = "TargetRightFoot"; public static readonly BoundKeyFunction ArcadeUp = "ArcadeUp"; public static readonly BoundKeyFunction ArcadeDown = "ArcadeDown"; public static readonly BoundKeyFunction ArcadeLeft = "ArcadeLeft"; diff --git a/Content.Shared/Medical/Surgery/Conditions/SurgeryComponentConditionComponent.cs b/Content.Shared/Medical/Surgery/Conditions/SurgeryComponentConditionComponent.cs new file mode 100644 index 00000000000..3f0fb6305c0 --- /dev/null +++ b/Content.Shared/Medical/Surgery/Conditions/SurgeryComponentConditionComponent.cs @@ -0,0 +1,16 @@ +using Content.Shared.Body.Part; +using Robust.Shared.GameStates; +using Robust.Shared.Prototypes; + +namespace Content.Shared.Medical.Surgery.Conditions; + +[RegisterComponent, NetworkedComponent] +public sealed partial class SurgeryComponentConditionComponent : Component +{ + [DataField] + public ComponentRegistry Component; + + [DataField] + public bool Inverse; + +} \ No newline at end of file diff --git a/Content.Shared/Medical/Surgery/SharedSurgerySystem.Steps.cs b/Content.Shared/Medical/Surgery/SharedSurgerySystem.Steps.cs index 2bde1f4c868..476a23a21b2 100644 --- a/Content.Shared/Medical/Surgery/SharedSurgerySystem.Steps.cs +++ b/Content.Shared/Medical/Surgery/SharedSurgerySystem.Steps.cs @@ -70,7 +70,7 @@ private void OnToolStep(Entity ent, ref SurgeryStepEvent a { foreach (var reg in ent.Comp.Tool.Values) { - if (!AnyHaveComp(args.Tools, reg.Component, out var tool)) + if (!AnyHaveComp(args.Tools, reg.Component, out var tool, out _)) return; if (_net.IsServer && @@ -93,6 +93,17 @@ private void OnToolStep(Entity ent, ref SurgeryStepEvent a } } + if (ent.Comp.BodyAdd != null) + { + foreach (var reg in ent.Comp.BodyAdd.Values) + { + var compType = reg.Component.GetType(); + if (HasComp(args.Body, compType)) + continue; + AddComp(args.Body, _compFactory.GetComponent(compType)); + } + } + if (ent.Comp.Remove != null) { foreach (var reg in ent.Comp.Remove.Values) @@ -148,6 +159,18 @@ private void OnToolCheck(Entity ent, ref SurgeryStepComple } } + if (ent.Comp.BodyAdd != null) + { + foreach (var reg in ent.Comp.BodyAdd.Values) + { + if (!HasComp(args.Body, reg.Component.GetType())) + { + args.Cancelled = true; + return; + } + } + } + if (ent.Comp.BodyRemove != null) { foreach (var reg in ent.Comp.BodyRemove.Values) @@ -193,21 +216,21 @@ private void OnToolCanPerform(Entity ent, ref SurgeryCanPe if (ent.Comp.Tool != null) { - args.ValidTools ??= new HashSet(); + args.ValidTools ??= new Dictionary(); foreach (var reg in ent.Comp.Tool.Values) { - if (!AnyHaveComp(args.Tools, reg.Component, out var withComp)) + if (!AnyHaveComp(args.Tools, reg.Component, out var tool, out var speed)) { args.Invalid = StepInvalidReason.MissingTool; - if (reg.Component is ISurgeryToolComponent tool) - args.Popup = $"You need {tool.ToolName} to perform this step!"; + if (reg.Component is ISurgeryToolComponent required) + args.Popup = $"You need {required.ToolName} to perform this step!"; return; } - args.ValidTools.Add(withComp); + args.ValidTools[tool] = speed; } } } @@ -250,11 +273,10 @@ private void OnTendWoundsStep(Entity ent, ref bonus *= 0.2; var adjustedDamage = new DamageSpecifier(ent.Comp.Damage); - var bonusPerType = bonus / group.Length; foreach (var type in group) { - adjustedDamage.DamageDict[type] -= bonusPerType; + adjustedDamage.DamageDict[type] -= bonus; } var ev = new SurgeryStepDamageEvent(args.User, args.Body, args.Part, args.Surgery, adjustedDamage, 0.5f); @@ -597,28 +619,41 @@ private void OnSurgeryTargetStepChosen(Entity ent, ref S if (!CanPerformStep(user, body, part, step, true, out _, out _, out var validTools)) return; - if (_net.IsServer && validTools?.Count > 0) + // make the doafter longer for ghetto tools, or shorter for advanced ones + var speed = 1f; + var usedEv = new SurgeryToolUsedEvent(user, body); + // We need to check for nullability because of surgeries that dont require a tool, like Cavity Implants + if (validTools?.Count > 0) { - foreach (var tool in validTools) + foreach (var (tool, toolSpeed) in validTools) { - if (TryComp(tool, out SurgeryToolComponent? toolComp) && - toolComp.EndSound != null) + RaiseLocalEvent(tool, ref usedEv); + if (usedEv.Cancelled) + return; + + speed *= toolSpeed; + } + + if (_net.IsServer) + { + foreach (var tool in validTools.Keys) { - _audio.PlayEntity(toolComp.StartSound, user, tool); + if (TryComp(tool, out SurgeryToolComponent? toolComp) && + toolComp.EndSound != null) + { + _audio.PlayEntity(toolComp.StartSound, user, tool); + } } } } + if (TryComp(body, out TransformComponent? xform)) _rotateToFace.TryFaceCoordinates(user, _transform.GetMapCoordinates(body, xform).Position); var ev = new SurgeryDoAfterEvent(args.Surgery, args.Step); - // TODO: Make this serialized on a per surgery step basis, and also add penalties based on ghetto tools. - var duration = 2f; - if (TryComp(user, out SurgerySpeedModifierComponent? surgerySpeedMod) - && surgerySpeedMod is not null) - duration = duration / surgerySpeedMod.SpeedModifier; - + // TODO: Serialize each surgery with a custom duration. + var duration = GetSurgeryDuration(step, user, body, speed); var doAfter = new DoAfterArgs(EntityManager, user, TimeSpan.FromSeconds(duration), ev, body, part) { BreakOnUserMove = true, @@ -646,6 +681,19 @@ private void OnSurgeryTargetStepChosen(Entity ent, ref S } } + private float GetSurgeryDuration(EntityUid surgeryStep, EntityUid user, EntityUid target, float toolSpeed) + { + if (!TryComp(surgeryStep, out SurgeryStepComponent? stepComp)) + return 2f; // Shouldnt really happen but just a failsafe. + + var speed = toolSpeed; + + if (TryComp(user, out SurgerySpeedModifierComponent? surgerySpeedMod)) + speed *= surgerySpeedMod.SpeedModifier; + + return stepComp.Duration / speed; + } + private (Entity Surgery, int Step)? GetNextStep(EntityUid body, EntityUid part, Entity surgery, List requirements) { if (!Resolve(surgery, ref surgery.Comp)) @@ -705,7 +753,7 @@ public bool PreviousStepsComplete(EntityUid body, EntityUid part, Entity? validTools) + out Dictionary? validTools) { var type = BodyPartType.Other; if (TryComp(part, out BodyPartComponent? partComp)) @@ -759,18 +807,20 @@ public bool IsStepComplete(EntityUid body, EntityUid part, EntProtoId step, Enti return !ev.Cancelled; } - private bool AnyHaveComp(List tools, IComponent component, out EntityUid withComp) + private bool AnyHaveComp(List tools, IComponent component, out EntityUid withComp, out float speed) { foreach (var tool in tools) { - if (HasComp(tool, component.GetType())) + if (EntityManager.TryGetComponent(tool, component.GetType(), out var found) && found is ISurgeryToolComponent toolComp) { withComp = tool; + speed = toolComp.Speed; return true; } } - withComp = default; + withComp = EntityUid.Invalid; + speed = 1f; return false; } } diff --git a/Content.Shared/Medical/Surgery/SharedSurgerySystem.cs b/Content.Shared/Medical/Surgery/SharedSurgerySystem.cs index 7fa0f94525e..db8f65c33a1 100644 --- a/Content.Shared/Medical/Surgery/SharedSurgerySystem.cs +++ b/Content.Shared/Medical/Surgery/SharedSurgerySystem.cs @@ -58,6 +58,7 @@ public override void Initialize() SubscribeLocalEvent(OnTargetDoAfter); SubscribeLocalEvent(OnCloseIncisionValid); //SubscribeLocalEvent(OnLarvaValid); + SubscribeLocalEvent(OnComponentConditionValid); SubscribeLocalEvent(OnPartConditionValid); SubscribeLocalEvent(OnOrganConditionValid); SubscribeLocalEvent(OnWoundedValid); @@ -127,6 +128,21 @@ private void OnWoundedValid(Entity ent, ref Su if (infected != null && infected.SpawnedLarva != null) args.Cancelled = true; }*/ + + private void OnComponentConditionValid(Entity ent, ref SurgeryValidEvent args) + { + var present = true; + foreach (var reg in ent.Comp.Component.Values) + { + var compType = reg.Component.GetType(); + if (!HasComp(args.Part, compType)) + present = false; + } + + if (ent.Comp.Inverse ? present : !present) + args.Cancelled = true; + } + private void OnPartConditionValid(Entity ent, ref SurgeryValidEvent args) { if (!TryComp(args.Part, out var part)) @@ -177,7 +193,7 @@ private void OnPartRemovedConditionValid(Entity? ValidTools = null -) : IInventoryRelayEvent; \ No newline at end of file + Dictionary? ValidTools = null +) : IInventoryRelayEvent; diff --git a/Content.Shared/Medical/Surgery/Steps/SurgeryStepComponent.cs b/Content.Shared/Medical/Surgery/Steps/SurgeryStepComponent.cs index 1c6e801a42c..529fc5a566f 100644 --- a/Content.Shared/Medical/Surgery/Steps/SurgeryStepComponent.cs +++ b/Content.Shared/Medical/Surgery/Steps/SurgeryStepComponent.cs @@ -14,9 +14,15 @@ public sealed partial class SurgeryStepComponent : Component [DataField] public ComponentRegistry? Add; + [DataField] + public ComponentRegistry? BodyAdd; + [DataField] public ComponentRegistry? Remove; [DataField] public ComponentRegistry? BodyRemove; + + [DataField] + public float Duration = 2f; } diff --git a/Content.Shared/Medical/Surgery/Tools/BoneGelComponent.cs b/Content.Shared/Medical/Surgery/Tools/BoneGelComponent.cs index 50f614afe16..601c8bc8a46 100644 --- a/Content.Shared/Medical/Surgery/Tools/BoneGelComponent.cs +++ b/Content.Shared/Medical/Surgery/Tools/BoneGelComponent.cs @@ -8,4 +8,7 @@ public sealed partial class BoneGelComponent : Component, ISurgeryToolComponent public string ToolName => "bone gel"; public bool? Used { get; set; } = null; -} \ No newline at end of file + + [DataField] + public float Speed { get; set; } = 1f; +} diff --git a/Content.Shared/Medical/Surgery/Tools/BoneSawComponent.cs b/Content.Shared/Medical/Surgery/Tools/BoneSawComponent.cs index 2b7c76eeac9..8392dad89bf 100644 --- a/Content.Shared/Medical/Surgery/Tools/BoneSawComponent.cs +++ b/Content.Shared/Medical/Surgery/Tools/BoneSawComponent.cs @@ -7,4 +7,6 @@ public sealed partial class BoneSawComponent : Component, ISurgeryToolComponent { public string ToolName => "a bone saw"; public bool? Used { get; set; } = null; -} \ No newline at end of file + [DataField] + public float Speed { get; set; } = 1f; +} diff --git a/Content.Shared/Medical/Surgery/Tools/BoneSetterComponent.cs b/Content.Shared/Medical/Surgery/Tools/BoneSetterComponent.cs index e68d64b4075..2a4edc4680b 100644 --- a/Content.Shared/Medical/Surgery/Tools/BoneSetterComponent.cs +++ b/Content.Shared/Medical/Surgery/Tools/BoneSetterComponent.cs @@ -3,4 +3,10 @@ namespace Content.Shared.Medical.Surgery.Tools; [RegisterComponent, NetworkedComponent] -public sealed partial class BoneSetterComponent : Component; \ No newline at end of file +public sealed partial class BoneSetterComponent : Component, ISurgeryToolComponent +{ + public string ToolName => "a bone setter"; + public bool? Used { get; set; } = null; + [DataField] + public float Speed { get; set; } = 1f; +} diff --git a/Content.Shared/Medical/Surgery/Tools/CauteryComponent.cs b/Content.Shared/Medical/Surgery/Tools/CauteryComponent.cs index 9a56f809733..a81315d69fc 100644 --- a/Content.Shared/Medical/Surgery/Tools/CauteryComponent.cs +++ b/Content.Shared/Medical/Surgery/Tools/CauteryComponent.cs @@ -7,4 +7,6 @@ public sealed partial class CauteryComponent : Component, ISurgeryToolComponent { public string ToolName => "a cautery"; public bool? Used { get; set; } = null; -} \ No newline at end of file + [DataField] + public float Speed { get; set; } = 1f; +} diff --git a/Content.Shared/Medical/Surgery/Tools/DrillComponent.cs b/Content.Shared/Medical/Surgery/Tools/DrillComponent.cs new file mode 100644 index 00000000000..1fa7c0726cb --- /dev/null +++ b/Content.Shared/Medical/Surgery/Tools/DrillComponent.cs @@ -0,0 +1,12 @@ +using Robust.Shared.GameStates; + +namespace Content.Shared.Medical.Surgery.Tools; + +[RegisterComponent, NetworkedComponent] +public sealed partial class DrillComponent : Component, ISurgeryToolComponent +{ + public string ToolName => "a drill"; + public bool? Used { get; set; } = null; + [DataField] + public float Speed { get; set; } = 1f; +} diff --git a/Content.Shared/Medical/Surgery/Tools/HemostatComponent.cs b/Content.Shared/Medical/Surgery/Tools/HemostatComponent.cs index 3e869e1c094..76934fff083 100644 --- a/Content.Shared/Medical/Surgery/Tools/HemostatComponent.cs +++ b/Content.Shared/Medical/Surgery/Tools/HemostatComponent.cs @@ -7,4 +7,6 @@ public sealed partial class HemostatComponent : Component, ISurgeryToolComponent { public string ToolName => "a hemostat"; public bool? Used { get; set; } = null; -} \ No newline at end of file + [DataField] + public float Speed { get; set; } = 1f; +} diff --git a/Content.Shared/Medical/Surgery/Tools/ISurgeryToolComponent.cs b/Content.Shared/Medical/Surgery/Tools/ISurgeryToolComponent.cs index 7fb4491f0c5..af9eb37e5a8 100644 --- a/Content.Shared/Medical/Surgery/Tools/ISurgeryToolComponent.cs +++ b/Content.Shared/Medical/Surgery/Tools/ISurgeryToolComponent.cs @@ -8,4 +8,11 @@ public interface ISurgeryToolComponent // Mostly intended for discardable or non-reusable tools. [DataField] public bool? Used { get; set; } -} \ No newline at end of file + + /// + /// Divide the doafter's duration by this value. + /// This is per-type so you can have something that's a good scalpel but a bad retractor. + /// + [DataField] + public float Speed { get; set; } +} diff --git a/Content.Shared/Medical/Surgery/Tools/RetractorComponent.cs b/Content.Shared/Medical/Surgery/Tools/RetractorComponent.cs index bf57c70729a..a81f6d6eb60 100644 --- a/Content.Shared/Medical/Surgery/Tools/RetractorComponent.cs +++ b/Content.Shared/Medical/Surgery/Tools/RetractorComponent.cs @@ -7,4 +7,6 @@ public sealed partial class RetractorComponent : Component, ISurgeryToolComponen { public string ToolName => "a retractor"; public bool? Used { get; set; } = null; -} \ No newline at end of file + [DataField] + public float Speed { get; set; } = 1f; +} diff --git a/Content.Shared/Medical/Surgery/Tools/ScalpelComponent.cs b/Content.Shared/Medical/Surgery/Tools/ScalpelComponent.cs index 40fb4af556d..394692c838a 100644 --- a/Content.Shared/Medical/Surgery/Tools/ScalpelComponent.cs +++ b/Content.Shared/Medical/Surgery/Tools/ScalpelComponent.cs @@ -7,4 +7,6 @@ public sealed partial class ScalpelComponent : Component, ISurgeryToolComponent { public string ToolName => "a scalpel"; public bool? Used { get; set; } = null; -} \ No newline at end of file + [DataField] + public float Speed { get; set; } = 1f; +} diff --git a/Content.Shared/Medical/Surgery/Tools/SurgeryToolComponent.cs b/Content.Shared/Medical/Surgery/Tools/SurgeryToolComponent.cs index f0dd96ecb0d..de999ed9285 100644 --- a/Content.Shared/Medical/Surgery/Tools/SurgeryToolComponent.cs +++ b/Content.Shared/Medical/Surgery/Tools/SurgeryToolComponent.cs @@ -13,4 +13,11 @@ public sealed partial class SurgeryToolComponent : Component [DataField, AutoNetworkedField] public SoundSpecifier? EndSound; -} \ No newline at end of file +} + +/// +/// Raised on a tool to see if it can be used in a surgery step. +/// If this is cancelled the step can't be completed. +/// +[ByRefEvent] +public record struct SurgeryToolUsedEvent(EntityUid User, EntityUid Target, bool Cancelled = false); diff --git a/Content.Shared/Medical/Surgery/Tools/SurgeryToolExamineSystem.cs b/Content.Shared/Medical/Surgery/Tools/SurgeryToolExamineSystem.cs new file mode 100644 index 00000000000..6bfbc59b5fe --- /dev/null +++ b/Content.Shared/Medical/Surgery/Tools/SurgeryToolExamineSystem.cs @@ -0,0 +1,65 @@ +using Content.Shared.Body.Organ; +using Content.Shared.Body.Part; +using Content.Shared.Examine; +using Content.Shared.Verbs; +using Robust.Shared.Utility; + +namespace Content.Shared.Medical.Surgery.Tools; + +/// +/// Examining a surgical or ghetto tool shows everything it can be used for. +/// +public sealed class SurgeryToolExamineSystem : EntitySystem +{ + [Dependency] private readonly ExamineSystemShared _examine = default!; + + public override void Initialize() + { + SubscribeLocalEvent>(OnGetVerbs); + + SubscribeLocalEvent(OnExamined); + SubscribeLocalEvent(OnExamined); + SubscribeLocalEvent(OnExamined); + SubscribeLocalEvent(OnExamined); + SubscribeLocalEvent(OnExamined); + SubscribeLocalEvent(OnExamined); + SubscribeLocalEvent(OnExamined); + SubscribeLocalEvent(OnExamined); + SubscribeLocalEvent(OnExamined); + + SubscribeLocalEvent(OnExamined); + SubscribeLocalEvent(OnExamined); + } + + private void OnGetVerbs(Entity ent, ref GetVerbsEvent args) + { + if (!args.CanInteract || !args.CanAccess) + return; + + var msg = FormattedMessage.FromMarkupOrThrow(Loc.GetString("surgery-tool-header")); + msg.PushNewline(); + var ev = new SurgeryToolExaminedEvent(msg); + RaiseLocalEvent(ent, ref ev); + + _examine.AddDetailedExamineVerb(args, ent.Comp, ev.Message, + Loc.GetString("surgery-tool-examinable-verb-text"), "/Textures/Objects/Specific/Medical/Surgery/scalpel.rsi/scalpel.png", + Loc.GetString("surgery-tool-examinable-verb-message")); + } + + private void OnExamined(EntityUid uid, ISurgeryToolComponent comp, ref SurgeryToolExaminedEvent args) + { + var msg = args.Message; + var color = comp.Speed switch + { + < 1f => "red", + > 1f => "green", + _ => "white" + }; + var key = "surgery-tool-" + (comp.Used == true ? "used" : "unlimited"); + var speed = comp.Speed.ToString("N2"); // 2 decimal places to not get trolled by float + msg.PushMarkup(Loc.GetString(key, ("tool", comp.ToolName), ("speed", speed), ("color", color))); + } +} + +[ByRefEvent] +public record struct SurgeryToolExaminedEvent(FormattedMessage Message); diff --git a/Content.Shared/Medical/Surgery/Tools/SurgeryToolsConditionsSystem.cs b/Content.Shared/Medical/Surgery/Tools/SurgeryToolsConditionsSystem.cs new file mode 100644 index 00000000000..4e86b764d9e --- /dev/null +++ b/Content.Shared/Medical/Surgery/Tools/SurgeryToolsConditionsSystem.cs @@ -0,0 +1,57 @@ +using Content.Shared.Item.ItemToggle.Components; +using Content.Shared.Popups; +using Content.Shared.Smoking; +using Content.Shared.Smoking.Components; +using Content.Shared.Weapons.Ranged; +using Content.Shared.Weapons.Ranged.Components; +using Content.Shared.Weapons.Ranged.Events; + +namespace Content.Shared.Medical.Surgery.Tools; + +/// +/// Prevents using esword or welder when off, laser when no charges. +/// +public sealed class SurgeryToolConditionsSystem : EntitySystem +{ + [Dependency] private readonly SharedPopupSystem _popup = default!; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnToggleUsed); + SubscribeLocalEvent(OnGunUsed); + SubscribeLocalEvent(OnMatchUsed); + } + + private void OnToggleUsed(Entity ent, ref SurgeryToolUsedEvent args) + { + if (ent.Comp.Activated) + return; + + _popup.PopupEntity(Loc.GetString("surgery-tool-turn-on"), ent, args.User); + args.Cancelled = true; + } + + private void OnGunUsed(Entity ent, ref SurgeryToolUsedEvent args) + { + var coords = Transform(args.User).Coordinates; + var ev = new TakeAmmoEvent(1, new List<(EntityUid? Entity, IShootable Shootable)>(), coords, args.User); + if (ev.Ammo.Count > 0) + return; + + _popup.PopupEntity(Loc.GetString("surgery-tool-reload"), ent, args.User); + args.Cancelled = true; + } + + private void OnMatchUsed(Entity ent, ref SurgeryToolUsedEvent args) + { + var state = ent.Comp.CurrentState; + if (state == SmokableState.Lit) + return; + + var key = "surgery-tool-match-" + (state == SmokableState.Burnt ? "replace" : "light"); + _popup.PopupEntity(Loc.GetString(key), ent, args.User); + args.Cancelled = true; + } +} diff --git a/Content.Shared/Medical/Surgery/Tools/SurgicalDrillComponent.cs b/Content.Shared/Medical/Surgery/Tools/SurgicalDrillComponent.cs deleted file mode 100644 index c8995edcec8..00000000000 --- a/Content.Shared/Medical/Surgery/Tools/SurgicalDrillComponent.cs +++ /dev/null @@ -1,10 +0,0 @@ -using Robust.Shared.GameStates; - -namespace Content.Shared.Medical.Surgery.Tools; - -[RegisterComponent, NetworkedComponent] -public sealed partial class SurgicalDrillComponent : Component, ISurgeryToolComponent -{ - public string ToolName => "a surgical drill"; - public bool? Used { get; set; } = null; -} \ No newline at end of file diff --git a/Content.Shared/Medical/Surgery/Tools/TendingComponent.cs b/Content.Shared/Medical/Surgery/Tools/TendingComponent.cs new file mode 100644 index 00000000000..365af320040 --- /dev/null +++ b/Content.Shared/Medical/Surgery/Tools/TendingComponent.cs @@ -0,0 +1,15 @@ +using Robust.Shared.GameStates; + +namespace Content.Shared.Medical.Surgery.Tools; + +/// +/// Like Hemostat but lets ghetto tools be used differently for clamping and tending wounds. +/// +[RegisterComponent, NetworkedComponent] +public sealed partial class TendingComponent : Component, ISurgeryToolComponent +{ + public string ToolName => "a wound tender"; + public bool? Used { get; set; } = null; + [DataField] + public float Speed { get; set; } = 1f; +} diff --git a/Content.Shared/Medical/Surgery/Tools/TweezersComponent.cs b/Content.Shared/Medical/Surgery/Tools/TweezersComponent.cs new file mode 100644 index 00000000000..6f0c8b4d294 --- /dev/null +++ b/Content.Shared/Medical/Surgery/Tools/TweezersComponent.cs @@ -0,0 +1,15 @@ +using Robust.Shared.GameStates; + +namespace Content.Shared.Medical.Surgery.Tools; + +/// +/// Like Hemostat but lets ghetto tools be used differently for clamping and removing organs. +/// +[RegisterComponent, NetworkedComponent] +public sealed partial class TweezersComponent : Component, ISurgeryToolComponent +{ + public string ToolName => "tweezers"; + public bool? Used { get; set; } = null; + [DataField] + public float Speed { get; set; } = 1f; +} diff --git a/Content.Shared/Overlays/ShowHealthBarsComponent.cs b/Content.Shared/Overlays/ShowHealthBarsComponent.cs index 48e3162269a..ed9ce4b7653 100644 --- a/Content.Shared/Overlays/ShowHealthBarsComponent.cs +++ b/Content.Shared/Overlays/ShowHealthBarsComponent.cs @@ -7,12 +7,12 @@ namespace Content.Shared.Overlays; /// /// This component allows you to see health bars above damageable mobs. /// -[RegisterComponent, NetworkedComponent] +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] public sealed partial class ShowHealthBarsComponent : Component { /// /// Displays health bars of the damage containers. /// - [DataField("damageContainers", customTypeSerializer: typeof(PrototypeIdListSerializer))] + [DataField("damageContainers", customTypeSerializer: typeof(PrototypeIdListSerializer)), AutoNetworkedField] public List DamageContainers = new(); } diff --git a/Content.Shared/Overlays/ShowHealthIconsComponent.cs b/Content.Shared/Overlays/ShowHealthIconsComponent.cs index c2526c2f401..b212b77289e 100644 --- a/Content.Shared/Overlays/ShowHealthIconsComponent.cs +++ b/Content.Shared/Overlays/ShowHealthIconsComponent.cs @@ -7,12 +7,12 @@ namespace Content.Shared.Overlays; /// /// This component allows you to see health status icons above damageable mobs. /// -[RegisterComponent, NetworkedComponent] +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] public sealed partial class ShowHealthIconsComponent : Component { /// /// Displays health status icons of the damage containers. /// - [DataField("damageContainers", customTypeSerializer: typeof(PrototypeIdListSerializer))] + [DataField("damageContainers", customTypeSerializer: typeof(PrototypeIdListSerializer)), AutoNetworkedField] public List DamageContainers = new(); } diff --git a/Content.Shared/Prying/Components/PryingComponent.cs b/Content.Shared/Prying/Components/PryingComponent.cs index 7a7f304d8f8..650c998f0df 100644 --- a/Content.Shared/Prying/Components/PryingComponent.cs +++ b/Content.Shared/Prying/Components/PryingComponent.cs @@ -3,13 +3,13 @@ namespace Content.Shared.Prying.Components; -[RegisterComponent, NetworkedComponent] +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] public sealed partial class PryingComponent : Component { /// /// Whether the entity can pry open powered doors /// - [DataField("pryPowered")] + [DataField("pryPowered"), AutoNetworkedField] public bool PryPowered = false; /// @@ -22,7 +22,7 @@ public sealed partial class PryingComponent : Component /// Modifier on the prying time. /// Lower values result in more time. /// - [DataField("speedModifier")] + [DataField("speedModifier"), AutoNetworkedField] public float SpeedModifier = 1.0f; /// diff --git a/Content.Shared/Smoking/Components/MatchstickComponent.cs b/Content.Shared/Smoking/Components/MatchstickComponent.cs new file mode 100644 index 00000000000..527553549b5 --- /dev/null +++ b/Content.Shared/Smoking/Components/MatchstickComponent.cs @@ -0,0 +1,28 @@ +using Content.Shared.Smoking.Systems; +using Robust.Shared.Audio; +using Robust.Shared.GameStates; + +namespace Content.Shared.Smoking.Components; + +[RegisterComponent, NetworkedComponent, Access(typeof(SharedMatchstickSystem))] +[AutoGenerateComponentState] +public sealed partial class MatchstickComponent : Component +{ + /// + /// Current state to matchstick. Can be Unlit, Lit or Burnt. + /// + [DataField("state"), AutoNetworkedField] + public SmokableState CurrentState = SmokableState.Unlit; + + /// + /// How long will matchstick last in seconds. + /// + [DataField] + public int Duration = 10; + + /// + /// Sound played when you ignite the matchstick. + /// + [DataField(required: true)] + public SoundSpecifier IgniteSound = default!; +} diff --git a/Content.Shared/Smoking/Systems/SharedMatchstickSystem.cs b/Content.Shared/Smoking/Systems/SharedMatchstickSystem.cs new file mode 100644 index 00000000000..bda75c42d29 --- /dev/null +++ b/Content.Shared/Smoking/Systems/SharedMatchstickSystem.cs @@ -0,0 +1,16 @@ +using Content.Shared.Smoking.Components; + +namespace Content.Shared.Smoking.Systems; + +public abstract class SharedMatchstickSystem : EntitySystem +{ + public virtual bool SetState(Entity ent, SmokableState state) + { + if (ent.Comp.CurrentState == state) + return false; + + ent.Comp.CurrentState = state; + Dirty(ent); + return true; + } +} diff --git a/Content.Shared/Standing/SharedLayingDownSystem.cs b/Content.Shared/Standing/SharedLayingDownSystem.cs index 2f95a06f197..d52986c7a99 100644 --- a/Content.Shared/Standing/SharedLayingDownSystem.cs +++ b/Content.Shared/Standing/SharedLayingDownSystem.cs @@ -6,6 +6,7 @@ using Content.Shared.Mobs.Systems; using Content.Shared.Movement.Systems; using Content.Shared.Body.Components; +using Content.Shared.Body.Organ; using Content.Shared.Standing; using Content.Shared.Popups; using Content.Shared.Stunnable; @@ -145,7 +146,8 @@ public bool TryStandUp(EntityUid uid, LayingDownComponent? layingDown = null, St || !_mobState.IsAlive(uid) || TerminatingOrDeleted(uid) || !TryComp(uid, out var body) - || body.LegEntities.Count == 0) + || body.LegEntities.Count == 0 + || HasComp(uid)) return false; var args = new DoAfterArgs(EntityManager, uid, layingDown.StandingUpTime, new StandingUpDoAfterEvent(), uid) @@ -188,4 +190,4 @@ public enum DropHeldItemsBehavior : byte NoDrop, DropIfStanding, AlwaysDrop -} \ No newline at end of file +} diff --git a/Resources/Locale/en-US/accent/ohio.ftl b/Resources/Locale/en-US/accent/ohio.ftl new file mode 100644 index 00000000000..be191ce9fcd --- /dev/null +++ b/Resources/Locale/en-US/accent/ohio.ftl @@ -0,0 +1,421 @@ +# Gondola +accent-words-gondola-1 = ... + +# Ohio +accent-ohio-prefix-1 = Gyatt dang, +accent-ohio-prefix-2 = Chat... +accent-ohio-prefix-3 = Epic win, +accent-ohio-prefix-4 = Widewawwy... +accent-ohio-prefix-5 = BRO... +accent-ohio-prefix-6 = Call me the rizzler cause, +accent-ohio-prefix-7 = It's giving... + +accent-ohio-suffix-1 = . Like in Ohio. +accent-ohio-suffix-2 = . From Ohio... +accent-ohio-suffix-3 = . Like in Fortnite. +accent-ohio-suffix-4 = . Like from Fortnite. +accent-ohio-suffix-5 = . For the Rizzler. +accent-ohio-suffix-6 = . Chat is this real? +accent-ohio-suffix-7 = . Bro knew what he was doing. +accent-ohio-suffix-8 = . Goofy ahh. +accent-ohio-suffix-9 = . Like erm... what the sigma??? +accent-ohio-suffix-10 = . What the scallop? +accent-ohio-suffix-11 = . It's so over. +accent-ohio-suffix-12 = . I oop!!!!!!11!!!111! +accent-ohio-suffix-13 = . I need to work on my mewing. + +accent-ohio-words-1 = charisma +accent-ohio-words-replace-1 = rizz + +accent-ohio-words-2 = cool +accent-ohio-words-replace-2 = sigma + +accent-ohio-words-3 = amazing +accent-ohio-words-replace-3 = rizzlike + +accent-ohio-words-4 = god +accent-ohio-words-replace-4 = gyatt + +accent-ohio-words-5 = attack +accent-ohio-words-replace-5 = unalive + +accent-ohio-words-6 = kill +accent-ohio-words-replace-6 = unalive + +accent-ohio-words-7 = murder +accent-ohio-words-replace-7 = unalive + +accent-ohio-words-8 = dead +accent-ohio-words-replace-8 = in ohio + +accent-ohio-words-9 = maints +accent-ohio-words-replace-9 = the backrooms + +accent-ohio-words-10 = maintenance +accent-ohio-words-replace-10 = the backrooms + +accent-ohio-words-11 = maint +accent-ohio-words-replace-11 = the backrooms + +accent-ohio-words-12 = attacked +accent-ohio-words-replace-12 = unalived + +accent-ohio-words-13 = nukie +accent-ohio-words-replace-13 = sussy baka impostor from Among Us + +accent-ohio-words-14 = syndicate +accent-ohio-words-replace-14 = sussy baka impostor from Among Us + +accent-ohio-words-15 = syndi +accent-ohio-words-replace-15 = sussy baka impostor from Among Us + +accent-ohio-words-16 = traitor +accent-ohio-words-replace-16 = sussy baka impostor from Among Us + +accent-ohio-words-17 = got +accent-ohio-words-replace-17 = gyatt + +accent-ohio-words-18 = delicious +accent-ohio-words-replace-18 = bussin' + +accent-ohio-words-19 = yummy +accent-ohio-words-replace-19 = bussin' + +accent-ohio-words-20 = women +accent-ohio-words-replace-20 = FEMALES + +accent-ohio-words-21 = girls +accent-ohio-words-replace-21 = FEMALES + +accent-ohio-words-22 = girl +accent-ohio-words-replace-22 = FEMALE + +accent-ohio-words-23 = woman +accent-ohio-words-replace-23 = FEMALE + +accent-ohio-words-24 = miss +accent-ohio-words-replace-24 = FEMALE + +accent-ohio-words-25 = ms +accent-ohio-words-replace-25 = FEMALE + +accent-ohio-words-26 = mrs +accent-ohio-words-replace-26 = FEMALE + +accent-ohio-words-27 = ms. +accent-ohio-words-replace-27 = FEMALE + +accent-ohio-words-28 = mrs. +accent-ohio-words-replace-28 = FEMALE + +accent-ohio-words-29 = bitch +accent-ohio-words-replace-29 = FEMALE + +accent-ohio-words-30 = really +accent-ohio-words-replace-30 = for real + +accent-ohio-words-31 = definitely +accent-ohio-words-replace-31 = lowkey + +accent-ohio-words-32 = mhm +accent-ohio-words-replace-32 = on god + +accent-ohio-words-33 = epic +accent-ohio-words-replace-33 = poggers + +accent-ohio-words-34 = lingium +accent-ohio-words-replace-34 = ligma + +accent-ohio-words-35 = game +accent-ohio-words-replace-35 = roblox + +accent-ohio-words-36 = nah +accent-ohio-words-replace-36 = cope + +accent-ohio-words-37 = weird +accent-ohio-words-replace-37 = sus + +accent-ohio-words-38 = brother +accent-ohio-words-replace-38 = bro + +accent-ohio-words-39 = man +accent-ohio-words-replace-39 = bro + +accent-ohio-words-40 = marijuana +accent-ohio-words-replace-40 = 420 leaf + +accent-ohio-words-41 = weed +accent-ohio-words-replace-41 = 420 leaf + +accent-ohio-words-42 = best +accent-ohio-words-replace-42 = GOAT + +accent-ohio-words-43 = loss +accent-ohio-words-replace-43 = L + +accent-ohio-words-44 = lose +accent-ohio-words-replace-44 = take an L + +accent-ohio-words-45 = lost +accent-ohio-words-replace-45 = took an L + +accent-ohio-words-46 = silly +accent-ohio-words-replace-46 = goofy ahh + +accent-ohio-words-47 = clown +accent-ohio-words-replace-47 = goofy ahh + +accent-ohio-words-48 = funny +accent-ohio-words-replace-48 = goofy + +accent-ohio-words-49 = joke +accent-ohio-words-replace-49 = meme + +accent-ohio-words-50 = idiot +accent-ohio-words-replace-50 = baka + +accent-ohio-words-51 = ugly +accent-ohio-words-replace-51 = rizzless + +accent-ohio-words-52 = smartass +accent-ohio-words-replace-52 = nerd + +accent-ohio-words-53 = smart +accent-ohio-words-replace-53 = nerdlike + +accent-ohio-words-54 = science +accent-ohio-words-replace-54 = nerdland + +accent-ohio-words-55 = scientist +accent-ohio-words-replace-55 = professional nerd + +accent-ohio-words-56 = story +accent-ohio-words-replace-56 = lorepage + +accent-ohio-words-57 = loser +accent-ohio-words-replace-57 = L + Ratio idiot + +accent-ohio-words-58 = nice +accent-ohio-words-replace-58 = rizzlike + +accent-ohio-words-59 = spesos +accent-ohio-words-replace-59 = rizzbucks + +accent-ohio-words-60 = dollars +accent-ohio-words-replace-60 = rizzbucks + +accent-ohio-words-61 = dollar +accent-ohio-words-replace-61 = rizzbuck + +accent-ohio-words-62 = speso +accent-ohio-words-replace-62 = rizzbuck + +accent-ohio-words-63 = money +accent-ohio-words-replace-63 = rizzbucks + +accent-ohio-words-64 = kill you +accent-ohio-words-replace-64 = send you to Brazil + +accent-ohio-words-65 = dick +accent-ohio-words-replace-65 = glizzy + +accent-ohio-words-66 = hot dog +accent-ohio-words-replace-66 = glizzy + +accent-ohio-words-67 = butt +accent-ohio-words-replace-67 = bussy + +accent-ohio-words-68 = bum +accent-ohio-words-replace-68 = bussy + +accent-ohio-words-69 = ass +accent-ohio-words-replace-69 = bussy + +accent-ohio-words-70 = kill yourself +accent-ohio-words-replace-70 = send yourself to Brazil you stupid rizzless citizen of Ohio + +accent-ohio-words-71 = felinid +accent-ohio-words-replace-71 = hecking chonker + +accent-ohio-words-72 = cat +accent-ohio-words-replace-72 = hecking chonker + +accent-ohio-words-73 = kitty +accent-ohio-words-replace-73 = hecking chonker + +accent-ohio-words-74 = ian +accent-ohio-words-replace-74 = hecking chonker + +accent-ohio-words-75 = dog +accent-ohio-words-replace-75 = hecking chonker + +accent-ohio-words-76 = cerberus +accent-ohio-words-replace-76 = hecking chonker + +accent-ohio-words-77 = puppy +accent-ohio-words-replace-77 = hecking chonker + +accent-ohio-words-78 = pup +accent-ohio-words-replace-78 = hecking chonker + +accent-ohio-words-79 = tesla +accent-ohio-words-replace-79 = sparkly rizzball + +accent-ohio-words-80 = singularity +accent-ohio-words-replace-80 = sussy singuawungoose + +accent-ohio-words-81 = singu +accent-ohio-words-replace-81 = sussy singuawungoose + +accent-ohio-words-82 = singulo +accent-ohio-words-replace-82 = sussy singuawungoose + +accent-ohio-words-83 = tesloose +accent-ohio-words-replace-83 = SPARKLY RIZZBALL LOOSE NO CAP + +accent-ohio-words-84 = tesla loose +accent-ohio-words-replace-84 = SPARKLY RIZZBALL LOOSE NO CAP + +accent-ohio-words-85 = hacking +accent-ohio-words-replace-85 = hacking like in a video game + +accent-ohio-words-86 = robust +accent-ohio-words-replace-86 = cooking + +accent-ohio-words-87 = die +accent-ohio-words-replace-87 = get unalived + +accent-ohio-words-88 = died +accent-ohio-words-replace-88 = was unalived + +accent-ohio-words-89 = goddamn +accent-ohio-words-replace-89 = gyattdamn + +accent-ohio-words-90 = godamn +accent-ohio-words-replace-90 = gyattdamn + +accent-ohio-words-91 = goddamned +accent-ohio-words-replace-91 = gyatdamned + +accent-ohio-words-92 = goddang +accent-ohio-words-replace-92 = gyattdang + +accent-ohio-words-93 = fuck +accent-ohio-words-replace-93 = skibidi + +accent-ohio-words-94 = shit +accent-ohio-words-replace-94 = skibidi + +accent-ohio-words-95 = im high +accent-ohio-words-replace-95 = im tweaking + +accent-ohio-words-96 = i'm high +accent-ohio-words-replace-96 = i'm tweaking + +accent-ohio-words-97 = supermatter +accent-ohio-words-replace-97 = fanum crystal + +accent-ohio-words-98 = erping +accent-ohio-words-replace-98 = going to freaky town + +accent-ohio-words-99 = erp +accent-ohio-words-replace-99 = freaky + +accent-ohio-words-100 = sm +accent-ohio-words-replace-100 = fanum crystal + +accent-ohio-words-101 = changeling +accent-ohio-words-replace-101 = shapeshifting ohioan + +accent-ohio-words-102 = cling +accent-ohio-words-replace-102 = shapeshifting ohioan + +accent-ohio-words-103 = heretic +accent-ohio-words-replace-103 = facebook crystal worshipper + +accent-ohio-words-104 = heretics +accent-ohio-words-replace-104 = members of a crystal-worshipping facebook group + +accent-ohio-words-105 = news +accent-ohio-words-replace-105 = fake news + +accent-ohio-words-106 = tax +accent-ohio-words-replace-106 = fanum tax + +accent-ohio-words-107 = cool guy +accent-ohio-words-replace-107 = real sigma alpha male guy + +accent-ohio-words-108 = fed +accent-ohio-words-replace-108 = fanum taxer + +accent-ohio-words-109 = athlete +accent-ohio-words-replace-109 = ishowspeed + +accent-ohio-words-110 = meth +accent-ohio-words-replace-110 = speed + +accent-ohio-words-111 = chemistry +accent-ohio-words-replace-111 = walter white + +accent-ohio-words-112 = chem +accent-ohio-words-replace-112 = walter white + +accent-ohio-words-113 = real news +accent-ohio-words-replace-113 = fake news + +accent-ohio-words-114 = important +accent-ohio-words-replace-114 = important like paying your fanum taxes + +accent-ohio-words-115 = literally +accent-ohio-words-replace-115 = widewawwy + +accent-ohio-words-116 = best friend +accent-ohio-words-replace-116 = bestie + +accent-ohio-words-117 = caught +accent-ohio-words-replace-117 = caught in 4k + +accent-ohio-words-118 = delusional +accent-ohio-words-replace-118 = delulu + +accent-ohio-words-119 = toes +accent-ohio-words-replace-119 = dogs + +accent-ohio-words-120 = boss +accent-ohio-words-replace-120 = girlboss + +accent-ohio-words-121 = make-over +accent-ohio-words-replace-121 = glow-up + +accent-ohio-words-122 = makeover +accent-ohio-words-replace-122 = glowup + +accent-ohio-words-123 = make over +accent-ohio-words-replace-123 = glow up + +accent-ohio-words-124 = greatest +accent-ohio-words-replace-124 = goat + +accent-ohio-words-125 = gross +accent-ohio-words-replace-125 = icky + +accent-ohio-words-126 = pun pun +accent-ohio-words-replace-126 = ipad-addicted monkey + +accent-ohio-words-127 = security +accent-ohio-words-replace-127 = karen department + +accent-ohio-words-128 = secoff +accent-ohio-words-replace-128 = pig + +accent-ohio-words-129 = hos +accent-ohio-words-replace-129 = donut-feasting karen + +accent-ohio-words-130 = rumor +accent-ohio-words-replace-130 = tea + +accent-ohio-words-131 = throw +accent-ohio-words-replace-131 = yeet + +accent-ohio-words-132 = gay +accent-ohio-words-replace-132 = zesty \ No newline at end of file diff --git a/Resources/Locale/en-US/medical/surgery/surgery-tools.ftl b/Resources/Locale/en-US/medical/surgery/surgery-tools.ftl new file mode 100644 index 00000000000..75b48e776f0 --- /dev/null +++ b/Resources/Locale/en-US/medical/surgery/surgery-tools.ftl @@ -0,0 +1,9 @@ +surgery-tool-turn-on = Turn it on first! +surgery-tool-reload = Reload it first! +surgery-tool-match-light = Light it first! +surgery-tool-match-replace = Get a new match! +surgery-tool-examinable-verb-text = Surgery Tool +surgery-tool-examinable-verb-message = Examine the uses of this tool in surgeries. +surgery-tool-header = This can be used in surgeries as: +surgery-tool-unlimited = - {$tool} at [color={$color}]{$speed}x[/color] speed +surgery-tool-used = - {$tool} at [color={$color}]{$speed}x[/color] speed, [color=red]then gets used up[/color] diff --git a/Resources/Locale/en-US/research/technologies.ftl b/Resources/Locale/en-US/research/technologies.ftl index fe7293d8481..b4d14468aa2 100644 --- a/Resources/Locale/en-US/research/technologies.ftl +++ b/Resources/Locale/en-US/research/technologies.ftl @@ -63,7 +63,9 @@ research-technology-advanced-entertainment = Advanced Entertainment research-technology-audio-visual-communication = A/V Communication research-technology-faux-astro-tiles = Faux Astro-Tiles research-technology-biochemical-stasis = Biochemical Stasis -research-technology-mechanized-treatment = Mechanized Treatment +research-technology-advanced-treatment = Advanced Treatment +research-technology-high-end-surgery = High End Surgical Tools +research-technology-cybernetic-enhancements = Cybernetic Enhancements research-technology-robotic-cleanliness = Robotic Cleanliness research-technology-advanced-cleaning = Advanced Cleaning research-technology-meat-manipulation = Meat Manipulation diff --git a/Resources/Maps/glacier.yml b/Resources/Maps/glacier.yml index 41acf600625..c4756e4c258 100644 --- a/Resources/Maps/glacier.yml +++ b/Resources/Maps/glacier.yml @@ -52959,6 +52959,14 @@ entities: - BorgModuleClowning - BorgModuleDiagnosis - BorgModuleDefibrillator + - BorgModuleJetpack + - BorgModulePka + - BorgModuleAdvancedSurgery + - JawsOfLifeLeftArm + - JawsOfLifeRightArm + - SpeedLeftLeg + - SpeedRightLeg + - BasicCyberneticEyes - BorgModuleAdvancedTreatment - RipleyHarness - RipleyLArm diff --git a/Resources/Prototypes/Body/Organs/Animal/animal.yml b/Resources/Prototypes/Body/Organs/Animal/animal.yml index 619ceebe19d..9355f9835e1 100644 --- a/Resources/Prototypes/Body/Organs/Animal/animal.yml +++ b/Resources/Prototypes/Body/Organs/Animal/animal.yml @@ -153,3 +153,21 @@ maxReagents: 5 metabolizerTypes: [ Animal ] removeEmpty: true + +- type: entity + parent: OrganAnimalLungs + id: OrganSpaceAnimalLungs + name: space animal lungs + components: + - type: Organ + onAdd: + - type: RespiratorImmune + +- type: entity + parent: OrganAnimalHeart + id: OrganSpaceAnimalHeart + name: space animal heart + components: + - type: Organ + onAdd: + - type: PressureImmunity diff --git a/Resources/Prototypes/Body/Organs/cybernetic.yml b/Resources/Prototypes/Body/Organs/cybernetic.yml new file mode 100644 index 00000000000..a7e68c5a29b --- /dev/null +++ b/Resources/Prototypes/Body/Organs/cybernetic.yml @@ -0,0 +1,51 @@ +- type: entity + parent: OrganHumanEyes + abstract: true + id: BaseCyberneticEyes + components: + - type: Cybernetics + - type: Sprite + sprite: Mobs/Species/IPC/organs.rsi + state: "eyes" + +- type: entity + parent: BaseCyberneticEyes + id: BasicCyberneticEyes + name: cybernetic eyes + description: A pair of cybernetic eyes that enhance your vision, and protect you from eye damage. + components: + - type: Organ + onAdd: + - type: FlashImmunity + - type: EyeProtection + +- type: entity + parent: BaseCyberneticEyes + id: SecurityCyberneticEyes + name: cybernetic security eyes + description: A pair of cybernetic eyes that enhance your vision, featuring an integrated SecHUD. + components: + - type: Organ + onAdd: + - type: FlashImmunity + - type: EyeProtection + - type: ShowJobIcons + - type: ShowMindShieldIcons + - type: ShowCriminalRecordIcons + +- type: entity + parent: BaseCyberneticEyes + id: MedicalCyberneticEyes + name: cybernetic diagnostic eyes + description: A pair of cybernetic eyes that enhance your vision, featuring an integrated MedHUD. + components: + - type: Organ + onAdd: + - type: FlashImmunity + - type: EyeProtection + - type: ShowHealthBars + damageContainers: + - Biological + - type: ShowHealthIcons + damageContainers: + - Biological diff --git a/Resources/Prototypes/Body/Organs/generic.yml b/Resources/Prototypes/Body/Organs/generic.yml new file mode 100644 index 00000000000..9f032de0748 --- /dev/null +++ b/Resources/Prototypes/Body/Organs/generic.yml @@ -0,0 +1,23 @@ +- type: entity + parent: OrganHumanHeart + id: BioSynthHeart + name: bio-synthetic heart + description: This heart can be transplanted into any living organism and it will adapt to its recipient. + +- type: entity + parent: OrganHumanLiver + id: BioSynthLiver + name: bio-synthetic liver + description: This liver can be transplanted into any living organism and it will adapt to its recipient. + +- type: entity + parent: OrganHumanLungs + id: BioSynthLungs + name: bio-synthetic lungs + description: These lungs can be transplanted into any living organism and it will adapt to its recipient. + +- type: entity + parent: OrganHumanEyes + id: BioSynthEyes + name: bio-synthetic eyes + description: These eyes can be transplanted into any living organism and it will adapt to its recipient. diff --git a/Resources/Prototypes/Body/Parts/animal.yml b/Resources/Prototypes/Body/Parts/animal.yml index bc3d4b935ce..bfd90d4fad4 100644 --- a/Resources/Prototypes/Body/Parts/animal.yml +++ b/Resources/Prototypes/Body/Parts/animal.yml @@ -103,4 +103,42 @@ components: - type: Sprite layers: - - state: head_m \ No newline at end of file + - state: head_m + +- type: entity + abstract: true + parent: PartAnimal + id: BaseCarpPart + components: + - type: Sprite + sprite: Mobs/Aliens/Carps/carp_parts.rsi + +- type: entity + categories: [ HideSpawnMenu ] + parent: BaseCarpPart + id: TailCarp + name: carp tail + description: Unique glands in this tail let space carp fly in a vacuum. + components: + - type: Sprite + layers: + - state: tail + - type: BodyPart + partType: Tail + - type: MovementBodyPart + walkSpeed: 2.5 + sprintSpeed: 3.5 + # TODO: Make it actually needed. Legs are hardcoded to be the only parts that matter for movement. + # TODO: space flight stuff + +- type: entity + categories: [ HideSpawnMenu ] + parent: BaseCarpPart + id: TorsoCarp + name: carp torso + components: + - type: Sprite + layers: + - state: torso + - type: BodyPart + partType: Torso diff --git a/Resources/Prototypes/Body/Parts/cybernetic.yml b/Resources/Prototypes/Body/Parts/cybernetic.yml new file mode 100644 index 00000000000..fe8901e2bbe --- /dev/null +++ b/Resources/Prototypes/Body/Parts/cybernetic.yml @@ -0,0 +1,169 @@ +- type: entity + id: LeftArmCybernetic + parent: LeftArmHuman + abstract: true + components: + - type: Damageable + damageContainer: Silicon + - type: BodyPart + baseLayerId: MobCyberneticBishopLArm + - type: GenerateChildPart + id: LeftHandCybernetic + - type: Cybernetics + - type: Sprite + sprite: Mobs/Customization/cyberlimbs/bishop/bishop_main.rsi + state: "l_arm-combined" + +- type: entity + id: RightArmCybernetic + parent: RightArmHuman + abstract: true + components: + - type: Damageable + damageContainer: Silicon + - type: BodyPart + baseLayerId: MobCyberneticBishopRArm + - type: GenerateChildPart + id: RightHandCybernetic + - type: Cybernetics + - type: Sprite + sprite: Mobs/Customization/cyberlimbs/bishop/bishop_main.rsi + state: "r_arm-combined" + +- type: entity + id: LeftLegCybernetic + parent: LeftLegHuman + abstract: true + components: + - type: Damageable + damageContainer: Silicon + - type: BodyPart + baseLayerId: MobCyberneticBishopLLeg + - type: GenerateChildPart + id: LeftFootCybernetic + - type: Cybernetics + - type: Sprite + sprite: Mobs/Customization/cyberlimbs/bishop/bishop_main.rsi + state: "l_leg-combined" + +- type: entity + id: RightLegCybernetic + parent: RightLegHuman + abstract: true + components: + - type: Damageable + damageContainer: Silicon + - type: BodyPart + baseLayerId: MobCyberneticBishopRLeg + - type: GenerateChildPart + id: RightFootCybernetic + - type: Cybernetics + - type: Sprite + sprite: Mobs/Customization/cyberlimbs/bishop/bishop_main.rsi + state: "r_leg-combined" + +- type: entity + id: LeftHandCybernetic + parent: LeftHandHuman + name: cybernetic left hand + components: + - type: Damageable + damageContainer: Silicon + - type: BodyPart + baseLayerId: MobCyberneticBishopLHand + - type: Cybernetics + - type: Sprite + sprite: Mobs/Customization/cyberlimbs/bishop/bishop_main.rsi + state: "l_hand" + +- type: entity + id: RightHandCybernetic + parent: RightHandHuman + name: cybernetic right hand + components: + - type: Damageable + damageContainer: Silicon + - type: BodyPart + baseLayerId: MobCyberneticBishopRHand + - type: Cybernetics + - type: Sprite + sprite: Mobs/Customization/cyberlimbs/bishop/bishop_main.rsi + state: "r_hand" + +- type: entity + id: LeftFootCybernetic + parent: LeftFootHuman + name: cybernetic left foot + components: + - type: Damageable + damageContainer: Silicon + - type: BodyPart + baseLayerId: MobCyberneticBishopLFoot + - type: Cybernetics + - type: Sprite + sprite: Mobs/Customization/cyberlimbs/bishop/bishop_main.rsi + state: "l_foot" + +- type: entity + id: RightFootCybernetic + parent: RightFootHuman + name: cybernetic right foot + components: + - type: Damageable + damageContainer: Silicon + - type: BodyPart + baseLayerId: MobCyberneticBishopRFoot + - type: Cybernetics + - type: Sprite + sprite: Mobs/Customization/cyberlimbs/bishop/bishop_main.rsi + state: "r_foot" + +- type: entity + parent: LeftArmCybernetic + id: JawsOfLifeLeftArm + name: J.W.L left arm + description: A cybernetic left arm with the ability to pry doors open. + components: + - type: BodyPart + onAdd: + - type: Prying + speedModifier: 1.5 + pryPowered: true + +- type: entity + parent: RightArmCybernetic + id: JawsOfLifeRightArm + name: J.W.L right arm + description: A cybernetic right arm with the ability to pry doors open. + components: + - type: BodyPart + onAdd: + - type: Prying + speedModifier: 1.5 + pryPowered: true + +- type: entity + parent: LeftLegCybernetic + id: SpeedLeftLeg + name: S.P.E.E.D left leg + description: A cybernetic left leg that allows its wearer to run faster. + components: + - type: MovementBodyPart + walkSpeed: 3.125 + sprintSpeed: 5.625 + - type: BodyPart + onAdd: + - type: NoSlip + +- type: entity + parent: RightLegCybernetic + id: SpeedRightLeg + name: S.P.E.E.D right leg + description: A cybernetic left leg that allows its wearer to run faster. + components: + - type: MovementBodyPart + walkSpeed: 3.125 + sprintSpeed: 5.625 + - type: BodyPart + onAdd: + - type: NoSlip diff --git a/Resources/Prototypes/Body/Parts/generic.yml b/Resources/Prototypes/Body/Parts/generic.yml new file mode 100644 index 00000000000..ef97ac86d88 --- /dev/null +++ b/Resources/Prototypes/Body/Parts/generic.yml @@ -0,0 +1,103 @@ +- type: entity + parent: LeftArmHuman + id: BioSynthLeftArm + name: bio-synthetic left arm + description: This left arm can be transplanted into any living organism and it will adapt to its recipient. + components: + - type: BodyPart + children: + left hand: + id: "left hand" + type: Hand + +- type: entity + parent: RightArmHuman + id: BioSynthRightArm + name: bio-synthetic right arm + description: This right arm can be transplanted into any living organism and it will adapt to its recipient. + components: + - type: BodyPart + children: + right hand: + id: "right hand" + type: Hand + +- type: entity + parent: LeftHandHuman + id: BioSynthLeftHand + name: bio-synthetic left hand + description: This left hand can be transplanted into any living organism and it will adapt to its recipient. + +- type: entity + parent: RightHandHuman + id: BioSynthRightHand + name: bio-synthetic right hand + description: This right hand can be transplanted into any living organism and it will adapt to its recipient. + +- type: entity + parent: LeftLegHuman + id: BioSynthLeftLeg + name: bio-synthetic left leg + description: This left leg can be transplanted into any living organism and it will adapt to its recipient. + components: + - type: BodyPart + children: + right foot: + id: "right foot" + type: Foot + +- type: entity + parent: RightLegHuman + id: BioSynthRightLeg + name: bio-synthetic right leg + description: This right leg can be transplanted into any living organism and it will adapt to its recipient. + components: + - type: BodyPart + children: + right foot: + id: "right foot" + type: Foot + +- type: entity + parent: LeftFootHuman + id: BioSynthLeftFoot + name: bio-synthetic left foot + description: This left foot can be transplanted into any living organism and it will adapt to its recipient. + +- type: entity + parent: RightFootHuman + id: BioSynthRightFoot + name: bio-synthetic right foot + description: This right foot can be transplanted into any living organism and it will adapt to its recipient. + +# JOKE ITEMS + +- type: entity + parent: LeftArmHuman + id: PizzaLeftArm + name: pizza left arm + description: For when you want to turn someone into a Space John's. + components: + - type: BodyPart + partType: Arm + symmetry: Left + toolName: "a left arm" + baseLayerId: MobPizzaLArm + - type: Sprite + sprite: Mobs/Species/Misc/Pizza/parts.rsi + state: "l_arm" + +- type: entity + parent: RightArmHuman + id: PizzaRightArm + name: pizza right arm + description: For when you want to turn someone into a Space John's. + components: + - type: BodyPart + partType: Arm + symmetry: Right + toolName: "a right arm" + baseLayerId: MobPizzaRArm + - type: Sprite + sprite: Mobs/Species/Misc/Pizza/parts.rsi + state: "r_arm" diff --git a/Resources/Prototypes/Body/Parts/silicon.yml b/Resources/Prototypes/Body/Parts/silicon.yml index 3208280db7d..092504960a0 100644 --- a/Resources/Prototypes/Body/Parts/silicon.yml +++ b/Resources/Prototypes/Body/Parts/silicon.yml @@ -41,6 +41,11 @@ - type: BodyPart partType: Arm symmetry: Left + toolName: "a left arm" + children: + left hand: + id: "left hand" + type: Hand - type: Tag tags: - Trash @@ -55,6 +60,11 @@ - type: BodyPart partType: Arm symmetry: Right + toolName: "a right arm" + children: + right hand: + id: "right hand" + type: Hand - type: Tag tags: - Trash @@ -69,6 +79,11 @@ - type: BodyPart partType: Leg symmetry: Left + toolName: "a left leg" + children: + left foot: + id: "left foot" + type: Foot - type: Tag tags: - Trash @@ -84,6 +99,11 @@ - type: BodyPart partType: Leg symmetry: Right + toolName: "a right leg" + children: + right foot: + id: "right foot" + type: Foot - type: Tag tags: - Trash @@ -113,4 +133,4 @@ partType: Torso - type: Tag tags: - - Trash \ No newline at end of file + - Trash diff --git a/Resources/Prototypes/Body/Prototypes/Animal/animal.yml b/Resources/Prototypes/Body/Prototypes/Animal/animal.yml index a8c81f9eb60..e37f329fa97 100644 --- a/Resources/Prototypes/Body/Prototypes/Animal/animal.yml +++ b/Resources/Prototypes/Body/Prototypes/Animal/animal.yml @@ -40,4 +40,4 @@ connections: - feet feet: - part: FeetAnimal \ No newline at end of file + part: FeetAnimal diff --git a/Resources/Prototypes/Body/Prototypes/Animal/carp.yml b/Resources/Prototypes/Body/Prototypes/Animal/carp.yml new file mode 100644 index 00000000000..81bf6a4bd5c --- /dev/null +++ b/Resources/Prototypes/Body/Prototypes/Animal/carp.yml @@ -0,0 +1,17 @@ +- type: body + id: Carp + name: carp + root: torso + slots: + torso: + part: TorsoAnimal + connections: + - tail + organs: + lungs: OrganSpaceAnimalLungs # Immunity to airloss + stomach: OrganAnimalStomach + liver: OrganAnimalLiver + heart: OrganSpaceAnimalHeart # Immunity to cold + kidneys: OrganAnimalKidneys + tail: + part: TailCarp diff --git a/Resources/Prototypes/DeltaV/Body/Organs/harpy.yml b/Resources/Prototypes/DeltaV/Body/Organs/harpy.yml index adc626bc114..d573ce0dfba 100644 --- a/Resources/Prototypes/DeltaV/Body/Organs/harpy.yml +++ b/Resources/Prototypes/DeltaV/Body/Organs/harpy.yml @@ -9,6 +9,8 @@ - state: lung-l - state: lung-r - type: Lung + - type: Organ + slotId: lungs - type: Metabolizer updateInterval: 2.0 removeEmpty: true diff --git a/Resources/Prototypes/DeltaV/Body/Parts/vulpkanin.yml b/Resources/Prototypes/DeltaV/Body/Parts/vulpkanin.yml index 1a6931df679..9f95eb25753 100644 --- a/Resources/Prototypes/DeltaV/Body/Parts/vulpkanin.yml +++ b/Resources/Prototypes/DeltaV/Body/Parts/vulpkanin.yml @@ -7,7 +7,7 @@ abstract: true components: - type: Damageable - damageContainer: Biological + damageContainer: OrganicPart - type: BodyPart - type: ContainerContainer containers: diff --git a/Resources/Prototypes/DeltaV/Body/Prototypes/harpy.yml b/Resources/Prototypes/DeltaV/Body/Prototypes/harpy.yml index b20b94cce2d..e695811fc94 100644 --- a/Resources/Prototypes/DeltaV/Body/Prototypes/harpy.yml +++ b/Resources/Prototypes/DeltaV/Body/Prototypes/harpy.yml @@ -17,6 +17,7 @@ - left arm - right leg - left leg + - head organs: heart: OrganHumanHeart lungs: OrganHarpyLungs diff --git a/Resources/Prototypes/DeltaV/Body/Prototypes/vulpkanin.yml b/Resources/Prototypes/DeltaV/Body/Prototypes/vulpkanin.yml index 4ac73acfc48..378e7eee6df 100644 --- a/Resources/Prototypes/DeltaV/Body/Prototypes/vulpkanin.yml +++ b/Resources/Prototypes/DeltaV/Body/Prototypes/vulpkanin.yml @@ -23,6 +23,7 @@ - left arm - right leg - left leg + - head right arm: part: RightArmVulpkanin connections: diff --git a/Resources/Prototypes/Entities/Mobs/Cyborgs/borg_chassis.yml b/Resources/Prototypes/Entities/Mobs/Cyborgs/borg_chassis.yml index e0dc4a0ad43..5c84f7258d8 100644 --- a/Resources/Prototypes/Entities/Mobs/Cyborgs/borg_chassis.yml +++ b/Resources/Prototypes/Entities/Mobs/Cyborgs/borg_chassis.yml @@ -258,6 +258,7 @@ - ActionFabricateGumball - type: SiliconLawProvider laws: Medical + - type: SurgeryTarget - type: entity id: BorgChassisService diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/carp.yml b/Resources/Prototypes/Entities/Mobs/NPCs/carp.yml index b26269d0708..bf13f9dfa49 100644 --- a/Resources/Prototypes/Entities/Mobs/NPCs/carp.yml +++ b/Resources/Prototypes/Entities/Mobs/NPCs/carp.yml @@ -81,6 +81,13 @@ interactFailureString: petting-failure-carp interactFailureSound: path: /Audio/Effects/bite.ogg + - type: Body # Shitmed - Adds carp organs. + prototype: Carp + - type: SurgeryTarget + - type: UserInterface + interfaces: + enum.SurgeryUIKey.Key: + type: SurgeryBui - type: entity parent: BaseMobCarp diff --git a/Resources/Prototypes/Entities/Objects/Materials/shards.yml b/Resources/Prototypes/Entities/Objects/Materials/shards.yml index 5e0b8890ccd..28f206a4f05 100644 --- a/Resources/Prototypes/Entities/Objects/Materials/shards.yml +++ b/Resources/Prototypes/Entities/Objects/Materials/shards.yml @@ -81,6 +81,13 @@ - type: DeleteOnTrigger - type: StaticPrice price: 0 + - type: Scalpel + speed: 0.45 + - type: SurgeryTool + startSound: + path: /Audio/Medical/Surgery/scalpel1.ogg + endSound: + path: /Audio/Medical/Surgery/scalpel2.ogg - type: entity parent: ShardBase diff --git a/Resources/Prototypes/Entities/Objects/Misc/paper.yml b/Resources/Prototypes/Entities/Objects/Misc/paper.yml index 9c54e14f50f..d30fead363c 100644 --- a/Resources/Prototypes/Entities/Objects/Misc/paper.yml +++ b/Resources/Prototypes/Entities/Objects/Misc/paper.yml @@ -332,6 +332,13 @@ - type: PhysicalComposition materialComposition: Steel: 25 + - type: Tending + speed: 0.55 + - type: SurgeryTool + startSound: + path: /Audio/Medical/Surgery/retractor1.ogg + endSound: + path: /Audio/Medical/Surgery/hemostat1.ogg - type: entity parent: Pen diff --git a/Resources/Prototypes/Entities/Objects/Misc/utensils.yml b/Resources/Prototypes/Entities/Objects/Misc/utensils.yml index 86667f094fd..7dee744ff7d 100644 --- a/Resources/Prototypes/Entities/Objects/Misc/utensils.yml +++ b/Resources/Prototypes/Entities/Objects/Misc/utensils.yml @@ -8,6 +8,13 @@ - type: Item # TODO add inhand sprites for all utensils sprite: Objects/Misc/utensils.rsi - type: SpaceGarbage + - type: Tweezers # Any utensil can poorly remove organs + speed: 0.2 + - type: SurgeryTool + startSound: + path: /Audio/Medical/Surgery/retractor1.ogg + endSound: + path: /Audio/Medical/Surgery/hemostat1.ogg - type: entity parent: UtensilBase @@ -50,6 +57,8 @@ damage: types: Piercing: 5 + - type: Tweezers # Forks are better than spoons + speed: 0.35 - type: entity parent: UtensilBasePlastic @@ -62,6 +71,8 @@ - type: Utensil types: - Fork + - type: Tweezers # Forks are better than spoons + speed: 0.35 - type: entity parent: UtensilBase diff --git a/Resources/Prototypes/Entities/Objects/Specific/Hydroponics/tools.yml b/Resources/Prototypes/Entities/Objects/Specific/Hydroponics/tools.yml index 75129601168..316294787b3 100644 --- a/Resources/Prototypes/Entities/Objects/Specific/Hydroponics/tools.yml +++ b/Resources/Prototypes/Entities/Objects/Specific/Hydroponics/tools.yml @@ -52,6 +52,15 @@ - type: Item sprite: Objects/Tools/Hydroponics/clippers.rsi storedRotation: -90 + - type: Retractor # Same as wirecutters + speed: 0.35 + - type: Hemostat + speed: 0.6 + - type: SurgeryTool + startSound: + path: /Audio/Medical/Surgery/retractor1.ogg + endSound: + path: /Audio/Medical/Surgery/retractor2.ogg - type: entity name: scythe @@ -109,6 +118,11 @@ heavyStaminaCost: 5 - type: Item sprite: Objects/Tools/Hydroponics/hatchet.rsi + - type: BoneSaw + speed: 0.35 + - type: SurgeryTool + startSound: + path: /Audio/Medical/Surgery/saw.ogg - type: entity name: spade diff --git a/Resources/Prototypes/Entities/Objects/Specific/Medical/surgery.yml b/Resources/Prototypes/Entities/Objects/Specific/Medical/surgery.yml index 5683f700f45..638b194c343 100644 --- a/Resources/Prototypes/Entities/Objects/Specific/Medical/surgery.yml +++ b/Resources/Prototypes/Entities/Objects/Specific/Medical/surgery.yml @@ -40,6 +40,39 @@ path: /Audio/Medical/Surgery/cautery2.ogg - type: Cautery +# TODO: Make a system to toggle modes so people have to think a bit more. + +- type: entity + name: searing tool + id: EnergyCautery + parent: Cautery + description: A cautery with an energy tip, also serves as a drill in its powered state. + components: + - type: Sprite + sprite: Objects/Specific/Medical/Surgery/e-cautery.rsi + state: e-cautery-on + - type: Item + sprite: Objects/Specific/Medical/Surgery/e-cautery.rsi + inhandVisuals: + left: + - state: inhand-left-on + right: + - state: inhand-right-on + - type: SurgeryTool + startSound: + path: /Audio/Medical/Surgery/cautery1.ogg + endSound: + path: /Audio/Medical/Surgery/cautery2.ogg + - type: MeleeWeapon + damage: + types: + Piercing: 10 + Heat: 1 + - type: Cautery + speed: 1.5 + - type: Drill + speed: 1.5 + # Drill - type: entity @@ -73,7 +106,7 @@ - type: SurgeryTool startSound: path: /Audio/Medical/Surgery/saw.ogg - - type: SurgicalDrill + - type: Drill # Scalpel @@ -116,6 +149,36 @@ path: /Audio/Medical/Surgery/scalpel2.ogg - type: Scalpel +- type: entity + name: energy scalpel + id: EnergyScalpel + parent: Scalpel + description: A scalpel which uses an energy blade, also serves as a saw in its powered state. + components: + - type: Sprite + sprite: Objects/Specific/Medical/Surgery/e-scalpel.rsi + state: e-scalpel-on + - type: Item + sprite: Objects/Specific/Medical/Surgery/e-scalpel.rsi + inhandVisuals: + left: + - state: inhand-left-on + right: + - state: inhand-right-on + - type: SurgeryTool + startSound: + path: /Audio/Medical/Surgery/scalpel1.ogg + endSound: + path: /Audio/Medical/Surgery/scalpel2.ogg + - type: MeleeWeapon + damage: + types: + Slash: 10 + Heat: 1 + - type: Scalpel + speed: 1.5 + - type: BoneSaw + speed: 1.5 - type: entity name: shiv @@ -124,8 +187,10 @@ description: A pointy piece of glass, abraded to an edge and wrapped in tape for a handle. # Could become a decent tool or weapon with right tool mods. components: - type: Sprite + sprite: Objects/Specific/Medical/Surgery/oldscalpel.rsi state: shiv - type: Item + sprite: Objects/Specific/Medical/Surgery/oldscalpel.rsi heldPrefix: shiv - type: entity @@ -135,13 +200,17 @@ description: Made of more expensive materials, sharper and generally more reliable. components: - type: Sprite + sprite: Objects/Specific/Medical/Surgery/oldscalpel.rsi state: advanced - type: Item + sprite: Objects/Specific/Medical/Surgery/oldscalpel.rsi heldPrefix: advanced - type: MeleeWeapon damage: types: Slash: 8 + - type: Scalpel + speed: 1.25 - type: entity name: laser scalpel @@ -150,16 +219,22 @@ description: A scalpel which uses a directed laser to slice instead of a blade, for more precise surgery while also cauterizing as it cuts. components: - type: Sprite + sprite: Objects/Specific/Medical/Surgery/oldscalpel.rsi state: laser + - type: Item + sprite: Objects/Specific/Medical/Surgery/oldscalpel.rsi + heldPrefix: laser - type: MeleeWeapon damage: types: Slash: 6.5 Heat: 1 - - type: Item - heldPrefix: laser + - type: Scalpel + speed: 1.25 # These shouldnt be obtainable but yknow they are better. + - type: Cautery + speed: 1.25 -# Scissors +# Retractor - type: entity name: retractor @@ -168,10 +243,10 @@ description: A surgical tool used to hold open incisions. components: - type: Sprite - sprite: Objects/Specific/Medical/Surgery/scissors.rsi + sprite: Objects/Specific/Medical/Surgery/retractor.rsi state: retractor - type: Item - sprite: Objects/Specific/Medical/Surgery/scissors.rsi + sprite: Objects/Specific/Medical/Surgery/retractor.rsi storedRotation: 90 - type: SurgeryTool startSound: @@ -179,6 +254,45 @@ endSound: path: /Audio/Medical/Surgery/retractor2.ogg - type: Retractor + - type: Tweezers + - type: Tending + +- type: entity + name: mechanical pinches + id: AdvancedRetractor + parent: Retractor + description: A retractor with mechanical pinches, also serves as a hemostat in its powered state. + components: + - type: Sprite + sprite: Objects/Specific/Medical/Surgery/adv-retractor.rsi + state: adv-retractor-on + - type: Item + sprite: Objects/Specific/Medical/Surgery/adv-retractor.rsi + inhandVisuals: + left: + - state: inhand-left-on + right: + - state: inhand-right-on + - type: SurgeryTool + startSound: + path: /Audio/Medical/Surgery/retractor1.ogg + endSound: + path: /Audio/Medical/Surgery/retractor2.ogg + - type: MeleeWeapon + damage: + types: + Slash: 6.5 + Heat: 1 + - type: Hemostat + speed: 1.5 + - type: Retractor + speed: 1.5 + - type: Tweezers + speed: 1.5 + - type: Tending + speed: 1.5 + +# Hemostat - type: entity name: hemostat @@ -187,11 +301,10 @@ description: A surgical tool used to compress blood vessels to prevent bleeding. components: - type: Sprite - sprite: Objects/Specific/Medical/Surgery/scissors.rsi + sprite: Objects/Specific/Medical/Surgery/hemostat.rsi state: hemostat - type: Item - heldPrefix: hemostat - sprite: Objects/Specific/Medical/Surgery/scissors.rsi + sprite: Objects/Specific/Medical/Surgery/hemostat.rsi storedRotation: 90 - type: SurgeryTool startSound: @@ -222,7 +335,7 @@ description: A container for bone gel that often needs to be refilled from a specialized machine. components: - type: Sprite - sprite: Objects/Specific/Medical/Surgery/bone_gel.rsi + sprite: Objects/Specific/Medical/Surgery/bone-gel.rsi state: bone-gel - type: BoneGel @@ -293,6 +406,7 @@ - Sawing speed: 0.5 - type: BoneSaw + speed: 0.5 - type: entity name: circular saw @@ -301,9 +415,10 @@ description: For heavy duty cutting. components: - type: Sprite - state: electric + sprite: Objects/Specific/Medical/Surgery/circular-saw.rsi + state: circular-saw - type: Item - heldPrefix: electric + sprite: Objects/Specific/Medical/Surgery/circular-saw.rsi storedRotation: 90 - type: MeleeWeapon attackRate: 1.15 @@ -328,6 +443,7 @@ startSound: path: /Audio/Medical/Surgery/saw.ogg - type: BoneSaw + speed: 1.25 - type: entity name: advanced circular saw @@ -360,112 +476,38 @@ - Sawing speed: 2.0 - type: BoneSaw - -# ORGANS - -- type: entity - parent: OrganHumanHeart - id: BioSynthHeart - name: bio-synthetic heart - description: This heart can be transplanted into any living organism and it will adapt to its recipient. - -- type: entity - parent: OrganHumanLiver - id: BioSynthLiver - name: bio-synthetic liver - description: This liver can be transplanted into any living organism and it will adapt to its recipient. - -- type: entity - parent: OrganHumanLungs - id: BioSynthLungs - name: bio-synthetic lungs - description: These lungs can be transplanted into any living organism and it will adapt to its recipient. - -- type: entity - parent: OrganHumanEyes - id: BioSynthEyes - name: bio-synthetic eyes - description: These eyes can be transplanted into any living organism and it will adapt to its recipient. - - -# PARTS - -- type: entity - parent: LeftArmHuman - id: BioSynthLeftArm - name: bio-synthetic left arm - description: This left arm can be transplanted into any living organism and it will adapt to its recipient. - -- type: entity - parent: RightArmHuman - id: BioSynthRightArm - name: bio-synthetic right arm - description: This right arm can be transplanted into any living organism and it will adapt to its recipient. - -- type: entity - parent: LeftHandHuman - id: BioSynthLeftHand - name: bio-synthetic left hand - description: This left hand can be transplanted into any living organism and it will adapt to its recipient. - -- type: entity - parent: RightHandHuman - id: BioSynthRightHand - name: bio-synthetic right hand - description: This right hand can be transplanted into any living organism and it will adapt to its recipient. - -- type: entity - parent: LeftLegHuman - id: BioSynthLeftLeg - name: bio-synthetic left leg - description: This left leg can be transplanted into any living organism and it will adapt to its recipient. - -- type: entity - parent: RightLegHuman - id: BioSynthRightLeg - name: bio-synthetic right leg - description: This right leg can be transplanted into any living organism and it will adapt to its recipient. - -- type: entity - parent: LeftFootHuman - id: BioSynthLeftFoot - name: bio-synthetic left foot - description: This left foot can be transplanted into any living organism and it will adapt to its recipient. - -- type: entity - parent: RightFootHuman - id: BioSynthRightFoot - name: bio-synthetic right foot - description: This right foot can be transplanted into any living organism and it will adapt to its recipient. - -# JOKE ITEMS - -- type: entity - parent: LeftArmHuman - id: PizzaLeftArm - name: pizza left arm - description: For when you want to turn someone into a Space John's. - components: - - type: BodyPart - partType: Arm - symmetry: Left - toolName: "a left arm" - baseLayerId: MobPizzaLArm - - type: Sprite - sprite: Mobs/Species/Misc/Pizza/parts.rsi - state: "l_arm" + speed: 1.5 - type: entity - parent: RightArmHuman - id: PizzaRightArm - name: pizza right arm - description: For when you want to turn someone into a Space John's. + name: medical multitool + id: OmnimedTool + parent: BaseToolSurgery components: - - type: BodyPart - partType: Arm - symmetry: Right - toolName: "a right arm" - baseLayerId: MobPizzaRArm - type: Sprite - sprite: Mobs/Species/Misc/Pizza/parts.rsi - state: "r_arm" + sprite: Objects/Specific/Medical/Surgery/omnimed.rsi + state: omnimed + - type: Item + sprite: Objects/Specific/Medical/Surgery/omnimed.rsi + - type: SurgeryTool + startSound: + path: /Audio/Medical/Surgery/saw.ogg + - type: Hemostat + speed: 2 + - type: Scalpel + speed: 2 + - type: Drill + speed: 2 + - type: BoneSetter + speed: 2 + - type: Retractor + speed: 2 + - type: Cautery + speed: 2 + - type: BoneGel + speed: 2 + - type: BoneSaw + speed: 2 + - type: Tweezers + speed: 2 + - type: Tending + speed: 2 diff --git a/Resources/Prototypes/Entities/Objects/Specific/Robotics/borg_modules.yml b/Resources/Prototypes/Entities/Objects/Specific/Robotics/borg_modules.yml index 53a7a8f075a..07ad5c760fb 100644 --- a/Resources/Prototypes/Entities/Objects/Specific/Robotics/borg_modules.yml +++ b/Resources/Prototypes/Entities/Objects/Specific/Robotics/borg_modules.yml @@ -381,6 +381,41 @@ - Syringe - Dropper +- type: entity + id: BorgModuleSurgery + parent: [ BaseBorgModuleMedical, BaseProviderBorgModule ] + name: surgery cyborg module + components: + - type: Sprite + layers: + - state: medical + - state: icon-surgery + - type: ItemBorgModule + items: + - Scalpel + - Drill + - Hemostat + - Retractor + - Cautery + - SawElectric + - BoneGel + +- type: entity + id: BorgModuleAdvancedSurgery + parent: [ BaseBorgModuleMedical, BaseProviderBorgModule ] + name: advanced surgery cyborg module + components: + - type: Sprite + layers: + - state: medical + - state: icon-advanced-surgery + - type: ItemBorgModule + items: + - EnergyScalpel + - EnergyCautery + - AdvancedRetractor + - BoneGel + - type: entity id: BorgModuleDefibrillator parent: [ BaseBorgModuleMedical, BaseProviderBorgModule ] diff --git a/Resources/Prototypes/Entities/Objects/Tools/lighters.yml b/Resources/Prototypes/Entities/Objects/Tools/lighters.yml index d03cc725efe..8a832c746e5 100644 --- a/Resources/Prototypes/Entities/Objects/Tools/lighters.yml +++ b/Resources/Prototypes/Entities/Objects/Tools/lighters.yml @@ -87,6 +87,13 @@ netsync: false radius: 1.1 #smallest possible color: orange + - type: Cautery + speed: 0.45 + - type: SurgeryTool + startSound: + collection: lighterOnSounds + endSound: + collection: lighterOffSounds - type: entity name: cheap lighter diff --git a/Resources/Prototypes/Entities/Objects/Tools/matches.yml b/Resources/Prototypes/Entities/Objects/Tools/matches.yml index 561e478d93a..1cdb207bb33 100644 --- a/Resources/Prototypes/Entities/Objects/Tools/matches.yml +++ b/Resources/Prototypes/Entities/Objects/Tools/matches.yml @@ -41,6 +41,13 @@ unlitIcon: match_unlit litIcon: match_lit burntIcon: match_burnt + - type: Cautery + speed: 0.2 + - type: SurgeryTool + startSound: + path: /Audio/Weapons/Guns/Hits/energy_meat1.ogg + endSound: + path: /Audio/Weapons/Guns/Hits/energy_meat1.ogg - type: entity parent: Matchstick diff --git a/Resources/Prototypes/Entities/Objects/Tools/tools.yml b/Resources/Prototypes/Entities/Objects/Tools/tools.yml index 1f1b67349f4..a58cf5fc660 100644 --- a/Resources/Prototypes/Entities/Objects/Tools/tools.yml +++ b/Resources/Prototypes/Entities/Objects/Tools/tools.yml @@ -59,6 +59,19 @@ Steel: 100 - type: StaticPrice price: 30 + - type: Retractor + speed: 0.35 + - type: Hemostat + speed: 0.6 + - type: SurgeryTool + startSound: + path: /Audio/Items/wirecutter.ogg + params: + variation: 0.125 + endSound: + path: /Audio/Items/wirecutter.ogg + params: + variation: 0.125 - type: entity name: screwdriver @@ -119,6 +132,15 @@ Steel: 100 - type: StaticPrice price: 30 + - type: Retractor + speed: 0.45 + - type: Tending + speed: 0.65 + - type: SurgeryTool + startSound: + collection: Screwdriver + endSound: + path: /Audio/Medical/Surgery/retractor2.ogg - type: entity name: wrench @@ -231,6 +253,10 @@ - type: StaticPrice price: 22 - type: Prying + - type: Tweezers + speed: 0.55 + - type: SurgeryTool + startSound: /Audio/Items/crowbar.ogg - type: entity parent: Crowbar diff --git a/Resources/Prototypes/Entities/Objects/Tools/welders.yml b/Resources/Prototypes/Entities/Objects/Tools/welders.yml index c501237b4c8..69d6d80ab4e 100644 --- a/Resources/Prototypes/Entities/Objects/Tools/welders.yml +++ b/Resources/Prototypes/Entities/Objects/Tools/welders.yml @@ -114,6 +114,13 @@ Blunt: -15 Piercing: -15 Slash: -15 + - type: Cautery + speed: 0.7 + - type: SurgeryTool + startSound: + collection: Welder + endSound: + collection: WelderOff - type: entity name: industrial welding tool diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Battery/battery_guns.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Battery/battery_guns.yml index 57db6326bcc..62a98bd5da8 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Battery/battery_guns.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Battery/battery_guns.yml @@ -32,6 +32,11 @@ - type: Appearance - type: StaticPrice price: 500 + - type: Cautery + speed: 0.9 + - type: SurgeryTool + endSound: + path: /Audio/Weapons/Guns/Gunshots/laser.ogg - type: entity id: BaseWeaponPowerCell @@ -68,6 +73,11 @@ - type: ContainerContainer containers: gun_magazine: !type:ContainerSlot + - type: Cautery + speed: 0.9 + - type: SurgeryTool + endSound: + path: /Audio/Weapons/Guns/Gunshots/laser.ogg - type: entity id: BaseWeaponBatterySmall diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Melee/armblade.yml b/Resources/Prototypes/Entities/Objects/Weapons/Melee/armblade.yml index 497876f3596..2d31e4372a0 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Melee/armblade.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Melee/armblade.yml @@ -22,3 +22,10 @@ qualities: - Prying - type: Prying + - type: Scalpel + speed: 0.3 + - type: BoneSaw + speed: 0.75 + - type: SurgeryTool + startSound: + path: /Audio/Medical/Surgery/saw.ogg diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Melee/chainsaw.yml b/Resources/Prototypes/Entities/Objects/Weapons/Melee/chainsaw.yml index b2727b334c6..d69173ff462 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Melee/chainsaw.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Melee/chainsaw.yml @@ -51,3 +51,10 @@ maxVol: 300 - type: UseDelay delay: 1 + - type: BoneSaw + speed: 0.5 # TODO: arm-mounted version becomes 0.65 - We dont have that though??? + - type: SurgeryTool + startSound: + path: /Audio/Weapons/chainsawwield.ogg + endSound: + path: /Audio/Weapons/chainsaw.ogg diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Melee/e_sword.yml b/Resources/Prototypes/Entities/Objects/Weapons/Melee/e_sword.yml index 72b43296af7..ec1d8a82be0 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Melee/e_sword.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Melee/e_sword.yml @@ -85,6 +85,17 @@ - NoPaint - type: IgnitionSource temperature: 700 + - type: Scalpel + speed: 0.75 + - type: Cautery + speed: 0.2 + - type: SurgeryTool + startSound: + path: /Audio/Weapons/ebladehum.ogg + endSound: + path: /Audio/Weapons/eblade1.ogg + params: + variation: 0.250 - type: entity name: antique energy sword diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Melee/fireaxe.yml b/Resources/Prototypes/Entities/Objects/Weapons/Melee/fireaxe.yml index 6630a22ea7d..ffbb1c6d057 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Melee/fireaxe.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Melee/fireaxe.yml @@ -52,6 +52,13 @@ stealGroup: FireAxe - type: IgniteOnMeleeHit fireStacks: -4 + - type: Scalpel + speed: 0.3 + - type: BoneSaw + speed: 0.5 + - type: SurgeryTool + startSound: + path: /Audio/Medical/Surgery/saw.ogg - type: entity id: FireAxeFlaming diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Melee/knife.yml b/Resources/Prototypes/Entities/Objects/Weapons/Melee/knife.yml index 5502f752892..3705775dd68 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Melee/knife.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Melee/knife.yml @@ -31,6 +31,13 @@ - Slicing useSound: path: /Audio/Items/Culinary/chop.ogg + - type: Scalpel + speed: 0.65 + - type: SurgeryTool + startSound: + path: /Audio/Medical/Surgery/scalpel1.ogg + endSound: + path: /Audio/Medical/Surgery/scalpel2.ogg - type: entity name: kitchen knife diff --git a/Resources/Prototypes/Entities/Structures/Machines/lathe.yml b/Resources/Prototypes/Entities/Structures/Machines/lathe.yml index 38a6185d584..a4dacc4aa20 100644 --- a/Resources/Prototypes/Entities/Structures/Machines/lathe.yml +++ b/Resources/Prototypes/Entities/Structures/Machines/lathe.yml @@ -285,6 +285,9 @@ - CryostasisBeaker - SyringeCryostasis - Syringe + - EnergyScalpel + - EnergyCautery + - AdvancedRetractor - Implanter - PillCanister - ChemistryEmptyBottle01 @@ -602,6 +605,7 @@ - BorgModuleConstruction - BorgModuleService - BorgModuleTreatment + - BorgModuleSurgery - BorgModuleCleaning - CyborgEndoskeleton - LeftArmBorg @@ -658,6 +662,12 @@ - BorgModuleDiagnosis - BorgModuleDefibrillator - BorgModuleAdvancedTreatment + - BorgModuleAdvancedSurgery + - JawsOfLifeLeftArm + - JawsOfLifeRightArm + - SpeedLeftLeg + - SpeedRightLeg + - BasicCyberneticEyes - RipleyHarness - RipleyLArm - RipleyRArm @@ -898,6 +908,8 @@ - MagazineBoxSpecialIncendiary - MagazineBoxSpecialUranium - MagazineBoxSpecialMindbreaker + - SecurityCyberneticEyes + - MedicalCyberneticEyes - type: MaterialStorage whitelist: tags: @@ -1027,6 +1039,11 @@ - ClothingEyesHudMedical # Nyano - ChemicalPayload # Nyano - SyringeCryostasis + - EnergyScalpel + - EnergyCautery + - AdvancedRetractor + - OmnimedTool + - MedicalCyberneticEyes - type: Machine board: MedicalTechFabCircuitboard - type: StealTarget diff --git a/Resources/Prototypes/Entities/Surgery/surgeries.yml b/Resources/Prototypes/Entities/Surgery/surgeries.yml index 43d8adfd6ed..ad71b278069 100644 --- a/Resources/Prototypes/Entities/Surgery/surgeries.yml +++ b/Resources/Prototypes/Entities/Surgery/surgeries.yml @@ -43,6 +43,41 @@ - type: SurgeryPartCondition part: Torso +- type: entity + parent: SurgeryBase + id: SurgeryLobotomize + name: Lobotomize + categories: [ HideSpawnMenu ] + components: + - type: Surgery + requirement: SurgeryOpenIncision + steps: + - SurgeryStepLobotomize + - SurgeryStepCloseIncision + - type: SurgeryComponentCondition + component: + - type: OhioAccent + inverse: true + - type: SurgeryPartCondition + part: Head + +- type: entity + parent: SurgeryBase + id: SurgeryMendBrainTissue + name: Mend brain tissue + categories: [ HideSpawnMenu ] + components: + - type: Surgery + requirement: SurgeryOpenIncision + steps: + - SurgeryStepMendBrainTissue + - SurgeryStepCloseIncision + - type: SurgeryComponentCondition + component: + - type: OhioAccent + - type: SurgeryPartCondition + part: Head + - type: entity parent: SurgeryBase id: SurgeryRemovePart @@ -283,6 +318,24 @@ part: Foot symmetry: None +- type: entity + parent: SurgeryBase + id: SurgeryAttachTail + name: Attach Tail + categories: [ HideSpawnMenu ] + components: + - type: Surgery + requirement: SurgeryOpenIncision + steps: + - SurgeryStepInsertFeature + - SurgeryStepSealWounds + - type: SurgeryPartCondition + part: Torso + - type: SurgeryPartRemovedCondition + connection: tail + part: Tail + symmetry: None + #- type: entity # parent: SurgeryBase # id: SurgeryAlienEmbryoRemoval diff --git a/Resources/Prototypes/Entities/Surgery/surgery_steps.yml b/Resources/Prototypes/Entities/Surgery/surgery_steps.yml index b157e6425d5..a0fd45cabd3 100644 --- a/Resources/Prototypes/Entities/Surgery/surgery_steps.yml +++ b/Resources/Prototypes/Entities/Surgery/surgery_steps.yml @@ -15,6 +15,7 @@ - type: Scalpel add: - type: IncisionOpen + duration: 2 - type: Sprite sprite: Objects/Specific/Medical/Surgery/scalpel.rsi state: scalpel @@ -36,8 +37,9 @@ - type: Hemostat add: - type: BleedersClamped + duration: 2 - type: Sprite - sprite: Objects/Specific/Medical/Surgery/scissors.rsi + sprite: Objects/Specific/Medical/Surgery/hemostat.rsi state: hemostat - type: SurgeryDamageChangeEffect damage: @@ -56,8 +58,9 @@ - type: Retractor add: - type: SkinRetracted + duration: 2 - type: Sprite - sprite: Objects/Specific/Medical/Surgery/scissors.rsi + sprite: Objects/Specific/Medical/Surgery/retractor.rsi state: retractor - type: entity @@ -71,6 +74,7 @@ - type: BoneSaw add: - type: RibcageSawed + duration: 4 - type: Sprite sprite: Objects/Specific/Medical/Surgery/saw.rsi state: saw @@ -87,8 +91,9 @@ - type: Retractor add: - type: RibcageOpen + duration: 2 - type: Sprite - sprite: Objects/Specific/Medical/Surgery/scissors.rsi + sprite: Objects/Specific/Medical/Surgery/retractor.rsi state: retractor #- type: entity @@ -120,7 +125,7 @@ # bodyRemove: # - type: VictimInfected # - type: Sprite -# sprite: Objects/Specific/Medical/Surgery/scissors.rsi +# sprite: Objects/Specific/Medical/Surgery/hemostat.rsi # state: hemostat # - type: SurgeryOperatingTableCondition # - type: SurgeryStepSpawnEffect @@ -137,8 +142,9 @@ - type: Retractor remove: - type: RibcageOpen + duration: 2 - type: Sprite - sprite: Objects/Specific/Medical/Surgery/scissors.rsi + sprite: Objects/Specific/Medical/Surgery/retractor.rsi state: retractor - type: entity @@ -152,8 +158,9 @@ - type: BoneGel remove: - type: RibcageSawed + duration: 2 - type: Sprite - sprite: Objects/Specific/Medical/Surgery/bone_gel.rsi + sprite: Objects/Specific/Medical/Surgery/bone-gel.rsi state: bone-gel - type: entity @@ -173,6 +180,7 @@ - type: IncisionOpen - type: BodyPartReattached - type: InternalBleedersClamped + duration: 2 - type: Sprite sprite: Objects/Specific/Medical/Surgery/cautery.rsi state: cautery @@ -194,6 +202,7 @@ - type: SurgeryStep tool: - type: BodyPart + duration: 6 - type: Sprite sprite: Objects/Specific/Medical/Surgery/manipulation.rsi state: insertion @@ -213,6 +222,7 @@ - type: BleedersClamped - type: IncisionOpen - type: InternalBleedersClamped + duration: 2 - type: SurgeryAffixPartStep - type: Sprite sprite: Objects/Specific/Medical/Surgery/cautery.rsi @@ -237,6 +247,7 @@ - type: BoneSaw add: - type: BodyPartSawed + duration: 4 - type: Sprite sprite: Objects/Specific/Medical/Surgery/saw.rsi state: saw @@ -253,8 +264,9 @@ - type: Hemostat add: - type: InternalBleedersClamped + duration: 2 - type: Sprite - sprite: Objects/Specific/Medical/Surgery/scissors.rsi + sprite: Objects/Specific/Medical/Surgery/hemostat.rsi state: hemostat - type: SurgeryDamageChangeEffect damage: @@ -277,6 +289,7 @@ - type: BleedersClamped - type: InternalBleedersClamped - type: IncisionOpen + duration: 8 - type: Sprite sprite: Objects/Specific/Medical/Surgery/saw.rsi state: saw @@ -296,6 +309,7 @@ - type: Scalpel add: - type: IncisionOpen + duration: 3 - type: Sprite sprite: Objects/Specific/Medical/Surgery/scalpel.rsi state: scalpel @@ -309,9 +323,10 @@ components: - type: SurgeryStep tool: - - type: Hemostat + - type: Tending + duration: 1 - type: Sprite - sprite: Objects/Specific/Medical/Surgery/scissors.rsi + sprite: Objects/Specific/Medical/Surgery/hemostat.rsi state: hemostat - type: SurgeryTendWoundsEffect damage: @@ -327,9 +342,10 @@ components: - type: SurgeryStep tool: - - type: Hemostat + - type: Tending + duration: 1 - type: Sprite - sprite: Objects/Specific/Medical/Surgery/scissors.rsi + sprite: Objects/Specific/Medical/Surgery/hemostat.rsi state: hemostat - type: SurgeryTendWoundsEffect mainGroup: Burn @@ -349,6 +365,7 @@ - type: Cautery remove: - type: IncisionOpen + duration: 2 - type: Sprite sprite: Objects/Specific/Medical/Surgery/cautery.rsi state: cautery @@ -368,6 +385,7 @@ categories: [ HideSpawnMenu ] components: - type: SurgeryStep + duration: 4 - type: Sprite sprite: Objects/Specific/Medical/Surgery/manipulation.rsi state: insertion @@ -382,6 +400,7 @@ categories: [ HideSpawnMenu ] components: - type: SurgeryStep + duration: 4 - type: Sprite sprite: Objects/Specific/Medical/Surgery/manipulation.rsi state: insertion @@ -399,9 +418,10 @@ components: - type: SurgeryStep tool: - - type: Hemostat + - type: Tweezers + duration: 8 - type: Sprite - sprite: Objects/Specific/Medical/Surgery/scissors.rsi + sprite: Objects/Specific/Medical/Surgery/hemostat.rsi state: hemostat - type: SurgeryRemoveOrganStep - type: SurgeryStepEmoteEffect @@ -415,6 +435,7 @@ - type: SurgeryStep tool: - type: Organ + duration: 6 - type: Sprite sprite: Objects/Specific/Medical/Surgery/manipulation.rsi state: insertion @@ -427,6 +448,8 @@ name: Add lungs categories: [ HideSpawnMenu ] components: + - type: SurgeryStep + duration: 6 - type: SurgeryDamageChangeEffect damage: types: @@ -440,6 +463,8 @@ name: Add liver categories: [ HideSpawnMenu ] components: + - type: SurgeryStep + duration: 6 - type: SurgeryDamageChangeEffect damage: types: @@ -453,9 +478,8 @@ name: Add eyes categories: [ HideSpawnMenu ] components: - - type: SurgerySpecialDamageChangeEffect - damageType: Eye - isConsumable: true + - type: SurgeryStep + duration: 6 - type: entity parent: SurgeryStepInsertOrgan @@ -463,6 +487,8 @@ name: Add heart categories: [ HideSpawnMenu ] components: + - type: SurgeryStep + duration: 6 - type: SurgerySpecialDamageChangeEffect damageType: Rot isConsumable: true @@ -473,6 +499,9 @@ id: SurgeryStepInsertStomach name: Add stomach categories: [ HideSpawnMenu ] + components: + - type: SurgeryStep + duration: 6 - type: entity parent: SurgeryStepBase @@ -483,6 +512,7 @@ - type: SurgeryStep tool: - type: Cautery + duration: 2 - type: SurgeryAffixOrganStep - type: Sprite sprite: Objects/Specific/Medical/Surgery/cautery.rsi @@ -494,6 +524,48 @@ Heat: -5 sleepModifier: 2 +- type: entity + parent: SurgeryStepBase + id: SurgeryStepLobotomize + name: Lobotomize patient + categories: [ HideSpawnMenu ] + components: + - type: SurgeryStep + tool: + - type: Drill + bodyAdd: + - type: OhioAccent + - type: RatvarianLanguage + - type: SlurredAccent + duration: 5 + - type: Sprite + sprite: Objects/Specific/Medical/Surgery/drill.rsi + state: drill + - type: SurgeryStepEmoteEffect + - type: SurgeryDamageChangeEffect + damage: + types: + Piercing: 10 + +- type: entity + parent: SurgeryStepBase + id: SurgeryStepMendBrainTissue + name: Mend brain tissue + categories: [ HideSpawnMenu ] + components: + - type: SurgeryStep + tool: + - type: Hemostat + duration: 5 + bodyRemove: + - type: OhioAccent + - type: RatvarianLanguage + - type: SlurredAccent + - type: Sprite + sprite: Objects/Specific/Medical/Surgery/drill.rsi + state: drill + - type: SurgeryStepEmoteEffect + # The lengths I go to just for a joke... I HATE HARDCODING AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA # Maybe I should modify species prototypes to include tails and ears properly... diff --git a/Resources/Prototypes/Nyanotrasen/Entities/Body/Parts/spider.yml b/Resources/Prototypes/Nyanotrasen/Entities/Body/Parts/spider.yml index 7e71227dbcb..fbd45804dd2 100644 --- a/Resources/Prototypes/Nyanotrasen/Entities/Body/Parts/spider.yml +++ b/Resources/Prototypes/Nyanotrasen/Entities/Body/Parts/spider.yml @@ -5,7 +5,7 @@ abstract: true components: - type: Damageable - damageContainer: Biological + damageContainer: OrganicPart - type: BodyPart - type: ContainerContainer containers: diff --git a/Resources/Prototypes/Nyanotrasen/Entities/Body/Prototypes/arachne.yml b/Resources/Prototypes/Nyanotrasen/Entities/Body/Prototypes/arachne.yml index 553391484e2..d8eb35629bf 100644 --- a/Resources/Prototypes/Nyanotrasen/Entities/Body/Prototypes/arachne.yml +++ b/Resources/Prototypes/Nyanotrasen/Entities/Body/Prototypes/arachne.yml @@ -16,6 +16,7 @@ - left arm - right arm - thorax + - head organs: heart: OrganHumanHeart lungs: OrganHumanLungs diff --git a/Resources/Prototypes/Nyanotrasen/Entities/Body/Prototypes/felinid.yml b/Resources/Prototypes/Nyanotrasen/Entities/Body/Prototypes/felinid.yml index a09f3b6ab7f..1f397ad04e2 100644 --- a/Resources/Prototypes/Nyanotrasen/Entities/Body/Prototypes/felinid.yml +++ b/Resources/Prototypes/Nyanotrasen/Entities/Body/Prototypes/felinid.yml @@ -17,6 +17,7 @@ - left arm - right leg - left leg + - head organs: heart: OrganAnimalHeart lungs: OrganHumanLungs diff --git a/Resources/Prototypes/Recipes/Lathes/medical.yml b/Resources/Prototypes/Recipes/Lathes/medical.yml index bec71ce3d13..3867fa7fd18 100644 --- a/Resources/Prototypes/Recipes/Lathes/medical.yml +++ b/Resources/Prototypes/Recipes/Lathes/medical.yml @@ -252,3 +252,52 @@ Steel: 600 Plastic: 300 +- type: latheRecipe + id: MedicalCyberneticEyes + result: MedicalCyberneticEyes + category: Robotics + completetime: 5 + materials: + Steel: 1000 + Glass: 500 + Plastic: 500 + Gold: 300 + Silver: 300 + +- type: latheRecipe + id: EnergyScalpel + result: EnergyScalpel + completetime: 2 + materials: + Steel: 600 + Glass: 150 + Gold: 150 + +- type: latheRecipe + id: AdvancedRetractor + result: AdvancedRetractor + completetime: 2 + materials: + Steel: 600 + Glass: 150 + Silver: 150 + +- type: latheRecipe + id: EnergyCautery + result: EnergyCautery + completetime: 2 + materials: + Steel: 600 + Glass: 150 + Plasma: 150 + +- type: latheRecipe + id: OmnimedTool + result: OmnimedTool + completetime: 2 + materials: + Steel: 600 + Glass: 150 + Gold: 150 + Silver: 150 + Plasma: 150 diff --git a/Resources/Prototypes/Recipes/Lathes/robotics.yml b/Resources/Prototypes/Recipes/Lathes/robotics.yml index 2dc0a65748e..3cf91c80a02 100644 --- a/Resources/Prototypes/Recipes/Lathes/robotics.yml +++ b/Resources/Prototypes/Recipes/Lathes/robotics.yml @@ -636,3 +636,83 @@ Gold: 100 Plasma: 1000 +- type: latheRecipe + id: BorgModuleSurgery + result: BorgModuleSurgery + category: Robotics + completetime: 3 + materials: + Steel: 250 + Glass: 250 + Plastic: 250 + +- type: latheRecipe + id: BorgModuleAdvancedSurgery + result: BorgModuleAdvancedSurgery + category: Robotics + completetime: 3 + materials: + Steel: 500 + Glass: 500 + Plastic: 250 + Gold: 50 + +- type: latheRecipe + id: JawsOfLifeLeftArm + result: JawsOfLifeLeftArm + category: Robotics + completetime: 5 + materials: + Steel: 1000 + Glass: 500 + Plastic: 500 + Gold: 300 + Silver: 300 + +- type: latheRecipe + id: JawsOfLifeRightArm + result: JawsOfLifeRightArm + category: Robotics + completetime: 5 + materials: + Steel: 1000 + Glass: 500 + Plastic: 500 + Gold: 300 + Silver: 300 + +- type: latheRecipe + id: SpeedLeftLeg + result: SpeedLeftLeg + category: Robotics + completetime: 5 + materials: + Steel: 1000 + Glass: 500 + Plastic: 500 + Gold: 300 + Silver: 300 + +- type: latheRecipe + id: SpeedRightLeg + result: SpeedRightLeg + category: Robotics + completetime: 5 + materials: + Steel: 1000 + Glass: 500 + Plastic: 500 + Gold: 300 + Silver: 300 + +- type: latheRecipe + id: BasicCyberneticEyes + result: BasicCyberneticEyes + category: Robotics + completetime: 5 + materials: + Steel: 1000 + Glass: 500 + Plastic: 500 + Gold: 300 + Silver: 300 diff --git a/Resources/Prototypes/Recipes/Lathes/security.yml b/Resources/Prototypes/Recipes/Lathes/security.yml index 4a2e737e153..594e6fcdb6f 100644 --- a/Resources/Prototypes/Recipes/Lathes/security.yml +++ b/Resources/Prototypes/Recipes/Lathes/security.yml @@ -888,3 +888,15 @@ completetime: 6 materials: Steel: 300 + +- type: latheRecipe + id: SecurityCyberneticEyes + result: SecurityCyberneticEyes + category: Robotics + completetime: 5 + materials: + Steel: 1000 + Glass: 500 + Plastic: 500 + Gold: 300 + Silver: 300 diff --git a/Resources/Prototypes/Research/civilianservices.yml b/Resources/Prototypes/Research/civilianservices.yml index 26b519e1efa..6bfb50a266c 100644 --- a/Resources/Prototypes/Research/civilianservices.yml +++ b/Resources/Prototypes/Research/civilianservices.yml @@ -133,16 +133,20 @@ - SyringeCryostasis - type: technology - id: MechanizedTreatment - name: research-technology-mechanized-treatment + id: AdvancedTreatment + name: research-technology-advanced-treatment icon: - sprite: Mobs/Silicon/chassis.rsi - state: medical + sprite: Objects/Specific/Medical/Surgery/e-scalpel.rsi + state: e-scalpel-on discipline: CivilianServices tier: 2 cost: 5000 recipeUnlocks: - BorgModuleAdvancedTreatment + - EnergyScalpel + - EnergyCautery + - AdvancedRetractor + - BorgModuleAdvancedSurgery - BorgModuleDefibrillator - type: technology @@ -203,6 +207,24 @@ recipeUnlocks: - CargoTelepadMachineCircuitboard +- type: technology + id: CyberneticEnhancements + name: research-technology-cybernetic-enhancements + icon: + sprite: Mobs/Species/IPC/organs.rsi + state: eyes + discipline: CivilianServices + tier: 2 + cost: 15000 + recipeUnlocks: + - JawsOfLifeLeftArm + - JawsOfLifeRightArm + - SpeedLeftLeg + - SpeedRightLeg + - BasicCyberneticEyes + - SecurityCyberneticEyes + - MedicalCyberneticEyes + # Tier 3 - type: technology @@ -217,6 +239,18 @@ recipeUnlocks: - ClothingShoesBootsSpeed +- type: technology + id: HighEndSurgery + name: research-technology-high-end-surgery + icon: + sprite: Objects/Specific/Medical/Surgery/omnimed.rsi + state: omnimed + discipline: CivilianServices + tier: 3 + cost: 10000 + recipeUnlocks: + - OmnimedTool + - type: technology id: BluespaceChemistry name: research-technology-bluespace-chemistry diff --git a/Resources/Prototypes/Species/arachne.yml b/Resources/Prototypes/Species/arachne.yml index 583fc442e7b..1bc2993f6d5 100644 --- a/Resources/Prototypes/Species/arachne.yml +++ b/Resources/Prototypes/Species/arachne.yml @@ -1,7 +1,7 @@ - type: species id: Arachne name: species-name-arachne - roundStart: true + roundStart: true # I'll kill these issues somehow. prototype: MobArachne sprites: MobArachneSprites markingLimits: MobArachneMarkingLimits diff --git a/Resources/Prototypes/Species/cybernetic.yml b/Resources/Prototypes/Species/cybernetic.yml new file mode 100644 index 00000000000..745212424f3 --- /dev/null +++ b/Resources/Prototypes/Species/cybernetic.yml @@ -0,0 +1,47 @@ +- type: humanoidBaseSprite + id: MobCyberneticBishopLArm + baseSprite: + sprite: Mobs/Customization/cyberlimbs/bishop/bishop_main.rsi + state: "l_arm-combined" + +- type: humanoidBaseSprite + id: MobCyberneticBishopRArm + baseSprite: + sprite: Mobs/Customization/cyberlimbs/bishop/bishop_main.rsi + state: "r_arm-combined" + +- type: humanoidBaseSprite + id: MobCyberneticBishopLLeg + baseSprite: + sprite: Mobs/Customization/cyberlimbs/bishop/bishop_main.rsi + state: "l_leg-combined" + +- type: humanoidBaseSprite + id: MobCyberneticBishopRLeg + baseSprite: + sprite: Mobs/Customization/cyberlimbs/bishop/bishop_main.rsi + state: "r_leg-combined" + +- type: humanoidBaseSprite + id: MobCyberneticBishopLHand + baseSprite: + sprite: Mobs/Customization/cyberlimbs/bishop/bishop_main.rsi + state: "l_hand" + +- type: humanoidBaseSprite + id: MobCyberneticBishopRHand + baseSprite: + sprite: Mobs/Customization/cyberlimbs/bishop/bishop_main.rsi + state: "r_hand" + +- type: humanoidBaseSprite + id: MobCyberneticBishopLFoot + baseSprite: + sprite: Mobs/Customization/cyberlimbs/bishop/bishop_main.rsi + state: "l_foot" + +- type: humanoidBaseSprite + id: MobCyberneticBishopRFoot + baseSprite: + sprite: Mobs/Customization/cyberlimbs/bishop/bishop_main.rsi + state: "r_foot" diff --git a/Resources/Textures/Mobs/Aliens/Carps/carp_parts.rsi/meta.json b/Resources/Textures/Mobs/Aliens/Carps/carp_parts.rsi/meta.json new file mode 100644 index 00000000000..cdecf550def --- /dev/null +++ b/Resources/Textures/Mobs/Aliens/Carps/carp_parts.rsi/meta.json @@ -0,0 +1,17 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Taken from and modified by deltanedas (github) for GoobStation", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "tail" + }, + { + "name": "torso" + } + ] +} diff --git a/Resources/Textures/Mobs/Aliens/Carps/carp_parts.rsi/tail.png b/Resources/Textures/Mobs/Aliens/Carps/carp_parts.rsi/tail.png new file mode 100644 index 0000000000000000000000000000000000000000..bb0b9458102d2bc45fcb23a1299ec5d627695ab9 GIT binary patch literal 244 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz&H|6fVg?4jBOuH;Rhv&5D7ehi z#W5tJ_3h--oX&~@uJ5@Sxo1wxIlz~5c&_Y?hOav|w>C!ZGFt5*By{LSv%rkaMGL>j z)Hftbw0%tOGj{UQ{A|akxWZ`tZYKr-K?Vln)tj%d7M%-rxpyim`xTS;Tc$L(o{tq% zdkwD?C4A7poqON4?wWY6Pv_9;3 n9Qsl0-tV8a(?B+<-(j%1;hefA>G*M=iy1s!{an^LB{Ts5fYV&u literal 0 HcmV?d00001 diff --git a/Resources/Textures/Mobs/Aliens/Carps/carp_parts.rsi/torso.png b/Resources/Textures/Mobs/Aliens/Carps/carp_parts.rsi/torso.png new file mode 100644 index 0000000000000000000000000000000000000000..ab0f5ff82f052cdae7df742d3821405ddace5baa GIT binary patch literal 479 zcmV<50U-W~P)@dbnRWJ$1S(W2k3w>ckat()*(Rn@GV z9~JTnsbM%CkE5JP1EI_T4Dfh7fX|93rLfi}2Ap%rSf|rzko9K{Gz^;OInFt} z_iY8f0s~lU(ONe{KX7883mqFY%QA!ztX8W@Fo5?S7~ehbalkp(d%_HYgb*$Kdc7tv z?>(E%hTU%0!ljgGt(({DmF%p^p3labT002ovPDHLkV1juf(YOEr literal 0 HcmV?d00001 diff --git a/Resources/Textures/Mobs/Customization/cyberlimbs/bishop/bishop_main.rsi/l_arm-combined.png b/Resources/Textures/Mobs/Customization/cyberlimbs/bishop/bishop_main.rsi/l_arm-combined.png new file mode 100644 index 0000000000000000000000000000000000000000..a6ddbf3589153940294455bcf47e5419d391323b GIT binary patch literal 388 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=oCO|{#S9GG!XV7ZFl&wkP>``W z$lZxy-8q?;Kn_c~qpu?a!^VE@KZ&eBIZ00!$B+ufx3?7YS{($Aee?{D?mt$*z{CEK zCp4zbdP0>9=R5_E4NI7M8Q80CudJGOJST42zxuj;6B3z|>;-`)GKihpRPv~CeN6FX zlbwq+eB{GEn}j=E*tS->?O+b)ti_eHwB`16Z``#`wM%K^6_Z|_(@J)GI@x2dznndJ z^>T;jrtY7c7V)oJwQAQEhPmO_?oV-#^Emz~;g~2LoBA?5c8$zQxtcWD1c$Pjx=m z9awF1+k3}Z&Kb`mKiN#*oVU5bqEFRR=;Wq1SMKDBCEWDn==<&C+a2j>^immQ+z<0Q Y29E!;8{FnRx&z{Sy85}Sb4q9e0AszG+yDRo literal 0 HcmV?d00001 diff --git a/Resources/Textures/Mobs/Customization/cyberlimbs/bishop/bishop_main.rsi/l_leg-combined.png b/Resources/Textures/Mobs/Customization/cyberlimbs/bishop/bishop_main.rsi/l_leg-combined.png new file mode 100644 index 0000000000000000000000000000000000000000..915b2af4d37aa4cd5b55f573c7c67326925572d6 GIT binary patch literal 523 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=oCO|{#S9GG!XV7ZFl&wkP>``W z$lZxy-8q?;Kn_c~qpu?a!^VE@KZ&eBxdomsjv*C{Z*OhvV+@pFeXx0UZ&*oIzT;w1 z{sjRqUv60>(C@JRl6Hs7(uE%xw4!8LSzC8onqTxWn|-(b-JQFSYC3(M|1o}-agM(O z4o%EV z?KDC7K>X9P-HL3_Y~=V`CjGK+*mYM=s+TS4#@n(LVXH0V`Z*L&a6ZsBkl<;OJ^lW} zv+J)-U66p$@i4LfQ&P=>O^+=o+ua+Z*Y32i;bh9A*B|57Pv5ofU+2Su7ZDRTtJ=*! zzfW7H|M&(2-ZSh0D?@7h&r3fqHIZ`N`BOZvd(WoIRNMTU;s(pP_n zhy5n~V9@b-s^NX%`De*eeTB}MXP)uQIU03l*6oMC|H_r>KhOpXochCMVDc=^;Zlj! zSNVNR(@(R8JrjN~r+b(9gd;v_#cb!4l+@;*jNIkA&+6A6VB9fyy85}Sb4q9e07Eb1 A^Z)<= literal 0 HcmV?d00001 diff --git a/Resources/Textures/Mobs/Customization/cyberlimbs/bishop/bishop_main.rsi/meta.json b/Resources/Textures/Mobs/Customization/cyberlimbs/bishop/bishop_main.rsi/meta.json index a3e6753cc44..94020ddda5b 100644 --- a/Resources/Textures/Mobs/Customization/cyberlimbs/bishop/bishop_main.rsi/meta.json +++ b/Resources/Textures/Mobs/Customization/cyberlimbs/bishop/bishop_main.rsi/meta.json @@ -23,6 +23,10 @@ "name": "l_leg-secondary", "directions": 4 }, + { + "name": "l_leg-combined", + "directions": 4 + }, { "name": "r_leg-primary", "directions": 4 @@ -31,6 +35,10 @@ "name": "r_leg-secondary", "directions": 4 }, + { + "name": "r_leg-combined", + "directions": 4 + }, { "name": "torso-primary", "directions": 4 @@ -51,6 +59,10 @@ "name": "l_arm-tertiary", "directions": 4 }, + { + "name": "l_arm-combined", + "directions": 4 + }, { "name": "r_arm-primary", "directions": 4 @@ -63,6 +75,10 @@ "name": "r_arm-tertiary", "directions": 4 }, + { + "name": "r_arm-combined", + "directions": 4 + }, { "name": "l_hand", "directions": 4 @@ -76,4 +92,4 @@ "directions": 4 } ] -} \ No newline at end of file +} diff --git a/Resources/Textures/Mobs/Customization/cyberlimbs/bishop/bishop_main.rsi/r_arm-combined.png b/Resources/Textures/Mobs/Customization/cyberlimbs/bishop/bishop_main.rsi/r_arm-combined.png new file mode 100644 index 0000000000000000000000000000000000000000..eabc7e4bd8837b684aa8a05ce0812f0cbb2ff994 GIT binary patch literal 401 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=oCO|{#S9GG!XV7ZFl&wkP>``W z$lZxy-8q?;Kn_c~qpu?a!^VE@KZ&eBIW+1k!xm2i?Yhd;vd#PNc@vppO@QyWwhCHj&M z?0>@3l(1&iDHmpw<@O;qNr}16=_I4fdCR?w%Ukc=>EKQ)=X_+2a4w zE?4~7z3=_f*H$~b?(%NfqP^khtCAn;_rEV)m%XzqmiL2=f6R5!zopr0FLCVg8%>k literal 0 HcmV?d00001 diff --git a/Resources/Textures/Mobs/Customization/cyberlimbs/bishop/bishop_main.rsi/r_leg-combined.png b/Resources/Textures/Mobs/Customization/cyberlimbs/bishop/bishop_main.rsi/r_leg-combined.png new file mode 100644 index 0000000000000000000000000000000000000000..a035dd862652e2af236f707e6e8aad17567c2b84 GIT binary patch literal 525 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=oCO|{#S9GG!XV7ZFl&wkP>``W z$lZxy-8q?;Kn_c~qpu?a!^VE@KZ&eBxka8Xjv*C{Z*MK^JLDk2@?hs_R_}t0drUmj zJ}_{I$jMAo;OJ+NYjt<<2#_$aVc_azW^C$umui;TWU;w^N7>OD&)}Oc=jWcaZ|H!7 zKe+}HJ3jw>BcS*!$&Tfh+k)ed8}H_cUlo|qzEh`8AY=F4M^$?l-Oby5Htln3li~5K ztxj8`T3s)2?ugN|kl}mrwW@>j^OV!65iGn5Zof_18<%V&w>WIIBHNil8@a&s*AoT* z@K@N)f0p@wx{7CwUiShPv$@&T-th-Zm{wfP`dJ-V?NlaOQ5fzi)8P7{ zYR(Q7-^*9_+x%vF!~5jz-qiU_Z!1?)S_8 z`}uu;|NP*nR*v9ahUK2BKLEI|0W6ZrS|pY2ZE_Qfq_Y1DfG%1VwC>;Lm6O?&sPRlu z&-XUD>-t;O1fYwy9rDWnYyhx-oA*XCn-T#m>2+lwXZbfm!vFxF?T}yo?c~%NK>*OZ zH^=7BgE^C9^#eGfiLm*Z#xq5YXNt*eN{sOSoUzknHsy@)e%T_a?5%^7B6}tzKYBVO zyGDa@RYzJma@P+{6qY6m>w4WoXrc)E_Za6PG*MV{ZH)5}V~!?@@YHedy4qHbfU2~L z9nnO%G~7210GmHM7r))@ohhfL-9rIcuUpzeVgAUZsPRmGjjjJ!-WK8gb06U{rH{Zp z6p(*7k)mpLfF?@3yQhbAbas*FdU^;=l(62t-s!I6K0*^ksN#U}xzK*fx6TD?wa#14 zOrP4Zr~g&HU4W`CLDMws>JE=R^uk|w_QWCpU__d70AI3v7Y z9+9S;okJmc-Jt-|gA-0OfYn^&h$g}+4g&z}+Ml36Au~INC;fYH{qhyiHX19qg{Ox? zvbqImzM)}u@Z36a17OweH*z4}-hXt!C2}Z8*YV7zO}O3CjNj82Q7kIRq$Xe1cxK#C z&qjE^JpHDmJ}2SIw`u$`JBRP5&K@(?mxlYsEs`4d_(B6a0(-Ht zx(d<#1U$abNsFY0OT&G!O3Ta`6-S^$lm)^7IsnX+-MQ1f`qtqNw>K~#`ns_4xQLqq z2R6TeM+y=$-=t9J4JC^oM-SBOfVn$eP~({x^U0?$&Rx$_psfZ|pT7hc?lqQK#& z`2ws>R+ReRdA|(nsvE%Q#0KdZ+D3!x+zqy{fZb=m1e;%glY0!SE2{wT(%sIlI)Ylj z^bzg!2FEwX*h|BGiwy@bhDB22UHe`cSYBENfHmR(-UIMK zHHiNNppVCJSplF!L*=o{M0$mj?Q$_9j` zI;j{JI$AGNQ|k)~I#TZWI7sdP0$(jrU6peeF9NkNmIV0)GdMiEkp|=>d%8G=XiQ8_ zkoe>fATV`3i%3uqgYis6d_zT2jLeLLM2r#=f(p|UzRXa3v`8s~Bk=r& zS&cVMPDY$u5#_>=CNnu>^`ZrfgeGy#lu%YpF`mJDA?IKLJKuCZMh1r6?z~=(pQ8AH P)-iax`njxgN@xNAxPC+i literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Specific/Medical/Surgery/adv-retractor.rsi/adv-retractor.png b/Resources/Textures/Objects/Specific/Medical/Surgery/adv-retractor.rsi/adv-retractor.png new file mode 100644 index 0000000000000000000000000000000000000000..7df819a183ec39bacfcdd30b7765a0032971ccaa GIT binary patch literal 254 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnF3?v&v(vJfv^#Gp`*8>L*$jIpE8`=vC$_9j` zszon#QZX)cv{vnXG@Np)u#8ihZleC!^M@t5*+_1pV zB~_hy@^w8?adlNi#u;g8o1Ky!4||C2sO-r)-7;kgYp;M-Nf8e#D-Z9(Gy`dc+e$CE wf-@M(*p-=M)Z4sgO7L9Vlis7Q!p6kFa6X;4R4XuC5a=KVPgg&ebxsLQ0KXhhH2?qr literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Specific/Medical/Surgery/adv-retractor.rsi/inhand-left-on.png b/Resources/Textures/Objects/Specific/Medical/Surgery/adv-retractor.rsi/inhand-left-on.png new file mode 100644 index 0000000000000000000000000000000000000000..3c2e8972821ee1557f396179b189f87ac8a00b79 GIT binary patch literal 397 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=oCO|{#S9F5M?jcysy3fA0|TSI zr;B4q#hkaZ47mg;KVh`t%s5&nTi>Bj9PljkT} z9bLrHq+-12&;PEHn{z8?rZOAzPEcl4aA$JpV`-4#WUv%sC{kf~;=yoYA_GW5J;q`8 zUER-r=7d(3Tg6YE`OiFWosKW$(WQU-+)A(nyLu?AxF^Uqzu| z{(1&wt)CuW8Rte4k5yyWlNv4-C-5E{%Ez(r8^E+ZJqlXScPtC`Yo|t!?lX5 zTzo>+&x>!1)>pRdU(29>Fmd|<^E6hQZx>8CpdQ@G`1V7aw|Mcw$H4Gq@O1TaS?83{ F1OReqo|FIp literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Specific/Medical/Surgery/adv-retractor.rsi/inhand-left.png b/Resources/Textures/Objects/Specific/Medical/Surgery/adv-retractor.rsi/inhand-left.png new file mode 100644 index 0000000000000000000000000000000000000000..9a93d2bb5fc5945ef09d4860560faa2a5fcc993c GIT binary patch literal 400 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=oCO|{#S9F5M?jcysy3fA0|TRz zr;B4q#hkaZ4z6S}6mebuf%}KSuFHIO9ikDFG8px89wc+_XRO}9BzR}{%(;9w4th*+ z5D=d~^Y@)Q)n+q&?|J(f&1{^m-;vBHaGXh@kJUkjyTL+?p-_k6Q3S)0jSL_O^_T-6 zc4w{Mo_1mB`=Y(M>dS4zcE>LN_rFmu!D{yQ)NJuvyXzu37y+DX(v?*EpZYhPbZ z-VhsZKQY|ycyEK6LhkkZXOjZ1pTFv*+np7nnDkZHgfa8e&z(C>5)So+JJ~aT@=G}8 zvp(464oj@V5e4PPzwD8$$LTJhgkML)il{mlyfV*SO)BTI{*G+K#5Ii~k$)|Jys0WMLADLEfD1G(n8!(6&JYD@< J);T3K0RSAeq1*rf literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Specific/Medical/Surgery/adv-retractor.rsi/inhand-right-on.png b/Resources/Textures/Objects/Specific/Medical/Surgery/adv-retractor.rsi/inhand-right-on.png new file mode 100644 index 0000000000000000000000000000000000000000..f91961a9df3aa8347df9b2bd44a5ba9a56e26d34 GIT binary patch literal 421 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=oCO|{#S9F5M?jcysy3fA0|R5Y zr;B4q#hkaZ47->NMcV2QN_Wh4mk{uOAbKPzT08q9b3{eM)V14hT|1>+!6f)bcgti; z=P$Y}Id?qM${wBgU;k8K()WFpGkNxGaqMGhkl|#o6k;e+VR+)faAG3E1Z74AcP0m* z#GK_!ReR6G>KzxmH|6}t8*?`+UR!;0z9mcef!!P*3;)e2^4Xv*^FQQ3@+Py)<+pd* zJ3roN(RfDo+wN;g@iullm~swXJboqD{C@8`rtZse5ifoyFoyB|J@~===g&{4Mc=Lt zPb!?%a^Yj3=!Gv&dS^W8U6H)u<;m%e|6%sybQn}Zi_@bvU18ftNheK4y9rau*>cYQ znf3qoo~0~5`fV7N1Qy85}Sb4q9e09WR$i~s-t literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Specific/Medical/Surgery/adv-retractor.rsi/inhand-right.png b/Resources/Textures/Objects/Specific/Medical/Surgery/adv-retractor.rsi/inhand-right.png new file mode 100644 index 0000000000000000000000000000000000000000..6444d084235a2774e056cba05235a803283dfc27 GIT binary patch literal 405 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=oCO|{#S9F5M?jcysy3fA0|TSG zr;B4q#hkaZ4ssqc5NWGF$k_5~t+L1w&N~aaEt+01$jLYqvbYyA3GS)hV6MBvQKj8O ze{1H_jZgpY_paus)Q^|TRLtinQek-F!Ej<*LW7)I-Mc< zTkQQx_q#TG`48IZ+zT@I|I3c#1e|UIO8oS6I5DqrTau}mz^3#CXCr!9TV6>P6yN^+ z&+7ZXeI{Z8tI`)(l+UfMkC)=+xNCeNY|VVWgA;6-bB|t17l8WuGu!F|H9eF0CQ1Us OnZeW5&t;ucLK6UUlAuul literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Specific/Medical/Surgery/adv-retractor.rsi/meta.json b/Resources/Textures/Objects/Specific/Medical/Surgery/adv-retractor.rsi/meta.json new file mode 100644 index 00000000000..592796b3e08 --- /dev/null +++ b/Resources/Textures/Objects/Specific/Medical/Surgery/adv-retractor.rsi/meta.json @@ -0,0 +1,33 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Taken from /tg/station at https://github.com/tgstation/tgstation/commit/67d7577947b5079408dce1b7646fdd6c3df13bb5", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "adv-retractor" + }, + { + "name": "adv-retractor-on" + }, + { + "name": "inhand-left", + "directions": 4 + }, + { + "name": "inhand-left-on", + "directions": 4 + }, + { + "name": "inhand-right", + "directions": 4 + }, + { + "name": "inhand-right-on", + "directions": 4 + } + ] +} diff --git a/Resources/Textures/Objects/Specific/Medical/Surgery/bone-gel.rsi/bone-gel.png b/Resources/Textures/Objects/Specific/Medical/Surgery/bone-gel.rsi/bone-gel.png new file mode 100644 index 0000000000000000000000000000000000000000..ac425d8014c65360682ea0aa8b90317352a0d87e GIT binary patch literal 258 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE3?yBabR7dyW&u7St_Kbr*uH)H&!0bgdV12* z(u}HGl%m34y?T}K|GUqP{}(S_R9Sj&(#<<(zkmPv^Xu)6>y$j4_T}aLnxeB9XaZwN zkY6x^!?PP{Ku(pXi(`mI@7q&`LWd1FTmqAsnUqz2|C?^=IXCpxnUvYO|88&lZ`b?6 z`~LT2PQFE|55yDhxb8F!YrNYMwb+Uy=6tYhvq7;rH_H|8kn+|8)t?G@4o!akA)@h2 z=Rwhf<@W@|*^<-NHSoNPH4s?&PKjemhtxaOdx!s~e`jz?Wfc$Je2ow23IyIm{0DQOrli zwz%2ivJHm)0bg1?=DAB$C3^8+*rv;uXy3nq+aN=>s^RNbTeZcPMGB|>70;GylzXr^ zI&pXP4(Eh3$^pzzZZ^FAqxHqAy5F=v;7EXW($Xblobg=0;JT3)|iX zDja!dD3M^d&n;O#u<8D6YnHt( z=UJ)IaQ3sv((7cRX!5d2^yc4L7n`&-Lah2vZC$@1EAy0p$G;za7tHUZ;Lkt+ z>2ofSK5)iC=)lG^Jb%K49AdAh{WmglZ$IF-k3Ggu?vMMlnT*-F@2~r?oiH_i;D77c zHpaBgaqDOEOvp|zopr0MIn4*Z=?k literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Specific/Medical/Surgery/bone-gel.rsi/meta.json b/Resources/Textures/Objects/Specific/Medical/Surgery/bone-gel.rsi/meta.json new file mode 100644 index 00000000000..48775ff522a --- /dev/null +++ b/Resources/Textures/Objects/Specific/Medical/Surgery/bone-gel.rsi/meta.json @@ -0,0 +1,22 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Taken from /tg/station at https://github.com/tgstation/tgstation/commit/67d7577947b5079408dce1b7646fdd6c3df13bb5", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "bone-gel" + }, + { + "name": "inhand-left", + "directions": 4 + }, + { + "name": "inhand-right", + "directions": 4 + } + ] +} diff --git a/Resources/Textures/Objects/Specific/Medical/Surgery/bone_gel.rsi/bone-gel.png b/Resources/Textures/Objects/Specific/Medical/Surgery/bone_gel.rsi/bone-gel.png deleted file mode 100644 index f66bf6cdf9eb1aea9b77e8819b3f0cd71609ab3b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 432 zcmV;h0Z;ykP)VQ!P3~dK!$;$qRv9CRT%t%)UfGl_SvPTGP zJNTa*M^F?3_wU?ixOM9hgPNKg*=CUJfBX2M(_jE z8DNgtuzn^&VR`F+VjV$p2%I>3nZd$XmqF23i{avO@QL{kgQy%2hTNHrrx{HAO@Yz!h2bGk9Zej7ZXpPO zECsQ*Pi|-M%&laQH`FA_9I_n%vKSqJ9FZ|^5q%s01IWGy0lI|%y5+DCdHsm^_$S)| zu=q!}oE$)w13(so0Hv0b?EsL)Fh_s@EJQ$nE@=SdYh>RehXPI0fG!sggW_KnaA5=T zDK^XWf%1Gnb$4mu02oNnH^eDN)4Bju#cJJp^nd5JgLu`E(lR1B1judsQOyC=2BQub abpQay3zG>w#k|=70000VQ!P3~dK!$;$qRv9CRT%t%)UfGl_SvPTGP zJNTa*M^F?3_wU?ixOM9hgPNKg*=CUJfBX2M(_jE z8DNgtuzn^&VR`F+VjV$p2%I>3nZd$XmqF23i{avVQ!P3~dK!$;$qRv9CRT%t%)UfGl_SvPTGP zJNTa*M^F?3_wU?ixOM9hgPNKg*=CUJfBX2M(_jE z8DNgtuzn^&VR`F+VjV$p2%I>3nZd$XmqF23i{avY_w?p_B&oewce;uwy-cXa_;kPfeaR3aM_?vmXquN zT`nF5#lI}TI^YY~r`Rmh2g>sS)!n6q17ILQ-w>x9O>+ULiq*RH=>N`b2l1*SrDa5N m2$0+MqnZP#4MrU>>Hq-vnwwVQ!P3~dK!$;$qRv9CRT%t%)UfGl_SvPTGP zJNTa*M^F?3_wU?ixOM9hgPNKg*=CUJfBX2M(_jE z8DNgtuzn^&VR`F+VjV$p2%I>3nZd$XmqF23i{avsS)!n6q17ILQ-w>x9P3r4&qfuO3R4k5FoehM>Pjf8;m+&)Bykn1(&uM)eu4e0000VQ!P3~dK!$;$qRv9CRT%t%)UfGl_SvPTGP zJNTa*M^F?3_wU?ixOM9hgPNKg*=CUJfBX2M(_jE z8DNgtuzn^&VR`F+VjV$p2%I>3nZd$XmqF23i{av+3c>X$AOx{ov%-%k^ zoxwA=62kxXg*Fa=0Z};~AU1{bAD)NMAV*}(TSSss6xRi3HlBw29t1!kKsN^_?HD(2Ydnh6q{xGKzTl(y1TS+01PDP8{(9sXfnX&I3m m0_3*+sOA7_gHZ>JIsgD|ZIr)=vS7Rb00003B@lXJo8&@^5KR&K1&oaTfJKE<(2`R(pR4EccK_e&tri~$@AVwt=XcI~ z-nUNrXSD&^0BrzA09*3rf>nGwuygt=0HM%`97zt*#Y(|)k;&zm?7dVmjaRD=0oMR9 zUtLerSF}dOiF4`>cIk3H-)j^v%qq_v5q8ueGAzgK#nJgQ{#Dzs;fS}Upskrhk z=6ad|{0Mu8MbUl?l{SXw!=q!h3z`CK<>(&3R-lD2;cB%IBAj+6S_WWY0L_HKgV1uP z)w=>{PO)K(PlcPx9RZ-dyP19UI6`*SxvAb30D60UQ9gN^PqLD-=Sz!8)d&L$nQxE> z0KSSLt{(f$7YpKe*B(jV03g2oguznp1%78pa)4g ziS zU?2wwF)E<&8BIh{1;iYS7%&7xPy`YS8QL6>1SC=u8Jdv=7=K$`1e1{k7$gG4Qc(mL zTTC-h1Q^7eBT!w!lwyh|Al4j$>NdrUFcDM{u{LK^V;M72jL?-hp_?MP0L>!rQ>aQ9 zQ+6t$nc|p?>N>`BF$XjyMd+p|+(EU7fq{3TBbvxP3jtICIdL=rkw!EvjA#nL008}4 W8z(3rkdgoZ00{s|MNUMnLSTZFmS7P8 delta 568 zcmV-80>}NI0>uQ77=H)`0001UdV2H#000SaNLh0L01m_e01m_fl`9S#0005^NklY2rexd)R<7sf<(~RSWad` zgoF@AIY2syVzG_<_@uARqC-+MguzI5mV;VRJwMA0RXz)cBmb z&bj^+0Kr#QmuPmzN6C{j3K40lAuIt(rB^CE7R5QTx#kFjA;4C6T`Rwo$ur@ht8`Yp zpwz{&a)<_iNw-_`Py56@>PL#tC06&f(=R<=O^iPQ? z$Q7Pkl+NlCp??aZ0YF&(6X@u0mtZ?GAL#GXE^qG}Ahu(1YDb0+$Pfs^djI&;0s+6? zlnhC+c*`!Bj-eR@`eI>mPC#H%xL;b88 zvLU-Av2__S1Tu&HSWu$&2)rDooxLcHjtq*1xnCOdN z0VELIEoPh3u_vPXp20Q+2qs8YTL3&ARvF4;%=<$b01Me!ZA7_ot7o+Uc3iNMvL0yl zSwRVaTrp>cuzO7_bD$o=u9S|Ud}nk7K!<2T-T&9jX?+8-P)~H#OfyaZ0000 zPZ!6KiaBp*ZS-Px6lnX;tk~)=;Gr3_m}S0#m|XH{l!Yus{_{QhlX%iOzG za`TR*30+|=`90ln-QhPc&U62pr<`%-tMn?SCBd0d#}f(`nWe|=>DVf;P)$L<&Z_qK z-@9vHIiz&nO>WwRSYkiMD)8i^=##cs$}`9tl)auZ-<3-gDQ|WIsL$My&tEz4+yNa vY1+jQdB)(d(*=v9snxv49zksX!t{*uLH~gTe~DWM4fCWgh% literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Specific/Medical/Surgery/bonesetter.rsi/inhand-right.png b/Resources/Textures/Objects/Specific/Medical/Surgery/bonesetter.rsi/inhand-right.png new file mode 100644 index 0000000000000000000000000000000000000000..3b9942e76d245ad340f50e5c2d91df9b3a912eb0 GIT binary patch literal 474 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=oCO|{#S9F5M?jcysy3fA0|R4^ zr;B4q#hkaZ_IfcpinN|@ns7*6Ac!lo<$-X9ppuxKtCZkTr|p8?TRlWrqz{^J5L)vm zvxbQ?YR6KE4~ExbQl%41(@baIw0)kvO|s4M{vAoSZ|53hI2kO37>ZOFo_H{vn8+|e znNh)=$)S&>VNML=*=J5xQnv0Z45lSk=QmU&o0_}lYCrguHbc$7+`_i2US_)Xf>XQm zA4adWymQZe|FeQs4Qqd>Y<+(-VYyJywXj&J92F8;!M`9-&1E-|xYQsaKN zE7Ff?ou2-pxctwX*R0v&H2uM5x98pl+N&Qom$sa_{%&`Fxmd!(|EEIT{1WWM?5y*Ha#_s5z7{6BzN zZ6%ZTaQHk^el`VQvV)_xZ$G`fx_+;hHCrvWy1eB3&Q7|S79tuTTbmbzl$-@(b2$)A0rvNH-TB4kkK>*8 zp&h`@?cG@8V*@m{w~83}&UVI4gOC+sGj}HY{CF=iLi)9e1|ZldJhUl1<-KNdamNHe z6z2Wh{6gUZ3R2S!K$M#I69Fh!Jf2hRR{;?9$KBJBy_O=xbG^Rdx4;YlvEL}%YbnP7 z0GJ2opLhvvH=8X#QVW@E?K18he*NGAIa zs77iB5RIUCFzuu?QY_%&3el9D>001*kOjJd{z`!ptKTuX>8%2~QjpEwi>Ly#I zv$@gv`SpvIw-hvFZFP+t94u=&G>u>`%A7|{B2DK?pd|nR00DGTPE!Ct=GbNc003!8 zL_t(IjqT7u7JwiK1W+ImNK5a3+VTL5%QnsS!+QfnfAX+kKUa#v3D#PSfxAbo`M`3u zbK`jhHkXY%=Pt`5(thIcdVb)}i9_AcgTz#!w`L6YqxGEWx+S2Gc_AmEF_BZ3jYIuB Y57+Jj&1?>nf&c&j07*qoM6N<$f;Ed_C;$Ke delta 165 zcmaFIxRr5&L_G^L0|P^2NcwRgr5@lD;tHgnJbx7ymR97dm0#b#e)loAfMNv`2PpwP zeRGeKX^tNkyEv&SJ8EYi0xD%J3GxeOaCmkj4al+aba4#Pn3$X(A?P45^>oUcB_d3Z zcTAlg?h|Wk9KaFDy8P?2ne$FC*@SiTFPL#~PxW?2xm7E}x>r8Da*&llu9)lng~vkb QK!X@OUHx3vIVCg!0517Ef&c&j diff --git a/Resources/Textures/Objects/Specific/Medical/Surgery/cautery.rsi/inhand-left.png b/Resources/Textures/Objects/Specific/Medical/Surgery/cautery.rsi/inhand-left.png index 1c94d4e488a3d58ee7a3da32f83d33075908adee..dcc6bd69467f0d5280509af48c389b57b2f07da5 100644 GIT binary patch literal 420 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=oCO|{#S9F5M?jcysy3fA0|R52 zr;B4q#hkad?6a5xMOr@!pI~d+8$F?cC5ThWGj-yjAf01=IYvtaH!*pN#x#e{@==Y* z;JCqIl%Vbr_GohZ5qy>5Dj z@t42;!*v%OKJWYVe)cwt$IE>ftF~Xg@P6yXs*HoXIDT9CoOSeJwDRQ4v~}D!clP}k z*KhO4&14K&m;G>=bzybN=Gzopr07}EBt^fc4 delta 346 zcmV-g0j2(=1M~urBYy!qNklrS1NT?8c-!e^L{>Zc4OJvv-HZTtABD|IB&qw?xqnD8K1pM znis8_P=7y|+^)FT+jrCoZx8m2h)92ZOKz@?t=9>o%*@{&MMUJGx>nn#I?oSG7-d#} zLKtPn^8=Mf?_bz7Vd)NE^Zda4^d_Wvv7Cno0000000000&=ALo)nKJF`GC%-lHs3@ zw%XdXjTqY0fke62|?pegbL006f>0bZ1HexMevfB*mh07*qoM6N<$f{jX@2mk;8 diff --git a/Resources/Textures/Objects/Specific/Medical/Surgery/cautery.rsi/inhand-right.png b/Resources/Textures/Objects/Specific/Medical/Surgery/cautery.rsi/inhand-right.png index 35db4795ef5a738a9f7dd846ecb1a5e5e069689d..1c1cc9c4d803a7ee8cbabd8049441b5b1f8396f3 100644 GIT binary patch literal 430 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=oCO|{#S9F5M?jcysy3fA0|R4% zr;B4q#hkad4852g8CoBjKj6J|`zC9XLetcQE;;|(>`C`0t_l15 zeT%Ma+Iw1xP1q&3?7xi3z2CAE{DLQMYdrRDVX32lX8C-@$IbCghW0gr(!05S1Tjnq zCWsm?@b6grY5%u7*F6gwp0@Mf?fSRg=$ZB(@q*n)?w<2ZO=q)WueSfZH>F?u?p!^Y z1+R>mm#>xD_uSb|_V`Ecf>l<=57zC!FE_R5@6;`ZPuGk?kO_rcavNg!6aRtma ztQXMi0-(V%#}o=AVFCnMQi%YAz(FQ=0pv%J%55!Mx3+m7+mrS`r%lawBme*a0001> z)b7R;)9v<5+WMV553>!=FL9>&r309a+9vKDr=IAx)h9y*yMG_4>lY5d4_RKlm5=XthP4qg6jol`u!$JdW|3E))m!Z>%>S>WA8wZ_ZQjD?|Ol;Y^OAD zd=blbjOzvId#O_MiPS^z!>Dr2CoJ1BY5oZS0000000000lB6uTds$R&KVYL~qxMF> zh&=Wb{uO)oJ5^0{y5G?4=TtvOXSy1k=N_N?VPxu)p(N>Y{Jys5t#qT6GWZM%zpIcr ugU_HeaeW>`C{6Q;b!PBY-cL*K ztDir=O1n-GF-h6H^P*bxQq|r^(o*L7hW0WtI(CLL7=gMNOM?7@862M7NCR@Fdb&7< zXiQ8_kYHWW5a{9Q=^1!~K`%k*5fjtFwx*`0W0|ZDjMpz*xR4OMe8GZ_js=m@5)vsk z4NQvb`~(FR6%`oWjte(Ac^R?KZk;-HcD0eYfdT8cEjui@xVT>5vn_s>^No$IPvN<7 z`Z^6w&3N`%$2Z7o2wc3h;>7Dmg<|h`rmOY3-7`)X;0xv~6?7=gY*#w#%*@bbr{O)J S!ekQAfefCmelF{r5}E)zi(bzF literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Specific/Medical/Surgery/circular-saw.rsi/inhand-left.png b/Resources/Textures/Objects/Specific/Medical/Surgery/circular-saw.rsi/inhand-left.png new file mode 100644 index 0000000000000000000000000000000000000000..fb5a065550e90bf9f235d8226c0587c9699d3317 GIT binary patch literal 666 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=oCO|{#S9F5M?jcysy3fA0|S$f zr;B4q#hkaZyuGCZMUMYxv~S`NtI2-k*Am3CG>n6*>DJWQue_E%%1&lwZW5W&#n0lp zVatxp?hCGhv8Fr{@z#NxHf_ASqC4+MzQT3OaHhzYJv)z|wcLMJ<;>j4JNM7oS^RJg z6NfvigM}8up+H7~KCXs>5Qdh;ObRlh3=dZ@fTeVp?v?RNSmpiwBUC83KJDct7eBs& ze~;%*uGncI9`Iw+eZPI{^IQ0iO>LQdM$e)^@4>Gh*-r%iE<5u1Lv6BT=ccI5yA0%_ z4!t-sY3HsV$(vuiuUPrH-j4gUvV+jK{Mo*T{{PARWgGRl@bbkl@d_d9{g=(UC*7-c z3$!sfxQ%0(|MwTm*0vm->1e%DK`0~U_3W&g8BxdgZSQ^k+ahPfKGrHWwZbXCT2o%h zX9P{T#&644GVj>M3a|QIcD7rNS9b4V%32+_V0Eq7>g@Xlrj~78vtBem&b+i<>effA zdzs=FBi2X=KWGhQSZcHM%Zq~bzR!=}<0#p;Zr{xx*==)cw(RLJ{mc2SH(d}7gmj*N#4Z4aa&wqO3r_Vqf1ZjuGn(p8>39OyyIWyi=ULzKb9!7 dfMW7F-#f`q58{q^Rsa(lgQu&X%Q~loCIEm1C+`3N literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Specific/Medical/Surgery/circular-saw.rsi/inhand-right.png b/Resources/Textures/Objects/Specific/Medical/Surgery/circular-saw.rsi/inhand-right.png new file mode 100644 index 0000000000000000000000000000000000000000..c0e064d10b1231794e3e09b5c561e0b642383720 GIT binary patch literal 668 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=oCO|{#S9F5M?jcysy3fA0|S$v zr;B4q#hkaZe6xiEMcVE={C9AS;iwDby*YK2h@**E8wca*me9(&>!R4$AR;wo zg>>@5rDwfd3Ie@$8?j6hxyxy!?JH_nqUiC`e!}ZH+^scdju=dqlsR9SFvG#9;GX*T zb3Aj5nVxkp7`U@ESSm4`5oAp0<6tOuVVI%JbU;Rs0VMT&JyY8HrJ{4q@2ztaU|MuN zUc2;}(!R7l-jMuwMiINIyV{F>s`Aa{#j8WOH>Fs*ls_nuK(hVcOmMjPetU3N;L4h&bjB@DGFM*mX$L*1T-DYUwp|dXj=WY zyAw{m)ODo&ge`4k{)l zM~)t4IG4^96cof+>eax#VuyyN=1z^ntP*n@xMJpm8r>mdKI;Vst0L7b8FaQ7m literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Specific/Medical/Surgery/drapes.rsi/inhand-left.png b/Resources/Textures/Objects/Specific/Medical/Surgery/drapes.rsi/inhand-left.png new file mode 100644 index 0000000000000000000000000000000000000000..7531299f2a4973619455df6e2bb1919e961b3b15 GIT binary patch literal 460 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=oCO|{#S9F5M?jcysy3fA0|R57 zr;B4q#hkad_Ie#okU08Lc}L`tNA7|wg_m4omNa)idZN)JzHoB*f(N1&FCWQrC~?&3 zEaKpEWhva)EOKz^ijXDeE}9DzbT51^ddl*@YViC?@srakE^&Y4VZe<9vOj$K7Fx8$ z^8Vo&TX&RA_|o6kVEVqiq@myuw|8*HmDy7&qt*RS{(Z}RO#M_x;1ulzU#~4YtHnQ6 zz}U*+o42ib)RfBU>HRZi${s%cTRh2yy<*48<;T1ChMxK>_3roi`TrZrK8qSIV&33q z^X-g|J)7b@Mg>ABi6?d4v1E7l8!JtPuVvZjvzdr0>^X5DruVt1*+s^h#ZjJutF(7} zzAe}*z#*DYm1ktTDeQ5*W<$HS;+hNV``>fb&*M4}2UNX)o$dD}?T01*WtN^Qcqkdt z@Zaj=nm2bF{r2sDE#EwMQMs+da!H0qKy;G1hPkpauHkVWUv%sC{kf~;=yoY zBEtk_Mg?~!hd!1Du*8Ge8!Ahl>wUZKCcqJv|NgP?*H?aPX6j~_MV0ara1GR%Op2>#{JYQesmfm9=$GoJL941& z#RBfx6$buGW8FGS_DSo}FR!Q0@-|-WqjO+Vcy-N(KVRm(-rcCNEIwkU``%gib}`E~ zuD&d-lfU*G_vz*}NxzOTt@-;#Vvmi<@8l;gV%5A?7(I=DB&yBGHqeHI%R=!F%sFsgQu&X%Q~loCIE@KyqEw0 literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Specific/Medical/Surgery/drapes.rsi/meta.json b/Resources/Textures/Objects/Specific/Medical/Surgery/drapes.rsi/meta.json new file mode 100644 index 00000000000..9c30d1b15d5 --- /dev/null +++ b/Resources/Textures/Objects/Specific/Medical/Surgery/drapes.rsi/meta.json @@ -0,0 +1,22 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Taken from /tg/station at https://github.com/tgstation/tgstation/commit/67d7577947b5079408dce1b7646fdd6c3df13bb5", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "drapes" + }, + { + "name": "inhand-left", + "directions": 4 + }, + { + "name": "inhand-right", + "directions": 4 + } + ] +} diff --git a/Resources/Textures/Objects/Specific/Medical/Surgery/drill.rsi/0.png b/Resources/Textures/Objects/Specific/Medical/Surgery/drill.rsi/0.png deleted file mode 100644 index 765094c4cf6e93c724abc5239b5834bba47b871e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 240 zcmeAS@N?(olHy`uVBq!ia0vp^4nVBH#0(_wf1V}|q&Ne7LR^9LJwux*?7Fr2GxUHQ z#*!evU)e_1 z!5cyiE*d|0q;uX!^CUx2Pwx&3;~?Y9#$F0@9!)wjDMTSybE$^0y8Cs9&TeDX%_}4{ zl1?0*88&6cY_23`)1^zEsf01jTxPW_<`mbuI=zHwh6e$%TZLS`mH?d~-W?(tNz#bIPm=Ba>@O1TaS?83{1OT>O B8UFwP diff --git a/Resources/Textures/Objects/Specific/Medical/Surgery/drill.rsi/25.png b/Resources/Textures/Objects/Specific/Medical/Surgery/drill.rsi/25.png deleted file mode 100644 index 6731fbc6064021d0f205a3f6f26c5840bf17f397..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 108 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnH3?%tPCZz)@&H$efS0H^qjA4TYgMYN{YaoZQ zB*-tA!Qt7BG$2RN)5S4FVrp`NM8yHK3w#Hd8CXs*um=S+<^v@eJYD@<);T3K0RT?z B7&rg` diff --git a/Resources/Textures/Objects/Specific/Medical/Surgery/drill.rsi/50.png b/Resources/Textures/Objects/Specific/Medical/Surgery/drill.rsi/50.png deleted file mode 100644 index 30578d4ca777af010d3947a7f706b77195305bc1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 108 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnH3?%tPCZz)@&H$efS0Md)r_!~2p47O%X+RER zNswPKgTu2MAdaA?i(`ny)Z_$-iUVdB_zo~Lu$*9E4+?0^2TC${y85}Sb4q9e0H=@{ At^fc4 diff --git a/Resources/Textures/Objects/Specific/Medical/Surgery/drill.rsi/75.png b/Resources/Textures/Objects/Specific/Medical/Surgery/drill.rsi/75.png deleted file mode 100644 index af4d131c02ba93084177f20c699b755154c0edd8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 108 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnH3?%tPCZz)@&H$efS0LT@E-W?(tNz#bIPm=Ba>@O1TaS?83{1OT>O B8UFwP diff --git a/Resources/Textures/Objects/Specific/Medical/Surgery/drill.rsi/drill.png b/Resources/Textures/Objects/Specific/Medical/Surgery/drill.rsi/drill.png index 267c3e0119a80a40f0487a8c12f56dcc13ff67a5..1f141fb217ba1f91d86c0e8b11d65ee85f05a685 100644 GIT binary patch delta 690 zcmV;j0!{ty0lo#07=H)`0001UdV2H#000SaNLh0L01FcU01FcV0GgZ_00001b5ch_ z0Itp)=>Px#1ZP1_K>z@;j|==^1poj7Q%OWYRCodHl|g6|K@^7nNTJd8U~I%DqNQlE z!5pfHibe=Rqas9wViCkZ4&FR?%)vtso+JnHtmNQ9FpyBA#edd7O(BX{s}Z8zZAz@t ztd+%hFwl5#+HVtd#R!kgJQGw+}GW+s4%iHV8H8e?f@kk{*F;c%GRu~-cG zd|sR9_xqV32uRHQK&Ndl4%l+o(dW_Teq5N<^*MJZ-$9waMQe043LcF{St^x6AP}Iw zBuQA>c$h`bdw)nwFc?HA6vD#`_ps^YXeBasMrhVm5`wg|^? z!ubh1`}Y{G^`ZEd?6@l6i#SPTXjpTD%;)o=@E`}M0*((3 zYI6m_p<8Qo?3V~0yy*-y%Xa4>2Jc1Kl{oeLU2dI!`sp+DZ0(`%FUkWz{tgyP&n+zz zP!nVJrqYR**pKH1!>jA5(|Xd(7(R@}HYLS^9RfZKR7zA77S6QC?DlZbj&UdjK$ zz&<}qjpyiBtyY-y{xdr}e2E#2ZD|JTnVm0@op@6C>$tWFsE5CP#W~5)*V0>1gWrbD zwr|vSd5@4idQe#PKhjnKyIod#IXV3KuCY=?!z-8YUl2u6XN_o^fWqAJA3WVKF-)pP()7(erm#yrdH!ns?qjZW+VlavxD%Uf!uuY(h6KUNkIjE19jas%xfj_|-`wtsyeJ57G>zHM!24SoP%e zCeBJQ>e@TU&Fj<(y_s{`Ry8$h`bva0Se|9@ZIzhSkR`E-;q<3T%qy7E&l&J2F)&1R WNyIotKbHo&fWgz%&t;ucLK6UryH7X( diff --git a/Resources/Textures/Objects/Specific/Medical/Surgery/drill.rsi/inhand-left.png b/Resources/Textures/Objects/Specific/Medical/Surgery/drill.rsi/inhand-left.png index 85164e2dc70098f0493a681710a400ee9657c3a3..e2108b95a749fb0fee11b55d57a446c3f4541a02 100644 GIT binary patch delta 662 zcmZo-S<5;>xt@Wuz$3Dlfr0M`2s2LA=96Y%V2by2aSW-L^LEz8Y~eteQxfT3aA)`RF+m}V?EV`PtR8ITn=G>xiJ(d{pd`0mMJHIad zJ?Ee742N3X?z?*@o?CySa?YdAT5O+#PxRQD1b%7DHB5Oo2R}la3_v6ni z6L)aiUOaf+|HDh=gi4l6Zjbb8cGQ1c@qa->%;z6_c!OgO&Da;qTs0|I{*Y(PVUhYG z#;dQg*L&QVT4VP*)L-j>+f6&55tlC;a~u}vbz?Tq^P82Q9aw&A_cx&lTpxOm#QwNA z@y@nQ>}ne}SKYBsaE_c_n33L)uJVp4^gqK&hWj3OSXcdH{N(zthH sfD`X-e`nxseX~!@p%EClN4PB*ay8HJr|};RSBYy$ONkl*p9HC=t{!(o95@Oz1Rj5q}n;ctd5vQ7&j2zaO4* zLDR*>yt0b}lN~vS|aPstddqerNtFdCdTwe69Yn=$yIuTWmH$bESs<>X6 ziHNf8Mj+d61SE3Ibphhr8{~Rr?w%=aaP0m2LsY$PxvQR|uV2@BHTz%cWS&!{`{4F>$fj`=8F~j9xwjF2w7{=5u8-LxIw)CS)fkbu}`1azCDzG z{=e?v?dRt&y!;Y)*KE5n*MioTxScV4c21?&Uw;+8Ey-#k)w>{UwWigfdglx+o@)k6 z^V`*g-ZLG~SGSwA?4JwczPMW7S-+k}VhLu5 zUXF}sujuXBy3G0fd99KP;e5dXWoZaZV#cHeEwE{XBq`2F8E>Fn2MBbZ9Q`PJNi z$rj?%{7rzTOS*<@`i`#G#=ebPB=_*f9Q`_zWy#qGxev6~omWxFWy|LlFRXnQ-!%D- u^8=-I=XDNzw`I9!!@a`^80T+T|1g^fr=4!CVzjbl00K`}KbLh*2~7ZI=Pd*P delta 492 zcmV`v7fbZzJ1Te29Z)#CqR-nK`Y;Pr$sGHcBUklqoa)_p@A~EPV(9ap1qdsn z(-e$OQy?O;O7_T|yKn^{`Z=?#lFd@v8zY~Mdfmtu^7Q=VP{XOwYqc!+n&BMrEI{Tc zLvmW8@?DaytAFJgrZhd%G=zs{gKZ{vso~Tn4|H&H9-7mCkgDm-D%sP0$Aq~6ME}cw zArHZE3@yOcPI6Xx01u1)I|cv%0000000002FpD7yo@n?q7aH?viqe`tSk9_XY1c0-o`g{tQ3? i{0PE(kOG4mz|S{|cgfjuOPP`Y0000iW*8>L*$jImj3(BhYJ_-m+ z)i<>Fx$$2uda09&aiODiUr^9b>#r3+#f&9Ee!&b5&u*jvIpv-%jv*QolM^Hg6grNj z3yC<08gM#=9-6bRLn|Td#=?d(=_S+WbSzTPC2^Gf)g+?doz}!6g%DYA~Z?K~{no(3}He5e-@iv-(b@yFE7EurM>hz~S*` c;|UxLENA)DPrB4E1v-Jj)78&qol`;+0M0l|;{X5v literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Specific/Medical/Surgery/e-cautery.rsi/e-cautery.png b/Resources/Textures/Objects/Specific/Medical/Surgery/e-cautery.rsi/e-cautery.png new file mode 100644 index 0000000000000000000000000000000000000000..2cd5b0e97c085a12aeb4ea76fdbd621b29e09f54 GIT binary patch literal 244 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnF3?v&v(vJfv-2k5u*8>L*=o{J#3(5wBrKd>;p?MapU~*b~tY)W}#81OOXn`1)>%+}UR(CDp*fF(iK}Mo!|D3Kx4jv_;%trGs1|+j~ zF(n3avWBoWI%;q^IlBhNKGkVi)!?ba5!$#aOK=raa0oBY?B+nz0(S0&S{B;B7+TL4 n7s{_lFq3wz5hGLVc(PTs!NLM>`w(5PAM}?ac9uz zX9$pETwufGP|4EpiGu+sQ5&-`z)1PEdPa_qb&&Bdsf3f#hhH}8TOGDK5L0>ZNMMiO z@_Ch4%e2CiwEs^HZJ7FLPvy5Rj`w|uyHl)hIQ*Sy%22#J<6Zdeh}C5ue~3iyzj%74 z_zu~K^HL4Q(LZZmsHqg`&r-U*aD9B!e?e56aXN{4+V;Ciw*S4KwsdZ`Y(i1Zp&fC8s$b3|zKs%j_}j+m?w_xd_mnm~af@3WyE(LD!}j^+ zhwC(&E>!RTb~ta!Pn)I_VjNM8#am{YJD-+&&@QArA*Py(m!)n3XT%%T9~(b8@y~zq oID`u0`T2P-r< z_*#`xCWmQgiX>e)deCtlTj5KwYClfP`~Mk>CdcnMS#Vyb$DKiQe^2 zYuV@azyE7f!7t_d*CW-sgHdJ~^Vh$t0$2WLy4-=oDX4DLVi%ah8#A%8=@g@m*c|l$ z#uMo*^LCX7TWZV1uYR%X5kt22>T~?BG9Fysy1RcB$Jx2M=66m!7fkwoU%9fd;g8!s zE9L8-g0?KY{qoN3BcD06q802<_y5{&%p7(6Se7$r4 literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Specific/Medical/Surgery/e-cautery.rsi/inhand-right-on.png b/Resources/Textures/Objects/Specific/Medical/Surgery/e-cautery.rsi/inhand-right-on.png new file mode 100644 index 0000000000000000000000000000000000000000..1bbb5332060f03feb501816dd5820248a9a81f37 GIT binary patch literal 496 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=oCO|{#S9F5M?jcysy3fA0|VnC zPZ!6KiaBp@*?S*$kU92IJwPNzWK}n>Q_GGm3U{x##vC6=T}->@xDD}#`EuUtzIRcUmx3iyTI_bn$7RLQP!<&x26kkWq-e1()%}v`|-YtyB_|Gd($60GFZHzopr08{hY-T(jq literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Specific/Medical/Surgery/e-cautery.rsi/inhand-right.png b/Resources/Textures/Objects/Specific/Medical/Surgery/e-cautery.rsi/inhand-right.png new file mode 100644 index 0000000000000000000000000000000000000000..fa95ce487dd4d157f5e7b837b95c5479d8447f02 GIT binary patch literal 475 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=oCO|{#S9F5M?jcysy3fA0|R5P zr;B4q#hkaZHhLWn5NZ40(7~}tV0Wuin}w*#?5+oT`xu z4z3^l+Fxzm+HKLdCbMv==!S~A2HSkewG~x!CNdn))YzT2`1;-rAN(&=zm+^9$yrgo zvwip0PPTiY%d2CvIDaMoEql8^S>?gQpBH~|xUYJt@?ycAAD{J-T#kJ_mhWJ|u_l3G z&ed113?!$06MIp+tkeH5$F!dxB3I;y8o07F$OtkNxiFj%WK?j+$x)xmaJP8B<+{&h zZ6)XTW-Sr=P;8fQ_kQ5!S&|xAYtQ5#c-6HwCZG2X#tQ%d literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Specific/Medical/Surgery/e-cautery.rsi/meta.json b/Resources/Textures/Objects/Specific/Medical/Surgery/e-cautery.rsi/meta.json new file mode 100644 index 00000000000..4a4c2c11d67 --- /dev/null +++ b/Resources/Textures/Objects/Specific/Medical/Surgery/e-cautery.rsi/meta.json @@ -0,0 +1,33 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Taken from /tg/station at https://github.com/tgstation/tgstation/commit/67d7577947b5079408dce1b7646fdd6c3df13bb5", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "e-cautery" + }, + { + "name": "e-cautery-on" + }, + { + "name": "inhand-left", + "directions": 4 + }, + { + "name": "inhand-left-on", + "directions": 4 + }, + { + "name": "inhand-right", + "directions": 4 + }, + { + "name": "inhand-right-on", + "directions": 4 + } + ] +} diff --git a/Resources/Textures/Objects/Specific/Medical/Surgery/e-scalpel.rsi/e-scalpel-on.png b/Resources/Textures/Objects/Specific/Medical/Surgery/e-scalpel.rsi/e-scalpel-on.png new file mode 100644 index 0000000000000000000000000000000000000000..04a27c34bbb860d83a26371b4c4bea8b8dcf3924 GIT binary patch literal 537 zcmeAS@N?(olHy`uVBq!ia0vp^3P9|@!3HF&`%2dVDb50q$YKTtz9S&aI8~cZnt_4w zw5N+>NX4ADGxmEQb`Uup?{F|^qw@w07Zs=I35#Y&yE`s<`{2gO`XeBeCwuGBg9kwy zy1kcjxMfUXVYw~vCornOqOyFi)a(eyUfm!2oZsD3E`LAy`=Nt-C1-5lXkdV#Wx@`Z zFZslVv~Rmyrf_0fa_Ii&|JLk0Q@i(_vdf~4{Mm1Ai^-c`wMa1!TUb@e&iheEVul2pL5SGZ>;`0S@qrNoc9ft#=G1!R8{K@p7^2t}s;X;5XuG zmTDJRWy(Hzg+#&Q^H*LxGCp_t{f=pmm?JbLyI2qO@dw}8cKZ512b)tmbDCDfY@ z%pfw2$%}2nVwulu&;G?_uP&i`Ng~`P;lC^&nhYmObQM4tRL8JT=FzO T((h3PjB5r@S3j3^P6L*2n))}$mr-B+N<_H za#Atw3kveN@n1$KJRmIfNV#XBqqSP}QZdKPZ9pxIB|(0{3=Yq3qyagJo-U3d8WWQf zBoZA?+&FRKNTg?Az|9B)oe2x?EUkR@#PhPYsjjJRx>R~@QiA?>12Z#|LNPP3prD{G zzLW$F{mh`CEtWb5!F*#p) z8d^Ut+Fh~kSc+nJc1?wP+Y)YmNw!1C3$uyH*76_uuji!Pt%DTj_;Y*pL*Ep^pEjr8u#D3XR2%d z|K#L;Zn+_-)$A2h3hVl8)f_vk>uZ1NE^GO})4lYmyT~@~78Wh7JqBjC7l>hZA%@$9 z)gKhpUX{InuX?_YtN4Vg+wVH-hudHMdwNB`fKXhAo+Uo~S1o>O))FSC&Z~+6)yz*itd|H2c&*`Ue5JRb@|^tZo5I_9 h+maxm_JwI5V{c58!JJA?7GTUVc)I$ztaD0e0s!>!z_tJY literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Specific/Medical/Surgery/e-scalpel.rsi/inhand-right-on.png b/Resources/Textures/Objects/Specific/Medical/Surgery/e-scalpel.rsi/inhand-right-on.png new file mode 100644 index 0000000000000000000000000000000000000000..358f397c5e53ecdee587622ad481073fc1912431 GIT binary patch literal 505 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=oCO|{#S9F5M?jcysy3fA0|Vn~ zPZ!6KiaBp**?J!i5NW&LWbbgr*Xm_}i@-}Ii-_3A3LJW`RxEy?FDO$QBFJ*^;5sSx z<4Ubcbz3YtW?%EOinDcEFr)5HP2i;OHr~@t``%Mme|X5!S;3vPK}M9JD1_leAR`86 z&Kb^#Svs>;SE;7&-nYJC=1tb%y}LKwE4aYIsb3;$U}lrGOx>$M`}s=F`+h5TWM%P+ zzhB!w@BID1hCN^3ugtx2%GyI)sP4$k<3Ij7p6B|;84-EgXsw%Yz9!%Mi+|24gzC)H zJI813^?|dZvhL9JV}j4-*ywTZ44JlHVd?%q31^ajiq1biJNEidmM8vq_h-*KTR-O)(e(>{tjYI+b`?;KRd_hh{ffYesY*_ba(gXwD-Tvf_o=BFzxx!JWF!IwDLP| ze+A5MXxaXD|MAu{+A16KU(`3`{0#rE58mtUN>zT96t>B}Cc490DLzpwZ+ zJG`UzzlUhT<@$cFOP{$Wo@ewtFRZe6zg&w$9~Xn=7p6LfKAo9m0g+csfN{y->FVdQ I&MBb@07nhd<^TWy literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Specific/Medical/Surgery/e-scalpel.rsi/inhand-right.png b/Resources/Textures/Objects/Specific/Medical/Surgery/e-scalpel.rsi/inhand-right.png new file mode 100644 index 0000000000000000000000000000000000000000..70a64d2b0e6b8b6718749584a5aad177130838d1 GIT binary patch literal 480 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=oCO|{#S9F5M?jcysy3fA0|VnE zPZ!6KiaBp*ZS*=EAkpf7&{IZacW1Dy6-Q7E3;W{D&65>gykP#p;8)8ae<09RfR#PH zw>eppl|9f~eS4Vo&bVssMu()?CY-94&!df0p4|Jay3_o_e`5uACWk(j1{qEUOCg3L z6^17s3@0WsOi*S7N%%cvd9!BC?BnO%G+%v9W?gf2o6qW>GC$ictNB%UuV9e=_5A~r z{a2|^BKQ0&>n`fdF*B^LG%<2^IB@UZ#+Tdoe>CN||Mq*4ti4Ghx%7DknkU`Ujmw!R?mr?_uxW4Rxp{G1p_W~$2e|Ef=P^dVi(6|^AYHz)&-$Wz!eRHd z`bP0l+XkKpPIco literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Specific/Medical/Surgery/e-scalpel.rsi/meta.json b/Resources/Textures/Objects/Specific/Medical/Surgery/e-scalpel.rsi/meta.json new file mode 100644 index 00000000000..701445e8ab8 --- /dev/null +++ b/Resources/Textures/Objects/Specific/Medical/Surgery/e-scalpel.rsi/meta.json @@ -0,0 +1,39 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Taken from /tg/station at https://github.com/tgstation/tgstation/commit/67d7577947b5079408dce1b7646fdd6c3df13bb5", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "e-scalpel" + }, + { + "name": "e-scalpel-on", + "delays": [ + [ + 0.1, + 0.1 + ] + ] + }, + { + "name": "inhand-left", + "directions": 4 + }, + { + "name": "inhand-left-on", + "directions": 4 + }, + { + "name": "inhand-right", + "directions": 4 + }, + { + "name": "inhand-right-on", + "directions": 4 + } + ] +} diff --git a/Resources/Textures/Objects/Specific/Medical/Surgery/hemostat.rsi/hemostat.png b/Resources/Textures/Objects/Specific/Medical/Surgery/hemostat.rsi/hemostat.png new file mode 100644 index 0000000000000000000000000000000000000000..951d323a52fc4dba01f24877ccbee580d5cf50cc GIT binary patch literal 261 zcmV+g0s8)lP)Gw0m&Em7yV`{yPcmR=Ie&$yGZhM)g9kI}1ZMa&x>8Z$9< zN!%;i%etto-)Ft!1a$_&=)3uI=0(?v**Dk=e{B5`-o5J8wKw$*N-69&K1_`7Dz4;> z-u(XM#0|0ne|O$_ZR2#pxu8S#0jtb6F^NZO8jed<@iy5oHh@r7gL%xCA}?i0(Tl)< OWbkzLb6Mw<&;$S}hmG6- literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Specific/Medical/Surgery/hemostat.rsi/inhand-right.png b/Resources/Textures/Objects/Specific/Medical/Surgery/hemostat.rsi/inhand-right.png new file mode 100644 index 0000000000000000000000000000000000000000..b83b2b02c0b93b94f7fd544712dd26266e0f8be5 GIT binary patch literal 385 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=oCO|{#S9F5M?jcysy3fA0|TS6 zr;B4q#hkaZ47m;&h_wB0x^PgsWAX0k8djAI{EB>!G`oWPA3ZUYIdU{GW{#{?XuRTs zkW1IvPW-R;wpOi-kNea%UGT(2h6&1y3hqn}eJl+!oD7yi3`HsoPdpev5|4EgHrt1| z?(-I~-2Qvj>68LrY zfWYTcp$Ap(yLFr=Dsx<$yN&Jb`r~g^4m54Q%W>7Ptk`8TW1FtZk=cyqWg(IeI3_YW rbH9sab=o5-QN%aZ5$Z#}y$$BZn+k;;y9GW2!<50()z4*}Q$iB}ml%(J literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Specific/Medical/Surgery/hemostat.rsi/meta.json b/Resources/Textures/Objects/Specific/Medical/Surgery/hemostat.rsi/meta.json new file mode 100644 index 00000000000..afbaa9cd516 --- /dev/null +++ b/Resources/Textures/Objects/Specific/Medical/Surgery/hemostat.rsi/meta.json @@ -0,0 +1,22 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Taken from /tg/station at https://github.com/tgstation/tgstation/commit/67d7577947b5079408dce1b7646fdd6c3df13bb5", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "hemostat" + }, + { + "name": "inhand-left", + "directions": 4 + }, + { + "name": "inhand-right", + "directions": 4 + } + ] +} diff --git a/Resources/Textures/Objects/Specific/Medical/Surgery/scalpel.rsi/0.png b/Resources/Textures/Objects/Specific/Medical/Surgery/oldscalpel.rsi/0.png similarity index 100% rename from Resources/Textures/Objects/Specific/Medical/Surgery/scalpel.rsi/0.png rename to Resources/Textures/Objects/Specific/Medical/Surgery/oldscalpel.rsi/0.png diff --git a/Resources/Textures/Objects/Specific/Medical/Surgery/scalpel.rsi/100.png b/Resources/Textures/Objects/Specific/Medical/Surgery/oldscalpel.rsi/100.png similarity index 100% rename from Resources/Textures/Objects/Specific/Medical/Surgery/scalpel.rsi/100.png rename to Resources/Textures/Objects/Specific/Medical/Surgery/oldscalpel.rsi/100.png diff --git a/Resources/Textures/Objects/Specific/Medical/Surgery/scalpel.rsi/25.png b/Resources/Textures/Objects/Specific/Medical/Surgery/oldscalpel.rsi/25.png similarity index 100% rename from Resources/Textures/Objects/Specific/Medical/Surgery/scalpel.rsi/25.png rename to Resources/Textures/Objects/Specific/Medical/Surgery/oldscalpel.rsi/25.png diff --git a/Resources/Textures/Objects/Specific/Medical/Surgery/scalpel.rsi/50.png b/Resources/Textures/Objects/Specific/Medical/Surgery/oldscalpel.rsi/50.png similarity index 100% rename from Resources/Textures/Objects/Specific/Medical/Surgery/scalpel.rsi/50.png rename to Resources/Textures/Objects/Specific/Medical/Surgery/oldscalpel.rsi/50.png diff --git a/Resources/Textures/Objects/Specific/Medical/Surgery/scalpel.rsi/75.png b/Resources/Textures/Objects/Specific/Medical/Surgery/oldscalpel.rsi/75.png similarity index 100% rename from Resources/Textures/Objects/Specific/Medical/Surgery/scalpel.rsi/75.png rename to Resources/Textures/Objects/Specific/Medical/Surgery/oldscalpel.rsi/75.png diff --git a/Resources/Textures/Objects/Specific/Medical/Surgery/scalpel.rsi/advanced-inhand-left.png b/Resources/Textures/Objects/Specific/Medical/Surgery/oldscalpel.rsi/advanced-inhand-left.png similarity index 100% rename from Resources/Textures/Objects/Specific/Medical/Surgery/scalpel.rsi/advanced-inhand-left.png rename to Resources/Textures/Objects/Specific/Medical/Surgery/oldscalpel.rsi/advanced-inhand-left.png diff --git a/Resources/Textures/Objects/Specific/Medical/Surgery/scalpel.rsi/advanced-inhand-right.png b/Resources/Textures/Objects/Specific/Medical/Surgery/oldscalpel.rsi/advanced-inhand-right.png similarity index 100% rename from Resources/Textures/Objects/Specific/Medical/Surgery/scalpel.rsi/advanced-inhand-right.png rename to Resources/Textures/Objects/Specific/Medical/Surgery/oldscalpel.rsi/advanced-inhand-right.png diff --git a/Resources/Textures/Objects/Specific/Medical/Surgery/scalpel.rsi/advanced.png b/Resources/Textures/Objects/Specific/Medical/Surgery/oldscalpel.rsi/advanced.png similarity index 100% rename from Resources/Textures/Objects/Specific/Medical/Surgery/scalpel.rsi/advanced.png rename to Resources/Textures/Objects/Specific/Medical/Surgery/oldscalpel.rsi/advanced.png diff --git a/Resources/Textures/Objects/Specific/Medical/Surgery/oldscalpel.rsi/inhand-left.png b/Resources/Textures/Objects/Specific/Medical/Surgery/oldscalpel.rsi/inhand-left.png new file mode 100644 index 0000000000000000000000000000000000000000..5c498d5f08cce46be2498bde81151ddf7dadd31c GIT binary patch literal 250 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=2R&UJLn`LHy|t0I*+9S{P&?>b zA|u-grk)AY1T$XDR21If?C~yknX8v$Yf7gXbBvfr^T$N>U-=D}@BWOrE6EHr0tiG_ zzGb`EQGJnPR@7}?p=XxmQa?@3#yYA(E;eVO7zgFJG@p{jmdGD`i&dq6|9x&Bmk rgW)gf#Md=Dk7obg{hN`2VZu@N#~MM$eyF%;gS30P`njxgN@xNA@D*ex literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Specific/Medical/Surgery/oldscalpel.rsi/inhand-right.png b/Resources/Textures/Objects/Specific/Medical/Surgery/oldscalpel.rsi/inhand-right.png new file mode 100644 index 0000000000000000000000000000000000000000..ce54cd652eb042d0ae7dd95ff8ea35f2e5816707 GIT binary patch literal 242 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=J3U<-Ln`LHy|tIO*+8J}VepbS zk6CRT#1dGd+!hp`=b3q6ZtIhIqAylVm=N(OXzB4k(tG`LZ~j~N*N+9L8wgHBg__SQ z`d50zeVx(Q+D`&<%Qa5bvISi2eOGpqwJqWL|5}c)==4pz`bw9q7TcA*l&pEPiT}U3 zU-2!0nl~kLp1HTMLkt3vMx`$A_h&jjI^)`+81Z+{{&d^zKCgT7UOf=sRT{l_S982Z h_cp7Y%|H!18s!@{8uVfz38 literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Specific/Medical/Surgery/scalpel.rsi/laser-inhand-left.png b/Resources/Textures/Objects/Specific/Medical/Surgery/oldscalpel.rsi/laser-inhand-left.png similarity index 100% rename from Resources/Textures/Objects/Specific/Medical/Surgery/scalpel.rsi/laser-inhand-left.png rename to Resources/Textures/Objects/Specific/Medical/Surgery/oldscalpel.rsi/laser-inhand-left.png diff --git a/Resources/Textures/Objects/Specific/Medical/Surgery/scalpel.rsi/laser-inhand-right.png b/Resources/Textures/Objects/Specific/Medical/Surgery/oldscalpel.rsi/laser-inhand-right.png similarity index 100% rename from Resources/Textures/Objects/Specific/Medical/Surgery/scalpel.rsi/laser-inhand-right.png rename to Resources/Textures/Objects/Specific/Medical/Surgery/oldscalpel.rsi/laser-inhand-right.png diff --git a/Resources/Textures/Objects/Specific/Medical/Surgery/scalpel.rsi/laser.png b/Resources/Textures/Objects/Specific/Medical/Surgery/oldscalpel.rsi/laser.png similarity index 100% rename from Resources/Textures/Objects/Specific/Medical/Surgery/scalpel.rsi/laser.png rename to Resources/Textures/Objects/Specific/Medical/Surgery/oldscalpel.rsi/laser.png diff --git a/Resources/Textures/Objects/Specific/Medical/Surgery/oldscalpel.rsi/meta.json b/Resources/Textures/Objects/Specific/Medical/Surgery/oldscalpel.rsi/meta.json new file mode 100644 index 00000000000..d72a4496791 --- /dev/null +++ b/Resources/Textures/Objects/Specific/Medical/Surgery/oldscalpel.rsi/meta.json @@ -0,0 +1,76 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Taken from cev-eris at https://github.com/discordia-space/CEV-Eris/commit/476e374cea95ff5e8b1603c48342bf700e2cd7af", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "shiv" + }, + { + "name": "scalpel" + }, + { + "name": "advanced" + }, + { + "name": "laser" + }, + { + "name": "shiv-inhand-left", + "directions": 4 + }, + { + "name": "shiv-inhand-right", + "directions": 4 + }, + { + "name": "inhand-left", + "directions": 4 + }, + { + "name": "inhand-right", + "directions": 4 + }, + { + "name": "advanced-inhand-left", + "directions": 4 + }, + { + "name": "advanced-inhand-right", + "directions": 4 + }, + { + "name": "laser-inhand-left", + "directions": 4 + }, + { + "name": "laser-inhand-right", + "directions": 4 + }, + { + "name": "0", + "delays": [ + [ + 0.1, + 0.1 + ] + ] + }, + { + "name": "25" + }, + { + "name": "50" + }, + { + "name": "75" + }, + { + "name": "100" + } + ] +} diff --git a/Resources/Textures/Objects/Specific/Medical/Surgery/oldscalpel.rsi/scalpel.png b/Resources/Textures/Objects/Specific/Medical/Surgery/oldscalpel.rsi/scalpel.png new file mode 100644 index 0000000000000000000000000000000000000000..8fbab261f4387147781bf3007b59cf57d3892887 GIT binary patch literal 166 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnF3?v&v(vJfvxd5LKS0KH9_p$u?{;;q#CpG0F zSFIf_22Y;9y0^_%-`s=$pk!7ya1imyW*ZAoBP9hQF4wK)N?zVsa@(tI#dGTA50_vr%=Ux5tIYw{2*3?OpuReGp z$e}k)uO`1*xWrt1a-{2IE89CiOO;yx3SV7u_xI{$Rpp+we+%{V-xs*5%wABgp4?oP zvtQ7XOE4k!zy}o}bN&}s*7rUtdG>rl|M?Y@)ceDNcC)HmL^5ufa{099{~iAEGpCgG z)Gh4_UH{c?)yEeZ-wIS3%np7^P&T={$IM9c|GC44e&z@N3#H3^QsaR5uK~B$fl>#` z4j7m+?h25aYjkpoi(zkKEW^@`K3Pm9oLL+ik7d|iGim6i1qmo@rUW)$og`gL-bxJB5i+ z!MEQ&&J&*%qQPg*S<8CC-v6NatI{{=#jhePq*~)WmK*!o)vse(W}zV`8_Tq*eYxMx ziuT2KIJvfqYyJ4vn!#iD@abFG(;KIJ4$)-eE8BimXF=_x!m>TrO@(){eBt?}mZ0x( zMRSZc|g%tFZ)I{T9thR%!4Gi2GVDUGh!)#xV=_imUg1UtC|G zAg%3rVeP-XLl(b8dstf5y${rmO_ccpRFkB^Xkse7+HmXJ(E9DJ>HC|`svitsVq3ZY vb`sEZXU-q%_caFoS+|F?2^tZ6)r|LJb&k1va53)yrVR#9S3j3^P6na*S0Ei0mZop+@#Oid^}CPd z*Y`^a=(zFwwr1v-+! M)78&qol`;+0GEtQ^Z)<= literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Specific/Medical/Surgery/retractor.rsi/inhand-left.png b/Resources/Textures/Objects/Specific/Medical/Surgery/retractor.rsi/inhand-left.png new file mode 100644 index 0000000000000000000000000000000000000000..a23bdae4c5b955ffe8519b516dadf79d9884a302 GIT binary patch literal 480 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=oCO|{#S9F5M?jcysy3fA0|VnE zPZ!6KiaBp*8G1Vr z590Rk3tSz0?EFlp!==)#N0b&l%a4`~x2bO6_hBiSZ-4jXOUrfgmn(K@KPqQRxcH|d zr%dwaTE#=vGm@1QHgA(Km+r0qU(1la=+{M&me9|aw*7Co^zmUtn<;zs?6_C6xISFn zPsswH=;Veq118p)*oB$rSFzm%c8e^cjKL-2bNy`d{4Ezopr0DhIl(f|Me literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Specific/Medical/Surgery/retractor.rsi/inhand-right.png b/Resources/Textures/Objects/Specific/Medical/Surgery/retractor.rsi/inhand-right.png new file mode 100644 index 0000000000000000000000000000000000000000..cced67007f51b69a3189eb9d6f7190721d24ee7b GIT binary patch literal 486 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=oCO|{#S9F5M?jcysy3fA0|Vm> zPZ!6KiaBp*8G0XfkU2VEp`@T7XhVSD!Llps6+|8F7_|ju~jz2rMtS_FI_*N;I(RR=8J0k6J69 z8e}*bEQJ_~R2ZIkFn}bC3z@>QxVP)zxhVd#+vO+6 z&hlTva(jPF-oc%FKZ{lTfA{O?TeBDT9$L~rZJK=gHZw$DIaf1@Jzuk8bz@lCf?$P} zr|U%2-bwIuVLA_+yANpS|KDrX-~9haoCf1I<+xqVUa7J(U$5&_*1zz&)c5hqUN@^- z3*0mq%f#Y-%XVq&C%l%Q8}sX7`|;JWE|t!*Roq8ric6fhtM^WFfkfup3rxo*ifc^g uSK7Zw{;j%1ahyWNkAtkT&Cmdw6F=)>m4r*yjRauCF?hQAxvXNVA literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Specific/Medical/Surgery/retractor.rsi/meta.json b/Resources/Textures/Objects/Specific/Medical/Surgery/retractor.rsi/meta.json new file mode 100644 index 00000000000..a38e04dcfd2 --- /dev/null +++ b/Resources/Textures/Objects/Specific/Medical/Surgery/retractor.rsi/meta.json @@ -0,0 +1,22 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Taken from /tg/station at https://github.com/tgstation/tgstation/commit/67d7577947b5079408dce1b7646fdd6c3df13bb5", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "retractor" + }, + { + "name": "inhand-left", + "directions": 4 + }, + { + "name": "inhand-right", + "directions": 4 + } + ] +} diff --git a/Resources/Textures/Objects/Specific/Medical/Surgery/retractor.rsi/retractor.png b/Resources/Textures/Objects/Specific/Medical/Surgery/retractor.rsi/retractor.png new file mode 100644 index 0000000000000000000000000000000000000000..24e04fe613a51b552d14e725e578eeabf2686c84 GIT binary patch literal 304 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnF3?v&v(vJfvl>na**8>L*NV`r^i(abQ`$)tj zMc>eV!pto{e}2s^?Y;HjRX|wk=A9S4UY->Ms%I<-@(X5gcy=QV$l2xT;uxYaF*!j& zoI`WrC&}Jk(Eyef(bk>-mN~K#0jzUmBzOW@B19xb0)0!xgd8?8WvEUzoYY`+!Ry)= zmKG-E1yf}oUKU_d<2kh`R_19YuYq)k#EdgcGs>pJN+~qHnUz zKcJSO8gVl+%2VqjuTIMZx6^wZwLEhd>nm&vySDGhDgHRko%Q+86=wc?b$j>R{@u4* z=Q4LBGYTAMQs`rKkl}8y5MwCRVR#h5aAYF`NFrUGr9LL^?v&|YvkvVr_jNe!x%m*g z38Uf5pMN*m=)YT~ZeLO(zheG@->;Whx%6~@%vr%?XMazr;-uG$L;ri1JN@T$>u5i| zoaxJCfrsbQj5oyp?F$TR?Ed`n$?Mj`3{KzEeui@4dx-B>@}~=k)Ieb!B|$ THUx$<1A`~KtDnm{r-UW|<9n$` delta 222 zcmZ3%{EKmdO8r4k7srr_Id5-mUePQPPx-?Dj_v#vADsO zuxoKiAEs|OskVEQ^_g?8-c;WgDocEJc>dj#XDm-R8E~Rfp@gE+$MdeOj+>jT%~%un zX8#l8d(8~x{Kebn+*LRISyOuKzjnjiKmT?)p1S#CwSX7nrjz;h_a^=Qvi9$fyNWGL z4YD>;d=o!~+s{|D@e}9MaMxhE6Sug&>{jQ=^w>W3z0aq=<#+hFlgZ(_+Wb_G)c*2M zb_diM8*B)mAM*?>_7|*NFZt{<+X=P*;@-~zwfoN9d&3ofXa#KjCl@4LEh@E>=hmgq&#!N1TyXN%jnx-!)H?JuZrd2{Xzrxo f&!EsRm%x7EeY;8RsbP0l+XkKvg5RY delta 214 zcmdnU{E2abO8rhx7srr_Id5<6eabIWjwf2*M+;WXmwQK=bd*7Aa zWNk~h{=b$ZEING?ufEbHtHpL@FC}ZiLuhG5DYG*T0!;VJzhKpf}AFFQigLHek L`njxgN@xNAWn^Dh diff --git a/Resources/Textures/Objects/Specific/Medical/Surgery/scalpel.rsi/meta.json b/Resources/Textures/Objects/Specific/Medical/Surgery/scalpel.rsi/meta.json index d72a4496791..7cbc1208942 100644 --- a/Resources/Textures/Objects/Specific/Medical/Surgery/scalpel.rsi/meta.json +++ b/Resources/Textures/Objects/Specific/Medical/Surgery/scalpel.rsi/meta.json @@ -1,32 +1,15 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from cev-eris at https://github.com/discordia-space/CEV-Eris/commit/476e374cea95ff5e8b1603c48342bf700e2cd7af", + "copyright": "Taken from /tg/station at https://github.com/tgstation/tgstation/commit/67d7577947b5079408dce1b7646fdd6c3df13bb5", "size": { "x": 32, "y": 32 }, "states": [ - { - "name": "shiv" - }, { "name": "scalpel" }, - { - "name": "advanced" - }, - { - "name": "laser" - }, - { - "name": "shiv-inhand-left", - "directions": 4 - }, - { - "name": "shiv-inhand-right", - "directions": 4 - }, { "name": "inhand-left", "directions": 4 @@ -34,43 +17,6 @@ { "name": "inhand-right", "directions": 4 - }, - { - "name": "advanced-inhand-left", - "directions": 4 - }, - { - "name": "advanced-inhand-right", - "directions": 4 - }, - { - "name": "laser-inhand-left", - "directions": 4 - }, - { - "name": "laser-inhand-right", - "directions": 4 - }, - { - "name": "0", - "delays": [ - [ - 0.1, - 0.1 - ] - ] - }, - { - "name": "25" - }, - { - "name": "50" - }, - { - "name": "75" - }, - { - "name": "100" } ] } diff --git a/Resources/Textures/Objects/Specific/Medical/Surgery/scalpel.rsi/scalpel.png b/Resources/Textures/Objects/Specific/Medical/Surgery/scalpel.rsi/scalpel.png index 8fbab261f4387147781bf3007b59cf57d3892887..44ec06e46319a765d5814f8eeb73d6e83931b1bb 100644 GIT binary patch delta 166 zcmV;X09pU00m1>0B!3uCOjJd{z`#&eWo>nhFEKx}xzUiBwE6k<+TiN)Rc={wRW@^JbC`=-Zoo(a}PdV^Z!5< zj3q&S!3+-1ZlnP@W}YsNAsQ2t6C@%V0&m_h)x9CX;^fTip!C#9OK|O@r%#`@O6Kw< ps6J)V(KB{Da5UB7u9XA>LzFv@XXTNKN}vf0p00i_>zJJqngDHkFhu|W diff --git a/Resources/Textures/Objects/Specific/Medical/Surgery/scissors.rsi/hemostat-inhand-left.png b/Resources/Textures/Objects/Specific/Medical/Surgery/scissors.rsi/hemostat-inhand-left.png deleted file mode 100644 index c498493780c91bc924975fb762126fde1ffd2808..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 332 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7T#lEU=;RraSW-L^Y+&Iyh8yZ$3Nab zA;;Y4ni#NRR-(X$H=5Hr+rBWKkV{Y$=Jt1V2sRGg$|d4?^+;`hw}Sb~$V=0zv%dX( z@$F9W{~h-y0u2R%hTUhvXKr7S8F=02Oxs#>yN=ib6W^MrUcKthOK0aUe|Guowf1`L z@GKMGGkgyZt}58E^ZIsi&r6>#ueli2zURZFEx&JhPx3p?zgbT8<;7JWDvYLFsd?=9 z!){N*Wy7*`TdOCn{N}fg*F!7=k^e+&E9b5^l5e_r{`=O bL&17&UXAQ)^FC_ZfK2yv^>bP0l+XkKJol9B diff --git a/Resources/Textures/Objects/Specific/Medical/Surgery/scissors.rsi/hemostat-inhand-right.png b/Resources/Textures/Objects/Specific/Medical/Surgery/scissors.rsi/hemostat-inhand-right.png deleted file mode 100644 index ac71c383af2371dfbf2d21100e7cd3e8eee11730..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 337 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7T#lEV3hE5aSW-L^Y*4;-XRBp)`!zO zl6Mq{o}9`Z6S%XnjY(j+gJ!@H#sEHng(87|f{whlvaF&)Ti*D7NRWdK+$$q_9P@BPj z>!hyuLN6X|Pi4<{$Mk2dzjiFoY3|?Yb`U#(WJA|FzuMeSRozc+v~Ag)`|z(_x>Zcr zBsZ^1&V}#S>pQZ2v|hD+=6?UFU45JH*tnkE{ByT{8Fvl;u1joRcG-F+N>8ubrtrl! gT(O>=fuZy(Z(m``a=Yx4(?J$^y85}Sb4q9e0F~g5QUCw| diff --git a/Resources/Textures/Objects/Specific/Medical/Surgery/scissors.rsi/hemostat.png b/Resources/Textures/Objects/Specific/Medical/Surgery/scissors.rsi/hemostat.png deleted file mode 100644 index 75be4d5e9c635b1453198bce5a55ee693f597348..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 201 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnF3?v&v(vJfvp#Yx{S0J5V-|rSsyngpFDFHnN z69@TFy)2+8V@Z%-FoVOh8)-mJs;7%%h{nX^1PM8Z07f6l13!H9&Lvm{aB8j3%3w;{ zuuFqW+Q5LT%}T=3;cDA13#r*{44Ey3K22RsJUmW32F^2ionxI?S$RYkv~e|GG2X%E sn44J0$;)6I)9QOcM(ouAgDH#*KEXT;ms0~7ffh1&y85}Sb4q9e0KV}y;{X5v diff --git a/Resources/Textures/Objects/Specific/Medical/Surgery/scissors.rsi/inhand-left.png b/Resources/Textures/Objects/Specific/Medical/Surgery/scissors.rsi/inhand-left.png deleted file mode 100644 index 79b85824e9d55247b7d72b5dce5e7afc1dc08566..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 356 zcmV-q0h|7bP)BJ%dWm-W-*RljBXoUM^o@aIQ!xu)4dlBzasg}xVm zd482B4lfzr+Ele^`~2H?c~P3Sd%d!$YLge`)nx`%{;W%(!IcL9000000000Oth^}y zbeW;=E`sy@01=TiTXdcY+L+FkCW^ye8P3P!UB}`!e(n(Lwkzvw=PzKlT?J`&8gR}Z z?gEk1z;o>&+p8S{jlY0*I|Nz>^rF0`e_b8`;LsODM6RUDd!JeW0000fg<4VC8 zJrk`gng8on><%-t>Sjd%000000DwwCX!O!KbP&vI?N&@{`nX+1}2mTMFzdb(~s6vc^NL-D2aCUiPrF`tXL#+m>C00000 z0002SG4{KGAT<5PTOBRhx72ezM?{Q%eZE*5pP!GohxV_;ZN4L@8`axvc5mfx8H7gD zEZ5#s*aoM=%t=qH|1^K^VbaByhP?Tz*f!!0ZZ?Sm0PyPw#0Ii`HQvC100000NkvXX Hu0mjfq#U7+ diff --git a/Resources/Textures/Objects/Specific/Medical/Surgery/scissors.rsi/meta.json b/Resources/Textures/Objects/Specific/Medical/Surgery/scissors.rsi/meta.json deleted file mode 100644 index 42737acdc7a..00000000000 --- a/Resources/Textures/Objects/Specific/Medical/Surgery/scissors.rsi/meta.json +++ /dev/null @@ -1,44 +0,0 @@ -{ - "version": 1, - "license": "CC-BY-SA-3.0", - "copyright": "Taken from cev-eris at https://github.com/discordia-space/CEV-Eris/commit/476e374cea95ff5e8b1603c48342bf700e2cd7af", - "size": { - "x": 32, - "y": 32 - }, - "states": [ - { - "name": "retractor" - }, - { - "name": "hemostat" - }, - { - "name": "setter" - }, - { - "name": "inhand-left", - "directions": 4 - }, - { - "name": "inhand-right", - "directions": 4 - }, - { - "name": "hemostat-inhand-left", - "directions": 4 - }, - { - "name": "hemostat-inhand-right", - "directions": 4 - }, - { - "name": "setter-inhand-left", - "directions": 4 - }, - { - "name": "setter-inhand-right", - "directions": 4 - } - ] -} diff --git a/Resources/Textures/Objects/Specific/Medical/Surgery/scissors.rsi/retractor.png b/Resources/Textures/Objects/Specific/Medical/Surgery/scissors.rsi/retractor.png deleted file mode 100644 index b37b9bb1a202a865a1c6c9e16fb3ca25d4c89a86..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 219 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnF3?v&v(vJfvp#Yx{S0KH9_p$u?ez$;PDFHnN z6Ng(n4LN|Kj3q&S!3+-1ZlnP@<(@8%AsQ2}`fucOaNyBRT7UT7>!W%?)E^-)pPcMHM_GZG=*XOop zAL3=6v3a>ir>NS~;0rI3?}vDMJPhO8%;hc{G^gA~@x;tWhI@bhcFt*cV78B O2@IaDelF{r5}E+j-%)J< diff --git a/Resources/Textures/Objects/Specific/Medical/Surgery/scissors.rsi/setter-inhand-left.png b/Resources/Textures/Objects/Specific/Medical/Surgery/scissors.rsi/setter-inhand-left.png deleted file mode 100644 index 6fefc908b27dd03e74c4d7feefb2b9fd515951cb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 340 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7T#lEV3hWBaSW-L^Y+%ltiu5!$3Cu4 z?iUP{77do@>6{T-{zcQtMWeQ11G`3I(i=^;Rno?WOv0kU&9C+xUn{Y8g~o34@7q%T z)T^m|KW*E-qgVxKE)Xo3{xT=iDW&ZM@3H5t&f;~CtqW{C&#t?z<+mtqy8WEHrP00W znH$u4oLI$EQ!lk!dtN&Je0tnG@%mrWUR#E5U)WT?Z}(&4)6czTU$e2jH(z&IUX-$D z{`&V_lV8j*j3~W4YtfoD_4gO8IkQl*Ioy10sNuHv%n+M_WO&e&tFF@}f4x(xxX(Xf ziOzg$ez#nobZ=qx!1X-u9~VyFxMS^Q*`~8qPv^Yf%Q*XM)|99FFUQ_*^=7`M$YJ~J jU$`~Pwi}8J3YU6vy$O;$vj!nkh>`5Qi*gj`S(SAxIt|_y7_d#HWySHj9GD`mK(c_IV;M_Bw5~Vj-ss2VtDJ^<^ccz00000006+G zroJ19;(%(!cLZ%w{m{$qRm@(H*!*3Rob&e% t?4rl0-P@n?_m1^XKH8o|lK=pq=?8^Qkv-r)XgdG^002ovPDHLkV1ht`rMLh9 diff --git a/Resources/Textures/Objects/Specific/Medical/Surgery/scissors.rsi/setter.png b/Resources/Textures/Objects/Specific/Medical/Surgery/scissors.rsi/setter.png deleted file mode 100644 index 135d8a72c4b9856ff8ab182a925a9414139047fd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 200 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnF3?v&v(vJfvp#Yx{S0J5V-|rSsEG3|~e)lm2 z6Ni?se_Mc}j3q&S!3+-1ZlnP@DV{ElAsQ2t6C~su0vM;BPsw3Q+~M#vRCew`9x+8n zL3TE`g8|Iy%o`YzGcr~z?9Mh|cGj3w=IH9k#-_+NLsGAA;jx8HOnqDi#!ii|Bz>9} sY-2dvu);*N(5*OP1>@2<=>P_Xy}P-~-Na2@fc7zXy85}Sb4q9e0LD~0L;wH) diff --git a/Resources/Textures/Objects/Specific/Robotics/borgmodule.rsi/icon-advanced-surgery.png b/Resources/Textures/Objects/Specific/Robotics/borgmodule.rsi/icon-advanced-surgery.png new file mode 100644 index 0000000000000000000000000000000000000000..291a889e4c196d0d2367f1828dd9b7bc28c5732f GIT binary patch literal 254 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz#^NA%Cx&(BWL^R}J3L(+Ln2y} z6C_v{Cy4Yk1sZU%Nf=C8<>=}8(w>=_`S9@oTb`ZU=Sq8+^>>Ew8XVaFOK4|QAOpAM ztQnj64M2cnzV(?8VQHqWd7M>@|HL%MAD$YuvIl_R!@E$q!ykV(h7_`# zyH0xwbDkR`&{@n3v6EGA*53V_4)gmdKI;Vst0H|4Ah5!Hn literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Specific/Robotics/borgmodule.rsi/icon-surgery.png b/Resources/Textures/Objects/Specific/Robotics/borgmodule.rsi/icon-surgery.png new file mode 100644 index 0000000000000000000000000000000000000000..8147a74b761d6cfc353859aab5531fd960172694 GIT binary patch literal 258 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz#^NA%Cx&(BWL^R}dpunnLn2z= zURua?C_v=c$Nh^=rfuwSZ22uxeo*6D>+EZ59!anH#iq3>%am)A= Date: Sat, 30 Nov 2024 12:07:06 -0400 Subject: [PATCH 12/35] Admin Tooling Cherry Picks (#1290) # Description Link to every PR I cherry-picked: 1. https://github.com/new-frontiers-14/frontier-station-14/pull/2283 2. https://github.com/space-wizards/space-station-14/pull/29219 3. https://github.com/space-wizards/space-station-14/pull/30075 4. https://github.com/space-wizards/space-station-14/pull/28639 5. https://github.com/space-wizards/space-station-14/pull/32527 6. https://github.com/space-wizards/space-station-14/pull/28030 7. https://github.com/space-wizards/space-station-14/pull/28178 The main purpose of this PR is the first cherry-picked PR. It adds the ability for admins to reply to ahelps via discord using an HTTP POST request. See all relevant details in the initial PR by Myzumi. --------- Co-authored-by: Myzumi <34660019+Myzumi@users.noreply.github.com> Co-authored-by: Whatstone <166147148+whatston3@users.noreply.github.com> Co-authored-by: Whatstone Co-authored-by: Pieter-Jan Briers Co-authored-by: to4no_fix <156101927+chavonadelal@users.noreply.github.com> Co-authored-by: Repo <47093363+Titian3@users.noreply.github.com> Co-authored-by: Chief-Engineer <119664036+Chief-Engineer@users.noreply.github.com> Co-authored-by: metalgearsloth Co-authored-by: Leon Friedrich <60421075+ElectroJr@users.noreply.github.com> Co-authored-by: ShadowCommander <10494922+ShadowCommander@users.noreply.github.com> --- .../UI/Bwoink/BwoinkWindow.xaml.cs | 21 +- .../CustomControls/PlayerListControl.xaml.cs | 230 +++--- .../UI/CustomControls/PlayerListEntry.xaml | 6 + .../UI/CustomControls/PlayerListEntry.xaml.cs | 58 ++ .../UI/Tabs/PlayerTab/PlayerTab.xaml | 26 +- .../UI/Tabs/PlayerTab/PlayerTab.xaml.cs | 104 ++- .../UI/Tabs/PlayerTab/PlayerTabEntry.xaml | 8 +- .../UI/Tabs/PlayerTab/PlayerTabEntry.xaml.cs | 26 +- .../UI/Tabs/PlayerTab/PlayerTabHeader.xaml | 3 +- Content.Client/Chat/Managers/ChatManager.cs | 10 + Content.Client/Chat/Managers/IChatManager.cs | 4 +- Content.Client/IoC/ClientContentIoC.cs | 9 +- .../RateLimiting/PlayerRateLimitManager.cs | 23 + Content.Client/Stylesheets/StyleNano.cs | 20 + .../UserInterface/Controls/ListContainer.cs | 39 +- .../Controls/SearchListContainer.cs | 68 ++ .../Systems/Admin/AdminUIController.cs | 9 +- Content.IntegrationTests/PoolManager.Cvars.cs | 4 +- .../Administration/Managers/AdminManager.cs | 2 +- Content.Server/Administration/ServerApi.cs | 51 +- .../Administration/Systems/BwoinkSystem.cs | 660 +++++++++++++++--- .../Chat/Managers/ChatManager.RateLimit.cs | 84 +-- Content.Server/Chat/Managers/ChatManager.cs | 19 +- Content.Server/Chat/Managers/IChatManager.cs | 10 +- Content.Server/Chat/Systems/ChatSystem.cs | 6 +- Content.Server/Discord/WebhookPayload.cs | 2 + Content.Server/Entry/EntryPoint.cs | 4 + .../GameTicking/GameTicker.GameRule.cs | 73 +- .../GameTicking/GameTicker.Player.cs | 11 + .../GameTicking/Rules/SecretRuleSystem.cs | 1 - Content.Server/IoC/ServerContentIoC.cs | 10 +- .../EntitySystems/FoodGuideDataSystem.cs | 2 +- .../RateLimiting/PlayerRateLimitManager.cs | 150 ++++ Content.Shared.Database/LogType.cs | 9 +- Content.Shared/Administration/PlayerInfo.cs | 2 + Content.Shared/CCVar/CCVars.cs | 152 +++- Content.Shared/Chat/ISharedChatManager.cs | 8 + .../Interaction/SharedInteractionSystem.cs | 31 +- .../RateLimiting/RateLimitRegistration.cs | 76 ++ .../SharedPlayerRateLimitManager.cs | 55 ++ .../Locale/en-US/administration/bwoink.ftl | 6 + .../administration/ui/tabs/player-tab.ftl | 3 + .../game-rules/gamerule-admin.ftl | 6 + .../game-ticking/game-rules/rule-secret.ftl | 2 - .../en-US/interaction/interaction-system.ftl | 3 +- .../Textures/Interface/Bwoink/pinned.png | Bin 0 -> 2267 bytes .../Textures/Interface/Bwoink/pinned2.png | Bin 0 -> 2028 bytes .../Textures/Interface/Bwoink/un_pinned.png | Bin 0 -> 2151 bytes 48 files changed, 1715 insertions(+), 391 deletions(-) create mode 100644 Content.Client/Administration/UI/CustomControls/PlayerListEntry.xaml create mode 100644 Content.Client/Administration/UI/CustomControls/PlayerListEntry.xaml.cs create mode 100644 Content.Client/Players/RateLimiting/PlayerRateLimitManager.cs create mode 100644 Content.Client/UserInterface/Controls/SearchListContainer.cs create mode 100644 Content.Server/Players/RateLimiting/PlayerRateLimitManager.cs create mode 100644 Content.Shared/Chat/ISharedChatManager.cs create mode 100644 Content.Shared/Players/RateLimiting/RateLimitRegistration.cs create mode 100644 Content.Shared/Players/RateLimiting/SharedPlayerRateLimitManager.cs create mode 100644 Resources/Locale/en-US/game-ticking/game-rules/gamerule-admin.ftl delete mode 100644 Resources/Locale/en-US/game-ticking/game-rules/rule-secret.ftl create mode 100644 Resources/Textures/Interface/Bwoink/pinned.png create mode 100644 Resources/Textures/Interface/Bwoink/pinned2.png create mode 100644 Resources/Textures/Interface/Bwoink/un_pinned.png diff --git a/Content.Client/Administration/UI/Bwoink/BwoinkWindow.xaml.cs b/Content.Client/Administration/UI/Bwoink/BwoinkWindow.xaml.cs index f8d06f758f4..6f6c1c8f6e8 100644 --- a/Content.Client/Administration/UI/Bwoink/BwoinkWindow.xaml.cs +++ b/Content.Client/Administration/UI/Bwoink/BwoinkWindow.xaml.cs @@ -16,18 +16,25 @@ public BwoinkWindow() Bwoink.ChannelSelector.OnSelectionChanged += sel => { - if (sel is not null) + if (sel is null) { - Title = $"{sel.CharacterName} / {sel.Username}"; + Title = Loc.GetString("bwoink-none-selected"); + return; + } + + Title = $"{sel.CharacterName} / {sel.Username}"; - if (sel.OverallPlaytime != null) - { - Title += $" | {Loc.GetString("generic-playtime-title")}: {sel.PlaytimeString}"; - } + if (sel.OverallPlaytime != null) + { + Title += $" | {Loc.GetString("generic-playtime-title")}: {sel.PlaytimeString}"; } }; - OnOpen += () => Bwoink.PopulateList(); + OnOpen += () => + { + Bwoink.ChannelSelector.StopFiltering(); + Bwoink.PopulateList(); + }; } } } diff --git a/Content.Client/Administration/UI/CustomControls/PlayerListControl.xaml.cs b/Content.Client/Administration/UI/CustomControls/PlayerListControl.xaml.cs index fdf935d7c04..b09cd727ef8 100644 --- a/Content.Client/Administration/UI/CustomControls/PlayerListControl.xaml.cs +++ b/Content.Client/Administration/UI/CustomControls/PlayerListControl.xaml.cs @@ -4,147 +4,155 @@ using Content.Client.Verbs.UI; using Content.Shared.Administration; using Robust.Client.AutoGenerated; +using Robust.Client.GameObjects; using Robust.Client.Graphics; using Robust.Client.UserInterface; using Robust.Client.UserInterface.Controls; using Robust.Client.UserInterface.XAML; using Robust.Shared.Input; +using Robust.Shared.Utility; -namespace Content.Client.Administration.UI.CustomControls +namespace Content.Client.Administration.UI.CustomControls; + +[GenerateTypedNameReferences] +public sealed partial class PlayerListControl : BoxContainer { - [GenerateTypedNameReferences] - public sealed partial class PlayerListControl : BoxContainer - { - private readonly AdminSystem _adminSystem; + private readonly AdminSystem _adminSystem; - private List _playerList = new(); - private readonly List _sortedPlayerList = new(); + private readonly IEntityManager _entManager; + private readonly IUserInterfaceManager _uiManager; + + private PlayerInfo? _selectedPlayer; - public event Action? OnSelectionChanged; - public IReadOnlyList PlayerInfo => _playerList; + private List _playerList = new(); + private readonly List _sortedPlayerList = new(); - public Func? OverrideText; - public Comparison? Comparison; + public Comparison? Comparison; + public Func? OverrideText; - private IEntityManager _entManager; - private IUserInterfaceManager _uiManager; + public PlayerListControl() + { + _entManager = IoCManager.Resolve(); + _uiManager = IoCManager.Resolve(); + _adminSystem = _entManager.System(); + RobustXamlLoader.Load(this); + // Fill the Option data + PlayerListContainer.ItemPressed += PlayerListItemPressed; + PlayerListContainer.ItemKeyBindDown += PlayerListItemKeyBindDown; + PlayerListContainer.GenerateItem += GenerateButton; + PlayerListContainer.NoItemSelected += PlayerListNoItemSelected; + PopulateList(_adminSystem.PlayerList); + FilterLineEdit.OnTextChanged += _ => FilterList(); + _adminSystem.PlayerListChanged += PopulateList; + BackgroundPanel.PanelOverride = new StyleBoxFlat { BackgroundColor = new Color(32, 32, 40) }; + } - private PlayerInfo? _selectedPlayer; + public IReadOnlyList PlayerInfo => _playerList; - public PlayerListControl() - { - _entManager = IoCManager.Resolve(); - _uiManager = IoCManager.Resolve(); - _adminSystem = _entManager.System(); - RobustXamlLoader.Load(this); - // Fill the Option data - PlayerListContainer.ItemPressed += PlayerListItemPressed; - PlayerListContainer.ItemKeyBindDown += PlayerListItemKeyBindDown; - PlayerListContainer.GenerateItem += GenerateButton; - PopulateList(_adminSystem.PlayerList); - FilterLineEdit.OnTextChanged += _ => FilterList(); - _adminSystem.PlayerListChanged += PopulateList; - BackgroundPanel.PanelOverride = new StyleBoxFlat {BackgroundColor = new Color(32, 32, 40)}; - } + public event Action? OnSelectionChanged; - private void PlayerListItemPressed(BaseButton.ButtonEventArgs? args, ListData? data) - { - if (args == null || data is not PlayerListData {Info: var selectedPlayer}) - return; + private void PlayerListNoItemSelected() + { + _selectedPlayer = null; + OnSelectionChanged?.Invoke(null); + } - if (selectedPlayer == _selectedPlayer) - return; + private void PlayerListItemPressed(BaseButton.ButtonEventArgs? args, ListData? data) + { + if (args == null || data is not PlayerListData { Info: var selectedPlayer }) + return; - if (args.Event.Function != EngineKeyFunctions.UIClick) - return; + if (selectedPlayer == _selectedPlayer) + return; - OnSelectionChanged?.Invoke(selectedPlayer); - _selectedPlayer = selectedPlayer; + if (args.Event.Function != EngineKeyFunctions.UIClick) + return; - // update label text. Only required if there is some override (e.g. unread bwoink count). - if (OverrideText != null && args.Button.Children.FirstOrDefault()?.Children?.FirstOrDefault() is Label label) - label.Text = GetText(selectedPlayer); - } + OnSelectionChanged?.Invoke(selectedPlayer); + _selectedPlayer = selectedPlayer; - private void PlayerListItemKeyBindDown(GUIBoundKeyEventArgs? args, ListData? data) - { - if (args == null || data is not PlayerListData { Info: var selectedPlayer }) - return; + // update label text. Only required if there is some override (e.g. unread bwoink count). + if (OverrideText != null && args.Button.Children.FirstOrDefault()?.Children?.FirstOrDefault() is Label label) + label.Text = GetText(selectedPlayer); + } - if (args.Function != EngineKeyFunctions.UIRightClick || selectedPlayer.NetEntity == null) - return; + private void PlayerListItemKeyBindDown(GUIBoundKeyEventArgs? args, ListData? data) + { + if (args == null || data is not PlayerListData { Info: var selectedPlayer }) + return; - _uiManager.GetUIController().OpenVerbMenu(selectedPlayer.NetEntity.Value, true); - args.Handle(); - } + if (args.Function != EngineKeyFunctions.UIRightClick || selectedPlayer.NetEntity == null) + return; - public void StopFiltering() - { - FilterLineEdit.Text = string.Empty; - } + _uiManager.GetUIController().OpenVerbMenu(selectedPlayer.NetEntity.Value, true); + args.Handle(); + } - private void FilterList() + public void StopFiltering() + { + FilterLineEdit.Text = string.Empty; + } + + private void FilterList() + { + _sortedPlayerList.Clear(); + foreach (var info in _playerList) { - _sortedPlayerList.Clear(); - foreach (var info in _playerList) - { - var displayName = $"{info.CharacterName} ({info.Username})"; - if (info.IdentityName != info.CharacterName) - displayName += $" [{info.IdentityName}]"; - if (!string.IsNullOrEmpty(FilterLineEdit.Text) - && !displayName.ToLowerInvariant().Contains(FilterLineEdit.Text.Trim().ToLowerInvariant())) - continue; - _sortedPlayerList.Add(info); - } - - if (Comparison != null) - _sortedPlayerList.Sort((a, b) => Comparison(a, b)); - - PlayerListContainer.PopulateList(_sortedPlayerList.Select(info => new PlayerListData(info)).ToList()); - if (_selectedPlayer != null) - PlayerListContainer.Select(new PlayerListData(_selectedPlayer)); + var displayName = $"{info.CharacterName} ({info.Username})"; + if (info.IdentityName != info.CharacterName) + displayName += $" [{info.IdentityName}]"; + if (!string.IsNullOrEmpty(FilterLineEdit.Text) + && !displayName.ToLowerInvariant().Contains(FilterLineEdit.Text.Trim().ToLowerInvariant())) + continue; + _sortedPlayerList.Add(info); } - public void PopulateList(IReadOnlyList? players = null) - { - players ??= _adminSystem.PlayerList; + if (Comparison != null) + _sortedPlayerList.Sort((a, b) => Comparison(a, b)); - _playerList = players.ToList(); - if (_selectedPlayer != null && !_playerList.Contains(_selectedPlayer)) - _selectedPlayer = null; + // Ensure pinned players are always at the top + _sortedPlayerList.Sort((a, b) => a.IsPinned != b.IsPinned && a.IsPinned ? -1 : 1); - FilterList(); - } + PlayerListContainer.PopulateList(_sortedPlayerList.Select(info => new PlayerListData(info)).ToList()); + if (_selectedPlayer != null) + PlayerListContainer.Select(new PlayerListData(_selectedPlayer)); + } - private string GetText(PlayerInfo info) - { - var text = $"{info.CharacterName} ({info.Username})"; - if (OverrideText != null) - text = OverrideText.Invoke(info, text); - return text; - } + public void PopulateList(IReadOnlyList? players = null) + { + players ??= _adminSystem.PlayerList; - private void GenerateButton(ListData data, ListContainerButton button) - { - if (data is not PlayerListData { Info: var info }) - return; - - button.AddChild(new BoxContainer - { - Orientation = LayoutOrientation.Vertical, - Children = - { - new Label - { - ClipText = true, - Text = GetText(info) - } - } - }); - - button.AddStyleClass(ListContainer.StyleClassListContainerButton); - } + _playerList = players.ToList(); + if (_selectedPlayer != null && !_playerList.Contains(_selectedPlayer)) + _selectedPlayer = null; + + FilterList(); } - public record PlayerListData(PlayerInfo Info) : ListData; + + private string GetText(PlayerInfo info) + { + var text = $"{info.CharacterName} ({info.Username})"; + if (OverrideText != null) + text = OverrideText.Invoke(info, text); + return text; + } + + private void GenerateButton(ListData data, ListContainerButton button) + { + if (data is not PlayerListData { Info: var info }) + return; + + var entry = new PlayerListEntry(); + entry.Setup(info, OverrideText); + entry.OnPinStatusChanged += _ => + { + FilterList(); + }; + + button.AddChild(entry); + button.AddStyleClass(ListContainer.StyleClassListContainerButton); + } } + +public record PlayerListData(PlayerInfo Info) : ListData; diff --git a/Content.Client/Administration/UI/CustomControls/PlayerListEntry.xaml b/Content.Client/Administration/UI/CustomControls/PlayerListEntry.xaml new file mode 100644 index 00000000000..af13ccc0e09 --- /dev/null +++ b/Content.Client/Administration/UI/CustomControls/PlayerListEntry.xaml @@ -0,0 +1,6 @@ + + diff --git a/Content.Client/Administration/UI/CustomControls/PlayerListEntry.xaml.cs b/Content.Client/Administration/UI/CustomControls/PlayerListEntry.xaml.cs new file mode 100644 index 00000000000..cd6a56ea71e --- /dev/null +++ b/Content.Client/Administration/UI/CustomControls/PlayerListEntry.xaml.cs @@ -0,0 +1,58 @@ +using Content.Client.Stylesheets; +using Content.Shared.Administration; +using Robust.Client.AutoGenerated; +using Robust.Client.GameObjects; +using Robust.Client.UserInterface.Controls; +using Robust.Client.UserInterface.XAML; +using Robust.Shared.Utility; + +namespace Content.Client.Administration.UI.CustomControls; + +[GenerateTypedNameReferences] +public sealed partial class PlayerListEntry : BoxContainer +{ + public PlayerListEntry() + { + RobustXamlLoader.Load(this); + } + + public event Action? OnPinStatusChanged; + + public void Setup(PlayerInfo info, Func? overrideText) + { + Update(info, overrideText); + PlayerEntryPinButton.OnPressed += HandlePinButtonPressed(info); + } + + private Action HandlePinButtonPressed(PlayerInfo info) + { + return args => + { + info.IsPinned = !info.IsPinned; + UpdatePinButtonTexture(info.IsPinned); + OnPinStatusChanged?.Invoke(info); + }; + } + + private void Update(PlayerInfo info, Func? overrideText) + { + PlayerEntryLabel.Text = overrideText?.Invoke(info, $"{info.CharacterName} ({info.Username})") ?? + $"{info.CharacterName} ({info.Username})"; + + UpdatePinButtonTexture(info.IsPinned); + } + + private void UpdatePinButtonTexture(bool isPinned) + { + if (isPinned) + { + PlayerEntryPinButton?.RemoveStyleClass(StyleNano.StyleClassPinButtonUnpinned); + PlayerEntryPinButton?.AddStyleClass(StyleNano.StyleClassPinButtonPinned); + } + else + { + PlayerEntryPinButton?.RemoveStyleClass(StyleNano.StyleClassPinButtonPinned); + PlayerEntryPinButton?.AddStyleClass(StyleNano.StyleClassPinButtonUnpinned); + } + } +} diff --git a/Content.Client/Administration/UI/Tabs/PlayerTab/PlayerTab.xaml b/Content.Client/Administration/UI/Tabs/PlayerTab/PlayerTab.xaml index 3071bf8358b..25a96df1d37 100644 --- a/Content.Client/Administration/UI/Tabs/PlayerTab/PlayerTab.xaml +++ b/Content.Client/Administration/UI/Tabs/PlayerTab/PlayerTab.xaml @@ -1,21 +1,19 @@  + xmlns:cc="clr-namespace:Content.Client.Administration.UI.CustomControls" + xmlns:co="clr-namespace:Content.Client.UserInterface.Controls"> -